移动 Chrome 错误 - 当 canvas 高度是屏幕高度的 3-5 倍并且使用 canvas 上的 canvas 时,动画 canvas 会使浏览器崩溃

Mobile Chrome bug - animated canvas crashes the browser when canvas height is 3-5 times the screen height AND canvas on canvas is used

如果你使用它,它工作正常(在 canvas 上使用 img):

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

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

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

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

此外,当 canvas 高度较小(1-2 屏幕高度)时,canvas 上的 canvas 工作正常。此外,它在桌面上运行良好 [=7​​0=]!

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

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

这使用第 2 个 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>

这使用第二个 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>

现在,我用一个 hack 解决了这个问题,首先将 canvas 数据转换为图像:

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

然后将其附加到 DOM 并将该图像加载到大 canvas。效率不高,因为对于大型 img 对象,渲染速度会变慢,所以我建议只使用它来渲染 phone 大小,并在桌面上 canvas 上使用 canvas。

将 "accepted answer" 奖励给另一个 post 不是 hack 的人,如果它出现了。

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