0

I found an odd behavior while working on my pet game. I wanted to draw few objects on canvas, some of them required image / icon to be rotated. It is quite common use case, usual solution is to make use of context's rotate method. Going with the blow I used also translate to nicely and consistently put images in desired place.

This worked fine, until I tried Chrome on Windows laptop, with hardware acceleration enabled. Images started to blink and teleport across the screen. I found that it is related to acceleration (turning off accelerated graphics fixes problem) and my best guess is that when updating frame the renderer assumes that drawing calls are independent and can be executed in parallel. When context transforms take place it is not the case because context state changes.

Example of undesired behavior: having a canvas element with ID 'screen' try the following:

var canvas = document.getElementById("screen"),
    ctx = canvas.getContext("2d");

var drawrect = function () {
    ctx.fillStyle = this.color;
    ctx.translate(this.x+10, this.y+10);
    ctx.rotate(this.rotation);
    ctx.fillRect(-10, -10, 20, 20);
    ctx.rotate(-this.rotation);
    ctx.translate(-this.x-10, -this.y-10);
};

var red = {
    x: 22,
    y: 22,
    rotation: 0,
    color: "#ff0000",
    draw: drawrect
};

var blu = {
    x: 22,
    y: 111,
    rotation: 0,
    color: "#0000ff",
    draw: drawrect
};

function main_loop() {
    ctx.clearRect(0, 0, 450, 450);
    frameId = requestAnimationFrame(main_loop);
    red.draw();
    red.x += 1;
    red.rotation +=0.1;
    blu.draw();
    blu.x += 1;
    blu.rotation -=0.1;
}

main_loop();

Working example: http://jsfiddle.net/1u2d7uhr/7/ (tested on Chrome, Chromium, Firefox; accelerated Chrome glitches, others do not)

I was able to 'fix' this by removing translations and rendering rotating elements to separate canvas, which is then (after rotations) drawn onto the main one. This seems hackish to me though.

  1. Is it code error on my part?

  2. In this case what is the right way to render rotations (perhaps with this question I should go do codereview, but I'm not sure if this is the case)?

  3. Or is it buggy behavior on browser side? I understand the logic behind it but it can be very much surprising (and cause some confusion) to developers. Or am I only one...

zencodism
  • 442
  • 4
  • 9
  • In canvas, "teleport across the screen" is usually a sign of transforming from a wrong origin. Perhaps just on Chrome+LaptopGPU you have a 'this' issue. Try explicitly sending an object to drawrect instead of implicitly relying on 'this' being the desired object. – markE Nov 13 '14 at 17:10
  • 1
    Thank you for a suggestion, I didn't think about this ('this', what a pun here...). Tried it though and with explicit references code behaves the same. Looks like it is not the cause here, for now I'm staying with parallel translate/rotate operations hypothesis. – zencodism Nov 13 '14 at 17:50
  • You should call `requestAnimationFrame` at the end of your main_loop-function, not in the middle of it. – Philipp Nov 13 '14 at 21:59

0 Answers0