I am about to draw many stars, like 10000 in canvas and continuouslly creating new one and fade out the old one.
Here is my thinking:
- create some stars per frame
- draw all stars per frame
- when star count reaches threshold, create a new canvas and leave the old canvas alone, empty star list. And from now, drawing stars in new canvas. This will make browser only drawing the max count of stars and looks like there are much more stars.
- when canvas count reaches threshold, just fade out and remove the very first one.
So there are always new stars created and old stars faded out, also high performance.
But after running about 1 minute, the fps suddenly became very low, what's the problem in there?
Here are my code sample below (only run in full-page mode will cause the 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 it was a Chrome Bug, works fine in IE 11 and FireFox