我有一个简单的画布动画,如下所示:
function animate(){
var canvas = document.getElementById("canvas");
canvas.width = $(window).width();
canvas.addEventListener("click", replay, false);
var context = canvas.getContext("2d");
//animation code
function replay(e){
animate();
}
}
所以我的期望是用户点击动画将重播的画布,因为我正在重新分配宽度:
canvas.width = $(window).width();
将重置整个上下文状态(在此处阅读http://diveintohtml5.info/canvas.html)
第一次单击画布时它会起作用,但之后它会记住上下文转换状态并显示一些奇怪的动画。
我尝试添加这个:
context.setTransform(1,0,0,1,0,0);
在重新绘制之前明确地将变换矩阵重置为单位矩阵,但没有效果。
与此How to clear the canvas for redrawing
不同因为它是关于如何清除上下文的显示,但我想清除所有 显示以及上下文状态
我尝试在动画期间记录每个变量的状态我用ff代码得到了一些奇怪的东西。
function moveHorizontal(x){
if(x < 100 ){
context.translate(1, 0);
console.log("x:"+x);
drawImage();
x += 1;
setTimeout(moveHorizontal,10,x);
}
}
我最初将此函数称为 moveHorizontal(0)。
所以日志是第一次出现的预期:
x:0
x:1
x:2
.
.
x:99
当我点击“重播”时,我会得到与上面相同的内容:
x:0
x:1
x:2
.
.
x:99
正确,但是当我第二次点击“重播”时 我得到了这个:
x:0
x:0
x:1
x:1
.
.
.
x:99
x:99
使翻译三倍,导致意想不到的效果。
任何解释?
答案 0 :(得分:1)
<强>更新强>
使用新信息可能是导致问题的原因(没有足够的代码可以100%确定,但它应该给出一个很好的指针,指出问题出在哪里):
由于代码是异步的并且似乎共享一个全局/父变量x
,所以会发生的情况是,在某个时刻,在一个先前停止之前调用重放时,x会重置为0两个(或n个循环)继续。
为了防止这种情况,您需要为每次运行隔离x变量,或者使用更简单的方法阻止循环运行(如果它已经使用先前调用的x运行)。您可以使用标志来执行此操作:
var x = 0,
isBusy = false;
function animation(x) {
if (isBusy) return;
if (x < 100) {
isBusy = true;
// ...
setTimeout(...); // etc.
}
else {
isBusy = false;
}
}
可选地,存储来自setTimeout(reqID = setTimeout(...)
)的超时ID,并在调用新循环时使用clearTimeout(reqID)
。
旧答案
完全重置上下文状态的唯一方法是:
后者应该是不必要的。
根据 standard :
当用户代理将位图尺寸设置为宽度和高度时, 它必须执行以下步骤:
- 将渲染上下文重置为默认状态 ...
醇>
在帖子的示例代码中,您使用的是jQuery和vanilla JavaScript。使用canvas(或视频元素)时,我总是建议只使用vanilla JavaScript。
由于您没有显示更多代码,因此我们无法查明任何特定错误。但由于既没有设置标识矩阵也没有为画布设置大小似乎都起作用,它表明问题出现在代码的不同部分。也许您对未重置的对象有持久的偏移。
尝试消除使用jQuery设置宽度时可能出现的任何错误:
canvas.width = window.innerWidth; // and the same for height
我注意到的另外两件事是你在一个似乎是循环的一部分的函数中设置canvas的大小 - 如果是这种情况应该避免。实际上,每次发生这种情况时,浏览器都必须构建一个新的画布。第二,这一行:
canvas.addEventListener("click", replay, false);
可以简单地替换为(基于所示的代码):
canvas.addEventListener("click", animate, false);
您需要发布更多代码才能获得更深入的答案。但作为上下文的结论:设置新的大小将重置它。问题可能在代码中的其他地方。