画布动画中闪烁的图像 [英] Flickering images in canvas animation

查看:61
本文介绍了画布动画中闪烁的图像的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  window.requestAnimFrame =(function(callback){
返回window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
函数(回调){
window.setTimeout(callback,1000/60);
};
})();

$ {function(){
var centerX = 400,
centerY = 400,
radius = 300;

function make_base( ctx,angle){
base_image = new Image();
base_image.src ='https://gxzzxb.files.wordpress.com/2014/12/16mario.png';
base_image.onload = function(){
ctx.save();
var x = centerX + Math.sin(angle)* radius;
var y = centerY + Math.cos(angle )*半径;
ctx.translate(x,y);
ctx.drawImage(base_image,0,0);
ctx.rotate(angle);
ctx.restore ();
}
}

函数draw(step){
var ctx = document.getElementById( canvas)。getContext( 2d);
ctx.clearRect(0,0,canvas.width,canvas.height);
可变角度;
for(var i = 0; i< 180; i + = 10){
angle = step +(i * Math.PI / 90);
make_base(ctx,angle);
}
}

var step = 0;

开奖(步骤);

setInterval(function(){
draw(step);
++ step;
},20);
});

问题是当我尝试循环图像以创建环形并使用setInterval对其进行动画处理时,清除并重新绘制画布上的图像会导致闪烁。



有没有一种方法可以使轨道动画变得平滑?还是创建轨道动画的更好方法?



Codepen

解决方案

画布动画。



在浏览器上进行动画制作时,请始终使用 resquestAnimationFrame ,它提供的结果比 setInterval setTimeout 好得多通过仅将新像素数据与刷新时间同步移动到显示器。



为什么闪烁



这很复杂...



基本原因是您每次想使用图像时都在加载图像。在代码停止运行之前,不会触发onload。当您的代码停止运行时,画布内容将显示在显示器上,并且由于您将其清除而将其显示为空(除非退出绘图功能,否则不会触发任何事件)。然后onload事件将开始触发,每个事件都会在画布上绘制图像。事件退出时,浏览器会认为确定,您希望将其显示在屏幕上!整个画布再次呈现给显示器。因为此操作比屏幕刷新速度快得多,所以您会得到怪异的剪切,闪烁,跳跃效果。



另一个原因是使用 setInterval DominicValenciana 的答案仍然使用 setInterval ,如果仔细看,您会发现使用 requestAnimationFrame 。好的动画应该像丝绸一样平滑(并尽可能接近)



演示下方的一些技巧。



