mirror of
https://github.com/nunocoracao/blowfish.git
synced 2025-04-21 13:51:53 +02:00
153 lines
4.5 KiB
JavaScript
153 lines
4.5 KiB
JavaScript
import {dispatch} from "d3-dispatch";
|
|
import {timer, timeout} from "d3-timer";
|
|
|
|
var emptyOn = dispatch("start", "end", "cancel", "interrupt");
|
|
var emptyTween = [];
|
|
|
|
export var CREATED = 0;
|
|
export var SCHEDULED = 1;
|
|
export var STARTING = 2;
|
|
export var STARTED = 3;
|
|
export var RUNNING = 4;
|
|
export var ENDING = 5;
|
|
export var ENDED = 6;
|
|
|
|
export default function(node, name, id, index, group, timing) {
|
|
var schedules = node.__transition;
|
|
if (!schedules) node.__transition = {};
|
|
else if (id in schedules) return;
|
|
create(node, id, {
|
|
name: name,
|
|
index: index, // For context during callback.
|
|
group: group, // For context during callback.
|
|
on: emptyOn,
|
|
tween: emptyTween,
|
|
time: timing.time,
|
|
delay: timing.delay,
|
|
duration: timing.duration,
|
|
ease: timing.ease,
|
|
timer: null,
|
|
state: CREATED
|
|
});
|
|
}
|
|
|
|
export function init(node, id) {
|
|
var schedule = get(node, id);
|
|
if (schedule.state > CREATED) throw new Error("too late; already scheduled");
|
|
return schedule;
|
|
}
|
|
|
|
export function set(node, id) {
|
|
var schedule = get(node, id);
|
|
if (schedule.state > STARTED) throw new Error("too late; already running");
|
|
return schedule;
|
|
}
|
|
|
|
export function get(node, id) {
|
|
var schedule = node.__transition;
|
|
if (!schedule || !(schedule = schedule[id])) throw new Error("transition not found");
|
|
return schedule;
|
|
}
|
|
|
|
function create(node, id, self) {
|
|
var schedules = node.__transition,
|
|
tween;
|
|
|
|
// Initialize the self timer when the transition is created.
|
|
// Note the actual delay is not known until the first callback!
|
|
schedules[id] = self;
|
|
self.timer = timer(schedule, 0, self.time);
|
|
|
|
function schedule(elapsed) {
|
|
self.state = SCHEDULED;
|
|
self.timer.restart(start, self.delay, self.time);
|
|
|
|
// If the elapsed delay is less than our first sleep, start immediately.
|
|
if (self.delay <= elapsed) start(elapsed - self.delay);
|
|
}
|
|
|
|
function start(elapsed) {
|
|
var i, j, n, o;
|
|
|
|
// If the state is not SCHEDULED, then we previously errored on start.
|
|
if (self.state !== SCHEDULED) return stop();
|
|
|
|
for (i in schedules) {
|
|
o = schedules[i];
|
|
if (o.name !== self.name) continue;
|
|
|
|
// While this element already has a starting transition during this frame,
|
|
// defer starting an interrupting transition until that transition has a
|
|
// chance to tick (and possibly end); see d3/d3-transition#54!
|
|
if (o.state === STARTED) return timeout(start);
|
|
|
|
// Interrupt the active transition, if any.
|
|
if (o.state === RUNNING) {
|
|
o.state = ENDED;
|
|
o.timer.stop();
|
|
o.on.call("interrupt", node, node.__data__, o.index, o.group);
|
|
delete schedules[i];
|
|
}
|
|
|
|
// Cancel any pre-empted transitions.
|
|
else if (+i < id) {
|
|
o.state = ENDED;
|
|
o.timer.stop();
|
|
o.on.call("cancel", node, node.__data__, o.index, o.group);
|
|
delete schedules[i];
|
|
}
|
|
}
|
|
|
|
// Defer the first tick to end of the current frame; see d3/d3#1576.
|
|
// Note the transition may be canceled after start and before the first tick!
|
|
// Note this must be scheduled before the start event; see d3/d3-transition#16!
|
|
// Assuming this is successful, subsequent callbacks go straight to tick.
|
|
timeout(function() {
|
|
if (self.state === STARTED) {
|
|
self.state = RUNNING;
|
|
self.timer.restart(tick, self.delay, self.time);
|
|
tick(elapsed);
|
|
}
|
|
});
|
|
|
|
// Dispatch the start event.
|
|
// Note this must be done before the tween are initialized.
|
|
self.state = STARTING;
|
|
self.on.call("start", node, node.__data__, self.index, self.group);
|
|
if (self.state !== STARTING) return; // interrupted
|
|
self.state = STARTED;
|
|
|
|
// Initialize the tween, deleting null tween.
|
|
tween = new Array(n = self.tween.length);
|
|
for (i = 0, j = -1; i < n; ++i) {
|
|
if (o = self.tween[i].value.call(node, node.__data__, self.index, self.group)) {
|
|
tween[++j] = o;
|
|
}
|
|
}
|
|
tween.length = j + 1;
|
|
}
|
|
|
|
function tick(elapsed) {
|
|
var t = elapsed < self.duration ? self.ease.call(null, elapsed / self.duration) : (self.timer.restart(stop), self.state = ENDING, 1),
|
|
i = -1,
|
|
n = tween.length;
|
|
|
|
while (++i < n) {
|
|
tween[i].call(node, t);
|
|
}
|
|
|
|
// Dispatch the end event.
|
|
if (self.state === ENDING) {
|
|
self.on.call("end", node, node.__data__, self.index, self.group);
|
|
stop();
|
|
}
|
|
}
|
|
|
|
function stop() {
|
|
self.state = ENDED;
|
|
self.timer.stop();
|
|
delete schedules[id];
|
|
for (var i in schedules) return; // eslint-disable-line no-unused-vars
|
|
delete node.__transition;
|
|
}
|
|
}
|