Performance analysis and improvement techniques of HTML5 canvas

Source: Internet
Author: User
Tags bitwise

Canvas code is also some optimization techniques, my previous several canvas articles simply about how to do using canvas, below to see how others say optimization canvas performance.

One: Use cache technology to implement the pre-drawing, reduce the repeated drawing Canvs content

Most of the time we draw and update on canvas, we always keep some unchanged content, for these content

The cache should be drawn beforehand, rather than each refresh.

The direct drawing code is as follows:

context.font= "24px Arial";
Context.fillstyle= "Blue";
Context.filltext ("Please press <Esc> to exit game", 5,50);
Requestanimationframe (render);
Using cache pre-plotting techniques:

function render (context) {
Context.drawimage (mtext_canvas, 0, 0);
Requestanimationframe (render);
}

function DrawText (context) {
Mtext_canvas = document.createelement ("Canvas");
Mtext_canvas.width = 450;
Mtext_canvas.height = 54;
var m_context = Mtext_canvas.getcontext ("2d");
m_context.font= "24px Arial";
M_context.fillstyle= "Blue";
M_context.filltext ("Please press <Esc> to exit game", 5,50);
}
When using canvas caching to draw technology, be sure to remember that the cache canvas object size is less than the actual canvas

Size. As much as possible to draw the line point of the operation together, and as far as possible to draw complete, a bad code is as follows:

for (var i = 0; i < points.length-1; i++) {
var p1 = points[i];
var p2 = points[i+1];
Context.beginpath ();
Context.moveto (p1.x, P1.Y);
Context.lineto (p2.x, P2.Y);
Context.stroke ();
}
The code with the higher performance after the modification is as follows:

Context.beginpath ();
for (var i = 0; i < points.length-1; i++) {
var p1 = points[i];
var p2 = points[i+1];
Context.moveto (p1.x, P1.Y);
Context.lineto (p2.x, P2.Y);
}
Context.stroke ();
Avoid unnecessary canvas drawing states to switch frequently, one example of frequent toggle drawing style is as follows:

var GAP = 10;
for (var i=0; i<10; i++) {
Context.fillstyle = (i% 2?) "Blue": "Red");
Context.fillrect (0, I * gap, the gap);
}
To avoid frequent switching of drawing states, the better performance of the drawing code is as follows:

Even
Context.fillstyle = "Red";
for (var i = 0; i < 5; i++) {
Context.fillrect (0, (i*2) * gap, the gap);
}

Odd
Context.fillstyle = "Blue";
for (var i = 0; i < 5; i++) {
Context.fillrect (0, (i*2+1) * gap, the gap);
}

When drawing, only the area that needs to be updated is plotted, avoiding unnecessary duplicate drawing and extra overhead at all times.

The layered rendering technique is used for complex scene rendering, which is divided into foreground and background drawing respectively. Defines the canvas layer's

HTML is as follows:

<canvas id= "BG" width= "640" height= "" style= "Position:absolute"; Z-index:0 ">
</canvas>
<canvas id= "FG" width= "640" height= "" style= "Position:absolute"; Z-index:1 ">
</canvas>
If not necessary, try to avoid drawing effects such as shadows, Blur, and so on.

Avoid using floating-point coordinates.

When drawing a graphic, the length and coordinates should select integers instead of floating-point numbers, because canvas supports half pixel rendering

The interpolation algorithm is implemented according to the decimal position to achieve the anti-aliasing effect of the drawing image, if it is not necessary, do not select floating-point values.

Empty the drawing on the canvas:

Context.clearrect (0, 0, canvas.width,canvas.height)

But in fact there is a hack-like method of emptying the canvas:

Canvas.width = Canvas.width;

You can also implement the effect of emptying content on canvas, but may not be supported on some browsers.


Performance test

