【问题标题】:Mobile Chrome bug - animated canvas crashes the browser when canvas height is 3-5 times the screen height AND canvas on canvas is used移动 Chrome 错误 - 当画布高度是屏幕高度的 3-5 倍并且使用画布上的画布时,动画画布会使浏览器崩溃
【发布时间】:2020-04-02 23:47:06
【问题描述】:

如果你使用它,它可以正常工作(在画布上使用 img):

ctx_bg.drawImage($("#image_tile")[0], positions[i].x, positions[i].y);

如果你使用这个,它会在 3 秒内让浏览器崩溃(使用 canvas on canvas):

ctx_bg.drawImage($(".canvas_tile")[0], positions[i].x, positions[i].y);

以上 2 行是下面 2 个展示之间的唯一区别。在 Android 上测试(三星 S10、Chrome 80.0.3987.149)。

此外,当画布高度较小(1-2 个屏幕高度)时,画布上的画布也能正常工作。此外,它在桌面 chrome 上也能正常工作!

这是移动浏览器的错误还是可以修复?

编辑: 由于您无法在 stackoverflow mobile view 上运行以下代码,因此这里是在移动设备上查看的快速链接:

这在移动设备上使用了第二个 CANVAS 粒子和崩溃:

$(document).ready(function() {

    ctx_bg = $(".bg_canvas")[0].getContext("2d");
    ctx_child = $(".canvas_tile")[0].getContext("2d");

    ctx_child.beginPath();
    ctx_child.arc(20, 20, 5, 0, 1.5 * Math.PI);
    ctx_child.stroke();

    innerWidth = $("body").innerWidth();
    innerHeight = $("body").innerHeight()*5; 
    numberOfElements = 222;
    positions = [];
    angle = 0;


    $(".bg_canvas")[0].width = innerWidth; 
    $(".bg_canvas")[0].height = innerHeight;

    for (var i=0; i<numberOfElements; i++) {
        positions.push({x: Math.random()*innerWidth, y: Math.random()*innerHeight});
    };


    function animateCircles() {
        bgAnimation = requestAnimationFrame(animateCircles)
        ctx_bg.clearRect(0, 0, innerWidth, innerHeight);
        for (var i = 0; i < numberOfElements; i++){
            positions[i].y+=3;
            if (positions[i].y > innerHeight) {
                positions[i].y = 0;
            }
            ctx_bg.drawImage($(".canvas_tile")[0], positions[i].x, positions[i].y);
            // ctx_bg.drawImage($("#image_tile")[0], positions[i].x, positions[i].y);
        }
    }
    animateCircles()
})
body, html {
    padding: 0;
    margin: 0;
    width: 100%;
    height: 100%;
}
#image_tile, .canvas_tile  {
    display: none;
}
<!DOCTYPE html>

<html>
    <head>
        <title>KRAATER</title>
        <meta charset="UTF-8">
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.0/jquery.min.js"></script>
    </head>
    <body>
        <img id="image_tile" src="https://www.gravatar.com/avatar/435af02114568dbaf00005b28c3ef592?s=48&d=identicon&r=PG">
        <canvas class="canvas_tile"></canvas>
        <canvas class="bg_canvas"></canvas>
    </body>
</html>

这使用了 2nd BITMAP 粒子并在移动设备上运行:

$(document).ready(function() {

    ctx_bg = $(".bg_canvas")[0].getContext("2d");
    ctx_child = $(".canvas_tile")[0].getContext("2d");

    ctx_child.beginPath();
    ctx_child.arc(20, 20, 5, 0, 1.5 * Math.PI);
    ctx_child.stroke();

    innerWidth = $("body").innerWidth();
    innerHeight = $("body").innerHeight()*5;
    numberOfElements = 222;
    positions = [];
    angle = 0;


    $(".bg_canvas")[0].width = innerWidth; 
    $(".bg_canvas")[0].height = innerHeight;

    for (var i=0; i<numberOfElements; i++) {
        positions.push({x: Math.random()*innerWidth, y: Math.random()*innerHeight});
    };


    function animateCircles() {
        bgAnimation = requestAnimationFrame(animateCircles)
        ctx_bg.clearRect(0, 0, innerWidth, innerHeight);
        for (var i = 0; i < numberOfElements; i++){
            positions[i].y+=3;
            if (positions[i].y > innerHeight) {
                positions[i].y = 0;
            }
            // ctx_bg.drawImage($(".canvas_tile")[0], positions[i].x, positions[i].y);
            ctx_bg.drawImage($("#image_tile")[0], positions[i].x, positions[i].y);
        }
    }
    animateCircles()
})
body, html {
    padding: 0;
    margin: 0;
    width: 100%;
    height: 100%;
}
#image_tile, .canvas_tile  {
    display: none;
}
<!DOCTYPE html>

<html>
    <head>
        <title>KRAATER</title>
        <meta charset="UTF-8">
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.0/jquery.min.js"></script>
    </head>
    <body>
        <img id="image_tile" src="https://www.gravatar.com/avatar/435af02114568dbaf00005b28c3ef592?s=48&d=identicon&r=PG">
        <canvas class="canvas_tile"></canvas>
        <canvas class="bg_canvas"></canvas>
    </body>
</html>

【问题讨论】:

  • 是的,这是一个错误。浏览器永远不应该崩溃。现在,您显然已经知道至少一种方法:使用 。你还想从 stackoverflow 社区获得什么?如果该错误不存在,请报告该错误。 this one 被标记为已修复,但它们的解决方法很可能不适合移动设备。也许你可以就这个问题发表评论。
  • 另外,不相关,但实际上将innerWidth = foo 设置 window.innerWidthfoo,弄乱了页面上依赖此值的任何其他脚本成为它应该的样子。此外,存储您的 DOM 元素,而不是在每次迭代时创建大量的 jQuery 对象。
  • @Kaiido,请解释一下,我如何在每次迭代中创建 jQuery 对象?
  • ctx_bg.drawImage( $(".canvas_tile")[0] ...这会在每次迭代时创建一个新的 jQuery 对象。只需在任何循环之外存储一次const source = $(.canvas_tile")[0],然后调用ctx_bg.drawImage(source...
  • 您最好能够使用可测试的源来备份此类声明,只需使用 jquery 执行 getelement... 不会创建新对象

标签: canvas html5-canvas mobile-chrome


【解决方案1】:

目前,我通过将画布数据首先转换为图像的 hack 解决了这个问题:

$("<img src='" + targetCanvas.toDataURL() + "'>");

然后将其附加到 DOM 并将该图像加载到大画布中。效率不是很高,因为对于大型 img 对象,渲染会变慢,所以我建议只使用它来渲染手机尺寸并在桌面上使用 canvas on canvas。

如果其他帖子出现,将奖励“接受的答案”给不是黑客的帖子。

另一种解决方案是固定主画布的位置并根据滚动量移动内容,但会有延迟。

【讨论】:

    猜你喜欢
    • 2023-04-03
    • 2014-04-07
    • 2014-02-16
    • 1970-01-01
    • 2015-02-01
    • 1970-01-01
    • 2016-11-05
    • 2012-05-17
    • 2012-07-04
    相关资源
    最近更新 更多