移动 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 工作正常。此外,它在桌面上运行良好 [=70=]!
这是移动浏览器的错误还是可以修复?
编辑:
由于您无法在 Whosebug 移动视图 上 运行 下面的代码,因此这里是在移动设备上查看的快速链接:
- http://kraater.ee/Whosebug/image_on_canvas.html
- http://kraater.ee/Whosebug/canvas_on_canvas.html <- 注意!会崩溃选项卡
这使用第 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 的位置并根据滚动量移动内容,但它会有延迟。
如果你使用它,它工作正常(在 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 工作正常。此外,它在桌面上运行良好 [=70=]!
这是移动浏览器的错误还是可以修复?
编辑: 由于您无法在 Whosebug 移动视图 上 运行 下面的代码,因此这里是在移动设备上查看的快速链接:
- http://kraater.ee/Whosebug/image_on_canvas.html
- http://kraater.ee/Whosebug/canvas_on_canvas.html <- 注意!会崩溃选项卡
这使用第 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 的位置并根据滚动量移动内容,但它会有延迟。