In order to deal with the rapidly changing HTML5 canvas,jsperf (jsperf.com) test proves that each of the methods we mentioned in this article is still in effect. Jsperf is a very useful Web application that Web developers can use to write JavaScript performance test cases. Each test case focuses on the results of one aspect of your attempt (say, a clear canvas), and each of these test cases contains several different ways to achieve the same result. Jsperf runs every method as much as possible over a short period of time and does not give a statistically significant number of iterations per second. High score means higher performance.

Viewers can open the Jsperf Performance test page in their browser, and allow Jsperf to store standardized test results in Browserscope (broserscope.org). Because the optimization techniques mentioned in this article have been backed up to the jsperf results, you can rerun the latest information to determine if the appropriate method is still valid. I have written a small help application (helper Applicatin) to draw the results of the test into a chart and embed it in the entire article.

The performance test results in this article are very important in relation to a particular browser version. Since we do not know what operating system your browser is running on, it is even more important not to know whether the HTML5 canvas is accelerated by hardware when you perform these tests. You can use the ABOUT:GPU command in the Chrome browser address bar to see if the chrome HTML5 canvas is accelerated by hardware.


1.pre-render to a off-screen CANVAS

When we write a game, we often experience the redrawing of similar objects in multiple consecutive frames. In this case, you can get a huge performance boost by rendering most of the objects in the scene. Pre-rendering renders temporary images in one or more temporary canvas that are not displayed on the screen, and then renders the invisible canvas as an image into the visible canvas. For computer graphics more familiar friends should know, this technology is also known as display list.

For example, suppose you are redrawing a Mario that runs at 60 frames per second. You can redraw his hat, beard, and "M" in every frame, and you can also pre-render Mario before running the animation.

No pre-render scenario:

Canvas, context are defined
function render () {
Drawmario (context);
Requestanimationframe (render);
}
Pre-rendered scenarios:

var M_canvas = document.createelement (' canvas ');
M_canvas.width = 64;
M_canvas.height = 64;
var m_context = M_canvas.getcontext (' 2d ');
Drawmario (M_context);
function render () {
Context.drawimage (m_canvas, 0, 0);
Requestanimationframe (render);
}
The use of Requestanimationframe will be described in detail in the following sections. The following icon shows the performance improvements that are shown by using the pre-rendering technique. (from Jsperf):


This method works well when rendering operations, such as the Drawmario in the previous example, are expensive. A very resource-intensive text rendering operation is a good example. From the table below you can see the strong performance improvements that are being made with the pre rendering operation. (from Jsperf):


However, looking at the example above we can see that the loose pre rendering (Pre-renderde loose) performance is poor. When using the pre rendering method, we want to make sure that the temporary canvas fits the size of the image you are rendering, or that an excessive canvas will result in the performance gains that we get when we copy a larger canvas onto another canvas.

The compact canvas in the above test cases are quite small:

Can2.width = 100;
Can2.height = 40;
The following loose canvas will result in poor performance:

Can3.width = 300;
Can3.height = 100;


2.BATCH CANVAS CALLS together

Because drawing is an expensive operation, loading the drawing state onboard with a long instruction set, and then writing all of the brain into the video buffer. This will be better and more efficient.

For example, creating a path that contains all of the lines when you need to draw a line of lines and then using a draw call will be much more efficient than each line of each individual drawing:

or (var i = 0; i < points.length-1; i++) {
var p1 = points[i];
var p2 = points[i+1];
Context.beginpath ();
Context.moveto (p1.x, P1.Y);
Context.lineto (p2.x, P2.Y);
Context.stroke ();
}
We can get better performance by drawing a path that contains more than one line:

Ontext.beginpath ();
for (var i = 0; i < points.length-1; i++) {
var p1 = points[i];
var p2 = points[i+1];
Context.moveto (p1.x, P1.Y);
Context.lineto (p2.x, P2.Y);
}
Context.stroke ();
This method also applies to HTML5 canvas. For example, when we draw a complex path, it is much more efficient to put all the points in the path than to draw each part individually (JSPERF):


