웹 프론트엔드 H5 튜토리얼 HTML5 Canvas의 성능을 최적화하기 위해 캐시를 사용하는 방법에 대한 간략한 설명 program_html5 튜토리얼 기술

HTML5 Canvas의 성능을 최적화하기 위해 캐시를 사용하는 방법에 대한 간략한 설명 program_html5 튜토리얼 기술

May 16, 2016 pm 03:46 PM
canvas html5

캔버스를 너무 많이 사용하면 자동으로 성능 문제를 고려하게 됩니다. 캔버스 애니메이션을 최적화하는 방법은 무엇입니까?

【캐시 사용하기】

캐시를 사용한다는 것은 사전 렌더링에 오프스크린 캔버스를 사용한다는 의미입니다. 즉, 먼저 오프스크린 캔버스에 그린 다음 drawImage를 통해 오프스크린 캔버스를 메인 캔버스에 그리는 것입니다. 많은 사람들이 이것을 오해할 수도 있습니다. 이것은 게임에서 많이 사용되는 이중 버퍼링 메커니즘이 아닌가요?

실제로 게임 프로그래밍에서는 화면 깜박임을 방지하기 위해 이중 버퍼링 메커니즘이 사용됩니다. 따라서 사용자 앞에 캔버스가 표시되고 그림을 그릴 때 화면 내용이 먼저 그려집니다. 배경 캔버스를 그리면 캔버스의 데이터가 전면 캔버스에 그려집니다. 이는 이중 버퍼링이지만 캔버스에는 이중 버퍼링이 없습니다. 최신 브라우저에는 기본적으로 이중 버퍼링 메커니즘이 내장되어 있기 때문입니다. 따라서 오프스크린 캔버스를 사용하는 것은 더블 버퍼링이 아니라 오프스크린 캔버스를 캐시 영역으로 취급하는 것입니다. 캔버스 API 호출 소모를 줄이기 위해 반복적으로 그려야 하는 캐시 화면 데이터입니다.

우리 모두 알고 있듯이 캔버스 API를 호출하면 성능이 소모됩니다. 따라서 반복되는 화면 데이터를 그리려는 경우 오프 스크린 캔버스를 적절하게 사용하면 다음 DEMO를 살펴볼 수 있습니다.

1. 캐시를 사용하지 않습니다

 2.캐시를 사용하지만 오프스크린 캔버스의 너비와 높이가 설정되지 않았습니다

3. 캐시를 사용하지만 오프스크린 캔버스의 너비와 높이가 설정되지 않았습니다

 4. 캐싱을 사용하고 오프스크린 캔버스의 너비와 높이를 설정합니다

위 DEMO의 성능이 다르다는 것을 알 수 있습니다. 아래에서 이유를 분석해 보겠습니다. 각 원의 스타일을 구현하기 위해 원을 그릴 때 캐싱이 활성화되지 않은 경우 루프 그리기를 사용했습니다. 페이지의 원이 특정 지점에 도달하면 애니메이션의 각 프레임마다 많은 수의 캔버스 API 호출이 필요하고 많은 양의 계산이 필요하므로 브라우저가 아무리 좋아도 가져옵니다. 아래에.
XML/HTML 코드클립보드에 콘텐츠 복사

  1. ctx.save();   
  2.                       var j=0;   
  3.                        ctx.lineWidth = borderWidth;   
  4.                        for(var i=1;i<this.r;i =borderWidth){   
  5.                            ctx.beginPath();   
  6.                            ctx.StrokeStyle = 이것.color[j];   
  7.                           ctx.arc(this.x , this.y , i , 0 , 2*Math.PI);   
  8.                            ctx.Stroke();   
  9.                            j ;   
  10.                        }   
  11.                        ctx.restore();  

  所以, 내 방식의 방법은 다음과 같습니다.

  除了创建离屏canvas works 为缓存 륙외, 하단의 현대적인 码中有一点很关键, 就是要设置离屏canvas적 크기와 높이, canvas生成后的默认大小是300 X150; 对于我的代码中每个缓存起来圈圈对象半径最大也就不超过80,所以300X150的大区域,会造成资源浪费,所以就要设置一下离屏캔버스의 크기와 높이, 让它跟缓存起来적 元素大小一致,这样也有利于提高动画性能。上side 4个demo很明显的显示了性能差距,如果没有设置宽高,当页side超过400个圈圈对象时就会卡的不行了,而设置了宽高1000个圈圈对象也不觉得卡。

