Canvas when drawing a huge amount of images
I am going to paint as many stars as 10,000 on canvas and constantly create new ones and fade out of the old.
Here's my thinking:
- create several stars per frame
- draw all the stars per frame
- when the number of stars reaches the threshold, create a new canvas and leave only the old canvas, an empty list of stars. And from now on, painting stars in a new canvas. This will force the browser to only draw as many stars as possible and looks like there are many more.
- when the number of canvases reaches the threshold, it just disappears and removes the first one.
In this way, new stars always appear and old stars disappear, as well as high performance.
But after starting for about 1 minute, the fps suddenly became very low, what's the problem there?
Here is my sample code below ( only works in full screen mode, this will cause a problem and I don't know why. Tested in Chrome 58 ):
var container, star, starCtx,
starList = [],
starShapeList = [],
canvasList = [],
starSize = 22,
maxCanvasCount = 10,
starCountPerCanvas = 500;
var width = window.innerWidth, height = window.innerHeight;
init();
function init() {
container = document.createElement('div');
// for drawing stars
starCtx = createCanvas();
star = document.createElement('img');
star.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAMAAADzapwJAAAAM1BMVEX/hAD/hQD1kA3+hQHykxH7iQbXsDDVsTHqnBnrmxjPtzjGwkTKvT7WsDC7zE++yUzNuTrg0dc+AAAAEXRSTlMBBhELFg0mMCAaOVNGH3psPn/xpHgAAACMSURBVBjTndBLDsMgDEXR5vFsbCCf/a+2CahYidRJ7vAIYcznXUvvadFdU294KCAAKN0nC1eCvuLyqUmo6q4KST+/FNRiuRhPDwZoR2vFnAgWrprbvrec1TEZpx5122q5cQLdSq3zkhhpJT9HLgJoNtPM8fA4rk5S2Q/HPiB6Y5vwJGep67+PjQJf9AUF8wQVfnj+ngAAAABJRU5ErkJggg==';
star.onload = function () {
var size = starSize;
// init 60 stars in each rotate (for star is a regular hexagon)
for (var i = 0; i < 60; i++) {
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
canvas.width = size;
canvas.height = size;
ctx.translate(size / 2, size / 2);
ctx.rotate(i * Math.PI / 180);
ctx.translate(-size / 2, -size / 2);
ctx.drawImage(star, 0, 0);
starShapeList.push(canvas);
}
// start animation
animate();
}
}
function createCanvas() {
var canvas = document.createElement('canvas');
canvas.style.width = width + 'px';
canvas.style.height = height + 'px';
canvas.width = width * window.devicePixelRatio;
canvas.height = height * window.devicePixelRatio;
container.appendChild(canvas);
canvasList.push(canvas);
// return the ctx of created canvas
return canvas.getContext('2d');
}
function Star() {
// pick a random shape
this.canvas = starShapeList[_.random(starShapeList.length - 1)];
this.size = starSize;
this.scale = 0.01;
// set a random max scale
this.maxScale = _.random(60, 120) / 100;
// set a random position
this.position = {
x: _.random(width),
y: _.random(height)
};
// start a scale animation
new TWEEN.Tween(this)
.to({
scale: this.maxScale
}, 1000)
.start()
}
function animate() {
// log time per frame
console.timeEnd('per frame');
console.time('per frame');
requestAnimationFrame(animate);
render();
}
function render() {
// update tween
TWEEN.update();
// clear
starCtx.clearRect(0, 0, width, height);
// draw each star in star list
starList.forEach(function (item) {
// get current size
var size = item.size * item.scale;
starCtx.drawImage(item.canvas, 0, 0, item.size, item.size, item.position.x - size / 2, item.position.y - size / 2, size, size);
});
// create 10 stars per frame
for (var i = 0; i < 10; i++) {
starList.push(new Star());
}
// when star count reached max star count per canvas
if (starList.length > starCountPerCanvas) {
// create a new canvas
starCtx = createCanvas();
// clear star list
starList.length = 0;
// when canvas count reached max canvas count, fade out and remove the very first one
if (canvasList.length > maxCanvasCount) {
var c = canvasList.shift();
$(c).fadeOut(1000, function () {
this.remove();
});
}
}
}
window.onload = function () {
document.body.appendChild(container);
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background-color: black;
}
canvas {
position: absolute;
top: 0;
left: 0;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Test</title>
</head>
<body>
<script src="http://cdn.bootcss.com/underscore.js/1.8.3/underscore-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tween.js/16.3.5/Tween.min.js"></script>
</body>
</html>
Confirmed this is a Chrome bug, works fine in IE 11 and FireFox
+3
troy
source
to share
No one has answered this question yet
Check out similar questions:
305
ten
five
4
2
1
1
0
0
-1