HTML5画布性能和优化提示,技巧和编码最佳实践 [英] HTML5 Canvas Performance and Optimization Tips, Tricks and Coding Best Practices

查看:124
本文介绍了HTML5画布性能和优化提示,技巧和编码最佳实践的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

你知道更多CANVAS的最佳实践吗



请添加到此线程你知道,已经学习或已经在线阅读任何和所有Canvas最好实践,性能提示/技巧



由于Canvas仍然是互联网的新特征,没有任何迹象显示我将来可以看到,太多的记录的最佳实践或其他真正重要的提示,是一个必须知道在任何一个特定的地方开发。这样的东西分散在周围,很多次在不太知名的网站。



有很多事情需要人们了解,还有很多东西需要了解。






我想分享一些东西,以帮助正在学习Canvas的人,也许有些人已经知道它很好,希望从他人那里得到一些反馈他们感觉是一些最佳实践或其他提示和技巧在HTML5中使用Canvas。



我想开始一个我个人认为对于开发人员来说非常有用但却令人吃惊的事情。



1。缩进代码



与任何其他时间一样,以任何其他语言(视情况而定)。它一直是一切的最佳实践,我发现在一个复杂的画布应用程序,当处理几个不同的上下文和保存/恢复状态时,事情可能会有点混乱。更不用说代码只是更加可读性和整体更清洁。



例如:

  ... 
/ /尝试告诉我这没有意义,做
ctx.fillStyle ='red';
ctx.fill();
ctx.save();
if(thing< 3){
//缩进
ctx.beginPath();
ctx.arc(2,6,11,0,Math.PI * 2,true);
ctx.closePath();
ctx.beginPath();
ctx.moveTo(20,40);
ctx.lineTo(10,200);
ctx.moveTo(20,40);
ctx.lineTo(100,40);
ctx.closePath();
ctx.save();
ctx.fillStyle ='blue'
ctx.fill();
ctx.restore();
} else {
//没有缩进
ctx.drawImage(img,0,0,200,200);
ctx.save();
ctx.shadowBlur();
ctx.beginPath();
ctx.arc(2,60,10,0,Math.PI * 2,false);
ctx.closePath();
ctx.fillStyle'green';
ctx.fill();
ctx.restore();
}
ctx.restore();
ctx.drawRect();
ctx.fill();
...

IF语句不容易阅读,什么立即进行比ELSE语句在这?你能看到我在这里说的吗?



使用requestAnimationFrame而不是setInterval /

这是一个开发人员应该继续练习的方法, setTimeout



setInterval和setTimeout从来不打算用作动画定时器,它们只是在一段时间后调用函数的通用方法。如果将来设置间隔为20ms,但是您的函数队列所需的时间比执行时间长,则在这些函数完成后,定时器才会触发。这可能是一个时间,这是不理想的动画。 RequestAnimationFrame 是一种告诉浏览器动画正在发生的方法,因此可以相应地优化重绘。它还会对非活动标签页的动画进行限制,因此如果您将移动设备的电池留在后台打开,就不会占用该电池。



Nicholas Zakas写了一个非常详细的在其博客上提供信息的关于requestAnimationFrame的文章读。如果您想要一些简单快速的实施说明,请 Paul Irish撰写一个requestAnimationFrame shim - 这是



ACTUALLY



偶尔比使用requestAnimationFrame代替setTimeout和setInterval更好,Joe Lambert写了一个新的和改进的垫片称为requestInterval和requestTimeout,他解释了在使用requestAnimFrame时存在什么问题。
您可以查看脚本的提示



ACTUALLY x2



现在所有的浏览器已经赶上了规范,有一个更新到requestAnimFrame()polyfill ,可能仍然是用于覆盖所有供应商的。



使用多个画布



@nicolahibbert 在关于优化Canvas游戏的帖子中写道了提到最好使用多层帆布,而不是在一个画布上做任何事情。 Nicola解释说,在同一时间画出太多的像素到同一个画布上会导致你的帧速率下降穿过地面。以突破为例,尝试绘制砖块,球,桨,任何电源ups或武器,然后在后台的每个明星 - 这根本不工作,它需要太长的时间执行每个这些指令依次。通过分割星空和游戏的其余部分在独立的画布,你能够确保一个体面的帧率。



渲染元素屏幕



我必须为几个应用程序执行此操作。包括三星奥运基因组计划facebook应用。这是一个非常有用的事情要知道和利用它是否需要。它减少了加载时间,加上它可以是一个非常有用的技术,以加载图像离开屏幕,因为他们有时可能需要一段时间。

  var tmpCanvas = document.createElement('canvas'),
tmpCtx = tmpCanvas.getContext('2d'),
img = document.createElement('img');

img.onload = function(){
tmpCtx.drawImage(thumbImg,0,0,200,200);
};
img.src ='/some/image/source.png';

请注意,图像的src在加载后设置。这是一个关键的事情要记住也做。一旦图像加载并绘制到这些临时画布中,您可以使用相同的ctx.drawImage()将它们绘制到您的主画布中,但是不使用图像作为第一个参数,您可以使用'tmpCtx.canvas'




  • 其他提示,技巧和资源 strong> 画布测试用例

  • 一些更多的canvas和JS测试

  • < a href =http://www.html5rocks.com/en/tutorials/canvas/performance/> HTML5Rocks性能改进

  • ** requestAnimFrame以优化拖动事件

  • ul>

    Canvas有一个反向引用



    2d上下文有一个对应的DOM元素的反向引用:

      var ctx = doc.getElementById('canvas')。getContext('2d'); 
    console.log(ctx.canvas); // HTMLCanvasElement

    我想听听更多来自其他人的意见。我正在制作一份清单,列出我们应该标准化的内容,为我公司的前端代码标准和最佳做法

    解决方案

    重绘区域



    动画的最佳画布优化技术是限制每帧上被清除/绘制的像素数量。最简单的解决方案是重置整个canvas元素并重新绘制一切,但这是一个昂贵的操作,您的浏览器可以处理。



    重复使用尽可能多的像素帧。这意味着每帧需要处理的像素越少,程序运行得越快。例如,当使用clearRect(x,y,w,h)方法擦除像素时,清除和重绘只有已更改的像素而非整个画布是非常有益的。



    程序精灵



    以程序生成图形通常是一种方法,但有时候并不是最有效的方法。如果你正在绘制简单的形状与实体填充,然后绘制它们的程序是最好的方式这样做。但是,如果你用笔触,渐变填充和其他性能敏感的化妆绘制更详细的实体,你最好使用图像精灵。



    用两者的混合去。在应用程序启动时,在画布上一次性绘制图形实体。之后,您可以通过绘制它们的副本来重复使用相同的精灵,而不是重复生成相同的阴影,渐变和描边。



    状态堆栈&转换



    可以通过旋转和缩放等变换操作画布,从而改变画布坐标系。这是重要的是知道有两种方法可用的状态堆栈:context.save()(推动当前状态到堆栈)和context.restore()(恢复到以前的状态)。这使您能够将变换应用到图形,然后恢复到先前的状态,以确保下一个形状不受任何早期变换的影响。



    合成



    这是一个非常强大的工具当使用画布是合成模式,其中,允许掩蔽和分层。有一个广泛的可用复合模式,它们都通过画布上下文的globalCompositeOperation属性设置。复合模式也是状态堆栈属性的一部分,因此您可以应用复合操作,堆叠状态并应用不同的模式,然后恢复到创建第一个模式之前的状态。



    抗锯齿



    为了支持子像素绘图,所有浏览器实现的canvas使用消除锯齿(虽然这似乎不是HTML5规范中的要求)。消除锯齿可能很重要,要记住,如果你想画出清晰的线条,并注意到结果看起来模糊。发生这种情况是因为浏览器会对图像进行插值,就像它实际上是在那些像素之间。它会导致更流畅的动画(你可以真正地移动半个像素每更新),但它会使你的图像模糊。



    要解决这个问题,你会



    使用整数DrawImage()x和y位置



    如果在Canvas元素上调用drawImage,如果将x和y位置舍入为一个整数,它会更快。



    这是jsperf上的测试用例,显示使用整数与使用小数相比较。



    在渲染之前,将x和y位置整圆。



    比Math.round()更快



    另一个jsperf测试显示,Math.round()不一定是最快的数字舍入方法。



    Canvas Sprite Optimization



    清除画布



    通常使用任何现有像素的context.clearRect(x,y,w,h)的整个画布 - 但是还有另一个选项可用。每当设置画布的宽度/高度时,即使它们被重复设置为相同的值,画布也会重置。这是很好知道什么时候使用动态大小的画布,你会注意到图纸消失。



    计算分布



    Chrome开发人员工具分析器非常有助于了解您的性能瓶颈。根据您的应用程序,您可能需要重构您的程序的某些部分以提高性能,以及浏览器如何处理代码的特定部分。



    优化技巧


    DO YOU KNOW SOME MORE BEST PRACTICES FOR CANVAS??

    Please add to this thread what you know, have learned, or have read online any and all Canvas best practices, tips/tricks for performance

    With Canvas being still very new to internet, and no signs of it ever getting old that I can see in the future, there are not too many documented "best practices" or other really important tips that are a 'must know' for developing with it in any one particular place. Things like this are scattered around and many times on lesser known sites.

    There's so many things that people need to know about, and still so much to learn about too.


    I wanted to share some things to help people who are learning Canvas and maybe some who already know it quite well and am hoping to get some feedback from others about what they feel are some best practices or other tips and tricks for working with Canvas in HTML5.

    I want to start off with one I personally found to be quite a useful yet surprisingly uncommon thing for developers to do.

    1. Indent your code

    Just as you would any other time, in any other language whatever the case may be. It has been a best practice for everything else, and I have come to find that in a complex canvas app, things can get a little confusing when dealing with several different contexts and saved/restore states. Not to mention the code is just more readable and overall cleaner looking too.

    For example:

    ...
    // Try to tell me this doesn't make sense to do
    ctx.fillStyle = 'red';
    ctx.fill();
    ctx.save();
        if (thing < 3) {
            // indenting
            ctx.beginPath();
                ctx.arc(2, 6, 11, 0, Math.PI*2, true);
            ctx.closePath();
            ctx.beginPath();
                ctx.moveTo(20, 40);
                ctx.lineTo(10, 200);
                ctx.moveTo(20, 40);
                ctx.lineTo(100, 40);
            ctx.closePath();
            ctx.save();
                ctx.fillStyle = 'blue'
                ctx.fill();
            ctx.restore();
        } else { 
            // no indenting
            ctx.drawImage(img, 0, 0, 200, 200);
            ctx.save();
            ctx.shadowBlur();
            ctx.beginPath();
            ctx.arc(2, 60, 10, 0, Math.PI*2, false);
            ctx.closePath();
            ctx.fillStyle 'green';
            ctx.fill();
            ctx.restore();
        }
    ctx.restore();
    ctx.drawRect();
    ctx.fill();
    ...
    

    Is the IF statement not easier and cleaner to read and know what is what immediately going on than the ELSE statement in this? Can you see what I'm saying here? I think this should be a method that developers should continue to practice just as they would when writing plain 'ol javascript or any other language even.

    Use requestAnimationFrame instead of setInterval / setTimeout

    setInterval and setTimeout were never intended to be used as animation timers, they're just generic methods for calling functions after a time delay. If you set an interval for 20ms in the future, but your queue of functions takes longer than that to execute, your timer won't fire until after these functions have completed. That could be a while, which isn't ideal where animation is concerned. RequestAnimationFrame is a method which tells the browser that an animation is taking place, so it can optimize repaints accordingly. It also throttles the animation for inactive tabs, so it won't kill your mobile device's battery if you leave it open in the background.

    Nicholas Zakas wrote a hugely detailed and informative article about requestAnimationFrame on his blog which is well worth reading. If you want some hard and fast implementation instructions, then Paul Irish has written a requestAnimationFrame shim – this is what I've used in every one of the Canvas apps I have made until recently.

    ACTUALLY

    Even better than using requestAnimationFrame in place of setTimeout and setInterval, Joe Lambert has written a NEW and improved shim called requestInterval and requestTimeout, which he explains what issues exist when using requestAnimFrame. You can view the gist of the script.

    ACTUALLY x2

    Now that all the browsers have caught up on the spec for this, there has been an update to the requestAnimFrame() polyfill, one which will probably remain the one to use to cover all vendors.

    Use more than one canvas

    A technique for animation-heavy games which @nicolahibbert wrote about in a post of hers on optimizing Canvas games mentions that it may be better to use multiple canvasses layered on top of one another rather than do everything in a single canvas. Nicola explains that "drawing too many pixels to the same canvas at the same time will cause your frame rate to fall through the floor. Take Breakout for example. Trying to draw the bricks, the ball, the paddle, any power-ups or weapons, and then each star in the background – this simply won't work, it takes too long to execute each of these instructions in turn. By splitting the starfield and the rest of the game onto separate canvases, you are able to ensure a decent framerate."

    Render Elements Off-screen

    I have had to do this for a few apps I've made including Samsung's Olympic Genome Project facebook app. It's an extremely useful thing to know and to make use of whether it's needed or not. It decreases load time immensely, plus it can be a really useful technique to load images off screen since they can sometimes take a while.

    var tmpCanvas = document.createElement('canvas'),
        tmpCtx = tmpCanvas.getContext('2d'),
        img = document.createElement('img');
    
    img.onload = function() {
        tmpCtx.drawImage(thumbImg, 0, 0, 200, 200);
    };
    img.src = '/some/image/source.png';
    

    Notice that the src of the image is set after it is loaded. This is a key thing to remember to do too. Once the images are done loading and drawn into these temp canvases, you can then draw them to your main canvas by using the same ctx.drawImage(), but instead of putting the image as the first argument, you use 'tmpCtx.canvas' to reference the temp canvas.

    Other tips, tricks and resources

    Canvas has a back-reference

    The 2d context has a back reference to it's associated DOM element:

    var ctx = doc.getElementById('canvas').getContext('2d');
    console.log(ctx.canvas);    // HTMLCanvasElement
    

    I'd love to hear more from other people on this. I am working on making a list of things that we should standardize to add a new section to my company's Front-end Code Standards and Best Practices. I'd love to get as much feedback on this as I can.

    解决方案

    Redraw Regions

    The best canvas optimization technique for animations is to limit the amount of pixels that get cleared/painted on each frame. The easiest solution to implement is resetting the entire canvas element and drawing everything over again but that is an expensive operation for your browser to process.

    Reuse as many pixels as possible between frames. What that means is the fewer pixels that need to be processed each frame, the faster your program will run. For example, when erasing pixels with the clearRect(x, y, w, h) method, it is very beneficial to clear and redraw only the pixels that have changed and not the full canvas.

    Procedural Sprites

    Generating graphics procedurally is often the way to go, but sometimes that's not the most efficient one. If you're drawing simple shapes with solid fills then drawing them procedurally is the best way do so. But if you're drawing more detailed entities with strokes, gradient fills and other performance sensitive make-up you'd be better off using image sprites.

    It is possible to get away with a mix of both. Draw graphical entities procedurally on the canvas once as your application starts up. After that you can reuse the same sprites by painting copies of them instead of generating the same drop-shadow, gradient and strokes repeatedly.

    State Stack & Transformation

    The canvas can be manipulated via transformations such as rotation and scaling, resulting in a change to the canvas coordinate system. This is where it's important to know about the state stack for which two methods are available: context.save() (pushes the current state to the stack) and context.restore() (reverts to the previous state). This enables you to apply transformation to a drawing and then restore back to the previous state to make sure the next shape is not affected by any earlier transformation. The states also include properties such as the fill and stroke colors.

    Compositing

    A very powerful tool at hand when working with canvas is compositing modes which, amongst other things, allow for masking and layering. There's a wide array of available composite modes and they are all set through the canvas context's globalCompositeOperation property. The composite modes are also part of the state stack properties, so you can apply a composite operation, stack the state and apply a different one, and restore back to the state before where you made the first one. This can be especially useful.

    Anti-Aliasing

    To allow for sub-pixel drawings, all browser implementations of canvas employ anti-aliasing (although this does not seem to be a requirement in the HTML5 spec). Anti-aliasing can be important to keep in mind if you want to draw crisp lines and notice the result looks blurred. This occurs because the browser will interpolate the image as though it was actually between those pixels. It results in a much smoother animation (you can genuinely move at half a pixel per update) but it'll make your images appear fuzzy.

    To work around this you will need to either round to whole integer values or offset by half a pixel depending on if you're drawing fills or strokes.

    Using Whole Numbers for drawImage() x and y positions

    If you call drawImage on the Canvas element, it's much faster if you round the x and y position to a whole number.

    Here's a test case on jsperf showing how much faster using whole numbers is compared to using decimals.

    So round your x and y position to whole numbers before rendering.

    Faster than Math.round()

    Another jsperf test shows that Math.round() is not necessarily the fastest method for rounding numbers. Using a bitwise hack actually turns out to be faster than the built in method.

    Canvas Sprite Optimization

    Clearing the Canvas

    To clear the entire canvas of any existing pixels context.clearRect(x, y, w, h) is typically used – but there is another option available. Whenever the width/height of the canvas are set, even if they are set to the same value repeatedly, the canvas is reset. This is good to know when working with a dynamically sized canvas as you will notice drawings disappearing.

    Computation Distribution

    The Chrome Developer Tools profiler is very useful for finding out what your performance bottlenecks are. Depending on your application you may need to refactor some parts of your program to improve the performance and how browsers handle specific parts of your code.

    Optimization techniques

    这篇关于HTML5画布性能和优化提示,技巧和编码最佳实践的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