此答案还将帮助解释图像的加载和绘制。



 (function(){const oneDeg = Math.PI / 180; const D1 = Math.PI / 180; //再次用于懒惰的程序员const centerX = 400; const centerY = 400; const radius = 300; //创建并加载图像const base_image = new Image(); base_image.src ='https://gxzzxb.files.wordpress.com/2014/12/16mario .png'; //创建尺寸并将画布添加到DOM常量c = document.createElement( canvas); c.width = 800; c.height = 800; document.body.appendChild(c); const ctx = c.getContext( 2d); //获取上下文var步骤= 0; //动画步骤函数draw(){//主绘制函数var x,y,i,angle; if(base_image.complete){//已加载图像ctx.setTransform(1,0,0,1,0,0); //重置变换ctx.clearRect(0,0,c.width,c.height); for(i = 0; i  



角度,PI和Trig



您计算的精灵位置

  x = Math.sin(angle); 
y = Math.cos(angle);

在显示屏顶部(12点钟位置)为零(角度= 0)。要使画布旋转功能使用相同的角度,请使用

  x = Math.cos(angle); 
y = Math.sin(angle);

在屏幕右侧(3点钟位置)为零



如果要继续创建动画和计算机图形。忘了360度吧。圆圈是2PI,而不是360,PI是180度的半圈,PI / 2是90度的四分之一圈,PI / 30是每分钟的分针运动,围绕圆圈的距离是 2 * PI *半径,大约半圆 PI *半径。 JS中的每个trig函数都使用弧度(不要烦人或钝角,但是因为它使用起来简单得多),如果在deg中工作,则始终需要在某个阶段使用PI,因此只需减少不必要的开销。 / p>

常量和变量



如果您从未打算对其进行更改,则仅初始化一次变量。更好的是,如果永远不需要更改变量引用,则将其设置为常量 const myVar = 10; 如果尝试以任何方式对其进行更改,将抛出错误 myVar = 10; 错误!!!!!



动画就是一切的表现



制作动画时,保持最佳性能非常重要,这样您可以在动画质量上进行更多投资。设置转换时,使用 ctx.setTransform(scale,0,0,scale,x,y); ctx.rotate(角); ,因为您无需保存和恢复仅用于转换的完整画布状态。如果希望获得默认的转换,请使用 ctx.setTransform(1,0,0,1,0,0);



不支持死者



不需要Moz,Webkit前缀为 requestAnimationFrame 无处不在。据我所知,如果浏览器不支持 requestAnimationFrame ,则它不支持canvas,我们也不应该像那样支持。同样,requestAnimationFrame不仅适用于画布,还应用于您创建的任何基于DOM javascript的动画。


window.requestAnimFrame = (function(callback) {
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
function(callback) {
    window.setTimeout(callback, 1000 / 60);
};
})();

$(function() {
    var centerX = 400,
    centerY = 400,
    radius = 300;

    function make_base(ctx, angle) {
        base_image = new Image();
        base_image.src = 'https://gxzzxb.files.wordpress.com/2014/12/16mario.png';
        base_image.onload = function(){
            ctx.save();
            var x = centerX + Math.sin(angle) * radius;
            var y = centerY + Math.cos(angle) * radius;
            ctx.translate(x, y);
            ctx.drawImage(base_image, 0, 0);
            ctx.rotate(angle);
            ctx.restore();
        }
    }

    function draw(step) {
        var ctx = document.getElementById("canvas").getContext("2d");
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        var angle;
        for (var i = 0; i < 180; i += 10) {
            angle = step + (i * Math.PI / 90);
            make_base(ctx, angle);
        }
    }

    var step = 0;

    draw(step);

    setInterval(function() {
        draw(step);
        ++step;
    }, 20);
});

The issue is when i try to loop the image to create a ring shape and animate it by using setInterval, clearing and redrawing the images on the canvas results to flicker.

Is there a way to smoothen the orbit animation? or a better way to create an orbit animation?

Codepen

解决方案

Canvas animations.

When animating on a browser always use resquestAnimationFrame, it gives far better results than setInterval and setTimeout by only moving new pixel data to the display in sync with the refresh time.

Why the flicker

It's complicated...

The basic reason is that you were loading the image each time you wanted to use it. The onload will not fire until after your code has stopped running. When your code stops running the canvas content will be presented to the display and it will be empty because you just cleared it (no event will fire until you exit the draw function). Then the onload events will start to fire, each drawing the image on the canvas. When the event exits the browser thinks "ok you want to put that to the display!" and the whole canvas is again presented to the display. Because this happens much faster than the screen refresh rate you get you weird shearing, flickering, jumping effect.

Another reason is the use of setInterval The Answer from DominicValenciana still uses setInterval and if you look carefully you will see that it is not a smooth as using requestAnimationFrame. Good animation should be smooth as silk (well as close a possible)

Some tips below the demo.

This answer will also help explain image loading and drawing.

(function () {
    const oneDeg = Math.PI / 180;
    const D1 = Math.PI / 180; // again for lazy programmers
    const centerX = 400;
    const centerY = 400;
    const radius = 300;
    // create and load image
    const base_image = new Image();
    base_image.src = 'https://gxzzxb.files.wordpress.com/2014/12/16mario.png';
    // create size and add to DOM a canvas
    const c = document.createElement("canvas");
    c.width = 800;
    c.height = 800;
    document.body.appendChild(c);        
    const ctx = c.getContext("2d");  // get context
    var step = 0;  // the animation step


    function draw() {  // the main draw function
        var x,y,i,angle; 
        if(base_image.complete){  // has the image loaded
            ctx.setTransform(1, 0, 0, 1, 0, 0);  // reset transform                 
            ctx.clearRect(0, 0, c.width, c.height); 
            for (i = 0; i < Math.PI * 2; i += D1 * 10) {  // 360 in steps of 10
                angle = step + i;  // angle in radians
                x = centerX + Math.sin(angle) * radius;
                y = centerY + Math.cos(angle) * radius;
                ctx.setTransform(1, 0, 0, 1, x, y); // set translate and scale no need for save restore
                ctx.rotate(angle);   // set angle
                ctx.drawImage(base_image, 0, 0); //draw image
            }
            step += 1* D1; // step 1 deg per frame
        }
        requestAnimationFrame(draw);
    }
    draw();
})();

Angles, PI, and Trig

Your calculation for the position of the sprite

x = Math.sin(angle);
y = Math.cos(angle);

has zero (angle = 0) at the top of the display (the 12 oclock position). To match the same angle as used by the canvas rotate function use

x = Math.cos(angle);
y = Math.sin(angle);

this has zero at the right of the screen (the 3oclock position)

If you want to keep creating animations and computer graphics. Forget about 360 deg. Circles are 2PI around not 360, PI is half a turn 180, PI/2 is a quarter turn 90, PI/30 is a minute hands movement per minute, the distance around a circle is 2*PI*radius, around half a circle PI * radius. Every trig function in JS uses radians (not to be annoying, or obtuse, but because it is far simpler to use), You will always need to use PI at some stage if you work in deg, so just drop the unnecessary overhead.

Constants and variables

Only initialize variables once if you never intend to change it. Better yet if a variable reference never needs to be changed make it a constant const myVar = 10; if you try and change it in any way it will throw an error myVar = 10; ERROR!!!!!

Animation where performance is everything

When animating it is important to keep performance at maximum so you can invest more into the quality of the animation. When setting the transform it is far easier to use ctx.setTransform(scale,0,0,scale,x,y); ctx.rotate(angle); as you do not need to save and restore the full canvas state just for transforms. If you wish to get the default transform use ctx.setTransform(1,0,0,1,0,0);

Don't support the dead

No need for the moz,webkit prefixed requestAnimationFrame is everywhere. and as far as I know if a browser does not support requestAnimationFrame it does not support canvas, and we should not support as browser that does. Also requestAnimationFrame is not just for canvas, it should be used for any DOM javascript based animations you create.

这篇关于画布动画中闪烁的图像的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