However, it should be noted that there is an important exception for canvas: If the object you want to draw has a small bounding box (for example, a vertical line or horizontal line), it may be more efficient to render the lines individually (JSPERF):


3.AVOID unnecessary CANVAS State CHANGES

HTML5 canvas elements are implemented on top of a state machine. State machines can track such things as fill, stroke-style, and previous points, which make up the current path. When trying to optimize the performance of a drawing, we tend to focus on graphics rendering only. In fact, manipulating the state machine can also result in performance overhead.

For example, if you use a variety of fill colors to render a scene, rendering it in different colors will be more resource-efficient than rendering it on a canvas layout. To render a pattern of stripes, you can render it like this: render a line with a color, then change the color, render the next line, and so on:

for (var i = 0; I < stripes; i++) {
Context.fillstyle = (i% 2?) COLOR1:COLOR2);
Context.fillrect (i * gap, 0, Gap, 480);
}
You can also first render all the even lines in one color and then render all the cardinal lines with another stain:

Context.fillstyle = COLOR1;
for (var i = 0; i < STRIPES/2; i++) {
Context.fillrect ((i*2) * gap, 0, Gap, 480);
}
Context.fillstyle = COLOR2;
for (var i = 0; i < STRIPES/2; i++) {
Context.fillrect ((i*2+1) * gap, 0, Gap, 480);
}
The following performance test cases draw an interlaced stripe pattern (Jsperf) using the top two methods:


As we expected, the staggered-state approach is much slower because of the extra overhead of changing the state machine.


4.RENDER screen differences only, not the WHOLE NEW state

It's easy to understand that drawing fewer things on the screen is less of a resource than drawing a lot of stuff. When redrawing, if there is only a small amount of difference, you can achieve significant performance gains by simply redrawing the difference section. In other words, do not clear the entire canvas before redrawing. :

Context.fillrect (0, 0, canvas.width, canvas.height);
Tracks the bounding box of the drawn part, only to clear things within the boundary:

Context.fillrect (Last.x, Last.y, Last.width, last.height);
The following test cases illustrate this point. The test case draws a white dot across the screen (JSPERF):


If you are familiar with computer graphics, you should probably know that this technique is also known as "redraw technique", which saves the bounding box of the previous render operation and only cleans up the contents of the part before the next drawing.

This technique also applies to pixel-based rendering environments. This is illustrated by this article, called JavaScript NIntendo emulator tallk.


5.USE mutiple layered canvases for COMPLEX scenes

As we mentioned before, the cost of drawing a larger picture is very high, so we should avoid it as much as possible. In addition to the pre-rendering using other invisible canvas, we can also stack the multilayer canvas. Well, you've been using the transparency of the foreground, we can rely on the GPU to consolidate different alpha values when rendering. You can set it up as follows, with two absolutely positioned canvas one on top of the other:

<canvas id= "BG" width= "640" height= "" style= "Position:absolute"; Z-index:0 ">
</canvas>
<canvas id= "FG" width= "640" height= "" style= "Position:absolute"; Z-index:1 ">
</canvas>
The advantage of this approach, as opposed to having only one canvas, is that we don't need to modify the background canvas every time we need to draw or clean up the foreground canvas. If your game or multimedia application can be divided into scenarios such as foreground and background, consider the decibel rendering foreground and background to gain significant performance gains. The chart below compares only one canvas situation and has a foreground background of two canvas and you just need to clean and redraw the foreground (Jsperf):


You can use the slower speed (relative to the foreground) to render the background, so you can use some visual characteristics of the human eye to achieve a certain degree of three-dimensional, which will be more attractive to the user's eyes. For example, you can render the foreground in each frame and only each n frame renders the background.

Note that this method can also be extended to include more canvas once complex canvas. Use this approach if your application uses more than ever before to run better.


6.AVOID Shadowblur

Like many other drawing environments, HTML5 canvas allows developers to use shadow effects on drawing primitives, but this is a fairly resource-intensive operation.

