Instantly share code, notes, and snippets.

Embed
What would you like to do?
An experiment in masking and animation with pure javascript. Inspired by Fong Qi Wei's series Time is a Dimension.
// timelapse images
var tINm = [
"http://vanbone.com/timelapse/640x480_000305.jpg",
"http://vanbone.com/timelapse/640x480_001658.jpg",
"http://vanbone.com/timelapse/640x480_003021.jpg",
"http://vanbone.com/timelapse/640x480_004348.jpg",
"http://vanbone.com/timelapse/640x480_005726.jpg",
"http://vanbone.com/timelapse/640x480_011131.jpg",
"http://vanbone.com/timelapse/640x480_012517.jpg",
"http://vanbone.com/timelapse/640x480_013910.jpg",
"http://vanbone.com/timelapse/640x480_015224.jpg",
"http://vanbone.com/timelapse/640x480_020548.jpg",
"http://vanbone.com/timelapse/640x480_021921.jpg",
"http://vanbone.com/timelapse/640x480_023331.jpg",
"http://vanbone.com/timelapse/640x480_025847.jpg",
"http://vanbone.com/timelapse/640x480_031344.jpg",
"http://vanbone.com/timelapse/640x480_032700.jpg",
"http://vanbone.com/timelapse/640x480_034011.jpg",
"http://vanbone.com/timelapse/640x480_035320.jpg",
"http://vanbone.com/timelapse/640x480_040639.jpg",
"http://vanbone.com/timelapse/640x480_044153.jpg",
"http://vanbone.com/timelapse/640x480_045516.jpg",
"http://vanbone.com/timelapse/640x480_051627.jpg",
"http://vanbone.com/timelapse/640x480_052023.jpg",
"http://vanbone.com/timelapse/640x480_052142.jpg",
"http://vanbone.com/timelapse/640x480_052258.jpg",
"http://vanbone.com/timelapse/640x480_052418.jpg",
"http://vanbone.com/timelapse/640x480_052535.jpg",
"http://vanbone.com/timelapse/640x480_052653.jpg",
"http://vanbone.com/timelapse/640x480_052812.jpg",
"http://vanbone.com/timelapse/640x480_052932.jpg",
"http://vanbone.com/timelapse/640x480_053048.jpg",
"http://vanbone.com/timelapse/640x480_053204.jpg",
"http://vanbone.com/timelapse/640x480_053319.jpg",
"http://vanbone.com/timelapse/640x480_053624.jpg",
"http://vanbone.com/timelapse/640x480_053900.jpg",
"http://vanbone.com/timelapse/640x480_054117.jpg",
"http://vanbone.com/timelapse/640x480_054308.jpg",
"http://vanbone.com/timelapse/640x480_054455.jpg",
"http://vanbone.com/timelapse/640x480_054642.jpg",
"http://vanbone.com/timelapse/640x480_054842.jpg",
"http://vanbone.com/timelapse/640x480_055040.jpg",
"http://vanbone.com/timelapse/640x480_055233.jpg",
"http://vanbone.com/timelapse/640x480_055414.jpg",
"http://vanbone.com/timelapse/640x480_055607.jpg",
"http://vanbone.com/timelapse/640x480_055719.jpg",
"http://vanbone.com/timelapse/640x480_055913.jpg",
"http://vanbone.com/timelapse/640x480_060058.jpg",
"http://vanbone.com/timelapse/640x480_060249.jpg",
"http://vanbone.com/timelapse/640x480_060400.jpg",
"http://vanbone.com/timelapse/640x480_060515.jpg",
"http://vanbone.com/timelapse/640x480_060708.jpg",
"http://vanbone.com/timelapse/640x480_060835.jpg",
"http://vanbone.com/timelapse/640x480_060950.jpg",
"http://vanbone.com/timelapse/640x480_061102.jpg",
"http://vanbone.com/timelapse/640x480_061221.jpg",
"http://vanbone.com/timelapse/640x480_061331.jpg",
"http://vanbone.com/timelapse/640x480_061524.jpg",
"http://vanbone.com/timelapse/640x480_061637.jpg",
"http://vanbone.com/timelapse/640x480_061750.jpg",
"http://vanbone.com/timelapse/640x480_061905.jpg",
"http://vanbone.com/timelapse/640x480_062058.jpg",
"http://vanbone.com/timelapse/640x480_062213.jpg",
"http://vanbone.com/timelapse/640x480_062326.jpg",
"http://vanbone.com/timelapse/640x480_062453.jpg",
"http://vanbone.com/timelapse/640x480_062609.jpg",
"http://vanbone.com/timelapse/640x480_062726.jpg",
"http://vanbone.com/timelapse/640x480_062835.jpg",
"http://vanbone.com/timelapse/640x480_063030.jpg",
"http://vanbone.com/timelapse/640x480_063439.jpg",
"http://vanbone.com/timelapse/640x480_063859.jpg",
"http://vanbone.com/timelapse/640x480_064245.jpg",
"http://vanbone.com/timelapse/640x480_064657.jpg",
"http://vanbone.com/timelapse/640x480_065053.jpg",
"http://vanbone.com/timelapse/640x480_065435.jpg",
"http://vanbone.com/timelapse/640x480_065818.jpg",
"http://vanbone.com/timelapse/640x480_070410.jpg",
"http://vanbone.com/timelapse/640x480_072312.jpg",
"http://vanbone.com/timelapse/640x480_074101.jpg",
"http://vanbone.com/timelapse/640x480_075807.jpg",
"http://vanbone.com/timelapse/640x480_081553.jpg",
"http://vanbone.com/timelapse/640x480_083252.jpg",
"http://vanbone.com/timelapse/640x480_084954.jpg",
"http://vanbone.com/timelapse/640x480_090659.jpg",
"http://vanbone.com/timelapse/640x480_092403.jpg",
"http://vanbone.com/timelapse/640x480_094108.jpg",
"http://vanbone.com/timelapse/640x480_095811.jpg",
"http://vanbone.com/timelapse/640x480_101527.jpg",
"http://vanbone.com/timelapse/640x480_103236.jpg",
"http://vanbone.com/timelapse/640x480_104939.jpg",
"http://vanbone.com/timelapse/640x480_110642.jpg",
"http://vanbone.com/timelapse/640x480_112350.jpg",
"http://vanbone.com/timelapse/640x480_114056.jpg",
"http://vanbone.com/timelapse/640x480_115801.jpg",
"http://vanbone.com/timelapse/640x480_121506.jpg",
"http://vanbone.com/timelapse/640x480_123213.jpg",
"http://vanbone.com/timelapse/640x480_124917.jpg",
"http://vanbone.com/timelapse/640x480_130621.jpg",
"http://vanbone.com/timelapse/640x480_132329.jpg",
"http://vanbone.com/timelapse/640x480_134029.jpg",
"http://vanbone.com/timelapse/640x480_135732.jpg",
"http://vanbone.com/timelapse/640x480_141520.jpg",
"http://vanbone.com/timelapse/640x480_143308.jpg",
"http://vanbone.com/timelapse/640x480_145013.jpg",
"http://vanbone.com/timelapse/640x480_150732.jpg",
"http://vanbone.com/timelapse/640x480_152433.jpg",
"http://vanbone.com/timelapse/640x480_154133.jpg",
"http://vanbone.com/timelapse/640x480_155833.jpg",
"http://vanbone.com/timelapse/640x480_161603.jpg",
"http://vanbone.com/timelapse/640x480_163335.jpg",
"http://vanbone.com/timelapse/640x480_164740.jpg",
"http://vanbone.com/timelapse/640x480_165009.jpg",
"http://vanbone.com/timelapse/640x480_165121.jpg",
"http://vanbone.com/timelapse/640x480_165232.jpg",
"http://vanbone.com/timelapse/640x480_165344.jpg",
"http://vanbone.com/timelapse/640x480_165459.jpg",
"http://vanbone.com/timelapse/640x480_165614.jpg",
"http://vanbone.com/timelapse/640x480_165727.jpg",
"http://vanbone.com/timelapse/640x480_165842.jpg",
"http://vanbone.com/timelapse/640x480_165953.jpg",
"http://vanbone.com/timelapse/640x480_170107.jpg",
"http://vanbone.com/timelapse/640x480_170220.jpg",
"http://vanbone.com/timelapse/640x480_170335.jpg",
"http://vanbone.com/timelapse/640x480_170527.jpg",
"http://vanbone.com/timelapse/640x480_170640.jpg",
"http://vanbone.com/timelapse/640x480_170754.jpg",
"http://vanbone.com/timelapse/640x480_170907.jpg",
"http://vanbone.com/timelapse/640x480_171019.jpg",
"http://vanbone.com/timelapse/640x480_171204.jpg",
"http://vanbone.com/timelapse/640x480_171316.jpg",
"http://vanbone.com/timelapse/640x480_171433.jpg",
"http://vanbone.com/timelapse/640x480_171542.jpg",
"http://vanbone.com/timelapse/640x480_171653.jpg",
"http://vanbone.com/timelapse/640x480_171845.jpg",
"http://vanbone.com/timelapse/640x480_172001.jpg",
"http://vanbone.com/timelapse/640x480_172113.jpg",
"http://vanbone.com/timelapse/640x480_172253.jpg",
"http://vanbone.com/timelapse/640x480_172404.jpg",
"http://vanbone.com/timelapse/640x480_172516.jpg",
"http://vanbone.com/timelapse/640x480_172630.jpg",
"http://vanbone.com/timelapse/640x480_172825.jpg",
"http://vanbone.com/timelapse/640x480_172939.jpg",
"http://vanbone.com/timelapse/640x480_173107.jpg",
"http://vanbone.com/timelapse/640x480_173302.jpg",
"http://vanbone.com/timelapse/640x480_173415.jpg",
"http://vanbone.com/timelapse/640x480_173543.jpg",
"http://vanbone.com/timelapse/640x480_173658.jpg",
"http://vanbone.com/timelapse/640x480_173854.jpg",
"http://vanbone.com/timelapse/640x480_174006.jpg",
"http://vanbone.com/timelapse/640x480_174119.jpg",
"http://vanbone.com/timelapse/640x480_174313.jpg",
"http://vanbone.com/timelapse/640x480_174439.jpg",
"http://vanbone.com/timelapse/640x480_174555.jpg",
"http://vanbone.com/timelapse/640x480_174747.jpg",
"http://vanbone.com/timelapse/640x480_174931.jpg",
"http://vanbone.com/timelapse/640x480_175126.jpg",
"http://vanbone.com/timelapse/640x480_175255.jpg",
"http://vanbone.com/timelapse/640x480_175455.jpg",
"http://vanbone.com/timelapse/640x480_175657.jpg",
"http://vanbone.com/timelapse/640x480_175924.jpg",
"http://vanbone.com/timelapse/640x480_180201.jpg",
"http://vanbone.com/timelapse/640x480_180402.jpg",
"http://vanbone.com/timelapse/640x480_180746.jpg",
"http://vanbone.com/timelapse/640x480_181028.jpg",
"http://vanbone.com/timelapse/640x480_181145.jpg",
"http://vanbone.com/timelapse/640x480_181304.jpg",
"http://vanbone.com/timelapse/640x480_181424.jpg",
"http://vanbone.com/timelapse/640x480_181543.jpg",
"http://vanbone.com/timelapse/640x480_181659.jpg",
"http://vanbone.com/timelapse/640x480_181818.jpg",
"http://vanbone.com/timelapse/640x480_182204.jpg",
"http://vanbone.com/timelapse/640x480_182600.jpg",
"http://vanbone.com/timelapse/640x480_182944.jpg",
"http://vanbone.com/timelapse/640x480_183244.jpg",
"http://vanbone.com/timelapse/640x480_183620.jpg",
"http://vanbone.com/timelapse/640x480_183958.jpg",
"http://vanbone.com/timelapse/640x480_184338.jpg",
"http://vanbone.com/timelapse/640x480_184715.jpg",
"http://vanbone.com/timelapse/640x480_185054.jpg",
"http://vanbone.com/timelapse/640x480_185436.jpg",
"http://vanbone.com/timelapse/640x480_185811.jpg",
"http://vanbone.com/timelapse/640x480_190520.jpg",
"http://vanbone.com/timelapse/640x480_191619.jpg",
"http://vanbone.com/timelapse/640x480_193604.jpg",
"http://vanbone.com/timelapse/640x480_194659.jpg",
"http://vanbone.com/timelapse/640x480_200632.jpg",
"http://vanbone.com/timelapse/640x480_201725.jpg",
"http://vanbone.com/timelapse/640x480_203732.jpg",
"http://vanbone.com/timelapse/640x480_204824.jpg",
"http://vanbone.com/timelapse/640x480_210817.jpg",
"http://vanbone.com/timelapse/640x480_211911.jpg",
"http://vanbone.com/timelapse/640x480_213005.jpg",
"http://vanbone.com/timelapse/640x480_215010.jpg",
"http://vanbone.com/timelapse/640x480_221018.jpg",
"http://vanbone.com/timelapse/640x480_222112.jpg",
"http://vanbone.com/timelapse/640x480_223209.jpg",
"http://vanbone.com/timelapse/640x480_224306.jpg",
"http://vanbone.com/timelapse/640x480_225400.jpg",
"http://vanbone.com/timelapse/640x480_231410.jpg",
"http://vanbone.com/timelapse/640x480_232504.jpg",
"http://vanbone.com/timelapse/640x480_234445.jpg"
];
var canvas, ctx, imageCache;
var SEGMENTS = 12;
var SEG_WIDTH = Math.floor(640 / SEGMENTS + 1);
var SEG_HEIGHT = Math.floor(480 / SEGMENTS + 1);
var SEG_RADIAL = Math.floor(400 / SEGMENTS + 1);
var IMAGE_COUNT = 198;
// settings
var style = "circles";
var step = 1;
// maintains the position of the cycle through the images
var cycler = 0;
// I couldn't be bothered to do the math to draw these programmatically :(
var RAYS = [
//0
[[0, 0],[640, 0],[640, 480],[0, 480]],
//1
[[0, 0],[570, 0],[640, 295],[570, 480],[0, 480]],
//2
[[0, 0],[500, 0],[640, 295],[500, 480],[0, 480]],
//3
[[0, 0],[420, 0],[640, 295],[420, 480],[0, 480]],
//4
[[0, 0],[330, 0],[640, 295],[330, 480],[0, 480]],
//5
[[0, 0],[230, 0],[640, 295],[230, 480],[0, 480]],
//6
[[0, 0],[120, 0],[640, 295],[120, 480],[0, 480]],
//7
[[0, 0],[640, 295],[0, 480]],
//8
[[0, 82],[640, 295],[0, 437]],
//9
[[0, 152],[640, 295],[0, 402]],
//10
[[0, 212],[640, 295],[0, 367]],
//11
[[0, 262],[640, 295],[0, 332]],
];
function loadImage (iii) {
// update preloader
ctx.clearRect(0,0,640,480);
ctx.fillText("Loading timelapse images:", 320, 220);
ctx.fillText(iii + " / " + IMAGE_COUNT, 320, 260);
var tImg = new Image();
tImg.onload = function() {
imageCache.push(tImg);
if (iii < IMAGE_COUNT) {
loadImage(++iii);
} else {
animate();
}
};
tImg.onerror = function() {
// err?
ctx.clearRect(0,0,640,480);
ctx.fillText("ERROR LOADING IMAGE", 320, 220);
ctx.fillText(iii + " / 198", 320, 260);
// populate with the previous one
imageCache.push(imageCache[imageCache.length-1]);
//keep going
if (iii < IMAGE_COUNT) {
loadImage(++iii);
} else {
animate();
}
};
tImg.src = tINm[iii];
}
function animate() {
// clear the canvas
ctx.clearRect(0,0,640,480);
// tCycle holds the imageCache position of the current image in the loop
var tCycle = cycler;
for (var iii = 0; iii < SEGMENTS; iii++) {
// jumps tCycle to the next image in the cycle, 'step'ing over some
tCycle = cycler + (iii * step);
if (tCycle>= IMAGE_COUNT) {
tCycle -= IMAGE_COUNT;
}
// save the ctx state (so we only clip 1 image)
ctx.save();
// Ideally this if statement would be abstracted out by using something like
// strategy pattern, swapping out the render function when the user clicks a
// radio button. But it will do for a tech demo.
if (style == "circles") {
// circles
// this draws and image in each circle starting from largest to smallest
// this may be worse than only drawing the ring of image needed, i don't know?
ctx.beginPath();
ctx.arc(
// small but consistent variations in position
320 + iii % 7 - iii % 13,
240 + iii % 5 - iii % 9,
400-(SEG_RADIAL*iii),
0,
Math.PI*2,true
);
ctx.clip();
ctx.drawImage(imageCache[tCycle], 0, 0);
} else if (style == "vbars") {
// straight segments - vertical
// basic drawImage clipping
ctx.drawImage(imageCache[tCycle],
iii * SEG_WIDTH, 0, SEG_WIDTH, 480,
iii * SEG_WIDTH, 0, SEG_WIDTH, 480);
} else if (style == "hbars") {
// straight segments - horizontal
// basic drawImage clipping
ctx.drawImage(imageCache[tCycle],
0, iii * SEG_HEIGHT, 640, SEG_HEIGHT,
0, iii * SEG_HEIGHT, 640, SEG_HEIGHT);
} else { // rays
// drays the shapes stored in the RAYS array, from largest to smallest
// then clips the image to the drawn shapes.
ctx.beginPath();
ctx.moveTo(RAYS[iii][0][0], RAYS[iii][0][1]);
for (var jjj = 1; jjj < RAYS[iii].length; jjj++) {
ctx.lineTo(RAYS[iii][jjj][0], RAYS[iii][jjj][1]);
}
ctx.clip();
ctx.drawImage(imageCache[tCycle], 0, 0);
}
// restore ctx state (so we only clip 1 image)
ctx.restore();
}
// cycle through the images by 'step' amount
cycler = cycler + step < IMAGE_COUNT ? cycler + step : 0;
// loop the animation, set at 6 frames / second for appearance,
// but can go faster / slower
window.setTimeout(animate, 1000 / 6);
}
$( document ).ready(function() {
// setup form change handler
$( "input[name='styleRadio']" ).change( function() {
style = $("input[name='styleRadio']:checked").val();
});
$( "input[name='step']" ).change( function() {
step = Number($("input[name='step']").val());
});
// get the canvas and drawing context (ctx)
canvas = $( '#myCanvas' );
ctx = canvas[0].getContext("2d");
//set font styles for Loader
ctx.font = "normal 20pt sans-serif";
ctx.textAlign = "center";
// start loading images
imageCache = [];
loadImage(0);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment