I'm performing a rotation of a 2d canvas which works pretty well on the desktop but there's one small issue in the mobile space. Here's a zoomed in screenshot:
The thumb image is rotated about 0.2rad over the course of 500ms. What I think is all of the relevant code is inline below. As you can see, there is some sort of "trail" left by each of the top corners of the image.
var duration = 500;
var start = 0;
var stop = 0.287554326;
var step = (stop - start) / 10;
var steps = (stop - start) / step;
var current = 0;
var delay = duration / steps;
var first = true;
if (navigator.userAgent.match(/iP(hone|[ao]d)|android/i)) step *= 1.5;
var rotate_int = setInterval(function() {
if (current >= stop) {
clearInterval(rotate_int);
callback && callback();
return;
}
ctx.clearRect(0, 0, cvs.width, cvs.height);
ctx.translate(cvs.width / 2, cvs.height / 2);
ctx.rotate(step);
current += step;
ctx.translate(cvs.width / -2, cvs.height / -2);
ctx.drawImage(i, 0, 0);
if (first) {
first = false;
thumb.hide();
}
}, delay);
Notes:
<canvas>
) which exhibits the behavior<canvas>
(while rotating) is being animated (via jQuery) to transit across the image behind it and come to a halt, which is visible in the screenshot.<canvas>
on the page also. It uses the same thumbs-up .png, and rotates using the same code posted above, and is also animated to transit across a different background image (but in the opposite direction, i.e., one "thumbs up" moves northwest, and one southeast), and the trails appear there as well, in the same location relative to the canvas context.I've thrown all the mud on this wall I can think of, in hopes that something may lead to a diagnosis. Has anyone else seen anything like this before? What could I try differently? Have I missed some big red warning label on an HTML5 tutorial site somewhere that warns of such behavior?
==EDIT 1==
Per @GGG's comment, I removed the UA sniff (which is designed to decrease the number and frequency of canvas redraws because the mobile browsers all chug if I use the same settings as for desktop) but that just caused the trails to become more pronounced (e.g. thicker). I then experimented by putting the UA sniff back in, but instead of decreasing the loops by 50%, I actually increased them by 500%. Again, this caused the trails to become even more pronounced. It does seem, however, that this thickening is asymptotic - in other words, there is a limit to how thick I can cause the trails to be by tweaking the parameters of the animation speed.
==EDIT 2==
Per @GGG's other comment, I went to go edit the image to add some transparent data in an attempt to find a suitable workaround. What I saw was that the image jutted up against the top and left edges of the canvas (that's "of the Photoshop canvas," not "of the HTML5 <canvas>
"). When I added an equal padding of transparent data to the top and left sides, the streaking problem disappeared. Here was the original PSD (pre me-adding-extra-spacing):
So my question then becomes: even if the image fills (with non-transparent pixels) the entirety of its [Photoshop] canvas, why isn't my canvas context clearRect()
behaving itself? Should that not obliterate anything within the bounds of the canvas? If so, why is it leaving these few pixels?
==EDIT 3==
After some research, it turns out that Cairo is pretty commonly used by several major rendering engines (at least WebKit and Gecko). Could it be the case, as @JonasWielicki first suggested, that the Cairo library - when optimized for mobile execution - is perhaps a bit overzealous?
Per comments, try adding some transparent pixels around the edge of the image as a workaround.
I really have no idea why this happens. I think it has something to do with odd handling of alpha channels on mobile devices, but this is nothing more than a guess.
I've noticed that mobile browsers seem to drop or "estimate" the alpha channel while scrolling (slowly scroll up and down, even the fonts look more "crispy"). I wonder if they render things in two stages, leaving the alpha channel for the second stage, and skipping the second stage if there is another "frame" to render immediately following the current "frame," if that makes any sense. Maybe that somehow confuses the renderer into thinking it hasn't drawn things in places where it has.
Anyway, this probably does warrant a bug report. I'd be curious to hear a real explanation for what's going on if nothing else.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With