UNPKG

just-animate

Version:
1,322 lines (1,274 loc) 40.5 kB
var just = (function (exports) { 'use strict'; var s4 = function () { return Math.floor((1 + Math.random()) * 0x10000) .toString(16) .substring(1); }; var uuid = function () { return s4() + s4() + s4() + s4() + s4() + s4() + s4() + s4(); }; function isDefined(a) { return !!a || a === 0 || a === false; } function isFunction(a) { return typeof a === 'function'; } function isNumber(a) { return typeof a === 'number'; } function isObject(a) { return typeof a === 'object' && !!a; } function isString(a) { return typeof a === 'string'; } function isArrayLike(a) { return a && isFinite(a.length) && !isString(a) && !isFunction(a); } function isDOM(target) { return target.nodeType || target instanceof SVGElement; } function isOwner(obj, name) { return obj.hasOwnProperty(name); } var S_INACTIVE = 1; var S_PAUSED = 2; var S_PLAYING = 3; var _ = undefined; var CONFIG = 'config'; function includes(items, item) { return getIndex(items, item) !== -1; } function getIndex(items, item) { return items.indexOf(item); } function find(indexed, predicate, reverse) { var ilen = indexed && indexed.length; if (!ilen) { return _; } if (predicate === _) { return indexed[reverse ? ilen - 1 : 0]; } if (reverse) { for (var i = ilen - 1; i > -1; i--) { if (predicate(indexed[i])) { return indexed[i]; } } } else { for (var i = 0; i < ilen; i++) { if (predicate(indexed[i])) { return indexed[i]; } } } return _; } function remove(items, item) { var index = items.indexOf(item); return index !== -1 ? items.splice(index, 1) : _; } function sortBy(fieldName) { return function (a, b) { var a1 = a[fieldName]; var b1 = b[fieldName]; return a1 < b1 ? -1 : a1 > b1 ? 1 : 0; }; } function list(indexed) { return !isDefined(indexed) ? [] : isArrayLike(indexed) ? indexed : [indexed]; } function push(indexed, item) { if (item !== _) { Array.prototype.push.call(indexed, item); } return item; } function pushDistinct(indexed, item) { if (!includes(indexed, item)) { push(indexed, item); } return item; } function mapFlatten(items, mapper) { var results = []; all(items, function (item) { var result = mapper(item); if (isArrayLike(result)) { all(result, function (item2) { return push(results, item2); }); } else { push(results, result); } }); return results; } function all(items, action) { var items2 = list(items); for (var i = 0, ilen = items2.length; i < ilen; i++) { action(items2[i], i, ilen); } } var APPEND = 'append'; var CANCEL = 'cancel'; var DESTROY = 'destroy'; var FINISH = 'finish'; var INSERT = 'insert'; var PAUSE = 'pause'; var PLAY = 'play'; var REVERSE = 'reverse'; var SET = 'set'; var TICK = 'tick'; var UPDATE = 'update'; var UPDATE_RATE = 'rate'; var UPDATE_TIME = 'time'; var raf = requestAnimationFrame; var caf = cancelAnimationFrame; var now = function () { return performance.now(); }; var active = []; var lastHandle = _; var lastTime = _; function cancel() { caf(lastHandle); lastHandle = lastTime = _; } function update() { var len = active.length; lastTime = lastTime || now(); if (!len) { cancel(); return; } var thisTime = now(); var delta = thisTime - lastTime; lastTime = thisTime; lastHandle = raf(update); for (var i = len - 1; i > -1; i--) { var activeId = active[i]; dispatch(TICK, activeId, delta); } } function loopOn(id) { if (!includes(active, id)) { push(active, id); } if (!lastHandle) { lastHandle = raf(update); } } function loopOff(id) { if (remove(active, id)) ; if (!active.length) { cancel(); } } var cancel$1 = function (model, _data, ctx) { all(model.players, function (effect) { return effect.cancel(); }); model.state = S_INACTIVE; model.time = _; model.round = _; model.players = _; loopOff(model.id); ctx.trigger(CANCEL); }; var destroy = function (model, _data, ctx) { cancel$1(model, _, ctx); ctx.destroyed = true; }; var flr = Math.floor; var max = Math.max; var min = Math.min; function inRange(val, a, z) { return val !== _ && a <= val && val <= z; } function minMax(val, a, z) { return min(max(val, a), z); } var plugins = {}; function addPlugin(plugin) { plugins[plugin.name] = plugin; } function removePlugin(plugin) { delete plugins[plugin.name]; } var refId = 0; var objNameExp = /\[object ([a-z]+)\]/i; function getName(target) { var name = target.id || target.name; if (!name) { name = Object.prototype.toString.call(target); var matches = objNameExp.exec(name); if (matches) { name = matches[1]; } } return '@' + name + '_' + ++refId; } function assignRef(refs, target) { for (var ref in refs) { if (refs[ref] === target) { return ref; } } var refName = getName(target); refs[refName] = target; return refName; } function replaceWithRefs(refs, target, recurseObjects) { if (!isDefined(target) || isString(target) || isNumber(target)) { return target; } if (isArrayLike(target)) { return mapFlatten(target, function (t) { return replaceWithRefs(refs, t, recurseObjects); }); } if (isFunction(target)) { return assignRef(refs, target); } if (recurseObjects) { for (var name in target) { if (isOwner(target, name)) { target[name] = replaceWithRefs(refs, target[name], recurseObjects && name !== 'targets'); } } return target; } return assignRef(refs, target); } function resolveRefs(refs, value, recurseObjects) { if (!isDefined(value) || isNumber(value) || isFunction(value)) { return value; } if (isString(value)) { var str = value; return isOwner(refs, str) && str.charAt(0) === '@' ? refs[str] : str; } if (isArrayLike(value)) { var results_1 = []; all(value, function (item) { return push(results_1, resolveRefs(refs, item, recurseObjects)); }); return results_1; } if (!recurseObjects || isDOM(value)) { return value; } var obj2 = {}; for (var name in value) { if (isOwner(value, name)) { var value2 = value[name]; obj2[name] = recurseObjects ? resolveRefs(refs, value2, name !== 'targets') : value2; } } return obj2; } function getTargets(target) { return isString(target) ? Array.prototype.slice.call(document.querySelectorAll(target)) : isFunction(target) ? getTargets(target()) : isArrayLike(target) ? mapFlatten(target, getTargets) : isObject(target) ? [target] : []; } function assign() { var result = {}; all(arguments, function (obj) { for (var name in obj) { if (isOwner(obj, name)) { result[name] = obj[name]; } } }); return result; } function resolveProperty(input, target, index, len) { return isFunction(input) ? resolveProperty(input(target, index, len), target, index, len) : input; } var offsetSorter = sortBy('offset'); function toEffects(config) { var keyframes = config.keyframes; var from = config.from; var to = config.to; var stagger = config.stagger || 0; var duration = config.duration; var result = []; all(getTargets(config.target), function (target, index, targetLength) { var effects = {}; var propToPlugin = {}; all(keyframes, function (p) { var effects3 = effects[p.prop] || (effects[p.prop] = []); var offset = (p.time - from) / (duration || 1); var easing = p.easing; var interpolate = p.interpolate; var value = resolveProperty(p.value, target, p.index, targetLength); propToPlugin[p.prop] = p.plugin; var effect2 = find(effects3, function (e) { return e.offset === offset; }) || push(effects3, { easing: easing, offset: offset, value: value, interpolate: interpolate }); effect2.easing = easing; effect2.value = value; effect2.interpolate = interpolate; }); for (var pluginName in plugins) { var plugin2 = plugins[pluginName]; if (plugin2.onWillAnimate && config.keyframes.some(function (c) { return c.plugin === pluginName; })) { var targetConfig2 = assign(config, { target: target }); plugin2.onWillAnimate(targetConfig2, effects, propToPlugin); } } for (var prop in effects) { var effects2 = effects[prop]; var pluginName2 = propToPlugin[prop]; var plugin = plugins[pluginName2]; if (effects2) { effects2.sort(offsetSorter); ensureFirstFrame(config, effects2, target, plugin, prop); fillValues(effects2); fillInterpolators(effects2); ensureLastFrame(config, effects2); push(result, { plugin: propToPlugin[prop], target: target, prop: prop, from: from + (stagger ? stagger * index : 0), to: to + (stagger ? stagger * index : 0), keyframes: effects2 }); } } }); return result; } function fillValues(items) { var lastValue; all(items, function (item) { if (item.value !== _) { lastValue = item.value; } else { item.value = lastValue; } }); } function fillInterpolators(items) { var lastInterpolator; for (var y = items.length - 1; y > -1; y--) { var item2 = items[y]; if (item2.interpolate !== _) { lastInterpolator = item2.interpolate; } else { item2.interpolate = lastInterpolator; } } } function ensureFirstFrame(config, items, target, plugin, prop) { var firstFrame = find(items, function (c) { return c.offset === 0; }); if (firstFrame === _ || firstFrame.value === _) { var value2 = plugin.getValue(target, prop); if (firstFrame === _) { items.splice(0, 0, { offset: 0, value: value2, easing: config.easing, interpolate: _ }); } else { firstFrame.value = value2; firstFrame.easing = config.easing; firstFrame.interpolate = _; } } } function ensureLastFrame(config, items) { var lastFrame = find(items, function (c) { return c.offset === 1; }, true); if (lastFrame === _ || lastFrame.value === _) { var value3 = items[items.length - 1].value; if (lastFrame === _) { push(items, { offset: 1, value: value3, easing: config.easing, interpolate: _ }); } else { lastFrame.value = value3; lastFrame.easing = lastFrame.easing || config.easing; } } } function calculatePlayers(model) { model.duration = max.apply(_, model.players.filter(function (a) { return isFinite(a.to); }).map(function (a) { return a.to; })); model.time = isFinite(model.time) ? model.time : model.rate < 0 ? model.duration : 0; } function setup(model) { model.players = []; all(model.configs, function (config) { return setupTarget(model, config); }); calculatePlayers(model); } function setupTarget(model, config) { var resolvedConfig = resolveRefs(model.refs, config, true); var effects = toEffects(resolvedConfig); all(effects, function (effect) { var player = plugins[effect.plugin].animate(effect); if (player) { player.from = effect.from; player.to = effect.to; push(model.players, player); } }); } var update$1 = function (model, _data, ctx) { if (model.players === _) { setup(model); } var isPlaying = model.state === S_PLAYING; var time = model.time; if (!isPlaying) { loopOff(model.id); } all(model.players, function (player) { var from = player.from; var to = player.to; var isActive = isPlaying && inRange(flr(time), from, to); var offset = minMax((time - from) / (to - from), 0, 1); player.update(offset, model.rate, isActive); }); ctx.trigger(UPDATE); }; var finish = function (model, _data, ctx) { model.round = 0; model.state = S_PAUSED; if (!model.yoyo) { model.time = model.rate < 0 ? 0 : model.duration; } loopOff(model.id); update$1(model, _, ctx); ctx.trigger(FINISH); if (model.destroy) { destroy(model, _, ctx); } }; var pause = function (model, _data, ctx) { model.state = S_PAUSED; loopOff(model.id); update$1(model, _, ctx); ctx.trigger(PAUSE); }; var play = function (model, options, ctx) { if (options) { model.repeat = options.repeat; model.yoyo = !!options.alternate; model.destroy = !!options.destroy; } model.repeat = model.repeat || 1; model.yoyo = model.yoyo || false; model.state = S_PLAYING; var isForwards = model.rate >= 0; if (isForwards && model.time === model.duration) { model.time = 0; } else if (!isForwards && model.time === 0) { model.time = model.duration; } loopOn(model.id); update$1(model, _, ctx); ctx.trigger(PLAY); }; var reverse = function (model, _data, ctx) { model.rate *= -1; update$1(model, _, ctx); ctx.trigger(REVERSE); }; var tick = function (model, delta, _ctx) { var duration = model.duration; var repeat = model.repeat; var rate = model.rate; var time = model.time === _ ? (rate < 0 ? duration : 0) : model.time; var round = model.round || 0; var isReversed = rate < 0; time += delta * rate; var iterationEnded = false; if (!inRange(time, 0, duration)) { model.round = ++round; time = isReversed ? 0 : duration; iterationEnded = true; if (model.yoyo) { model.rate = (model.rate || 0) * -1; } time = model.rate < 0 ? duration : 0; } model.time = time; model.round = round; if (iterationEnded && repeat === round) { finish(model, _, _ctx); return; } update$1(model, _, _ctx); }; var updateRate = function (model, rate, ctx) { model.rate = rate || 1; update$1(model, _, ctx); }; var updateTime = function (model, time, ctx) { var currentTime = +time; model.time = isFinite(currentTime) ? currentTime : model.rate < 0 ? model.duration : 0; update$1(model, _, ctx); }; var calculateConfigs = function (model) { var maxTo = 0; var cursor = 0; var configs = model.configs; for (var i = 0, ilen = configs.length; i < ilen; i++) { var config = configs[i]; var times = config.keyframes.map(function (k) { return k.time; }); var to = max.apply(_, times); var from = min.apply(_, times); config.to = to; config.from = from; config.duration = to - from; maxTo = max(to, maxTo); cursor = max(to + config.endDelay, cursor); } model.cursor = cursor; model.duration = maxTo; }; var propKeyframeSort = sortBy('time'); var insert = function (model, options, ctx) { all(options, function (opts) { if (opts.to === _) { throw new Error('missing duration'); } opts = replaceWithRefs(model.refs, opts, true); all(opts.targets, function (target, i, ilen) { var config = addPropertyKeyframes(model, target, i, ilen, opts); ctx.dirty(config); }); }); calculateConfigs(model); ctx.trigger(CONFIG); }; function addPropertyKeyframes(model, target, index, ilen, opts) { var defaultEasing = 'ease'; var delay = resolveProperty(opts.delay, target, index, ilen) || 0; var config = find(model.configs, function (c) { return 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: target, targetLength: ilen, propNames: [], keyframes: [] }); var staggerMs = (opts.stagger && opts.stagger * (index + 1)) || 0; var delayMs = resolveProperty(opts.delay, config, index, config.targetLength) || 0; var from = max(staggerMs + delayMs + opts.from, 0); var duration = opts.to - opts.from; var easing = opts.easing || defaultEasing; for (var pluginName in plugins) { if (isOwner(opts, pluginName)) { var 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) { var defaultInterpolator; var values; var isValueObject = !isArrayLike(val) && isObject(val); if (isValueObject) { var objVal = val; if (objVal.easing) { defaultEasing = objVal.easing; } if (objVal.interpolate) { defaultInterpolator = objVal.interpolate; } values = list(objVal.value); } else { values = list(val); } var keyframes = values.map(function (v, i, vals) { var valOrObj = resolveProperty(v, config.target, index, config.targetLength); var valObj = valOrObj; var isObj2 = isObject(valOrObj); var value = isObj2 ? valObj.value : valOrObj; var offset = isObj2 && isNumber(valObj.offset) ? valObj.offset : i === vals.length - 1 ? 1 : i === 0 ? 0 : _; var interpolate = (valObj && valObj.interpolate) || defaultInterpolator; var easing = (valObj && valObj.easing) || defaultEasing; return { offset: offset, value: value, easing: easing, interpolate: interpolate }; }); inferOffsets(keyframes); all(keyframes, function (keyframe) { var offset = keyframe.offset, value = keyframe.value; var time = flr(duration * offset + from); var frame = find(config.keyframes, function (k) { return k.prop === name && k.time === time; }) || push(config.keyframes, { plugin: plugin, easing: keyframe.easing, index: index, prop: name, time: time, value: value, interpolate: keyframe.interpolate }); frame.value = value; }); find(config.keyframes, function (k) { return k.prop === name && k.time === from; }) || push(config.keyframes, { plugin: plugin, easing: defaultEasing, index: index, prop: name, time: from, value: _, interpolate: defaultInterpolator }); var to = from + duration; find(config.keyframes, function (k) { return k.prop === name && k.time === to; }, true) || push(config.keyframes, { plugin: plugin, easing: defaultEasing, index: index, prop: name, time: to, value: _, interpolate: defaultInterpolator }); pushDistinct(config.propNames, name); } function inferOffsets(keyframes) { if (!keyframes.length) { return; } var first = find(keyframes, function (k) { return k.offset === 0; }) || keyframes[0]; if (!isDefined(first.offset)) { first.offset = 0; } var last = find(keyframes, function (k) { return k.offset === 1; }, true) || keyframes[keyframes.length - 1]; if (keyframes.length > 1 && !isDefined(last.offset)) { last.offset = 1; } for (var i = 1, ilen = keyframes.length; i < ilen; i++) { var target = keyframes[i]; if (!isDefined(target.offset)) { for (var j = i + 1; j < ilen; j++) { var endTime = keyframes[j].offset; if (isDefined(endTime)) { var startTime = keyframes[i - 1].offset; var timeDelta = endTime - startTime; var deltaLength = j - i + 1; for (var k = 1; k < deltaLength; k++) { keyframes[k - 1 + i].offset = (k / j) * timeDelta + startTime; } i = j; break; } } } } } var append = function (model, data, ctx) { var cursor = model.cursor; var opts2 = list(data).map(function (opt) { var to = opt.to, from = opt.from, duration = opt.duration; var hasTo = isDefined(to); var hasFrom = isDefined(from); var hasDuration = isDefined(duration); var opt2 = opt; opt2.to = hasTo && (hasFrom || hasDuration) ? to : hasDuration && hasFrom ? from + duration : hasTo && !hasDuration ? cursor + to : hasDuration ? cursor + duration : _; opt2.from = hasFrom && (hasTo || hasDuration) ? from : hasTo && hasDuration ? to - duration : hasTo || hasDuration ? cursor : _; return opt2; }); insert(model, opts2, ctx); }; var set = function (model, options, ctx) { var pluginNames = Object.keys(plugins); var opts2 = list(options).map(function (opts) { var at = opts.at || model.cursor; var opt2 = {}; for (var name in opts) { if (includes(pluginNames, name)) { var props = opts[name]; var props2 = {}; for (var propName in props) { var value = props[propName]; props2[propName] = [_, value]; } opt2[name] = props2; } else { opt2[name] = opts[name]; } } opt2.from = at - 0.000000001; opt2.to = at; return opt2; }); insert(model, opts2, ctx); }; function rebuild(model, ctx) { var state = model.state; all(model.players, function (p) { return p.cancel(); }); model.players = _; switch (state) { case S_PAUSED: pause(model, _, ctx); break; case S_PLAYING: play(model, _, ctx); break; } } var _a; var stateSubs = []; var stores = {}; var reducers = (_a = {}, _a[APPEND] = append, _a[CANCEL] = cancel$1, _a[DESTROY] = destroy, _a[FINISH] = finish, _a[INSERT] = insert, _a[PAUSE] = pause, _a[PLAY] = play, _a[REVERSE] = reverse, _a[SET] = set, _a[TICK] = tick, _a[UPDATE] = update$1, _a[UPDATE_RATE] = updateRate, _a[UPDATE_TIME] = updateTime, _a); function createInitial(opts) { var refs = {}; if (opts.references) { for (var name in opts.references) { refs['@' + name] = opts.references[name]; } } var newModel = { configs: [], cursor: 0, duration: 0, id: opts.id, players: _, rate: 1, refs: refs, repeat: _, round: _, state: S_INACTIVE, time: _, yoyo: false }; return newModel; } function getState(id) { var model = stores[id]; if (!model) { throw new Error('not found'); } return model.state; } function addState(opts) { stores[opts.id] = { state: createInitial(opts), subs: {} }; } function on(id, eventName, listener) { var store = stores[id]; if (store) { var subs = (store.subs[eventName] = store.subs[eventName] || []); pushDistinct(subs, listener); } } function off(id, eventName, listener) { var store = stores[id]; if (store) { remove(store.subs[eventName], listener); } } function dispatch(action, id, data) { var fn = reducers[action]; var store = stores[id]; if (!fn || !store) { throw new Error('not found'); } var ctx = { events: [], needUpdate: [], trigger: trigger, dirty: dirty }; var model = store.state; fn(model, data, ctx); all(ctx.events, function (evt) { var subs = store.subs[evt]; if (subs) { all(subs, function (sub) { sub(model.time); }); } }); if (ctx.destroyed) { delete stores[id]; } else if (ctx.needUpdate.length) { if (model.state !== S_INACTIVE) { rebuild(model, ctx); } else { calculateConfigs(model); } all(stateSubs, function (sub) { sub(store); }); } } function trigger(eventName) { pushDistinct(this.events, eventName); } function dirty(config) { pushDistinct(this.needUpdate, config); } if (typeof window !== 'undefined') { window.just_devtools = { dispatch: dispatch, subscribe: function (fn) { pushDistinct(stateSubs, fn); }, unsubscribe: function (fn) { remove(stateSubs, fn); } }; } var timelineProto = { get state() { return getState(this.id).state; }, get duration() { return getState(this.id).duration; }, get currentTime() { return getState(this.id).time; }, set currentTime(time) { dispatch(UPDATE_TIME, this.id, time); }, get playbackRate() { return getState(this.id).rate; }, set playbackRate(rate) { dispatch(UPDATE_RATE, this.id, rate); }, add: function (opts) { dispatch(APPEND, this.id, opts); return this; }, animate: function (opts) { dispatch(APPEND, this.id, opts); return this; }, fromTo: function (from, to, options) { all(options, function (options2) { options2.to = to; options2.from = from; }); dispatch(INSERT, this.id, options); return this; }, cancel: function () { dispatch(CANCEL, this.id); return this; }, destroy: function () { dispatch(DESTROY, this.id); }, finish: function () { dispatch(FINISH, this.id); return this; }, on: function (name, fn) { on(this.id, name, fn); return this; }, once: function (eventName, listener) { var self = this; self.on(eventName, function s(time) { self.off(eventName, s); listener(time); }); return self; }, off: function (name, fn) { off(this.id, name, fn); return this; }, pause: function () { dispatch(PAUSE, this.id); return this; }, play: function (options) { dispatch(PLAY, this.id, options); return this; }, reverse: function () { dispatch(REVERSE, this.id); return this; }, seek: function (time) { dispatch(UPDATE_TIME, this.id, time); return this; }, sequence: function (seqOptions) { var _this = this; all(seqOptions, function (opt) { return dispatch(APPEND, _this.id, opt); }); return this; }, set: function (opts) { dispatch(SET, this.id, opts); return this; } }; function timeline(opts) { var t1 = Object.create(timelineProto); opts = opts || {}; opts.id = opts.id || uuid(); t1.id = opts.id; addState(opts); return t1; } var pi = Math.PI; var epsilon = 0.0001; var c = "cubic-bezier"; var s = "steps"; var ease = c + "(.25,.1,.25,1)"; var easeIn = c + "(.42,0,1,1)"; var easeInOut = c + "(.42,0,.58,1)"; var easeOut = c + "(0,0,.58,1)"; var linear = c + "(0,0,1,1)"; var stepEnd = s + "(1,0)"; var stepStart = s + "(1,1)"; var steps = function (count, pos) { var q = count / 1; var p = pos === 'end' ? 0 : pos === 'start' ? 1 : pos || 0; return function (x) { return x >= 1 ? 1 : (p * q + x) - (p * q + x) % q; }; }; var bezier = function (n1, n2, t) { return 3 * n1 * (1 - t) * (1 - t) * t + 3 * n2 * (1 - t) * t * t + t * t * t; }; var cubicBezier$$1 = function (p0, p1, p2, p3) { if (p0 < 0 || p0 > 1 || p2 < 0 || p2 > 1) { return function (x) { return x; }; } return function (x) { if (x === 0 || x === 1) { return x; } var start = 0; var end = 1; var limit = 19; do { var mid = (start + end) * .5; var xEst = bezier(p0, p2, mid); if (abs$1(x - xEst) < epsilon) { return bezier(p1, p3, mid); } if (xEst < x) { start = mid; } else { end = mid; } } while (--limit); // limit is reached return x; }; }; var camelCaseRegex = /([a-z])[- ]([a-z])/ig; var cssFunctionRegex = /^([a-z-]+)\(([^\)]+)\)$/i; var cssEasings = { ease: ease, easeIn: easeIn, easeOut: easeOut, easeInOut: easeInOut, stepStart: stepStart, stepEnd: stepEnd, linear: linear }; var camelCaseMatcher = function (match, p1, p2) { return p1 + p2.toUpperCase(); }; var toCamelCase = function (value) { return typeof value === 'string' ? value.replace(camelCaseRegex, camelCaseMatcher) : ''; }; var find$1 = function (nameOrCssFunction) { // search for a compatible known easing var easingName = toCamelCase(nameOrCssFunction); var easing = cssEasings[easingName] || nameOrCssFunction; var matches = cssFunctionRegex.exec(easing); if (!matches) { throw new Error('css parse error'); } return [matches[1]].concat(matches[2].split(',')); }; var cssFunction = function (easingString) { var p = find$1(easingString); var fnName = p[0]; if (fnName === 'steps') { return steps(+p[1], p[2]); } if (fnName === 'cubic-bezier') { return cubicBezier$$1(+p[1], +p[2], +p[3], +p[4]); } throw new Error('css parse error'); }; var abs$1 = Math.abs; /** * Animations change at a constant speed */ function memoize(func) { var cache = []; return function () { var args = arguments; for (var h = 0, hlen = cache.length; h < hlen; h++) { var keys = cache[h].args; var ilen = args.length; if (keys.length !== ilen) { continue; } var matches = 0; for (var i = 0; i < ilen; i++) { if (keys[i] !== args[i]) { break; } ++matches; } if (matches === ilen) { return cache[h].value; } } var value = func.apply(_, args); cache.push({ args: args, value: value }); return value; }; } function findEndIndex(ns, n) { var ilen = ns.length; for (var i = 0; i < ilen; i++) { if (ns[i] > n) { return i; } } return ilen - 1; } var getEasing = memoize(cssFunction); var getInterpolator = memoize(function (fn) { return memoize(fn); }); function interpolate(l, r, o) { return l + (r - l) * o; } function fallbackInterpolator(l, r, o) { return o < 0.5 ? l : r; } function interpolator(duration, keyframes) { var times = keyframes.map(function (k) { return k.offset * duration; }); all(keyframes, function (k) { var isSimple = !isFunction(k.interpolate); k.simpleFn = isSimple; k.interpolate = !isSimple ? getInterpolator(k.interpolate) : isNumber(k.value) ? interpolate : fallbackInterpolator; }); return function (timelineOffset) { var absTime = duration * timelineOffset; var r = findEndIndex(times, absTime); var l = r ? r - 1 : 0; var rt = times[r]; var lt = times[l]; var lk = keyframes[l]; var time = (absTime - lt) / (rt - lt); var progression = lk.easing ? getEasing(lk.easing)(time) : time; if (lk.simpleFn) { return lk.interpolate(lk.value, keyframes[r].value, progression); } return lk.interpolate(lk.value, keyframes[r].value)(progression); }; } function hyphenate(value) { return value.replace(/([A-Z])/g, function (match) { return "-" + match[0].toLowerCase(); }); } var PROPERTY = 0; var ATTRIBUTE = 1; var ATTRIBUTE_HYPHENATE = 2; var CSSVAR = 3; var cssVarExp = /^\-\-[a-z0-9\-]+$/i; var viewbox = 'viewBox'; var svgReadonly = 'rx ry viewBox transform x x1 x2 y y1 y2'.split(' '); var noHyphenate = [viewbox]; var propsPlugin = { name: 'props', animate: function (effect) { var target = effect.target, prop = effect.prop; var interpolate$$1 = interpolator(effect.to - effect.from, effect.keyframes); var propSetter = getTargetSetter(target, prop); var propGetter = getTargetGetter(target, prop); var initial = _; return { cancel: function () { if (initial !== _) { propSetter(initial); } initial = _; }, update: function (localTime, _playbackRate, _isActive) { if (initial === _) { initial = propGetter(); } propSetter(interpolate$$1(localTime)); } }; }, getValue: function (target, prop) { return getTargetGetter(target, prop)(); } }; function getTargetType(target, prop) { if (!isDOM(target)) { return PROPERTY; } if (cssVarExp.test(prop)) { return CSSVAR; } if (typeof target[prop] !== 'undefined' && !includes(svgReadonly, prop)) { return PROPERTY; } if (includes(noHyphenate, prop)) { return ATTRIBUTE; } return ATTRIBUTE_HYPHENATE; } function getTargetGetter(target, prop) { var targetType = getTargetType(target, prop); return targetType === CSSVAR ? getVariable(target, prop) : targetType === ATTRIBUTE ? getAttribute(target, prop) : targetType === ATTRIBUTE_HYPHENATE ? getAttributeHyphenate(target, prop) : getProperty(target, prop); } function getTargetSetter(target, prop) { var targetType = getTargetType(target, prop); return targetType === CSSVAR ? setVariable(target, prop) : targetType === ATTRIBUTE ? setAttribute(target, prop) : targetType === ATTRIBUTE_HYPHENATE ? setAttributeHyphenate(target, prop) : setProperty(target, prop); } function getAttribute(target, name) { return function () { return target.getAttribute(name); }; } function setAttribute(target, name) { return function (value) { return target.setAttribute(name, value); }; } function setAttributeHyphenate(target, name) { var attName = hyphenate(name); return function (value) { return target.setAttribute(attName, value); }; } function getAttributeHyphenate(target, name) { var attName = hyphenate(name); return function () { return target.getAttribute(attName); }; } function getVariable(target, name) { return function () { return target.style.getPropertyValue(name); }; } function setVariable(target, name) { return function (value) { return target.style.setProperty(name, value ? value + '' : ''); }; } function setProperty(target, name) { return function (value) { return (target[name] = value); }; } function getProperty(target, name) { return function () { return target[name]; }; } function animate(options) { return timeline().add(options); } function sequence(seqOptions) { return timeline().sequence(seqOptions); } addPlugin(propsPlugin); exports.animate = animate; exports.sequence = sequence; exports.timeline = timeline; exports.addPlugin = addPlugin; exports.removePlugin = removePlugin; exports.interpolate = interpolate; return exports; }({}));