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为其设置动画时,清除并重绘画布上的图像会导致闪烁。
有没有办法让轨道动画变得平滑?或者更好的方法来创建轨道动画?
答案 0 :(得分:2)
问题是每次在圆圈中渲染时都会重新加载图像的新实例。网络延迟会导致您看到此闪烁。首先加载图像然后重新使用数据我删除了闪烁。
这是一个工作版本: http://codepen.io/anon/pen/JRVJRJ
我已将base_image
的{{1}}加载移出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);
}
});
答案 1 :(得分:2)
当浏览器上的动画始终使用resquestAnimationFrame
时,只需将新的像素数据与刷新时间同步移动到显示器,它就会比setInterval
和setTimeout
提供更好的结果。
闪烁的原因
这很复杂......
基本原因是您每次要使用它时都要加载图像。在代码停止运行之前,onload不会触发。当您的代码停止运行时,画布内容将显示在显示屏上,并且它将为空,因为您刚清除它(在您退出绘图功能之前不会触发任何事件)。然后onload事件将开始触发,每个事件都在画布上绘制图像。当事件退出时,浏览器认为&#34;好的,你想把它放到显示器上!&#34;并且整个画布再次呈现给显示器。因为这比屏幕刷新率快得多,你会得到奇怪的剪切,闪烁和跳跃效果。
另一个原因是使用setInterval
来自 DominicValenciana 的答案仍然使用setInterval
,如果你仔细观察,你会发现它不像使用{{{ 1}}。好的动画应该像丝绸一样光滑(尽可能接近)
演示下面的一些提示。
This answer也有助于解释图片加载和绘图。
requestAnimationFrame
&#13;
Angles,PI和Trig
您对精灵位置的计算
(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();
})();
在显示屏顶部(12点位置)有零(角度= 0)。要匹配画布旋转功能使用的相同角度,请使用
x = Math.sin(angle);
y = Math.cos(angle);
屏幕右侧(3挂锁位置)<零>
如果您想继续创建动画和计算机图形。忘了大约360度。圈子是2PI不是360左右,PI是半圈180,PI / 2是四分之一圈90,PI / 30是每分钟一分钟的动作,圈子周围的距离是x = Math.cos(angle);
y = Math.sin(angle);
,大约半圈2*PI*radius
。 JS中的每个trig函数都使用弧度(不是烦人的,或者是钝的,但因为它使用起来要简单得多),如果你在deg中工作,你总是需要在某个阶段使用PI,所以只需减少不必要的开销。 / p>
常量和变量
如果您从未打算更改变量,则仅初始化变量一次。更好的是,如果变量引用永远不需要更改,则使其成为常量PI * radius
如果您尝试以任何方式更改它将导致错误const myVar = 10;
ERROR !!!!!
表现一切的动画
制作动画时,保持最佳性能非常重要,这样您就可以在动画质量上投入更多。设置变换时,使用myVar = 10;
ctx.setTransform(scale,0,0,scale,x,y);
要容易得多,因为您不需要为变换保存和恢复完整的画布状态。如果您希望获得默认转换,请使用ctx.rotate(angle);
不要支持死者
不需要moz,webkit前缀ctx.setTransform(1,0,0,1,0,0);
无处不在。据我所知,如果浏览器不支持requestAnimationFrame
它不支持画布,我们不应该支持浏览器。 requestAnimationFrame不仅适用于canvas,它还应该用于您创建的任何基于DOM javascript的动画。