just-animate
Version:
_Making Animation Simple_
127 lines (126 loc) • 3.19 kB
JavaScript
import { S_INACTIVE, _ } from './utils/constants';
import { CANCEL, DESTROY, FINISH, PAUSE, PLAY, REVERSE, TICK, UPDATE, UPDATE_TIME, UPDATE_RATE, APPEND, INSERT, SET } from './actions';
import { append, cancel, destroy, finish, insert, pause, play, reverse, set, tick, update, updateRate, updateTime } from './reducers/index';
import { pushDistinct, all, remove } from './utils/lists';
import { calculateConfigs } from './reducers/calc-configs';
import { rebuild } from './reducers/rebuild';
const stateSubs = [];
const stores = {};
const reducers = {
[APPEND]: append,
[CANCEL]: cancel,
[DESTROY]: destroy,
[FINISH]: finish,
[INSERT]: insert,
[PAUSE]: pause,
[PLAY]: play,
[REVERSE]: reverse,
[SET]: set,
[TICK]: tick,
[UPDATE]: update,
[UPDATE_RATE]: updateRate,
[UPDATE_TIME]: updateTime
};
function createInitial(opts) {
const refs = {};
if (opts.references) {
for (var name in opts.references) {
refs['@' + name] = opts.references[name];
}
}
const newModel = {
configs: [],
cursor: 0,
duration: 0,
id: opts.id,
players: _,
rate: 1,
refs: refs,
repeat: _,
round: _,
state: S_INACTIVE,
time: _,
yoyo: false
};
return newModel;
}
export function getState(id) {
const model = stores[id];
if (!model) {
throw new Error('not found');
}
return model.state;
}
export function addState(opts) {
stores[opts.id] = {
state: createInitial(opts),
subs: {}
};
}
export function on(id, eventName, listener) {
const store = stores[id];
if (store) {
const subs = (store.subs[eventName] = store.subs[eventName] || []);
pushDistinct(subs, listener);
}
}
export function off(id, eventName, listener) {
const store = stores[id];
if (store) {
remove(store.subs[eventName], listener);
}
}
export function dispatch(action, id, data) {
const fn = reducers[action];
const store = stores[id];
if (!fn || !store) {
throw new Error('not found');
}
const ctx = {
events: [],
needUpdate: [],
trigger,
dirty
};
const model = store.state;
fn(model, data, ctx);
all(ctx.events, evt => {
const subs = store.subs[evt];
if (subs) {
all(subs, 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, 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,
subscribe(fn) {
pushDistinct(stateSubs, fn);
},
unsubscribe(fn) {
remove(stateSubs, fn);
}
};
}