Skip to content

Instantly share code, notes, and snippets.

@pbogden
Last active April 21, 2017 19:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pbogden/d0aee90f42acc6009d4a5cd309c7da32 to your computer and use it in GitHub Desktop.
Save pbogden/d0aee90f42acc6009d4a5cd309c7da32 to your computer and use it in GitHub Desktop.
canvas performance

Canvas performance

Canvas starts having problems when drawing more than 100K points at a time.

  • 2m -- ~1 / 15 fps = 130K dots/sec (but startup is noticeable)
  • 1m -- ~ 1 / 7 fps = 180K dots/sec (ditto)
  • 500K -- ~1 / 2 fps = 206K dots/sec (ditto)
  • 200K -- ~1 fps = 240K dots/sec
  • 100K -- ~3 fps = 310K dots/sec
  • 50K -- ~6 fps = 320K dots/sec
  • 10K -- ~32 fps = 320K dots/sec
  • 5K -- 60 fps = 300K dots/sec // maximum fps (frames/sec)

Chrome & Firefox max speed: ~320K dots/sec.

Safari max speed: ~200K dots/sec (39 fps for 5K points).

Bottom line: Use context.fill() every ~5-50K points for more than 100K total points.

<!DOCTYPE html>
<meta charset="utf-8">
<title>canvas performance</title>
<style>
body {
margin: 0;
}
div {
position: absolute;
top: 0px;
left: 0px;
}
</style>
<body>
<canvas width="960" height="500"></canvas>
<script src="//d3js.org/d3.v4.min.js"></script>
<script>
// # of points to draw
var n = 5000;
var fmt = d3.format(",d");
var canvas = d3.select("canvas").node();
var context = canvas.getContext("2d");
var width = canvas.width, height = canvas.height;
var x = d3.scaleLinear().range([0, width]),
y = d3.scaleLinear().range([height, 0]);
var info = d3.select('body').append('div')
.style('position', 'absolute')
.style('top', '0')
.style('left', '0')
.style('padding', '5px')
.style('background-color', '#aaa')
var start = d3.now(), t0 = 0, sum = 0, cnt = 0;
addPoints(t0);
function addPoints(t) {
var fps = 1000 / (t - t0);
if (t !== 0) { sum += fps; cnt++ };
info.html(fmt(fps) + " fps for " + fmt(n) +' points = ' + fmt(n * fps) + ' dots/sec');
console.log('cnt, sec/frame', cnt, 1 / fps)
// Stop after 30 seconds
if (t > 30 * 1000) return finalTime(t);
context.clearRect(0, 0, width, height);
context.beginPath();
for (var i = 0, px, py; i < n; ++i) {
px = x(Math.random()), py = y(Math.random());
if (px < 0 || py < 0 || px > width || py > height) console.log('bad', i, px, py)
context.moveTo(px + 2.5, py);
context.arc(px, py, 2.5, 0, 2 * Math.PI);
}
context.fill();
t0 = t;
requestAnimationFrame(addPoints)
}
function finalTime(t) {
var dt = (d3.now() - start) / 1000; // Total elapsed time (seconds), including startup
var fps = cnt / dt; // Average FPS, including startup
info.html(fmt(fps) + " fps for " + fmt(n)
+ ' points = ' + fmt(n * fps) + ' dots/sec'
+ ', initial startup: ' + fmt(dt - t / 1000));
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment