Skip to content

Instantly share code, notes, and snippets.

@tmcw
Created August 28, 2012 15:17
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 tmcw/3499001 to your computer and use it in GitHub Desktop.
Save tmcw/3499001 to your computer and use it in GitHub Desktop.
Make runs.png
var Canvas = require('canvas'),
fs = require('fs'),
w = 1280,
h = 800,
m = 50,
c = new Canvas(w * 2, h * 2),
ctx = c.getContext('2d');
ctx.scale(2, 2);
var td = 'json/tcx/';
var tweets = fs.readdirSync(td);
function sx(x) {
return ((x / (13000)) * w);
}
function sbpm(x) {
return ((x / (200)) * 300);
}
function salt(x) {
return ((x / (300)) * 300);
}
function speed(x) {
return ((x / (15)) * 300);
}
ctx.fillStyle = '#f8f8f8';
ctx.fillRect(0, 0, w, h);
ctx.fillStyle = '#000';
ctx.font = '11px Helvetica Neue';
var t = tweets.map(function(t) {
return JSON.parse(fs.readFileSync(td + t, 'utf8'));
}).filter(function(t) {
return t.features.length > 0 && t.features[0].bpm;
});
ctx.fillStyle = '#ccc';
ctx.textAlign = 'right';
ctx.globalAlpha = 0.2;
ctx.fillStyle = '#1f78b4';
ctx.textAlign = 'left';
ctx.fillText('heart rate in bpm', sx(5000) + m + 10, 20);
ctx.textAlign = 'right';
ctx.fillRect(m, 800 - sbpm(200), w - m, 1);
ctx.fillText('200bpm', m - 10, 800 - ~~sbpm(200) + 2);
ctx.fillRect(m, 800 - sbpm(150), w - m, 1);
ctx.fillText('150bpm', m - 10, 800 - ~~sbpm(150) + 2);
ctx.fillRect(m, 800 - sbpm(100), w - m, 1);
ctx.fillText('100bpm', m - 10, 800 - ~~sbpm(100) + 2);
ctx.globalAlpha = 0.5;
ctx.fillStyle = '#b2df8a';
ctx.textAlign = 'left';
ctx.fillText('altitude in meters', sx(5000) + m + 10, 40);
ctx.textAlign = 'right';
ctx.fillRect(m, 350 - salt(0), w - m, 1);
ctx.fillText('0m', m - 10, ~~(350 - salt(0)) + 2);
ctx.fillRect(m, 350 - salt(100), w - m, 1);
ctx.fillText('100m', m - 10, ~~(350 - salt(100)) + 2);
ctx.fillRect(m, 350 - salt(200), w - m, 1);
ctx.fillText('200m', m - 10, ~~(350 - salt(200)) + 2);
ctx.globalAlpha = 0.5;
ctx.fillStyle = '#fb9a99'
ctx.textAlign = 'left';
ctx.fillText('speed in miles per hour', sx(5000) + m + 10, 60);
ctx.textAlign = 'right';
ctx.fillRect(m, 480 - speed(0), w - m, 1);
ctx.fillText('0mph', m - 10, ~~(480 - speed(0)));
ctx.fillRect(m, 480 - speed(5), w - m, 1);
ctx.fillText('5mph', m - 10, ~~(480 - speed(5)));
ctx.globalAlpha = 0.5;
ctx.fillStyle = '#ccc'
ctx.fillRect(sx(0) + m, 0, 1, h);
ctx.fillRect(sx(5000) + m, 0, 1, h);
ctx.fillText('5km', sx(5000) + m- 10, 20);
ctx.fillRect(sx(10000) + m, 0, 1, h);
ctx.fillText('10km', sx(10000) - 10 + m, 20);
ctx.textAlign = 'left';
ctx.fillStyle = '#aaa';
ctx.fillText('2009 - 2012 / 391mi total', sx(000) + 10 + m, 20);
ctx.globalCompositeOperation = 'multiply';
ctx.globalAlpha = 0.6;
ctx.strokeStyle = '#1f78b4';
ctx.lineWidth = 0.5;
t.forEach(function(t, i) {
ctx.beginPath();
t.features.forEach(function(f) {
if (f.bpm) {
ctx.lineTo(sx(f.dist) + m, ~~(800 - sbpm(f.bpm)));
}
});
ctx.stroke();
});
ctx.strokeStyle = '#b2df8a';
t.forEach(function(t, i) {
ctx.beginPath();
t.features.forEach(function(f) {
if (f.alt) {
ctx.lineTo(~~sx(f.dist) + m, ~~(350 - salt(f.alt)));
}
});
ctx.stroke();
});
ctx.strokeStyle = '#fb9a99';
var smooth = 10;
for (var k = 0; k < t.length; k++) {
var j = t[k];
for (var i = 0; i < j.features.length - smooth; i += smooth) {
var avg = 0;
for (var l = 0; l < smooth; l++) {
avg += j.features[i + l].speed;
}
avg /= smooth;
j.features[i].speed = avg;
}
}
t.forEach(function(t) {
ctx.beginPath();
for (var i = 0; i < t.features.length - smooth; i += smooth) {
var f = t.features[i];
if (f.speed > 0) {
ctx.lineTo(~~sx(f.dist) + m, ~~(480 - speed(f.speed)));
}
}
ctx.stroke();
});
t = t.map(function(t) {
t.d = new Date(t.date);
return t;
}).sort(function(a, b) {
return +a.d - +b.d;
});
var start = +new Date('Janary 1, 2009');
var end = +new Date('Janary 1, 2013');
function sd(x) {
return ((+x - start) / (end - start)) * 50;
}
ctx.strokeStyle = '#fb9a99';
ctx.fillStyle = '#fb9a99';
ctx.globalAlpha = 1;
var y = 0;
ctx.beginPath();
ctx.moveTo(sx(000) + 180, m * 0.5);
t.forEach(function(t) {
y += t.features[t.features.length - 1].dist;
ctx.lineTo(sx(000) + 180 + sd(t.d), m * 0.5 - (y / 50000));
});
ctx.stroke();
ctx.globalAlpha = 0.5;
ctx.beginPath();
y = 0;
ctx.moveTo(sx(000) + 180, m * 0.5);
t.forEach(function(t) {
y += t.features[t.features.length - 1].dist;
ctx.lineTo(sx(000) + 180 + sd(t.d), m * 0.5 - (y / 50000));
});
ctx.lineTo(sx(000) + 180 + sd(t[t.length - 1].d), m * 0.5);
ctx.fill();
c.toBuffer(function(err, buf) {
fs.writeFileSync('runs.png', buf);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment