Skip to content

Instantly share code, notes, and snippets.

@joshblack
Last active August 29, 2015 14:23
Show Gist options
  • Save joshblack/9f3d00d8657983f736c8 to your computer and use it in GitHub Desktop.
Save joshblack/9f3d00d8657983f736c8 to your computer and use it in GitHub Desktop.
Motion Tutorials
function particle() {
const node = document.createElement('div');
node.style.position = 'absolute';
return document.body.appendChild(node);
}
function position(particle, pv) {
const { translate } = transform,
p = pv.map((p) => px(p));
return particle.style.transform = translate(...p.concat(0));
}
function add(v1, v2) {
return v1.map((e, i) => e + v2[i]);
}
function magnitude(v) {
const { pow } = Math;
return Math.sqrt(v.reduce((p, e) => p + pow(e, 2), 0));
}
function move(particle, from, to) {
const { isEqual } = _;
let prev = from;
// find direction?
const rate = magnitude(from) > magnitude(to) ? [-5, -5] : [5, 5];
position(particle, from);
return function loop() {
// isEqual is a very bad check, can skip frame.
if (!isEqual(prev, to)) {
prev = add(prev, rate);
position(particle, prev);
requestAnimationFrame(loop);
}
}
}
move(particle(), [0], [500])();
// problem!
//move(particle(), [0, 500], [500, 0])();
move(particle(), [0, 0], [500, 500])();
move(particle(), [500, 500], [0, 0])();
function px(unit) {
return `${unit}px`;
}
// Let's build the idea of a particle. Every time we call particle,
// we will create a div in the DOM (this could be abstracted into any
// primitive depending on the implementation) and we'll style it
// with an absolute positioning to deal with box layout shenanigans
// Afterwards, we'll append it to the body and return the particle
function particle() {
const node = document.createElement('div');
node.style.position = 'absolute';
node.style.background = 'black';
node.style.width = '50px';
node.style.height = '50px';
node.style.borderRadius = '50%';
return document.body.appendChild(node);
}
// Now, let's write a function that can set the position of a
// particle. For starters, we'll stick with only one-dimension
// and grow from there.
function position(particle, x) {
const { translateX } = transform;
return particle.style.transform = translateX(x);
}
// We can make a variety of points by doing the following:
const p1 = position(particle(), px(0));
const p2 = position(particle(), px(50px));
const p3 = position(particle(), px(100px));
const p4 = position(particle(), px(150px));
// So this was kind of cool, but everything is static.
// Now, let's try and add some motion.
// We can start by writing a move function that takes in
// a particle and moves it from a beginning location to
// an ending location.
function move(particle, from, to) {
const { translateX } = transform,
// rate adjusts and is static
rate = from - to > 0 ? -1 : 1;
let prev = from;
return function loop() {
if (prev !== to) {
const change = prev + rate;
prev = change;
position(particle, px(change));
requestAnimationFrame(loop);
}
};
}
move(particle(), 0, 500)();
move(particle(), 500, 0)();
// OR a simpler demo
const p1 = particle();
let start = 0;
function loop() {
position(p1, start += 5);
requestAnimationFrame(loop);
}
loop();
// Now, let's abstract this into 2 dimensions.
function position(particle, vector) {
const { translate } = transform;
vector = vector.map((i) => `${i}px`);
return particle.style.transform = translate(...vector);
}
const p1 = particle();
position(p1, [100, 100]);
let start = [0, 0];
function loop() {
position(p1, start = start.map((e) => e + 5));
requestAnimationFrame(loop);
}
loop();
// In this situation, we can now move a particle
// from one position to another 1 pixel at a time.
// We can adjust this rate to get a faster speed
// but for the most part it's completely static.
// Now, let's talk about the idea of motion.
const transform = {
translate(x, y) {
return transformFunction('translate', x, y);
},
translateX(x) {
return transformFunction('translateX', x);
},
translateY(y) {
return transformFunction('translateY', y);
},
translate3d(x, y, z) {
return transformFunction('translate3d', x, y, z);
},
scale(x, y) {
return transformFunction('scale', x, y);
},
scaleX(x) {
return transformFunction('scaleX', x);
},
scaleY(y) {
return transformFunction('scaleY', y);
},
scale3d(x, y, z) {
return transformFunction('scale3d', x, y, z);
},
rotate(x, y) {
return transformFunction('rotate', x, y);
},
rotateX(x) {
return transformFunction('rotateX', x);
},
rotateY(y) {
return transformFunction('rotateY', y);
},
rotate3d(x, y, z) {
return transformFunction('rotate3d', x, y, z);
},
skew(x, y) {
return transformFunction('skew', x, y);
},
skewX(x) {
return transformFunction('skewX', x);
},
skewY(y) {
return transformFunction('skewY', y);
},
perspective(x) {
return transformFunction('perspective', x);
},
matrix(a, b, c, d, tx, ty) {
return transformFunction('matrix', a, b, c, d, tx, ty);
},
matrix3d(a1, b1, c1, d1, a2, b2, c2, d2, a3, b3, c3, d3, a4, b4, c4, d4) {
return transformFunction('matrix3d', a1, b1, c1, d1, a2, b2, c2, d2, a3, b3, c3, d3, a4, b4, c4, d4);
}
}
function transformFunction(property, ...values) {
return `${property}(${values.join(', ')})`;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment