简体   繁体   中英

Detect if canvas/css3 animations are being optimized when not visible and outside viewport

I'm assuming with all these hardware accelerated animations in HTML5 that animations that are running outside the viewport are not actually rendered. I want to be able to detect if that is happening.

I've tried using webkitCSSMatrix in a loop on an object that moves up and down 100px every second to try and determine how many pixels it was moving each tick but there's no difference if I move the animation out of view.

Any ideas?

You can use an individual timer test to see difference in objects being drawn outside versus inside for the pseudo-empirical side (timers doesn't actually prove anything but gives you a strong indisium ).

However, knowing how the canvas work can give you a solid pointer too. For example, a canvas is a simple bitmap without any internal management (beyond screen refresh). That means you cannot possibly actually write anything outside its bound as this would corrupt memory. In other words, clipping do take place for this very basic reason.

For the timer tests you can run a simple test where you draw something within the bounds and then the same offset to outside the bounds:

Update: It seems as I misunderstood the question to be outside the canvas bitmap and not outside viewport in general.

So a small update in regards to outside viewport regardless if that is canvas or not -

It's a bit more complicated to describe browser updates than just a canvas but in principle: Everything that is not visible on a screen is clipped (not drawn). Seems perhaps obvious and it sort of it, but that doesn't mean there isn't any updates going on elsewhere.

Browser may or may not keep an internal bitmap of the elements that are to be drawn to the screen (clipped if partly in view or not at all if outside view).

The main difference is that the browser may (dependent on implementation) update this internal bitmap if there is a need to, even if it won't be visible, ie. DOM re-flow that is affected by this element's position, dimension and stack position.

For that reason you may see performance hit in some browsers. The browser can also choose to only update the bitmap content when visible and only adjust sizes when it is not.

Unfortunately there is no accurate way to measure if this happens as it is dependent on many factors (fixed/absolute elements versus non-fixed/absolute, what content, browser implementation, hardware accelerated or not and so forth).

The canvas element is naiv so it is simple to predict, but if you draw something to canvas while canvas is outside viewport it will be drawn to its bitmap and shown when canvas is in view again. However, try to do a window resize and the content of the canvas will disappear (in some browsers) and you will need to redraw. This means there is at least one layer less involved in the process with canvas than with other elements.

I hope that made any sense - my apologies, I was a bit unprepared to do this explanation as I just realized I misunderstood the question.

End of update

Here is a simple online test

In this test we draw 10,000 filled rectangles, at one button inside, at the other button inside. It's not a scientific accurate test, but it shows clearly a difference as when drawing is outside everything it does is to check bound and doesn't update anything in the bitmap's array -

function draw(x) {

    console.time('timer');
    var cnt = 10000, w = ez.width, h = ez.height;

    while(cnt--) {
        ctx.fillRect(x, 0, w, h);
    }

    console.timeEnd('timer');
}

inside.addEventListener('click', function(){draw(0)}, false);
outside.addEventListener('click', function(){draw(ez.width)}, false);

The result of this on my snail computer using the console timer and Chrome is:

timer: 3156.000ms
timer: 112.000ms

That is a ratio of (inside:outside) 3156:112 - or - it took 28x longer when actually drawing something. This indicate that the browser only spend time to check the bounds but doesn't actually move any data in memory if outside bound.

The other method is similar to what is already answered, to use the built in tools. But for this use the profiler instead:

Go go the console and select profiles and CPU profile:

在此输入图像描述

  • Start to record one profile and then hit Inside button. Stop when done
  • Start to record a second profile and then hit Outside button. Stop when done

Now you can compare the two profiles - for inside drawing I got this result:

在此输入图像描述

Here you see it uses about 9.92% to draw the filled rectangles (not adjusted for idle time).

In the second profile I got this:

在此输入图像描述

Here only 1.24% was used to "draw".

Ratio here is 9.92:1.24 or 8 times. In both cases you can see there a huge differences in performance when something is updated to memory (bitmap buffer) and not.

So what about off-screen canvas? The same would be the case with these as something needs to be updated in the off-screen canvas' buffer. The "only" thing it saves is updates to the browser's main buffer which may or may not be optimized.

If you use Chrome DevTools can use the Timeline panel to view page performance.

时间轴面板概述

Another option is to enable the "Show paint rectangles" option in the web inspector. Which will draw a square around the area that is repainted. Web Inspector > Settings > General > Rendering : Show paint rectangles

显示绘画矩形


Resource:

Paul Irish has a really good blog post on this, Why Moving Elements With Translate() Is Better Than Pos:abs Top/left .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM