search
HomeWeb Front-endH5 TutorialA brief discussion on using cache to optimize the performance of HTML5 Canvas program_html5 tutorial skills

After you play with canvas too much, you will automatically start to consider performance issues. How to optimize canvas animation?

【Use cache】

Using cache means using off-screen canvas for pre-rendering. The principle is very simple, that is, first draw into an off-screen canvas, and then draw the off-screen canvas into the main canvas through drawImage. Many people may misunderstand this. Isn't this a double-buffering mechanism used a lot in games?

In fact, the double buffering mechanism is used in game programming to prevent screen flickering. Therefore, there will be a canvas displayed in front of the user and a background canvas. When drawing, the screen content will first be drawn to the background canvas, and then the background canvas will be drawn. The data in the canvas is drawn to the front canvas. This is double buffering, but there is no double buffering in canvas, because modern browsers basically have a built-in double buffering mechanism. Therefore, using off-screen canvas is not double buffering, but treating off-screen canvas as a cache area. Cache screen data that needs to be drawn repeatedly to reduce the consumption of calling the canvas API.

As we all know, calling the canvas API consumes performance. Therefore, when we want to draw some repeated screen data, proper use of off-screen canvas can greatly improve performance. You can take a look at the following DEMO

1. No cache is used

 2. Cache is used but the width and height of the off-screen canvas are not set

3. Cache is used but the width and height of the off-screen canvas are not set

 4. Use caching and set the width and height of the off-screen canvas

You can see that the performance of the above DEMO is different. Let’s analyze the reasons below: In order to achieve the style of each circle, I used loop drawing when drawing circles. If caching is not enabled, when the number of circles on the page When it reaches a certain point, a large number of canvas API calls are required for each frame of the animation, and a large amount of calculations are required, so that no matter how good the browser is, it will be brought down.
XML/HTML CodeCopy content to clipboard

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

  所以,我的方法很简单,每个圈圈对象里面给他一个离屏canvas作缓存区。

  除了创建离屏canvas作为缓存之外,下面的代码中有一点很关键,就是要设置离屏canvas的宽度和高度,canvas生成后的默认大小是300X150;对于我的代码中每个缓存起来圈圈对象半径最大也就不超过80,所以300X150的大小明显会造成很多空白区域,会造成资源浪费,所以就要设置一下离屏canvas的宽度和高度,让它跟缓存起来的元素大小一致,这样也有利于提高动画性能。上面的四个demo很明显的显示出了性能差距,如果没有设置宽高,当页面超过400个圈圈对象时就会卡的不行了,而设置了宽高1000个圈圈对象也不觉得卡。

XML/HTML Code复制内容到剪贴板
  1. var ball = function(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;jnum;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.             }  

When I instantiate the circle object, I directly call the cache method and draw the complex circle directly into the off-screen canvas of the circle object and save it.

