为什么每次删除和重新创建目标元素时动画速度都会增加

Why is animation speed increasing each time the target element is deleted and recreated?

本文关键字:元素 目标 动画 速度 增加 创建 删除 新创建 为什么      更新时间:2023-09-26

我基于别人的Chrome实验创建了一个jQuery插件,它将画布元素插入到你的目标元素中,并在画布中绘制一个交互式星形字段。

每次调整窗口大小时,画布元素都会被移除,然后恢复,以便其大小与其父元素匹配,并且所有内容都会正确地设置动画;它反应灵敏。

但是,无论何时恢复,动画的速度都会增加。它为什么要这样做?我以为所有的变量(包括速度)都用这个.start()方法重置为默认值。

您可以在CodePen上看到代码(和演示);你也可以在Github上分叉,尽管我认为Github版本比我自己的版本晚了几次提交。

(此外,这是我的第一个真正的jQuery插件,所以如果你看到任何问题,请告诉我。)

有线索吗?

单独使用cancelAnimationFrame不需要停止动画循环(事实证明)。

为了绝对确定,您还需要使用条件检查-一个通用示例:

var isPlaying; /// our condition
function loop() {
    /* funky stuff here */
    If (isPlaying === true)
        requestId = requestAnimationFrame(loop);
}

然后启动:

functiom start() {
    isPlaying = true;
    loop();
}

现在,当你想停止动画你需要做:

function stop() {
    isPlaying = false;
    /// kill any request in progress
    if (requestId) cancelAnimationFrame(requestId);
}

如果你不这样做,你就有把调用堆叠到循环中的风险——例如:

如果您调整大小,并且cAF没有阻止rAF重新触发循环,则旧循环仍将在后台运行,您将在此基础上启动一个新循环。

这就是为什么你会看到速度的增加,因为新旧循环都会在恒星被绘制到屏幕之前增加位置。

在第三次重新调整大小时,又开始了另一个循环,最终整个过程将阻塞浏览器。

然而

与其使用循环的启动和停止,我建议您采用以下方法:

  • 创建一次画布
  • 循环只启动一次
  • 在这种情况下,对整个重新调整大小机制进行重新分解可能是有益的(例如,将所需的初始化(元素的宽度和高度)与以后可以重新使用的第一次初始化分开)
  • 没有必要为每个重新大小重新初始化星形,因为您将使用宽度和高度来检查它们的边界(画布将进行剪裁)

调整大小时,可以考虑使用条件标志来防止在重新调整大小时渲染

尽管通常情况下,由于JavaScript的单线程特性,在画布更改大小时阻止渲染的条件实际上是不必要的,在这种情况下,您可以对当前元素大小进行边界检查。画布本身会为您处理剪裁。

话虽如此:不应该每次都重新创建画布元素。

这会产生不必要的开销。如果画布已经创建,只需在其属性上设置新的宽度和高度:

if (typeof canvas === 'undefined')
    canvas = /* only create if it doesn't exist */
canvas.width = width;
canvas.height = height;

PS:I";"受阻";带有上面的一些暴力实现的版本。它远未完成或质量不高,但为了举例说明,它消除了一些痛苦,给你一些建议。

请根据您的需要领养。

更新

要包含更多来自附加评论的信息:

当在画布元素上设置新大小时,其上下文将重置为默认值(fillStyle变为透明,strokeStyle变为黑色,转换重置,依此类推)。

这意味着在设置每个新大小后,必须重新设置所有非默认设置。

设置新的大小也可以(通常也可以)清除画布的内容,使所有像素都变成透明的黑色。

对于手动更新canvas元素维度的用户:

调整canvas元素的大小会导致它丢弃任何绘制到调整大小点的内容。

这个脚本的动画应该在调整大小后继续绘制到画布上,但唯一会更新的是背景的fillRect;星星消失了。

在更改canvas元素的维度后,唯一能让恒星返回的方法是:额外调用context.strokeStyle。我不知道为什么;如果有人能澄清这件事,我将不胜感激。

编辑: 根据下面的注释,画布中的所有都会重置,包括笔划和填充样式(显然都默认为黑色)。因此,当调整大小时,我不得不重新定义笔划和填充样式。