在画布动画中闪烁的图像
Flickering images in canvas animation
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);
});
问题是当我尝试循环图像创建一个环形形状和动画它通过使用setInterval,清除和重新绘制画布上的图像结果闪烁。
有办法使轨道动画平滑吗?或者更好的方法来创建轨道动画?
Codepen
画布动画。
当浏览器上的动画总是使用requestAnimationFrame
时,它提供了比setInterval
和setTimeout
更好的结果,它只移动新的像素数据到显示器与刷新时间同步。
为什么闪烁
很复杂…
基本原因是每次想要使用它时都要加载图像。onload直到代码停止运行后才会触发。当代码停止运行时,画布内容将呈现给显示器,并且它将为空,因为您刚刚清除了它(在退出绘制函数之前不会触发任何事件)。然后onload事件将开始触发,每个事件都在画布上绘制图像。当事件退出时,浏览器认为"好吧,你想把它显示出来!"整个画布再次呈现在显示器上。因为这比屏幕刷新率快得多,所以你会得到奇怪的剪切,闪烁,跳跃效果。
另一个原因是使用setInterval
的答案来自DominicValenciana仍然使用setInterval
,如果你仔细看,你会发现它不像使用requestAnimationFrame
那样流畅。好的动画应该平滑如丝(以及尽可能接近)
下面的一些提示。
这个答案也将有助于解释图像加载和绘制。
(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();
})();
角度、PI和三角函数
你对精灵位置的计算
x = Math.sin(angle);
y = Math.cos(angle);
在显示器的顶部(12点钟位置)为零(角度= 0)。要匹配画布旋转函数使用的相同角度,请使用
x = Math.cos(angle);
y = Math.sin(angle);
这个在屏幕的右边有0 (3clock的位置)
如果你想继续创建动画和计算机图形。忘掉360度吧,圆是2PI,不是360,PI是半圈180,PI/2是四分之一圈90,PI/30是分针每分钟的运动,绕一个圆的距离是2*PI*radius
,绕半个圆的距离是PI * radius
。JS中的每个三角函数都使用弧度(不是为了烦人,也不是为了钝化,而是因为它使用起来更简单),如果你用度来工作,在某些阶段你总是需要使用PI,所以只要减少不必要的开销就可以了。
常量和变量
如果你不打算改变变量,只初始化它一次。更好的是,如果一个变量引用永远不需要改变,让它成为一个常量const myVar = 10;
,如果你试图以任何方式改变它,它会抛出一个错误myVar = 10;
error !!!!!
动画,表现就是一切
当制作动画时,保持最大的性能是很重要的,这样你就可以在动画质量上投入更多。当设置转换时,使用ctx.setTransform(scale,0,0,scale,x,y);
ctx.rotate(angle);
要容易得多,因为您不需要为转换保存和恢复完整的画布状态。如果您希望获得默认转换,请使用ctx.setTransform(1,0,0,1,0,0);
不支持已死
不需要moz,webkit前缀requestAnimationFrame
无处不在。据我所知,如果浏览器不支持requestAnimationFrame
,它不支持画布,我们不应该支持浏览器。此外,requestAnimationFrame不只是用于画布,它应该用于任何基于DOM javascript的动画你创建。
问题是每次在圆圈中渲染图像时都会重新加载图像的新实例。网络延迟导致您看到的这种闪烁。通过首先加载图像,然后重用数据,我已经删除了闪烁。
这是一个工作版本:http://codepen.io/anon/pen/JRVJRJ
我已经将base_image
的加载移出make_base
函数,并使其成为make_base
函数中重用的全局变量。导致图像被加载一次,并重新应用多次。
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) {
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);
}
}
base_image = new Image();
base_image.src = 'https://gxzzxb.files.wordpress.com/2014/12/16mario.png';
base_image.onload = function(){
var step = 0;
draw(step);
setInterval(function() {
draw(step);
++step;
}, 20);
}
});
- 如何使用按键避免图像闪烁
- 使用setInterval()函数进行图像闪烁
- addClass,它更改bg图像,但在第一次加载时没有闪烁
- 悬停时setInterval中的图像闪烁
- 按下按钮时图像持续闪烁
- jQuery图像在悬停时闪烁
- 当使用MouseEvent将图像更改为其他图像时,如何避免闪烁
- 正在创建随机图像闪烁
- 滚动的背景图像仍在闪烁
- jQuery-鼠标输入闪烁图像
- Javascript图像动画闪烁图像错误
- skrollr背景图像在Firefox中闪烁
- iOS 8中滚动时的背景图像闪烁问题
- 在画布中拖动时图像会闪烁
- 卡曼图像操纵和闪烁
- 猫头鹰图像轮播 - 闪烁的按钮
- 将闪烁的图像从左向右移动 jquery
- JQuery循环闪烁图像
- Jquery旋转木马闪烁图像问题
- Jquery .hover -闪烁图像