0

html:

<canvas id="cnv" width="786" height="1113">

js:

var img = new Image(),
    cnv = document.getElementById('cnv');

var context = cnv.getContext('2d');

img.onload = function () {

    context.drawImage(img, 0, 0, 786, 1113);
    alert('finished drawing');

}

img.src = 'https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo/logo_white_fe6da1ec.png';

http://jsfiddle.net/FxrSa/14/

I want to show the alert after the canvas finished his rendering. But the alert show before the image is drawn.

How can I wait for the GUI thread to finish his rendering?

Lixin Wei
  • 441
  • 5
  • 17

3 Answers3

2

Canvas drawImage is synchronous. And even, really synchronous.

Your problem is that alert() is blocking, and even really blocking.

By this I mean it does not only block the js execution, it also blocks the page rendering. So the browser has painted your image on your canvas, but didn't display it yet when you called alert().

One should always avoid alert and replace it with normal DOM elements.

Ps: Here is a proof that your image is indeed already painted on the canvas.

Himanshu
  • 2,384
  • 2
  • 24
  • 42
Kaiido
  • 123,334
  • 13
  • 219
  • 285
  • if it is really synchronous, shouldnt it completely render before returning? – Jonas Wilms Dec 27 '16 at 15:02
  • No, the rendering is blocked by alert before it should have fired – Kaiido Dec 27 '16 at 15:03
  • ive got that. But if it was implemented perfeclty, wouldnt it be drawImage-> render Canvas -> await Browser rendering -> await OS rendering return return return – Jonas Wilms Dec 27 '16 at 15:04
  • no!!! how would you make several drawImage + image processing on the same frame ??? – Kaiido Dec 27 '16 at 15:05
  • so.. the DOM rendering and the js is tow different thread but only one of them can be running, is it? – Lixin Wei Dec 27 '16 at 15:16
  • @LixinWei ... Technically, I am not sure how different UAs do implement DOM rendering vs js execution... It seems implementations do differ since FF does render the canvas before the alert occurs, while chrome doesn't. But a blocking script will block further rendering : http://jsfiddle.net/oo3jbukb/ At least because it needs the js to be free before fetching the current state of the DOM – Kaiido Dec 28 '16 at 00:40
1

As a workaround you may try this:

//after the rendering
setTimeout(function(){
 alert("Yay");
 },100);

HTML5 Canvas: Get Event when drawing is finished

Community
  • 1
  • 1
Jonas Wilms
  • 132,000
  • 20
  • 149
  • 151
  • Not really a bug nope. – Kaiido Dec 27 '16 at 15:00
  • @Kaiido: the spec say its synchronous. The code says its not -> bug – Jonas Wilms Dec 27 '16 at 15:01
  • no you don't read the code correctly, just check for the imageData, you'll see that it's synchronous. What is not is the page rendering (CSS + media + ...) – Kaiido Dec 27 '16 at 15:02
  • Believe it or not, this answer is essentially correct. However, there's a more accurate way to make the timing happen in the linked question where I added a new answer. – trusktr Oct 18 '21 at 22:53
1

Double buffered canvas

An on screen canvas has two pixel buffers. One is called the back buffer, all rendering is done directly to the back buffer. When you make a render call, ctx.drawImage(foo,0,0); the function will not return until it has drawn the back buffer pixels. Even if the GPU is doing the rendering and the CPU is doing nothing, Javascript will wait until the rendering is complete befor moving on to the next line.

When the canvas is on the screen, you will not see the results of any rendering until the current execution has finished.

function myRender(){
    ctx.draw(foo,0,0); // draw stuff  

    ... new pixel content is only in back buffer
    return;
}
function myLoop(){
    ctx.clearRect(,0,0,w,h);
    myRender();  // draw stuff
   .. new pixels not visible
}

myLoop(); 
// no more code

When the myLoop function has returned and javascript has nothing to do, the DOM will see that the canvas backbuffer has changed. It then moves the back buffer to the front buffer so that it can be seen by the hardware that creates the display signal.

This is called double buffering, and it stop artifacts like shearing and flickering caused when you draw to the screen and the screen displays part of the rendering before it is finished.

When the canvas is offscreen, there is no front buffer.

The same is true for all DOM content.

Community
  • 1
  • 1
Blindman67
  • 51,134
  • 11
  • 73
  • 136