Context.shadowoffsetx = 5;
Context.shadowoffsety = 5;
Context.shadowblur = 4;
Context.shadowcolor = ' Rgba (255, 0, 0, 0.5) ';
Context.fillrect (20, 20, 150, 100);
The following test shows the significant performance difference in drawing the same scene using the Shadow Effect (JSPERF):


7.KNOW various WAYS to clear the CANVAS

Because HTML5 canvas is a drawing paradigm (drawing paradigm) of instant mode (immediate mode), the scene must be redrawn at every frame. Because of this, it is clear that canvas operations are of fundamental importance for HTML5 applications or games.

As mentioned in the section to avoid canvas state changes, it is often undesirable to be aware of the entire canvas operation. If you have to do this, there are two ways to choose: Call

Context.clearrect (0, 0, width, height)
Or use a canvas specific technique.

Canvas.width = Canvas.width
When writing this article, the Clearect method is generally superior to the method of resetting the canvas width. However, in some cases, the technique of resetting the canvas width in Chrome14 is much faster than the Clearrect method (Jsperf):


Use this technique with caution, because it relies heavily on the underlying canvas implementation, so it's easy to change and see Simon Sarris's article on clearing the canvas for more information.

8.AVOID floating Point coordinates

HTML5 Canvas supports sub-pixel rendering (sub-pixel rendering), and there is no way to turn off this feature. If you draw a non integer coordinate, he will automatically use anti-aliasing to smooth the edges. The following are the corresponding visual effects (see Seb Lee-delisle's article on the performance of the Sub-pixel canvas)


If the smoothed sprite is not the effect you expect, then using the Math.floor method or the Math.Round method to convert your floating-point coordinates to integer coordinates will greatly increase the speed (Jsperf):


You can use a lot of clever tricks to get the floating-point coordinates to the integer coordinates, where the most superior performance is to add 0.5 and then shift the result to eliminate the decimal part.

With a bitwise OR.
Rounded = (0.5 + somenum) | 0;
A Double bitwise NOT.
rounded = ~ ~ (0.5 + somenum);
Finally, a left bitwise shift.
Rounded = (0.5 + somenum) << 0;
The performance of the two methods is compared as follows (JSPERF):


9.OPTIMIZE YOUR animations with ' Requestanimationframe '

The relatively new Requeatanimationframe API is the recommended standard for implementing interactive applications in browsers. Unlike the traditional rendering of a fixed-frequency command browser, this method can be friendlier to browsers, which are rendered when the browser is available. Another advantage of this is that when the page is not visible, it will be smart to stop rendering.

The goal of the Requestanimationframe call is to call at 60 frames per second, but he is not guaranteed to do so. So you have to track how long it took from the last call to the wire. This may look like the following:

var x = 100;
var y = 100;
var lastrender = new Date ();
function render () {
var delta = new Date ()-Lastrender;
x = = Delta;
Y + + Delta;
Context.fillrect (x, Y, W, H);
Requestanimationframe (render);
}
Render ();
Note that Requestanimationframe is not only suitable for canvas but also for rendering techniques such as WEBGL.

When writing this article, this API only applies to Chrome,safari and Firefox, so you should use this code fragment

MOST MOBILE CANVAS Implementation ARE slow

Let's talk about mobile platforms. Unfortunately, in writing this article, only the Safari1.5 running on iOS 5.0beta has a GPU-accelerated mobile platform canvas implementation. Without GPU acceleration, mobile platform browsers typically do not have a strong enough CPU to handle canvas based applications. The results of the JSPERF test cases on the mobile platform are much worse than those of the desktop platform. This greatly limits the successful operation of applications across device classes.
Conclusion

J Briefly, this article describes a variety of very useful optimization methods to help developers to develop a superior performance based on HTML5 Canvas project. You have learned something new and you have to quickly optimize your awesome creations! If you haven't created an app or game yet, go to the chrome experiment and creative JS to see what inspires you.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.