If you use this, it works fine (using img on canvas):
ctx_bg.drawImage($("#image_tile")[0], positions[i].x, positions[i].y);
If you use this, it crashes the browser within 3 seconds (using canvas on canvas):
ctx_bg.drawImage($(".canvas_tile")[0], positions[i].x, positions[i].y);
Above 2 lines are the only difference between the 2 showcases below. Tested on Android (Samsung S10, Chrome 80.0.3987.149).
Also, canvas on canvas works fine when the canvas height is smaller (1-2 screen heights). Also, it works fine on desktop chrome!
Is this a mobile browser bug or is it fixable?
EDIT: Since you can't run below code on stackoverflow mobile view, then here are quick links to view on mobile:
This uses 2nd CANVAS particles and CRASHES on mobile:
$(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>
This uses 2nd BITMAP particles and WORKS on mobile:
$(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>
For now, I solved it with a hack which converts the canvas data first to image:
$("<img src='" + targetCanvas.toDataURL() + "'>");
Then appending this to the DOM and loading that image into the large canvas. Not very efficient, as with large img objects the rendering will slow down, so I suggest only using it to render for phone sizes and use canvas on canvas on desktop.
Will award "accepted answer" to another post that is not a hack, if it comes around.
Another solution would be to make the main canvas's position fixed and moving the content based on scrolled amount, but it will have lag.