XML/HTML 코드复复内容到剪贴板
  1. var  = 함수(x , y , vx , vy , useCache){   
  2.                this.x = x;   
  3.                this.y = y;   
  4.                this.vx = vx;   
  5.                this.vy = vy;   
  6.                this.r = getZ(getRandom(20,40));   
  7.                this.color = [];   
  8.                this.cacheCanvas = document.createElement("canvas");   
  9.                thisthis.cacheCtx = this.cacheCanvas.getContext("2d");   
  10.                this.cacheCanvas.width = 2*this.r;   
  11.                this.cacheCanvas.height = 2*this.r;   
  12.                var num = getZ(this.r/borderWidth);   
  13.                for(var j=0;j<번호;j ){   
  14.                    this.color.push("rgba(" getZ(getRandom(0,255)) "," getZ(getRandom(0,255)) "," getZ(getRandom(0,255)) ",1)");   
  15.                 }   
  16.                this.useCache = useCache;   
  17.                 if(useCache){   
  18.                    this.cache();   
  19.                 }   
  20.             }  

원 개체를 인스턴스화할 때 캐시 메서드를 직접 호출하고 원 개체의 오프스크린 캔버스에 복잡한 원을 직접 그려서 저장합니다.

XML/HTML 코드클립보드에 콘텐츠 복사
  1. 캐시:함수(){
  2. this.cacheCtx.save()
  3. var j=0;
  4. this.cacheCtx.lineWidth = borderWidth
  5. for(var
  6. i=1;i<this.r;i =borderWidth){
  7. this.cacheCtx.beginPath()
  8.  
  9. thisthis.cacheCtx.StrokeStyle = this.color[j]; this.cacheCtx.arc(this.r, this.r, i, 0, 2*Math.PI)
  10. this.cacheCtx.Stroke()
  11.                                                               
  12. this.cacheCtx.restore()
  13.                                                                           
  14. 그런 다음 다음 애니메이션에서는 원 개체의 오프스크린 캔버스를 기본 캔버스에 그리기만 하면 됩니다. 이런 식으로 각 프레임에서 호출되는 canvasAPI에는 다음 문장만 있습니다.
  15. XML/HTML 코드
클립보드에 콘텐츠 복사

ctx.drawImage(this.cacheCanvas , this.x-this.r , this.y-this.r)
  1. 이전 for 루프 그리기에 비해 정말 훨씬 빠릅니다. 따라서 벡터 그래픽을 반복적으로 그리거나 여러 그림을 그려야 하는 경우 오프스크린 캔버스를 합리적으로 사용하여 그림 데이터를 미리 캐시할 수 있으므로 각 후속 작업에서 불필요한 성능 소비를 많이 줄일 수 있습니다. 원 개체 1000개에 대한 매끄러운 버전 코드는 다음과 같습니다.  
XML/HTML 코드

클립보드에 콘텐츠 복사


  1. >  
  2. <html lang="ko" >  
  3. <머리>  
  4.     <메타 문자 집합="UTF- 8">  
  5.     <스타일>  
  6.         몸{   
  7.             패딩:0;   
  8.             여백:0;   
  9.             오버플로: 숨김;   
  10.         }   
  11.         #cas{   
  12.             디스플레이: 차단;   
  13.             배경색:rgba(0,0,0,0);   
  14.             여백:자동;   
  15.             테두리:1px 단색;   
  16.         }
  17.  스타일> 
  18.  <제목>테스트제목>
  19. 머리>
  20. <>
  21. <div >
  22.  <캔버스 id='cas' 너비="800" 높이="600">브라우저가 캔버스를 지원하지 않습니다캔버스 > ;
  23.  <div style="text- align:center">1000개의 원 개체가 붙어 있지 않습니다div>
  24.  div> 
  25.  <스크립트> 
  26. var testBox = 함수(){
  27. var 캔버스 = 문서.getElementById("cas"),
  28. ctx = 캔버스.getContext('2d'),
  29.  테두리 너비 = 2,
  30. = []
  31. var = 함수(x, y, vx, vy, useCache){
  32.  this.x = x
  33.  this.y = y;
  34.  
  35. this.vx = vx
  36.                this.vy = vy;   
  37.                this.r = getZ(getRandom(20,40));   
  38.                this.color = [];   
  39.                this.cacheCanvas = document.createElement("canvas");   
  40.                thisthis.cacheCtx = this.cacheCanvas.getContext("2d");   
  41.                this.cacheCanvas.width = 2*this.r;   
  42.                this.cacheCanvas.height = 2*this.r;   
  43.                var num = getZ(this.r/borderWidth);   
  44.                for(var j=0;j<번호;j ){   
  45.                    this.color.push("rgba(" getZ(getRandom(0,255)) "," getZ(getRandom(0,255)) "," getZ(getRandom(0,255)) ",1)");   
  46.                 }   
  47.                this.useCache = useCache;   
  48.                 if(useCache){   
  49.                    this.cache();   
  50.                 }   
  51.             }  
  52.   
  53.             함수 getZ(num){   
  54.                 var 반올림;   
  55.                반올림 = (0.5   num) | 0;   
  56.                 // 더블비트가 아닙니다.   
  57.                반올림 = ~~ (0.5   num);   
  58.                 // 마지막으로 왼쪽 비트 시프트입니다.   
  59.                반올림 = (0.5   num) << 0;   
  60.   
  61.                 반올림하여 반환합니다.   
  62.             }  
  63.   
  64.             ball.prototype = {   
  65.                 페인트:기능(ctx){   
  66.                    if(!this.useCache){   
  67.                        ctx.save();   
  68.                       var j=0;   
  69.                        ctx.lineWidth = borderWidth;   
  70.                        for(var i=1;i<this.r;i =borderWidth){   
  71.                            ctx.beginPath();   
  72.                            ctx.StrokeStyle = 이것.color[j];   
  73.                           ctx.arc(this.x , this.y , i , 0 , 2*Math.PI);   
  74.                            ctx.Stroke();   
  75.                            j ;   
  76.                        }   
  77.                        ctx.restore();   
  78.                    } 그 외{   
  79.                        ctx.drawImage(this.cacheCanvas , this.x-this.r , this.y-this.r);   
  80.                    }   
  81.                 },   
  82.   
  83.                 캐시:기능(){   
  84.                    this.cacheCtx.save();   
  85.                    var j=0;   
  86.                    this.cacheCtx.lineWidth = borderWidth;   
  87.                    for(var i=1;i<this.r;i =borderWidth){   
  88.                        this.cacheCtx.beginPath();   
  89.                        thisthis.cacheCtx.StrokeStyle = this.color[j];   
  90.                       this.cacheCtx.arc(this.r , this.r , i , 0 , 2*Math.PI);   
  91.                        this.cacheCtx.Stroke();   
  92.                        j ;   
  93.                    }   
  94.                    this.cacheCtx.restore();   
  95.                 },   
  96.   
  97.                 이동:기능(){   
  98.                    this.x  = this.vx;   
  99.                    this.y  = this.vy;   
  100.                    if(this.x>(canvas.width-this.r)||this.x< this.r){   
  101.                        thisthis.x=this.x<this.r?this.r:(canvas.width-this.r);   
  102.                        this.vx = -this.vx;   
  103.                     }  
  104.                    if(this.y>(canvas.height-this.r)||this.y< this.r){   
  105.                        thisthis.y=this.y<this.r?this.r:(canvas.height-this.r);   
  106.                        this.vy = -this.vy;   
  107.                    }   
  108.   
  109.                    this.paint(ctx);   
  110.                 }   
  111.             }   
  112.   
  113.             var 게임 = {   
  114.                 init:function(){   
  115.                    for(var i=0;i<1000;i ){   
  116.                        var b = new ball(getRandom(0,canvas.width) , getRandom(0,canvas .height) , getRandom(-10 , 10) ,  getRandom(-10 , 10) , true)   
  117.                        Balls.push(b);   
  118.                    }   
  119.                 },   
  120.   
  121.                 업데이트:기능(){   
  122.                    ctx.clearRect(0,0,canvas.width,canvas.height);   
  123.                    for(var i=0;i<공.길이;i ){   
  124.                        공[i].move();   
  125.                    }   
  126.                 },   
  127.   
  128.                 loop:function(){   
  129.                    var _this = this;   
  130.                    this.update();   
  131.                    RAF(함수(){   
  132.                        _this.loop();   
  133.                    })   
  134.                 },   
  135.   
  136.                 start:function(){   
  137.                    this.init();   
  138.                     this.loop();   
  139.                 }   
  140.             }   
  141.   
  142.             window.RAF = (function(){   
  143.                 return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || 함수 (콜백) {window.setTimeout(콜백, 1000 / 60); };   
  144.             })();   
  145.   
  146.             게임 반환;   
  147.         }();   
  148.   
  149.         함수 getRandom(a , b){   
  150.             반환 Math.random()*(ba) a;   
  151.         }   
  152.   
  153.         window.onload = 함수(){   
  154.             testBox.start();   
  155.         }   
  156.     스크립트>  
  157. >  
  158. html>  

오프 스크린 캔버스에 대한 또 다른 참고 사항이 있습니다. 지속적으로 객체를 생성하고 파괴하는 것이라면, 적어도 위에서 쓴 것처럼 각 객체의 속성을 바인딩하지 않도록 주의하세요. 오프스크린 캔버스를 설정합니다.

이렇게 바인딩하면 객체가 소멸되면 오프스크린 캔버스도 소멸되며, 수많은 오프스크린 캔버스가 지속적으로 생성 및 소멸되므로 캔버스 버퍼가 GPU 리소스가 많아 브라우저가 쉽게 충돌하거나 심각한 프레임 정지가 발생할 수 있습니다. 해결책은 오프스크린 캔버스 배열을 만들고, 충분한 수의 오프스크린 캔버스를 미리 로드하고, 아직 살아있는 객체만 캐시하고, 객체가 소멸되면 캐시를 취소하는 것입니다. 이로 인해 오프스크린 캔버스가 파괴되지는 않습니다.

【requestAnimationFrame 사용】

이에 대해서는 자세히 설명하지 않겠습니다. setTimeout이나 setInterval이 아닌 이것이 애니메이션에 가장 적합한 루프라는 것을 많은 사람들이 알고 있을 것입니다. 호환성 작성법 직접 게시:

XML/HTML 코드클립보드에 콘텐츠 복사
  1. window.RAF = (function(){
  2. window.requestAnimationFrame || window.mozRequestAnimationFrame || window.msRequestAnimationFrame || 함수(콜백)
  3. })()

 

【부동소수점 연산 피하기】

JavaScript는 Math.floor, Math.ceil 및parseInt와 같은 몇 가지 매우 편리한 반올림 메서드를 제공하지만 외국 친구들은 테스트를 수행했으며parseInt 메서드는 몇 가지 추가 작업(예: 데이터가 유효한 값인지 감지하고,parseInt)을 수행합니다. 심지어 매개변수를 먼저 문자열로 변환하기도 합니다!) 따라서 직접parseInt를 사용하는 것은 상대적으로 성능 집약적입니다. 따라서 반올림하는 방법은 외국인이 작성한 매우 영리한 방법을 직접 사용할 수 있습니다.

    JavaScript 코드클립보드에 콘텐츠 복사

    1.반올림 = (0.5 somenum)

    2.반올림 = ~~ (0.5 somenum) 3.rounded = (0.5 somenum)

    연산자를 이해하지 못하시면 여기를 클릭하세요: http://www.w3school.com.cn/js/pro_js_operators_bitwise.asp 안에 자세한 설명이 있습니다

 

【canvasAPI 호출을 최대한 줄입니다】

파티클 효과를 만들 때는 원을 최대한 적게 사용하고, 파티클이 너무 작기 때문에 사각형을 사용하는 것이 좋습니다. 그 이유는 이해하기 쉽습니다. 원을 그리려면 세 단계가 필요합니다. 먼저 startPath를 사용한 다음 arc를 사용하여 호를 그린 다음 fill을 사용하여 원을 만듭니다. 하지만 정사각형을 그리려면 fillRect가 하나만 필요합니다. 두 호출의 차이만 있을 뿐이지만 입자 개체의 수가 일정 수준에 도달하면 성능 격차가 나타납니다.

그 밖에도 주의할 사항이 있는데, Google에 꽤 많이 있기 때문에 모두 나열하지는 않겠습니다. 이는 나 자신을 위한 기록이라 할 수 있으며, 주로 캐시의 사용량을 기록하기 위한 것이다. 캔버스의 성능을 향상시키려면 가장 중요한 것은 코드 구조에 주의를 기울이고, 불필요한 API 호출을 줄이고, 각 프레임의 복잡한 작업을 줄이거나, 복잡한 작업을 프레임당 한 번에서 여러 프레임에 한 번으로 변경하는 것입니다. 프레임. 동시에 위에서 언급한 캐시 활용을 위해 각 개체에 대해 오프스크린 캔버스를 사용했습니다. 실제로 오프스크린 캔버스를 너무 많이 사용하면 너무 광범위하게 사용할 수 없습니다. 성능 문제가 발생할 수 있으니 최대한 오프스크린 캔버스를 활용해 보세요.

소스코드 주소 : https://github.com/whxaxes/canvas-test/tree/gh-pages/src/Other-demo/cache

본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

Video Face Swap

Video Face Swap

완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

뜨거운 도구

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전

SublimeText3 중국어 버전

중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)

HTML의 테이블 테두리 HTML의 테이블 테두리 Sep 04, 2024 pm 04:49 PM

HTML의 테이블 테두리 안내. 여기에서는 HTML의 테이블 테두리 예제를 사용하여 테이블 테두리를 정의하는 여러 가지 방법을 논의합니다.

HTML 여백-왼쪽 HTML 여백-왼쪽 Sep 04, 2024 pm 04:48 PM

HTML 여백-왼쪽 안내. 여기에서는 HTML margin-left에 대한 간략한 개요와 코드 구현과 함께 예제를 논의합니다.

HTML의 중첩 테이블 HTML의 중첩 테이블 Sep 04, 2024 pm 04:49 PM

HTML의 Nested Table에 대한 안내입니다. 여기에서는 각 예와 함께 테이블 내에 테이블을 만드는 방법을 설명합니다.

HTML 테이블 레이아웃 HTML 테이블 레이아웃 Sep 04, 2024 pm 04:54 PM

HTML 테이블 레이아웃 안내. 여기에서는 HTML 테이블 레이아웃의 값에 대해 예제 및 출력 n 세부 사항과 함께 논의합니다.

HTML 입력 자리 표시자 HTML 입력 자리 표시자 Sep 04, 2024 pm 04:54 PM

HTML 입력 자리 표시자 안내. 여기서는 코드 및 출력과 함께 HTML 입력 자리 표시자의 예를 논의합니다.

HTML에서 텍스트 이동 HTML에서 텍스트 이동 Sep 04, 2024 pm 04:45 PM

HTML에서 텍스트 이동 안내. 여기서는 Marquee 태그가 구문과 함께 작동하는 방식과 구현할 예제에 대해 소개합니다.

HTML 정렬 목록 HTML 정렬 목록 Sep 04, 2024 pm 04:43 PM

HTML 순서 목록에 대한 안내입니다. 여기서는 HTML Ordered 목록 및 유형에 대한 소개와 각각의 예에 대해서도 설명합니다.

HTML 온클릭 버튼 HTML 온클릭 버튼 Sep 04, 2024 pm 04:49 PM

HTML onclick 버튼에 대한 안내입니다. 여기에서는 각각의 소개, 작업, 예제 및 다양한 이벤트의 onclick 이벤트에 대해 설명합니다.

See all articles