Skip to content

Instantly share code, notes, and snippets.

@Andrew-Reid
Last active September 17, 2018 03:28
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 Andrew-Reid/4a5757eb86bf00c6f2e2987d0c064410 to your computer and use it in GitHub Desktop.
Save Andrew-Reid/4a5757eb86bf00c6f2e2987d0c064410 to your computer and use it in GitHub Desktop.
A Fair Number of Transitions

An effort to see how many points I can animate along their own paths (each path has three segments, each path goes through 2 of six rough areas).

100 000 nodes are animated in this (10 loops).

Some browsers may not work with this many transitions. Based on quick work for this SO question.

No D3, awkward code to try and improve performance, not as readable as I'd like, but the results are pretty good (for me it is best on Chrome, Firefox is slower, haven't tried others yet).

There are 500 000 node and 1 000 000 node versions of this (same code, more nodes, just to see not intended for actual use).

Updated to swap parseInt for Math.floor, as noted by RioV8 in linked SO question as an improvement

<!DOCTYPE html>
<meta charset="utf-8">
<body>
<canvas id="canvas" width="960" height="960"></canvas>
<script>
var total = 100000;
var points = new Array(total);
var lengths = [];
for (var i = 0; i < total; i++) {
let p0 = new Int16Array(2);
let p1 = new Int16Array(2);
let p2 = new Int16Array(2);
let p3 = new Int16Array(2);
let width = 960;
let height = 500;
p0[0] = parseInt(Math.random()*(width));
p0[1] = parseInt(Math.random()*(height));
p1[0] = parseInt(width/2-100 + (Math.random() - 0.5)*30);
p1[1] = parseInt(height/2 + (i%3*50 + (Math.random() - 0.5)*30) - 100);
p2[0] = parseInt(width/2+100 + (Math.random() - 0.5)*30);
p2[1] = parseInt(height/2 + (Math.floor(Math.random()*3)*50 + (Math.random() - 0.5)*30) - 100);
p3[0] = parseInt(Math.random()*(width));
p3[1] = parseInt(Math.random()*(height));
points[i] = [p0,p1,p2,p3];
}
for (var i = 0; i < total; i++) {
for(var i = 0; i < total; i++) {
let length = 0;
for(var j = 1; j < 4; j++) {
length += Math.sqrt( Math.pow(points[i][j-1][0] - points[i][j][0],2) + Math.pow(points[i][j-1][1] - points[i][j][1],2) );
}
lengths[i] = parseInt(length);
}
}
var context = document.getElementById("canvas").getContext("2d");
var t0 = 0; // old t
var t1 = 0; // new t
var start = Date.now();
var cycle = 0;
function render() {
context.clearRect(0, 0, 960, 500);
let pow = Math.pow;
let sqrt = Math.sqrt;
let floor = Math.floor;
let t = Date.now() - start;
t = t % 4000 / 4000; // duration.
t0 = t1;
t1 = t;
if( t1 < t0 ) cycle++;
let order = true;
if(t > 0.5) order = false, t = 1-t;
let imageData = context.getImageData(0, 0, 960, 500);
let data = imageData.data;
let i = total;
while (--i) {
let p;
let current = 0;
let segment = 0;
let pts = points[i];
let l = lengths[i]*t;
if(order) {
let i = 0;
for(i; i < 3; i++) {
segment = sqrt( pow(pts[i][0] - pts[i+1][0],2) + pow(pts[i][1] - pts[i+1][1],2) );
current += segment;
if (current > l) break;
}
let d = current - l;
let r = d/segment;
p = floor((1-r)*pts[i+1][0] + r*pts[i][0]) + floor((1-r)*pts[i+1][1] + r*pts[i][1]) * 960;
p *= 4;
}
else {
let i = 4;
while(i--) {
segment = sqrt( pow(pts[i][0] - pts[i-1][0],2) + pow(pts[i][1] - pts[i-1][1],2) );
current += segment;
if (current > l) break;
}
let d = current - l;
let r = d/segment;
p = floor((1-r)*pts[i-1][0] + r*pts[i][0]) + floor((1-r)*pts[i-1][1] + r*pts[i][1]) * 960;
p*= 4;
}
data[p] += 120;
data[++p] += 20;
data[++p] += 10;
data[++p] = 100;
}
context.putImageData(imageData, 0, 0);
delete data;
if(cycle < 10) window.requestAnimationFrame(render)
}
window.requestAnimationFrame(render)
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment