scene
Version:
Scene is a simple but powerful property interpolation class for creating (CSS) animation and parallax effects.
214 lines (182 loc) • 6.82 kB
JavaScript
import Scene from '../src/scene.js';
const period = 1000;
const height = 100;
const paddingV = 20;
const paddingH = 5;
const step = 10;
const scripts = [
`// Lineair
const scene = new Scene(0, period);
scene.addItem('demo', demoCallback);
scene.step('demo', 150, {y: 100});
scene.step('demo', 300, {x: -100, y: -100});
scene.step('demo', 400, {x: 50});
scene.step('demo', 600, {x: -50, y: 50});
scene.step('demo', 700, {x: 100});`,
`// Lineair circular
const scene = new Scene(0, period);
scene.circular = true;
scene.addItem('demo', demoCallback);
scene.step('demo', 150, {y: 100});
scene.step('demo', 300, {x: -100, y: -100});
scene.step('demo', 400, {x: 50});
scene.step('demo', 600, {x: -50, y: 50});
scene.step('demo', 700, {x: 100});`,
`// Lineair smooth
const scene = new Scene(0, period);
scene.addItem('demo', demoCallback);
scene.step('demo', 150, {y: 100});
scene.step('demo', 300, {x: -100, y: -100});
scene.step('demo', 400, {x: 50});
scene.step('demo', 600, {x: -50, y: 50});
scene.step('demo', 700, {x: 100});
scene.smooth('demo', ['x', 'y']);
`,
`// Lineair smooth cirlular
const scene = new Scene(0, period);
scene.circular = true;
scene.addItem('demo', demoCallback);
scene.step('demo', 150, {y: 100});
scene.step('demo', 300, {x: -100, y: -100});
scene.step('demo', 400, {x: 50});
scene.step('demo', 600, {x: -50, y: 50});
scene.step('demo', 700, {x: 100});
scene.smooth('demo', ['x', 'y']);
`,
`// Sinus easing
const scene = new Scene(0, period);
scene.addItem('demo', demoCallback);
scene.step('demo', 0, {x: 0, y: -100});
scene.step('demo', 500, {y: 100}, {timing: 'sinOut'});
scene.step('demo', 1000, {x: 0, y: -100}, {timing: 'sinInOut'});`,
`// PowInOut easing
const scene = new Scene(0, period);
scene.addItem('demo', demoCallback);
scene.step('demo', 0, {x: 0, y: -100});
scene.step('demo', 500, {x: 0, y: 100}, {timing: 'powInOut 6'});
scene.step('demo', 1000, {x: 0, y: -100}, {timing: 'cubIn'});`,
`// Back easing
const scene = new Scene(0, period);
scene.addItem('demo', demoCallback);
scene.step('demo', 0, {x: -100, y: -100});
scene.step('demo', 500, {y: 100}, {timing: 'backInOut'});
scene.step('demo', 500, {x: 100}, {timing: 'backOut'});
scene.step('demo', 1000, {y: -100}, {timing: 'backIn 2'});
scene.step('demo', 1000, {x: -100}, {timing: 'backInOut'});`,
`// Circ easing
const scene = new Scene(0, period);
scene.addItem('demo', demoCallback);
scene.step('demo', 0, {x: -100});
scene.step('demo', 250, {y: 100}, {timing: 'circIn'});
scene.step('demo', 500, {x: 100}, {timing: 'circIn'});
scene.step('demo', 750, {y: -100}, {timing: 'circOut'});
scene.step('demo', 1000, {x: -100}, {timing: 'circOut'});`,
`// Elastic easing
const scene = new Scene(0, period);
scene.addItem('demo', demoCallback);
scene.step('demo', 0, {x: -100, y: -100});
scene.step('demo', 500, {y: 100}, {timing: 'elasticInOut'});
scene.step('demo', 500, {x: 100}, {timing: 'elasticOut'});
scene.step('demo', 1000, {y: -100}, {timing: 'elasticIn'});
scene.step('demo', 1000, {x: -100}, {timing: 'elasticInOut'});`,
`// String
const scene = new Scene(0, period);
scene.addItem('demo', demoCallback);
scene.step('demo', 150, {x: -100, y: 0, className: 'blue'});
scene.step('demo', 400, {x: 0, y: 0, className: 'red'});
scene.step('demo', 600, {x: 100, y: 0, className: ''});
`,
// `// Events and strings
// const scene = new Scene(0, period);
// scene.addItem('demo', 0, {funcProp:val=>console.log('event'), type=''});
// scene.addItem('demo', 500, {funcProp:0, type='hello'})`,
];
const animations = [];
function runHelloWorld() {
const period = 5000;
const scene = new Scene(0, period);
const myElem = document.getElementById('myElem');
scene.addItem(myElem);
scene.step(myElem, 0 * period, {x: 0, y: 0, rotate: 0, scale: 1});
scene.step(myElem, 0.5 * period, {x: 100, y: 100, rotate: 180, scale: 2});
scene.step(myElem, 1 * period, {x: 0, y: 0, rotate: 360, scale: 1});
const animate = () => {
scene.animate((window.scrollY * period / (document.body.clientHeight - window.innerHeight)) || ((performance.now()/2) % period));
requestAnimationFrame(animate);
};
animate();
}
function runTests() {
for (let i = 0; i < scripts.length; i += 1) {
let script = scripts[i];
let desc = document.createElement('pre');
let canvas = drawScene(script);
desc.innerText = script.replace(/demoCallback/g, 'props => plot(props.x, props.y)');
let aniCanvas = drawAnimation(script);
let wrap = document.createElement('div');
wrap.append(canvas);
wrap.append(aniCanvas);
wrap.append(desc);
let demos = document.getElementById('demos');
demos.appendChild(wrap);
}
}
function drawScene(script) {
const canvas = document.createElement('canvas');
let scene = eval(`(function(){${script};return scene})();`);
canvas.width = scene.endValue +2*paddingH;
canvas.height = height + 2*paddingV;
let g = canvas.getContext('2d');
for (let i = 0; i <= period; i += step) {
scene.animate(i);
}
function demoCallback(props, stepPhases, sceneValue) {
mark(props.x, 'red');
mark(props.y, 'blue');
canvas.className = props.className;
function mark(val, color) {
if (val !== undefined) {
g.beginPath();
g.arc(sceneValue + paddingH, height/2 + paddingV - val / 2, 3, 0, 2*Math.PI, false);
g.fillStyle = color;
g.fill();
}
}
}
return canvas;
}
function drawAnimation(script) {
const canvas = document.createElement('canvas');
canvas.height = canvas.width = height + 2*paddingV;
let g = canvas.getContext('2d');
let scene = eval(`(function(){${script};return scene})();`);
function demoCallback(props) {
canvas.className = props.className;
g.clearRect(0, 0, canvas.width, canvas.height);
let x = props.x;
let y = props.y;
g.beginPath();
g.arc(height/2 + paddingV + x/2, height/2 + paddingV - y/2, 3, 0, 2*Math.PI, false);
g.fillStyle = 'blue';
g.fill();
}
animations.push(() => {
scene.animate((performance.now()/2) % period);
});
return canvas;
}
function animate() {
for (let animation of animations) {
animation();
}
requestAnimationFrame(animate);
}
function addPageParallax() {
function callback(props, stepPhases, value, elem) {
elem.style.top = `${props.top}px`;
}
}
// runHelloWorld();
runTests();
animate();
addPageParallax();