pixel-love.js | |
|---|---|
Pixel Love - a js1k 2012 entry by @aaronsnoswellThis demo is on github | |
| You can also browse the annotated source code at http://aaronsnoswell.github.com/js1k-2012-love/docs/ | |
| Define some variables: | |
| A heart | var h = "♥", |
| The granularity - determines the size of each 'pixel' | g = 5, |
| The threshold / limit, used for determining where to place pixels | l = 10, |
| Arrays of locations for the outline and fill pixles | outline = [],
fill = [], |
| Where to draw the heart | sx = 100,
sy = 350, |
| The bounding box of the heart (computed later) | box = [999, 999, 0, 0]; |
| Set the canvas size | c.width = 500;
c.height = 400; |
| A utility function, used for looping over an x and y variable | var loopxy = function(w, h, step, callback) {
for(var x=0; x<w; x+=step) {
for(var y=0; y<h; y+=step) {
callback(x, y, step);
}
}
} |
| Shortcut method for clearing the canvas | a.clear = function() {
a.clearRect(0, 0, c.width, c.height);
} |
| Normalise browser font rendering in the canvas. See https://twitter.com/#!/aaronsnoswell/status/165642474109419520 | a.textBaseline = "bottom";
a.font="300pt arial";
a.lineWidth = g*2; |
| Draw a filled heart on the canvas | a.fillText(h, sx, sy); |
| Loop over the entire canvas and wherever there are filled pixels, store that location in the fill array | var d = a.getImageData(0, 0, c.width, c.height)
loopxy(d.width, d.height, g, function(x, y) {
if(d.data[(x + y*d.width)*4+3] >= l) fill.push([x, y]);
}); |
| Clear the screen | a.clear(); |
| Draw an outline of a heart on the canvas | a.strokeText(h, sx, sy); |
| Loop over the entire canvas once again. Wherever there are filled pixels, store that location in the outline array | var d = a.getImageData(0, 0, c.width, c.height)
loopxy(d.width, d.height, g, function(x, y) {
if(d.data[(x + y*d.width)*4+3] >= l) {
outline.push([x, y]);
|
| Compute the bounding box of the heart | if(x<box[0]) box[0] = x;
if(x>box[2]) box[2] = x;
if(y<box[1]) box[1] = y;
if(y>box[3]) box[3] = y;
}
}); |
| Find the middle x and y locations of the heart | box.push((box[0]+box[2])/2);
box.push((box[1]+box[3])/2); |
| Store the current time as ms since epoch | var t0 = new Date().getTime(); |
| Use a recursive named function + setTimeout to ensure each frame has time to finish before the next one is drawn | (function render() {
window.setTimeout(function() { |
| Time delta and elapsed time | var d = new Date().getTime()-t0;
t0 += d;
|
| Clear the screen | a.clear();
|
| Draw the red heart | a.fillStyle = "#f00";
loopxy(fill.length, 1, 1, function(i) {
var x = fill[i][0],
y = fill[i][1]; |
| Offset each pixel by a sinusoidal, time based ammount | a.fillRect(x-g/2+Math.sin(t0/500+y/80)*(x-box[4])+10, y-g/2+10, g, g);
})
|
| Draw the outline using the same logic as above | a.fillStyle = "#000";
loopxy(outline.length, 1, 1, function(i) {
var x = outline[i][0],
y = outline[i][1];
a.fillRect(x-g/2+Math.sin(t0/500+y/80)*(x-box[4])+10, y-g/2+10, g, g);
})
|
| Loop at 30fps | render();
}, 1/30);
})();
|