XML/HTML CodeCopy content to clipboard
  1. cache:function(){
  2. this.cacheCtx.save();
  3. var j=0;
  4. this.cacheCtx.lineWidth = borderWidth;
  5. for(var i=1;ithis.r;i =borderWidth){
  6. this.cacheCtx.beginPath();
  7.  thisthis.cacheCtx.strokeStyle = this.color[j];
  8. this.cacheCtx.arc(this.r, this.r, i, 0, 2*Math.PI);
  9. this.cacheCtx.stroke();
  10. j ;
  11.                                                                       
  12. this.cacheCtx.restore();
  13.                                                                                     
  14. Then in the next animation, I only need to draw the off-screen canvas of the circle object into the main canvas. In this way, the canvasAPI called in each frame only has this sentence:

XML/HTML Code

Copy content to clipboard
ctx.drawImage(this.cacheCanvas , this.x-this.r , this.y-this.r);
  1. Compared with the previous for loop drawing, it is really much faster. So when we need to repeatedly draw vector graphics or draw multiple pictures, we can reasonably use the off-screen canvas to cache the picture data in advance, which can reduce a lot of unnecessary performance consumption in each subsequent frame. operation.
The smooth version code for 1000 circle objects is posted below:
 


XML/HTML Code

Copy content to clipboard
  1. html>  
  2. html lang="en">  
  3. head>  
  4.     meta charset="UTF-8">  
  5.     style>  
  6.         body{   
  7.             padding:0;   
  8.             margin:0;   
  9.             overflow: hidden;   
  10.         }   
  11.         #cas{   
  12.             display: block;   
  13.             background-color:rgba(0,0,0,0);   
  14.             margin:auto;   
  15.             border:1px solid;   
  16.         }
  17.  style> 
  18.  title>Testtitle>
  19. head>
  20. body>
  21. div >
  22.  canvas id='cas' width="800" height="600">The browser does not support canvascanvas> ;
  23.  div style="text- align:center">1000 circle objects are not stuckdiv>
  24.  div> 
  25.  script> 
  26. var testBox = function(){
  27. var canvas = document.getElementById("cas"),
  28. ctx = canvas.getContext('2d'),
  29.  borderWidth = 2,
  30. Balls = [];
  31. var ball = function(x, y, vx, vy, useCache){
  32.  this.x = x;
  33.  this.y = y;
  34.  this.vx = vx;
  35.                 this.vy = vy;   
  36.                 this.r = getZ(getRandom(20,40));   
  37.                 this.color = [];   
  38.                 this.cacheCanvas = document.createElement("canvas");   
  39.                 thisthis.cacheCtx = this.cacheCanvas.getContext("2d");   
  40.                 this.cacheCanvas.width = 2*this.r;   
  41.                 this.cacheCanvas.height = 2*this.r;   
  42.                 var num = getZ(this.r/borderWidth);   
  43.                 for(var j=0;jnum;j ){   
  44.                     this.color.push("rgba(" getZ(getRandom(0,255)) "," getZ(getRandom(0,255)) "," getZ(getRandom(0,255)) ",1)");   
  45.                 }   
  46.                 this.useCache = useCache;   
  47.                 if(useCache){   
  48.                     this.cache();   
  49.                 }   
  50.             }  
  51.   
  52.             function getZ(num){   
  53.                 var rounded;   
  54.                 rounded = (0.5   num) | 0;   
  55.                 // A double bitwise not.   
  56.                 rounded = ~~ (0.5   num);   
  57.                 // Finally, a left bitwise shift.   
  58.                 rounded = (0.5   num)  0;   
  59.   
  60.                 return rounded;   
  61.             }  
  62.   
  63.             ball.prototype = {   
  64.                 paint:function(ctx){   
  65.                     if(!this.useCache){   
  66.                         ctx.save();   
  67.                         var j=0;   
  68.                         ctx.lineWidth = borderWidth;   
  69.                         for(var i=1;ithis.r;i =borderWidth){   
  70.                             ctx.beginPath();   
  71.                             ctx.strokeStyle = this.color[j];   
  72.                             ctx.arc(this.x , this.y , i , 0 , 2*Math.PI);   
  73.                             ctx.stroke();   
  74.                             j ;   
  75.                         }   
  76.                         ctx.restore();   
  77.                     } else{   
  78.                         ctx.drawImage(this.cacheCanvas , this.x-this.r , this.y-this.r);   
  79.                     }   
  80.                 },   
  81.   
  82.                 cache:function(){   
  83.                     this.cacheCtx.save();   
  84.                     var j=0;   
  85.                     this.cacheCtx.lineWidth = borderWidth;   
  86.                     for(var i=1;ithis.r;i =borderWidth){   
  87.                         this.cacheCtx.beginPath();   
  88.                         thisthis.cacheCtx.strokeStyle = this.color[j];   
  89.                         this.cacheCtx.arc(this.r , this.r , i , 0 , 2*Math.PI);   
  90.                         this.cacheCtx.stroke();   
  91.                         j ;   
  92.                     }   
  93.                     this.cacheCtx.restore();   
  94.                 },   
  95.   
  96.                 move:function(){   
  97.                     this.x  = this.vx;   
  98.                     this.y  = this.vy;   
  99.                     if(this.x>(canvas.width-this.r)||this.xthis.r){   
  100.                         thisthis.x=this.xthis.r?this.r:(canvas.width-this.r);   
  101.                         this.vx = -this.vx;   
  102.                     }  
  103.                     if(this.y>(canvas.height-this.r)||this.ythis.r){   
  104.                         thisthis.y=this.ythis.r?this.r:(canvas.height-this.r);   
  105.                         this.vy = -this.vy;   
  106.                     }   
  107.   
  108.                     this.paint(ctx);   
  109.                 }   
  110.             }   
  111.   
  112.             var Game = {   
  113.                 init:function(){   
  114.                     for(var i=0;i1000;i ){   
  115.                         var b = new ball(getRandom(0,canvas.width) , getRandom(0,canvas.height) , getRandom(-10 , 10) ,  getRandom(-10 , 10) , true)   
  116.                         Balls.push(b);   
  117.                     }   
  118.                 },   
  119.   
  120.                 update:function(){   
  121.                     ctx.clearRect(0,0,canvas.width,canvas.height);   
  122.                     for(var i=0;iBalls.length;i ){   
  123.                         Balls[i].move();   
  124.                     }   
  125.                 },   
  126.   
  127.                 loop:function(){   
  128.                     var _this = this;   
  129.                     this.update();   
  130.                     RAF(function(){   
  131.                         _this.loop();   
  132.                     })   
  133.                 },   
  134.   
  135.                 start:function(){   
  136.                     this.init();   
  137.                     this.loop();   
  138.                 }   
  139.             }   
  140.   
  141.             window.RAF = (function(){   
  142.                 return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function (callback) {window.setTimeout(callback, 1000 / 60); };   
  143.             })();   
  144.   
  145.             return Game;   
  146.         }();   
  147.   
  148.         function getRandom(a , b){   
  149.             return Math.random()*(b-a) a;   
  150.         }   
  151.   
  152.         window.onload = function(){   
  153.             testBox.start();   
  154.         }   
  155.     script>  
  156. body>  
  157. html>  

There is another note about off-screen canvas. If the effect you do is to continuously create and destroy objects, please use off-screen canvas with caution. At least do not bind the attributes of each object as I wrote above. Set off-screen canvas.

Because if bound like this, when the object is destroyed, the off-screen canvas will also be destroyed, and a large number of off-screen canvases are constantly being created and destroyed, which will cause the canvas buffer to consume a lot of GPU resources and easily cause the browser to Crash or serious frame freeze. The solution is to create an off-screen canvas array, preload a sufficient number of off-screen canvases, cache only the objects that are still alive, and uncache them when the objects are destroyed. This will not cause the off-screen canvas to be destroyed.

【Use requestAnimationFrame】

I won’t explain this in detail. I guess many people know that this is the best loop for animation, not setTimeout or setInterval. Directly post the compatibility writing method:

XML/HTML CodeCopy content to clipboard
  1. window.RAF = (function(){
  2. Return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function (callback) {window.setTimeout(callback, 1000 / 60 ); };
  3. })();

 

【Avoid floating point operations】

Although JavaScript provides some very convenient rounding methods, such as Math.floor, Math.ceil, and parseInt, foreign friends have done tests and the parseInt method does some extra work (such as detecting whether the data is valid value, parseInt even converts the parameter into a string first!), so using parseInt directly is relatively more performance-intensive. So how to round up, you can directly use a very clever method written by foreigners:

    JavaScript CodeCopy content to clipboard

    1.rounded = (0.5 somenum) | 0;

    2.rounded = ~~ (0.5 somenum); 3.rounded = (0.5 somenum)

    If you don’t understand the operators, you can just click here: http://www.w3school.com.cn/js/pro_js_operators_bitwise.asp There are detailed explanations inside

 

【Reduce canvasAPI calls as much as possible】

When making particle effects, try to use circles as little as possible and preferably use squares. Because the particles are too small, squares look similar to circles. As for the reason, it is easy to understand. We need three steps to draw a circle: first beginPath, then use arc to draw an arc, and then use fill to fill it to produce a circle. But to draw a square, you only need one fillRect. Although there is only a difference of two calls, when the number of particle objects reaches a certain level, the performance gap will show up.

There are some other things to note, I won’t list them all because there are quite a few on Google. This can be regarded as a record for myself, mainly to record the usage of cache. If you want to improve the performance of canvas, the most important thing is to pay attention to the structure of the code, reduce unnecessary API calls, reduce complex operations in each frame, or change complex operations from once for each frame to once for several frames. At the same time, for the cache usage mentioned above, for convenience, I used an off-screen canvas for each object. In fact, off-screen canvas cannot be used too extensively. If you use too many off-screen canvases, there will be performance problems. Please try your best. Make reasonable use of off-screen canvas.

Source code address: https://github.com/whxaxes/canvas-test/tree/gh-pages/src/Other-demo/cache

Statement
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
What Does H5 Refer To? Exploring the ContextWhat Does H5 Refer To? Exploring the ContextApr 12, 2025 am 12:03 AM

H5referstoHTML5,apivotaltechnologyinwebdevelopment.1)HTML5introducesnewelementsandAPIsforrich,dynamicwebapplications.2)Itsupportsmultimediawithoutplugins,enhancinguserexperienceacrossdevices.3)SemanticelementsimprovecontentstructureandSEO.4)H5'srespo

H5: Tools, Frameworks, and Best PracticesH5: Tools, Frameworks, and Best PracticesApr 11, 2025 am 12:11 AM

The tools and frameworks that need to be mastered in H5 development include Vue.js, React and Webpack. 1.Vue.js is suitable for building user interfaces and supports component development. 2.React optimizes page rendering through virtual DOM, suitable for complex applications. 3.Webpack is used for module packaging and optimize resource loading.

The Legacy of HTML5: Understanding H5 in the PresentThe Legacy of HTML5: Understanding H5 in the PresentApr 10, 2025 am 09:28 AM

HTML5hassignificantlytransformedwebdevelopmentbyintroducingsemanticelements,enhancingmultimediasupport,andimprovingperformance.1)ItmadewebsitesmoreaccessibleandSEO-friendlywithsemanticelementslike,,and.2)HTML5introducednativeandtags,eliminatingthenee

H5 Code: Accessibility and Semantic HTMLH5 Code: Accessibility and Semantic HTMLApr 09, 2025 am 12:05 AM

H5 improves web page accessibility and SEO effects through semantic elements and ARIA attributes. 1. Use, etc. to organize the content structure and improve SEO. 2. ARIA attributes such as aria-label enhance accessibility, and assistive technology users can use web pages smoothly.

Is h5 same as HTML5?Is h5 same as HTML5?Apr 08, 2025 am 12:16 AM

