HTML5 canvas: Elements drawn with / cached for drawImage are smoothed when scaled and / or moved

I know about the case of float / integer values ​​for drawImage x and y . But I need smooth animation with the ability to cache my shapes.

For example, I want to draw some complex shape (i.e. an SVG tiger, converted to canvas command ) onto the canvas only once, and then smoothly move it with ctx.translate and ctx.drawImage . I need float values ​​because instead I get a stepwise move:

Here are the examples in the JSFiddle:

  • One : Fast speed, with Math.floor applied to the translate parameters ( x and y , equal to the time in seconds, multiplied by 10 ): The animation is strange (sequential, non-smooth).
  • Two : slow speed, with Math.floor applied to the translate parameters ( x and y , equal to time per second): The animation is strange (sequential, non-smooth).
  • Three : fast speed, no rounding, float values ​​( x and y are equal to time in seconds times 10 ). The speed is fast, so the animation looks good.
  • Four : Slow speed, without rounding, float values ​​( x and y equal time in seconds). The speed is slow, so the animation looks throbbing. Why?

The last case is the one that bothers me. Am I mistaken in my attempts and is it possible to make this caching trick enjoyable?

In Firefox, there is a canvas property called mozImageSmoothingEnabled ( see ), but there is no help in other browsers. It also removes track smoothing.

Code output:

 var shapeCanvas = null; var w = 320, h = 240; var startTime = 0; function start() { startTime = Date.now(); var docCanvas = document.getElementById('canvas'); . . . shapeCanvas = document.createElement('canvas'); . . . drawShape(shapeCanvas.getContext('2d')); drawNext(docCanvas.getContext('2d')); } function drawNext(ctx) { var msec = (Date.now() - startTime); var time = msec / 1000; // seconds passed from start ctx.clearRect(0, 0, w, h); ctx.save(); // the lines to change: time | (time * 10) | Math.floor(time * 10) ctx.translate((time < 500) ? Math.floor(time * 10) : 500, (time < 500) ? Math.floor(time * 10) : 500); ctx.drawImage(shapeCanvas, 0, 0); ctx.restore(); __nextFrame(function() { drawNext(ctx); }); } function drawShape(ctx) { . . . } 
+6
source share
2 answers

I wrote a tutorial in your first link.

Just clean the air:

 shapeCanvas.style.width = w + 'px'; shapeCanvas.style.height = h + 'px'; 

not worth doing. It makes no sense to customize the style, if it is just a canvas in memory, and in any case, you never want to set the style of the width and height of the canvas, it just confuses things.

What ellisbben said in a comment is pretty much what happens.

You can get around this in several hacker ways, like me. One way could be to never paint on an integer pixel. Another might be to use ctx.scale(.99,.99) before drawing anything so it always smoothes out. It is difficult to get a consistent solution here because the different implementations of anti-aliasing are different from each other.

Here are some experiments from me:

http://jsfiddle.net/KYZYT/29/

The first two are a form taken from a canvas, and also taken from PNG

The second two are the same pair, but scaled .99,.99

The latter is the real thing. It is still a bit blurry, but it looks a lot sharper than using images.

None of my experiments stop pulsation, at least at the microscopic level. I think this is just what you have to live with if you want to animate images that are perfect for a pixel into half-pixel spaces.

If you really feel that you can’t just draw perfect pixels, then your (second) best bet for consistency is probably finding a way to smooth out smoothing at all times. Making sure that you always translate to a non-integer number or scale it, are ever slightly decent candidates, but there may be others.

Honestly, it’s best not to cache these animated paths until you need performance. Attach stylized buttons and other static things that you do, but if you have animated tracks that need to move slowly and accurately and look very good, you can also stick with the true thing in my caching optimization, unless you need it too .

+4
source

Bit a shameless plugin, but: I implement smooth animation in an HTML5 slot game with a bit of a hacker way. The generated cached image is drawn on a small canvas once, and then I used translate3d () with the -moz-transform / -webkit-transform styles for the canvas to move, mirror and scale the image around.

Pregeneration

  • Create image
  • Draw image content
  • Create a canvas object in the DOM

Animation phase

  • Clear canvas
  • Draw a cached image on canvas
  • Use CSS3 transforms (scale3d and translate3d) to move the canvas.
+2
source

Source: https://habr.com/ru/post/903273/


All Articles