UNPKG

just-animate

Version:
166 lines (165 loc) 6.1 kB
import { replaceWithRefs } from '../core/references'; import { _, CONFIG } from '../utils/constants'; import { all, find, push, list, pushDistinct, sortBy } from '../utils/lists'; import { flr, max } from '../utils/math'; import { resolveProperty } from '../utils/resolve-property'; import { isObject, isNumber, isArrayLike, isOwner, isDefined } from '../utils/inspect'; import { plugins } from '../core/plugins'; import { calculateConfigs } from './calc-configs'; const propKeyframeSort = sortBy('time'); export const insert = (model, options, ctx) => { all(options, opts => { if (opts.to === _) { throw new Error('missing duration'); } opts = replaceWithRefs(model.refs, opts, true); all(opts.targets, (target, i, ilen) => { const config = addPropertyKeyframes(model, target, i, ilen, opts); ctx.dirty(config); }); }); calculateConfigs(model); ctx.trigger(CONFIG); }; function addPropertyKeyframes(model, target, index, ilen, opts) { const defaultEasing = 'ease'; const delay = resolveProperty(opts.delay, target, index, ilen) || 0; const config = find(model.configs, c => c.target === target) || push(model.configs, { from: max(opts.from + delay, 0), to: max(opts.to + delay, 0), easing: opts.easing || defaultEasing, duration: opts.to - opts.from, endDelay: resolveProperty(opts.endDelay, target, index, ilen) || 0, stagger: opts.stagger || 0, target, targetLength: ilen, propNames: [], keyframes: [] }); const staggerMs = (opts.stagger && opts.stagger * (index + 1)) || 0; const delayMs = resolveProperty(opts.delay, config, index, config.targetLength) || 0; const from = max(staggerMs + delayMs + opts.from, 0); const duration = opts.to - opts.from; const easing = opts.easing || defaultEasing; for (var pluginName in plugins) { if (isOwner(opts, pluginName)) { const props = opts[pluginName]; for (var name in props) { var propVal = props[name]; if (isOwner(props, name) && isDefined(propVal)) { addProperty(config, pluginName, index, name, propVal, duration, from, easing); } } } } config.keyframes.sort(propKeyframeSort); return config; } function addProperty(config, plugin, index, name, val, duration, from, defaultEasing) { let defaultInterpolator; let values; const isValueObject = !isArrayLike(val) && isObject(val); if (isValueObject) { const objVal = val; if (objVal.easing) { defaultEasing = objVal.easing; } if (objVal.interpolate) { defaultInterpolator = objVal.interpolate; } values = list(objVal.value); } else { values = list(val); } const keyframes = values.map((v, i, vals) => { const valOrObj = resolveProperty(v, config.target, index, config.targetLength); const valObj = valOrObj; const isObj2 = isObject(valOrObj); const value = isObj2 ? valObj.value : valOrObj; const offset = isObj2 && isNumber(valObj.offset) ? valObj.offset : i === vals.length - 1 ? 1 : i === 0 ? 0 : _; const interpolate = (valObj && valObj.interpolate) || defaultInterpolator; const easing = (valObj && valObj.easing) || defaultEasing; return { offset, value, easing, interpolate }; }); inferOffsets(keyframes); all(keyframes, keyframe => { const { offset, value } = keyframe; const time = flr(duration * offset + from); const frame = find(config.keyframes, k => k.prop === name && k.time === time) || push(config.keyframes, { plugin, easing: keyframe.easing, index, prop: name, time, value, interpolate: keyframe.interpolate }); frame.value = value; }); find(config.keyframes, k => k.prop === name && k.time === from) || push(config.keyframes, { plugin, easing: defaultEasing, index, prop: name, time: from, value: _, interpolate: defaultInterpolator }); var to = from + duration; find(config.keyframes, k => k.prop === name && k.time === to, true) || push(config.keyframes, { plugin, easing: defaultEasing, index, prop: name, time: to, value: _, interpolate: defaultInterpolator }); pushDistinct(config.propNames, name); } function inferOffsets(keyframes) { if (!keyframes.length) { return; } const first = find(keyframes, k => k.offset === 0) || keyframes[0]; if (!isDefined(first.offset)) { first.offset = 0; } const last = find(keyframes, k => k.offset === 1, true) || keyframes[keyframes.length - 1]; if (keyframes.length > 1 && !isDefined(last.offset)) { last.offset = 1; } for (let i = 1, ilen = keyframes.length; i < ilen; i++) { const target = keyframes[i]; if (!isDefined(target.offset)) { for (let j = i + 1; j < ilen; j++) { const endTime = keyframes[j].offset; if (isDefined(endTime)) { const startTime = keyframes[i - 1].offset; const timeDelta = endTime - startTime; const deltaLength = j - i + 1; for (let k = 1; k < deltaLength; k++) { keyframes[k - 1 + i].offset = (k / j) * timeDelta + startTime; } i = j; break; } } } } }