"h5" and "HTML5" are the same in most cases, but they may have different meanings in certain specific scenarios. 1. "HTML5" is a W3C-defined standard that contains new tags and APIs. 2. "h5" is usually the abbreviation of HTML5, but in mobile development, it may refer to a framework based on HTML5. Understanding these differences helps to use these terms accurately in your project.

What is the function of H5?What is the function of H5?Apr 07, 2025 am 12:10 AM

H5, or HTML5, is the fifth version of HTML. It provides developers with a stronger tool set, making it easier to create complex web applications. The core functions of H5 include: 1) elements that allow drawing graphics and animations on web pages; 2) semantic tags such as, etc. to make the web page structure clear and conducive to SEO optimization; 3) new APIs such as GeolocationAPI support location-based services; 4) Cross-browser compatibility needs to be ensured through compatibility testing and Polyfill library.

How to do h5 linkHow to do h5 linkApr 06, 2025 pm 12:39 PM

How to create an H5 link? Determine the link target: Get the URL of the H5 page or application. Create HTML anchors: Use the <a> tag to create an anchor and specify the link target URL. Set link properties (optional): Set target, title, and onclick properties as needed. Add to webpage: Add HTML anchor code to the webpage where you want the link to appear.

How to solve the h5 compatibility problemHow to solve the h5 compatibility problemApr 06, 2025 pm 12:36 PM

Solutions to H5 compatibility issues include: using responsive design that allows web pages to adjust layouts according to screen size. Use cross-browser testing tools to test compatibility before release. Use Polyfill to provide support for new APIs for older browsers. Follow web standards and use effective code and best practices. Use CSS preprocessors to simplify CSS code and improve readability. Optimize images, reduce web page size and speed up loading. Enable HTTPS to ensure the security of the website.

See all articles

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

AI Hentai Generator

AI Hentai Generator

Generate AI Hentai for free.

Hot Article

R.E.P.O. Energy Crystals Explained and What They Do (Yellow Crystal)
3 weeks agoBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Best Graphic Settings
3 weeks agoBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. How to Fix Audio if You Can't Hear Anyone
3 weeks agoBy尊渡假赌尊渡假赌尊渡假赌
WWE 2K25: How To Unlock Everything In MyRise
3 weeks agoBy尊渡假赌尊渡假赌尊渡假赌

Hot Tools

WebStorm Mac version

WebStorm Mac version

Useful JavaScript development tools

Dreamweaver Mac version

Dreamweaver Mac version

Visual web development tools

PhpStorm Mac version

PhpStorm Mac version

The latest (2018.2.1) professional PHP integrated development tool

MantisBT

MantisBT

Mantis is an easy-to-deploy web-based defect tracking tool designed to aid in product defect tracking. It requires PHP, MySQL and a web server. Check out our demo and hosting services.

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment