d3-jsnext
Version:
d3, but futuristic
426 lines (354 loc) • 13.5 kB
JavaScript
import { d3_true } from '../core/true';
import { d3_timer_active, d3$timer } from '../event/timer';
import { d3_Map } from '../arrays/map';
import { d3_selection_each, d3_selection_filter, d3_selection_selectorAll, d3_selection_selector, d3_selectionPrototype, d3$selection } from '../selection/selection';
import { d3_window } from '../core/document';
import { d3_interpolate } from '../interpolate/interpolate';
import { d3_interpolateTransform } from '../interpolate/transform';
import { d3_subclass } from '../core/subclass';
import { d3$dispatch } from '../event/dispatch';
import { d3$ease } from '../interpolate/ease';
import { d3$ns } from '../core/ns';
var d3$transition;
function d3_transition(groups, ns, id) {
d3_subclass(groups, d3_transitionPrototype);
// Note: read-only!
groups.namespace = ns;
groups.id = id;
return groups;
}
var d3_transitionPrototype = [],
d3_transitionId = 0,
d3_transitionInheritId,
d3_transitionInherit;
d3_transitionPrototype.call = d3_selectionPrototype.call;
d3_transitionPrototype.empty = d3_selectionPrototype.empty;
d3_transitionPrototype.node = d3_selectionPrototype.node;
d3_transitionPrototype.size = d3_selectionPrototype.size;
d3$transition = function(selection, name) {
return selection && selection.transition
? (d3_transitionInheritId ? selection.transition(name) : selection)
: d3$selection().transition(selection);
};
d3$transition.prototype = d3_transitionPrototype;
d3_transitionPrototype.select = function(selector) {
var id = this.id,
ns = this.namespace,
subgroups = [],
subgroup,
subnode,
node;
selector = d3_selection_selector(selector);
for (var j = -1, m = this.length; ++j < m;) {
subgroups.push(subgroup = []);
for (var group = this[j], i = -1, n = group.length; ++i < n;) {
if ((node = group[i]) && (subnode = selector.call(node, node.__data__, i, j))) {
if ("__data__" in node) subnode.__data__ = node.__data__;
d3_transitionNode(subnode, i, ns, id, node[ns][id]);
subgroup.push(subnode);
} else {
subgroup.push(null);
}
}
}
return d3_transition(subgroups, ns, id);
};
d3_transitionPrototype.selectAll = function(selector) {
var id = this.id,
ns = this.namespace,
subgroups = [],
subgroup,
subnodes,
node,
subnode,
transition;
selector = d3_selection_selectorAll(selector);
for (var j = -1, m = this.length; ++j < m;) {
for (var group = this[j], i = -1, n = group.length; ++i < n;) {
if (node = group[i]) {
transition = node[ns][id];
subnodes = selector.call(node, node.__data__, i, j);
subgroups.push(subgroup = []);
for (var k = -1, o = subnodes.length; ++k < o;) {
if (subnode = subnodes[k]) d3_transitionNode(subnode, k, ns, id, transition);
subgroup.push(subnode);
}
}
}
}
return d3_transition(subgroups, ns, id);
};
d3_transitionPrototype.filter = function(filter) {
var subgroups = [],
subgroup,
group,
node;
if (typeof filter !== "function") filter = d3_selection_filter(filter);
for (var j = 0, m = this.length; j < m; j++) {
subgroups.push(subgroup = []);
for (var group = this[j], i = 0, n = group.length; i < n; i++) {
if ((node = group[i]) && filter.call(node, node.__data__, i, j)) {
subgroup.push(node);
}
}
}
return d3_transition(subgroups, this.namespace, this.id);
};
d3_transitionPrototype.attr = function(nameNS, value) {
if (arguments.length < 2) {
// For attr(object), the object specifies the names and values of the
// attributes to transition. The values may be functions that are
// evaluated for each element.
for (value in nameNS) this.attr(value, nameNS[value]);
return this;
}
var interpolate = nameNS == "transform" ? d3_interpolateTransform : d3_interpolate,
name = d3$ns.qualify(nameNS);
// For attr(string, null), remove the attribute with the specified name.
function attrNull() {
this.removeAttribute(name);
}
function attrNullNS() {
this.removeAttributeNS(name.space, name.local);
}
// For attr(string, string), set the attribute with the specified name.
function attrTween(b) {
return b == null ? attrNull : (b += "", function() {
var a = this.getAttribute(name), i;
return a !== b && (i = interpolate(a, b), function(t) { this.setAttribute(name, i(t)); });
});
}
function attrTweenNS(b) {
return b == null ? attrNullNS : (b += "", function() {
var a = this.getAttributeNS(name.space, name.local), i;
return a !== b && (i = interpolate(a, b), function(t) { this.setAttributeNS(name.space, name.local, i(t)); });
});
}
return d3_transition_tween(this, "attr." + nameNS, value, name.local ? attrTweenNS : attrTween);
};
d3_transitionPrototype.attrTween = function(nameNS, tween) {
var name = d3$ns.qualify(nameNS);
function attrTween(d, i) {
var f = tween.call(this, d, i, this.getAttribute(name));
return f && function(t) { this.setAttribute(name, f(t)); };
}
function attrTweenNS(d, i) {
var f = tween.call(this, d, i, this.getAttributeNS(name.space, name.local));
return f && function(t) { this.setAttributeNS(name.space, name.local, f(t)); };
}
return this.tween("attr." + nameNS, name.local ? attrTweenNS : attrTween);
};
d3_transitionPrototype.style = function(name, value, priority) {
var n = arguments.length;
if (n < 3) {
// For style(object) or style(object, string), the object specifies the
// names and values of the attributes to set or remove. The values may be
// functions that are evaluated for each element. The optional string
// specifies the priority.
if (typeof name !== "string") {
if (n < 2) value = "";
for (priority in name) this.style(priority, name[priority], value);
return this;
}
// For style(string, string) or style(string, function), use the default
// priority. The priority is ignored for style(string, null).
priority = "";
}
// For style(name, null) or style(name, null, priority), remove the style
// property with the specified name. The priority is ignored.
function styleNull() {
this.style.removeProperty(name);
}
// For style(name, string) or style(name, string, priority), set the style
// property with the specified name, using the specified priority.
// Otherwise, a name, value and priority are specified, and handled as below.
function styleString(b) {
return b == null ? styleNull : (b += "", function() {
var a = d3_window(this).getComputedStyle(this, null).getPropertyValue(name), i;
return a !== b && (i = d3_interpolate(a, b), function(t) { this.style.setProperty(name, i(t), priority); });
});
}
return d3_transition_tween(this, "style." + name, value, styleString);
};
d3_transitionPrototype.styleTween = function(name, tween, priority) {
if (arguments.length < 3) priority = "";
function styleTween(d, i) {
var f = tween.call(this, d, i, d3_window(this).getComputedStyle(this, null).getPropertyValue(name));
return f && function(t) { this.style.setProperty(name, f(t), priority); };
}
return this.tween("style." + name, styleTween);
};
d3_transitionPrototype.text = function(value) {
return d3_transition_tween(this, "text", value, d3_transition_text);
};
function d3_transition_text(b) {
if (b == null) b = "";
return function() { this.textContent = b; };
}
d3_transitionPrototype.remove = function() {
var ns = this.namespace;
return this.each("end.transition", function() {
var p;
if (this[ns].count < 2 && (p = this.parentNode)) p.removeChild(this);
});
};
d3_transitionPrototype.ease = function(value) {
var id = this.id, ns = this.namespace;
if (arguments.length < 1) return this.node()[ns][id].ease;
if (typeof value !== "function") value = d3$ease.apply(d3, arguments);
return d3_selection_each(this, function(node) { node[ns][id].ease = value; });
};
d3_transitionPrototype.delay = function(value) {
var id = this.id, ns = this.namespace;
if (arguments.length < 1) return this.node()[ns][id].delay;
return d3_selection_each(this, typeof value === "function"
? function(node, i, j) { node[ns][id].delay = +value.call(node, node.__data__, i, j); }
: (value = +value, function(node) { node[ns][id].delay = value; }));
};
d3_transitionPrototype.duration = function(value) {
var id = this.id, ns = this.namespace;
if (arguments.length < 1) return this.node()[ns][id].duration;
return d3_selection_each(this, typeof value === "function"
? function(node, i, j) { node[ns][id].duration = Math.max(1, value.call(node, node.__data__, i, j)); }
: (value = Math.max(1, value), function(node) { node[ns][id].duration = value; }));
};
d3_transitionPrototype.each = function(type, listener) {
var id = this.id, ns = this.namespace;
if (arguments.length < 2) {
var inherit = d3_transitionInherit,
inheritId = d3_transitionInheritId;
try {
d3_transitionInheritId = id;
d3_selection_each(this, function(node, i, j) {
d3_transitionInherit = node[ns][id];
type.call(node, node.__data__, i, j);
});
} finally {
d3_transitionInherit = inherit;
d3_transitionInheritId = inheritId;
}
} else {
d3_selection_each(this, function(node) {
var transition = node[ns][id];
(transition.event || (transition.event = d3$dispatch("start", "end", "interrupt"))).on(type, listener);
});
}
return this;
};
d3_transitionPrototype.transition = function() {
var id0 = this.id,
id1 = ++d3_transitionId,
ns = this.namespace,
subgroups = [],
subgroup,
group,
node,
transition;
for (var j = 0, m = this.length; j < m; j++) {
subgroups.push(subgroup = []);
for (var group = this[j], i = 0, n = group.length; i < n; i++) {
if (node = group[i]) {
transition = node[ns][id0];
d3_transitionNode(node, i, ns, id1, {time: transition.time, ease: transition.ease, delay: transition.delay + transition.duration, duration: transition.duration});
}
subgroup.push(node);
}
}
return d3_transition(subgroups, ns, id1);
};
d3_transitionPrototype.tween = function(name, tween) {
var id = this.id, ns = this.namespace;
if (arguments.length < 2) return this.node()[ns][id].tween.get(name);
return d3_selection_each(this, tween == null
? function(node) { node[ns][id].tween.remove(name); }
: function(node) { node[ns][id].tween.set(name, tween); });
};
function d3_transition_tween(groups, name, value, tween) {
var id = groups.id, ns = groups.namespace;
return d3_selection_each(groups, typeof value === "function"
? function(node, i, j) { node[ns][id].tween.set(name, tween(value.call(node, node.__data__, i, j))); }
: (value = tween(value), function(node) { node[ns][id].tween.set(name, value); }));
}
function d3_transitionNamespace(name) {
return name == null ? "__transition__" : "__transition_" + name + "__";
}
function d3_transitionNode(node, i, ns, id, inherit) {
var lock = node[ns] || (node[ns] = {active: 0, count: 0}),
transition = lock[id];
if (!transition) {
var time = inherit.time;
transition = lock[id] = {
tween: new d3_Map,
time: time,
delay: inherit.delay,
duration: inherit.duration,
ease: inherit.ease,
index: i
};
inherit = null; // allow gc
++lock.count;
d3$timer(function(elapsed) {
var delay = transition.delay,
duration,
ease,
timer = d3_timer_active,
tweened = [];
timer.t = delay + time;
if (delay <= elapsed) return start(elapsed - delay);
timer.c = start;
function start(elapsed) {
if (lock.active > id) return stop();
var active = lock[lock.active];
if (active) {
--lock.count;
delete lock[lock.active];
active.event && active.event.interrupt.call(node, node.__data__, active.index);
}
lock.active = id;
transition.event && transition.event.start.call(node, node.__data__, i);
transition.tween.forEach(function(key, value) {
if (value = value.call(node, node.__data__, i)) {
tweened.push(value);
}
});
// Deferred capture to allow tweens to initialize ease & duration.
ease = transition.ease;
duration = transition.duration;
d3$timer(function() { // defer to end of current frame
timer.c = tick(elapsed || 1) ? d3_true : tick;
return 1;
}, 0, time);
}
function tick(elapsed) {
if (lock.active !== id) return 1;
var t = elapsed / duration,
e = ease(t),
n = tweened.length;
while (n > 0) {
tweened[--n].call(node, e);
}
if (t >= 1) {
transition.event && transition.event.end.call(node, node.__data__, i);
return stop();
}
}
function stop() {
if (--lock.count) delete lock[id];
else delete node[ns];
return 1;
}
}, 0, time);
}
}
export {
d3$transition,
d3_transitionNode,
d3_transitionNamespace,
d3_transition_tween,
d3_transition_text,
d3_transitionPrototype,
d3_transitionId,
d3_transitionInheritId,
d3_transitionInherit,
d3_transition
};