-
-
Save jkuri/7fba95d8488f40ddcb687e88ce14e93b to your computer and use it in GitHub Desktop.
Basic javascript linear value animation that can accept easing functions and provides update & complete callbacks
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @desc Basic linear value animation that can accept simple easing functions and provides update & complete callbacks | |
* @param {Object} values - Object with numerical values. eg. { value1: 0, value2: 20, someKey: 55 } | |
* @param {Number} duration - How long (in milliseconds) the animation will be | |
* @param {Object} options - target values, update callback & complete callback | |
* @param {Function} [options.onComplete=(values) => values] - Callback that fires once animation is complete | |
* @param {Function} [options.onUpdate=(values) => values] - Callback that fires when animation frame updates | |
* @param {Function} [options.ease=(t) => t] - easing method eg. https://gist.github.com/gre/1650294 | |
* @example | |
* | |
* const a = document.getElementById('a') | |
* animateValues({ a: 0 }, 800, { | |
* a: 500, | |
* onUpdate: v => a.style.transform = 'scaleX('+ v.a +')', | |
* onComplete: v => alert('Done!'), | |
* ease: t => t<.5 ? 2*t*t : -1+(4-2*t)*t, // From: https://gist.github.com/gre/1650294 | |
* }) | |
* | |
*/ | |
// CodePen Example: https://codepen.io/xerxesnoble/pen/JNgmJR?editors=0011 | |
function animateValues(values, duration, options) { | |
// Linear interpolation | |
const lerp = (source, target, amount) => source + amount * (target - source) | |
// Validation methods | |
const checkNum = n => typeof n === 'number' ? n : null | |
const checkFunc = f => typeof f === 'function' ? f : _ => _ | |
// Ensure methods. | |
const onComplete = checkFunc(options.onComplete) | |
const onUpdate = checkFunc(options.onUpdate) | |
const ease = checkFunc(options.ease) | |
// Animation start time | |
const start = Date.now() | |
// Create a map <key: [from, to]> | |
const animationMap = Object.keys(values).reduce((map, key) => { | |
const _from = checkNum(values[key]) | |
const _to = checkNum(options[key]) | |
if (_from !== null && _to !== null) map[key] = [_from, _to] | |
return map | |
}, {}) | |
// List of animating values | |
const keys = Object.keys(animationMap) | |
// Create & run animation function | |
const animation = () => { | |
const now = Date.now() | |
let t = duration > 0 ? (now - start) / duration : 1 | |
// Update all values using 't' | |
keys.forEach(key => { | |
// If both 'from' and 'to' are numbers: animate! | |
const [_from, _to] = animationMap[key] | |
const progress = ease(t, _from, _to, duration) | |
// Update value | |
values[key] = lerp(_from, _to, progress) | |
}) | |
// If complete.. | |
if (t >= 1) { | |
// Final update for all keys | |
keys.forEach(key => (values[key] = options[key])) | |
onUpdate(values) | |
onComplete(values) | |
} else { | |
// Run update callback and loop until finished | |
onUpdate(values) | |
requestAnimationFrame(animation) | |
} | |
} | |
animation() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment