Merge remote-tracking branch 'origin/map' into 2.10.0

Conflicts:
	src/core/transition-attr.js
	src/core/transition-style.js
This commit is contained in:
Mike Bostock 2012-08-08 18:08:47 -07:00
Родитель 2d9fe177d0 48570c61ba
Коммит 15ba641fa3
17 изменённых файлов: 526 добавлений и 215 удалений

195
d3.v2.js поставляемый
Просмотреть файл

@ -373,7 +373,7 @@
return d == null; return d == null;
} }
function d3_collapse(s) { function d3_collapse(s) {
return s.replace(/^\s+|\s+$/g, "").replace(/\s+/g, " "); return s.trim().replace(/\s+/g, " ");
} }
d3.range = function(start, stop, step) { d3.range = function(start, stop, step) {
if (arguments.length < 3) { if (arguments.length < 3) {
@ -958,8 +958,8 @@
}; };
}; };
var d3_interpolate_number = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g; var d3_interpolate_number = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g;
function d3_interpolateByName(n) { function d3_interpolateByName(name) {
return n == "transform" ? d3.interpolateTransform : d3.interpolate; return name == "transform" ? d3.interpolateTransform : d3.interpolate;
} }
d3.interpolators = [ d3.interpolateObject, function(a, b) { d3.interpolators = [ d3.interpolateObject, function(a, b) {
return b instanceof Array && d3.interpolateArray(a, b); return b instanceof Array && d3.interpolateArray(a, b);
@ -1329,11 +1329,19 @@
}; };
} }
d3_selectionPrototype.attr = function(name, value) { d3_selectionPrototype.attr = function(name, value) {
name = d3.ns.qualify(name);
if (arguments.length < 2) { if (arguments.length < 2) {
var node = this.node(); if (typeof name === "string") {
return name.local ? node.getAttributeNS(name.space, name.local) : node.getAttribute(name); var node = this.node();
name = d3.ns.qualify(name);
return name.local ? node.getAttributeNS(name.space, name.local) : node.getAttribute(name);
}
for (value in name) this.each(d3_selection_attr(value, name[value]));
return this;
} }
return this.each(d3_selection_attr(name, value));
};
function d3_selection_attr(name, value) {
name = d3.ns.qualify(name);
function attrNull() { function attrNull() {
this.removeAttribute(name); this.removeAttribute(name);
} }
@ -1354,52 +1362,73 @@
var x = value.apply(this, arguments); var x = value.apply(this, arguments);
if (x == null) this.removeAttributeNS(name.space, name.local); else this.setAttributeNS(name.space, name.local, x); if (x == null) this.removeAttributeNS(name.space, name.local); else this.setAttributeNS(name.space, name.local, x);
} }
return this.each(value == null ? name.local ? attrNullNS : attrNull : typeof value === "function" ? name.local ? attrFunctionNS : attrFunction : name.local ? attrConstantNS : attrConstant); return value == null ? name.local ? attrNullNS : attrNull : typeof value === "function" ? name.local ? attrFunctionNS : attrFunction : name.local ? attrConstantNS : attrConstant;
}; }
d3_selectionPrototype.classed = function(name, value) { d3_selectionPrototype.classed = function(name, value) {
var names = d3_collapse(name).split(" "), n = names.length, i = -1;
if (arguments.length > 1) {
while (++i < n) d3_selection_classed.call(this, names[i], value);
return this;
} else {
while (++i < n) if (!d3_selection_classed.call(this, names[i])) return false;
return true;
}
};
function d3_selection_classed(name, value) {
var re = new RegExp("(^|\\s+)" + d3.requote(name) + "(\\s+|$)", "g");
if (arguments.length < 2) { if (arguments.length < 2) {
var node = this.node(); if (typeof name === "string") {
if (c = node.classList) return c.contains(name); var node = this.node(), n = (name = name.trim().split(/^|\s+/g)).length, i = -1;
var c = node.className; if (value = node.classList) {
re.lastIndex = 0; while (++i < n) if (!value.contains(name[i])) return false;
return re.test(c.baseVal != null ? c.baseVal : c); } else {
} value = node.className;
function classedAdd() { if (value.baseVal != null) value = value.baseVal;
if (c = this.classList) return c.add(name); while (++i < n) if (!d3_selection_classedRe(name[i]).test(value)) return false;
var c = this.className, cb = c.baseVal != null, cv = cb ? c.baseVal : c; }
re.lastIndex = 0; return true;
if (!re.test(cv)) {
cv = d3_collapse(cv + " " + name);
if (cb) c.baseVal = cv; else this.className = cv;
} }
for (value in name) this.each(d3_selection_classed(value, name[value]));
return this;
} }
function classedRemove() { return this.each(d3_selection_classed(name, value));
if (c = this.classList) return c.remove(name); };
var c = this.className, cb = c.baseVal != null, cv = cb ? c.baseVal : c; function d3_selection_classedRe(name) {
if (cv) { return new RegExp("(?:^|\\s+)" + d3.requote(name) + "(?:\\s+|$)", "g");
cv = d3_collapse(cv.replace(re, " ")); }
if (cb) c.baseVal = cv; else this.className = cv; function d3_selection_classed(name, value) {
} name = name.trim().split(/\s+/).map(d3_selection_classedName);
var n = name.length;
function classedConstant() {
var i = -1;
while (++i < n) name[i](this, value);
} }
function classedFunction() { function classedFunction() {
(value.apply(this, arguments) ? classedAdd : classedRemove).call(this); var i = -1, x = value.apply(this, arguments);
while (++i < n) name[i](this, x);
} }
return this.each(typeof value === "function" ? classedFunction : value ? classedAdd : classedRemove); return typeof value === "function" ? classedFunction : classedConstant;
}
function d3_selection_classedName(name) {
var re = d3_selection_classedRe(name);
return function(node, value) {
if (c = node.classList) return value ? c.add(name) : c.remove(name);
var c = node.className, cb = c.baseVal != null, cv = cb ? c.baseVal : c;
if (value) {
re.lastIndex = 0;
if (!re.test(cv)) {
cv = d3_collapse(cv + " " + name);
if (cb) c.baseVal = cv; else node.className = cv;
}
} else if (cv) {
cv = d3_collapse(cv.replace(re, " "));
if (cb) c.baseVal = cv; else node.className = cv;
}
};
} }
d3_selectionPrototype.style = function(name, value, priority) { d3_selectionPrototype.style = function(name, value, priority) {
if (arguments.length < 3) priority = ""; var n = arguments.length;
if (arguments.length < 2) return window.getComputedStyle(this.node(), null).getPropertyValue(name); if (n < 3) {
if (typeof name !== "string") {
if (n < 2) value = "";
for (priority in name) this.each(d3_selection_style(priority, name[priority], value));
return this;
}
if (n < 2) return window.getComputedStyle(this.node(), null).getPropertyValue(name);
priority = "";
}
return this.each(d3_selection_style(name, value, priority));
};
function d3_selection_style(name, value, priority) {
function styleNull() { function styleNull() {
this.style.removeProperty(name); this.style.removeProperty(name);
} }
@ -1410,10 +1439,17 @@
var x = value.apply(this, arguments); var x = value.apply(this, arguments);
if (x == null) this.style.removeProperty(name); else this.style.setProperty(name, x, priority); if (x == null) this.style.removeProperty(name); else this.style.setProperty(name, x, priority);
} }
return this.each(value == null ? styleNull : typeof value === "function" ? styleFunction : styleConstant); return value == null ? styleNull : typeof value === "function" ? styleFunction : styleConstant;
}; }
d3_selectionPrototype.property = function(name, value) { d3_selectionPrototype.property = function(name, value) {
if (arguments.length < 2) return this.node()[name]; if (arguments.length < 2) {
if (typeof name === "string") return this.node()[name];
for (value in name) this.each(d3_selection_property(value, name[value]));
return this;
}
return this.each(d3_selection_property(name, value));
};
function d3_selection_property(name, value) {
function propertyNull() { function propertyNull() {
delete this[name]; delete this[name];
} }
@ -1424,8 +1460,8 @@
var x = value.apply(this, arguments); var x = value.apply(this, arguments);
if (x == null) delete this[name]; else this[name] = x; if (x == null) delete this[name]; else this[name] = x;
} }
return this.each(value == null ? propertyNull : typeof value === "function" ? propertyFunction : propertyConstant); return value == null ? propertyNull : typeof value === "function" ? propertyFunction : propertyConstant;
}; }
d3_selectionPrototype.text = function(value) { d3_selectionPrototype.text = function(value) {
return arguments.length < 1 ? this.node().textContent : this.each(typeof value === "function" ? function() { return arguments.length < 1 ? this.node().textContent : this.each(typeof value === "function" ? function() {
var v = value.apply(this, arguments); var v = value.apply(this, arguments);
@ -1609,21 +1645,34 @@
}; };
} }
d3_selectionPrototype.on = function(type, listener, capture) { d3_selectionPrototype.on = function(type, listener, capture) {
if (arguments.length < 3) capture = false; var n = arguments.length;
if (n < 3) {
if (typeof type !== "string") {
if (n < 2) listener = false;
for (capture in type) this.each(d3_selection_on(capture, type[capture], listener));
return this;
}
if (n < 2) return (n = this.node()["__on" + type]) && n._;
capture = false;
}
return this.each(d3_selection_on(type, listener, capture));
};
function d3_selection_on(type, listener, capture) {
var name = "__on" + type, i = type.indexOf("."); var name = "__on" + type, i = type.indexOf(".");
if (i > 0) type = type.substring(0, i); if (i > 0) type = type.substring(0, i);
if (arguments.length < 2) return (i = this.node()[name]) && i._; function onRemove() {
return this.each(function() { var wrapper = this[name];
var node = this, args = arguments, o = node[name]; if (wrapper) {
if (o) { this.removeEventListener(type, wrapper, wrapper.$);
node.removeEventListener(type, o, o.$); delete this[name];
delete node[name];
} }
if (listener) { }
node.addEventListener(type, node[name] = l, l.$ = capture); function onAdd() {
l._ = listener; var node = this, args = arguments;
} onRemove.call(this);
function l(e) { this.addEventListener(type, this[name] = wrapper, wrapper.$ = capture);
wrapper._ = listener;
function wrapper(e) {
var o = d3.event; var o = d3.event;
d3.event = e; d3.event = e;
args[0] = node.__data__; args[0] = node.__data__;
@ -1633,8 +1682,9 @@
d3.event = o; d3.event = o;
} }
} }
}); }
}; return listener ? onAdd : onRemove;
}
d3_selectionPrototype.each = function(callback) { d3_selectionPrototype.each = function(callback) {
return d3_selection_each(this, function(node, i, j) { return d3_selection_each(this, function(node, i, j) {
callback.call(node, node.__data__, i, j); callback.call(node, node.__data__, i, j);
@ -1836,7 +1886,11 @@
return d3_transition(subgroups, this.id, this.time).ease(this.ease()); return d3_transition(subgroups, this.id, this.time).ease(this.ease());
}; };
d3_transitionPrototype.attr = function(name, value) { d3_transitionPrototype.attr = function(name, value) {
return this.attrTween(name, d3.tween(value, d3_interpolateByName(name))); if (arguments.length < 2) {
for (value in name) this.attrTween(value, d3_tweenByName(name[value], value));
return this;
}
return this.attrTween(name, d3_tweenByName(value, name));
}; };
d3_transitionPrototype.attrTween = function(nameNS, tween) { d3_transitionPrototype.attrTween = function(nameNS, tween) {
var name = d3.ns.qualify(nameNS); var name = d3.ns.qualify(nameNS);
@ -1855,8 +1909,16 @@
return this.tween("attr." + nameNS, name.local ? attrTweenNS : attrTween); return this.tween("attr." + nameNS, name.local ? attrTweenNS : attrTween);
}; };
d3_transitionPrototype.style = function(name, value, priority) { d3_transitionPrototype.style = function(name, value, priority) {
if (arguments.length < 3) priority = ""; var n = arguments.length;
return this.styleTween(name, d3.tween(value, d3_interpolateByName(name)), priority); if (n < 3) {
if (typeof name !== "string") {
if (n < 2) value = "";
for (priority in name) this.styleTween(priority, d3_tweenByName(name[priority], priority), value);
return this;
}
priority = "";
}
return this.styleTween(name, d3_tweenByName(value, name), priority);
}; };
d3_transitionPrototype.styleTween = function(name, tween, priority) { d3_transitionPrototype.styleTween = function(name, tween, priority) {
if (arguments.length < 3) priority = ""; if (arguments.length < 3) priority = "";
@ -1924,6 +1986,9 @@
function d3_tweenNull(d, i, a) { function d3_tweenNull(d, i, a) {
return a != "" && d3_tweenRemove; return a != "" && d3_tweenRemove;
} }
function d3_tweenByName(b, name) {
return d3.tween(b, d3_interpolateByName(name));
}
var d3_timer_queue = null, d3_timer_interval, d3_timer_timeout; var d3_timer_queue = null, d3_timer_interval, d3_timer_timeout;
d3.timer = function(callback, delay, then) { d3.timer = function(callback, delay, then) {
var found = false, t0, t1 = d3_timer_queue; var found = false, t0, t1 = d3_timer_queue;

8
d3.v2.min.js поставляемый

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@ -1,3 +1,3 @@
function d3_collapse(s) { function d3_collapse(s) {
return s.replace(/^\s+|\s+$/g, "").replace(/\s+/g, " "); return s.trim().replace(/\s+/g, " ");
} }

Просмотреть файл

@ -217,8 +217,8 @@ d3.interpolateObject = function(a, b) {
var d3_interpolate_number = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g; var d3_interpolate_number = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g;
function d3_interpolateByName(n) { function d3_interpolateByName(name) {
return n == "transform" return name == "transform"
? d3.interpolateTransform ? d3.interpolateTransform
: d3.interpolate; : d3.interpolate;
} }

Просмотреть файл

@ -1,44 +1,59 @@
d3_selectionPrototype.attr = function(name, value) { d3_selectionPrototype.attr = function(name, value) {
name = d3.ns.qualify(name);
// If no value is specified, return the first value.
if (arguments.length < 2) { if (arguments.length < 2) {
var node = this.node();
return name.local // For attr(string), return the attribute value for the first node.
? node.getAttributeNS(name.space, name.local) if (typeof name === "string") {
: node.getAttribute(name); var node = this.node();
name = d3.ns.qualify(name);
return name.local
? node.getAttributeNS(name.space, name.local)
: node.getAttribute(name);
}
// For attr(object), 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.
for (value in name) this.each(d3_selection_attr(value, name[value]));
return this;
} }
return this.each(d3_selection_attr(name, value));
};
function d3_selection_attr(name, value) {
name = d3.ns.qualify(name);
// For attr(string, null), remove the attribute with the specified name.
function attrNull() { function attrNull() {
this.removeAttribute(name); this.removeAttribute(name);
} }
function attrNullNS() { function attrNullNS() {
this.removeAttributeNS(name.space, name.local); this.removeAttributeNS(name.space, name.local);
} }
// For attr(string, string), set the attribute with the specified name.
function attrConstant() { function attrConstant() {
this.setAttribute(name, value); this.setAttribute(name, value);
} }
function attrConstantNS() { function attrConstantNS() {
this.setAttributeNS(name.space, name.local, value); this.setAttributeNS(name.space, name.local, value);
} }
// For attr(string, function), evaluate the function for each element, and set
// or remove the attribute as appropriate.
function attrFunction() { function attrFunction() {
var x = value.apply(this, arguments); var x = value.apply(this, arguments);
if (x == null) this.removeAttribute(name); if (x == null) this.removeAttribute(name);
else this.setAttribute(name, x); else this.setAttribute(name, x);
} }
function attrFunctionNS() { function attrFunctionNS() {
var x = value.apply(this, arguments); var x = value.apply(this, arguments);
if (x == null) this.removeAttributeNS(name.space, name.local); if (x == null) this.removeAttributeNS(name.space, name.local);
else this.setAttributeNS(name.space, name.local, x); else this.setAttributeNS(name.space, name.local, x);
} }
return this.each(value == null return value == null
? (name.local ? attrNullNS : attrNull) : (typeof value === "function" ? (name.local ? attrNullNS : attrNull) : (typeof value === "function"
? (name.local ? attrFunctionNS : attrFunction) ? (name.local ? attrFunctionNS : attrFunction)
: (name.local ? attrConstantNS : attrConstant))); : (name.local ? attrConstantNS : attrConstant));
}; }

Просмотреть файл

@ -1,61 +1,77 @@
d3_selectionPrototype.classed = function(name, value) { d3_selectionPrototype.classed = function(name, value) {
var names = d3_collapse(name).split(" "), if (arguments.length < 2) {
n = names.length,
i = -1; // For classed(string), return true only if the first node has the specified
if (arguments.length > 1) { // class or classes. Note that even if the browser supports DOMTokenList, it
while (++i < n) d3_selection_classed.call(this, names[i], value); // probably doesn't support it on SVG elements (which can be animated).
if (typeof name === "string") {
var node = this.node(),
n = (name = name.trim().split(/^|\s+/g)).length,
i = -1;
if (value = node.classList) {
while (++i < n) if (!value.contains(name[i])) return false;
} else {
value = node.className;
if (value.baseVal != null) value = value.baseVal;
while (++i < n) if (!d3_selection_classedRe(name[i]).test(value)) return false;
}
return true;
}
// For classed(object), the object specifies the names of classes to add or
// remove. The values may be functions that are evaluated for each element.
for (value in name) this.each(d3_selection_classed(value, name[value]));
return this; return this;
} else {
while (++i < n) if (!d3_selection_classed.call(this, names[i])) return false;
return true;
} }
// Otherwise, both a name and a value are specified, and are handled as below.
return this.each(d3_selection_classed(name, value));
}; };
function d3_selection_classedRe(name) {
return new RegExp("(?:^|\\s+)" + d3.requote(name) + "(?:\\s+|$)", "g");
}
// Multiple class names are allowed (e.g., "foo bar").
function d3_selection_classed(name, value) { function d3_selection_classed(name, value) {
var re = new RegExp("(^|\\s+)" + d3.requote(name) + "(\\s+|$)", "g"); name = name.trim().split(/\s+/).map(d3_selection_classedName);
var n = name.length;
// If no value is specified, return the first value. function classedConstant() {
if (arguments.length < 2) { var i = -1;
var node = this.node(); while (++i < n) name[i](this, value);
if (c = node.classList) return c.contains(name);
var c = node.className;
re.lastIndex = 0;
return re.test(c.baseVal != null ? c.baseVal : c);
} }
function classedAdd() { // When the value is a function, the function is still evaluated only once per
if (c = this.classList) return c.add(name); // element even if there are multiple class names.
var c = this.className, function classedFunction() {
cb = c.baseVal != null, var i = -1, x = value.apply(this, arguments);
cv = cb ? c.baseVal : c; while (++i < n) name[i](this, x);
re.lastIndex = 0;
if (!re.test(cv)) {
cv = d3_collapse(cv + " " + name);
if (cb) c.baseVal = cv;
else this.className = cv;
}
} }
function classedRemove() { return typeof value === "function"
if (c = this.classList) return c.remove(name); ? classedFunction
var c = this.className, : classedConstant;
}
function d3_selection_classedName(name) {
var re = d3_selection_classedRe(name);
return function(node, value) {
if (c = node.classList) return value ? c.add(name) : c.remove(name);
var c = node.className,
cb = c.baseVal != null, cb = c.baseVal != null,
cv = cb ? c.baseVal : c; cv = cb ? c.baseVal : c;
if (cv) { if (value) {
re.lastIndex = 0;
if (!re.test(cv)) {
cv = d3_collapse(cv + " " + name);
if (cb) c.baseVal = cv;
else node.className = cv;
}
} else if (cv) {
cv = d3_collapse(cv.replace(re, " ")); cv = d3_collapse(cv.replace(re, " "));
if (cb) c.baseVal = cv; if (cb) c.baseVal = cv;
else this.className = cv; else node.className = cv;
} }
} };
function classedFunction() {
(value.apply(this, arguments)
? classedAdd
: classedRemove).call(this);
}
return this.each(typeof value === "function"
? classedFunction : value
? classedAdd
: classedRemove);
} }

Просмотреть файл

@ -1,35 +1,48 @@
// type can be namespaced, e.g., "click.foo"
// listener can be null for removal
d3_selectionPrototype.on = function(type, listener, capture) { d3_selectionPrototype.on = function(type, listener, capture) {
if (arguments.length < 3) capture = false; var n = arguments.length;
if (n < 3) {
// parse the type specifier // For on(object) or on(object, boolean), the object specifies the event
// types and listeners to add or remove. The optional boolean specifies
// whether the listener captures events.
if (typeof type !== "string") {
if (n < 2) listener = false;
for (capture in type) this.each(d3_selection_on(capture, type[capture], listener));
return this;
}
// For on(string), return the listener for the first node.
if (n < 2) return (n = this.node()["__on" + type]) && n._;
// For on(string, function), use the default capture.
capture = false;
}
// Otherwise, a type, listener and capture are specified, and handled as below.
return this.each(d3_selection_on(type, listener, capture));
};
function d3_selection_on(type, listener, capture) {
var name = "__on" + type, i = type.indexOf("."); var name = "__on" + type, i = type.indexOf(".");
if (i > 0) type = type.substring(0, i); if (i > 0) type = type.substring(0, i);
// if called with only one argument, return the current listener function onRemove() {
if (arguments.length < 2) return (i = this.node()[name]) && i._; var wrapper = this[name];
if (wrapper) {
this.removeEventListener(type, wrapper, wrapper.$);
delete this[name];
}
}
// remove the old event listener, and add the new event listener function onAdd() {
return this.each(function() {
var node = this, var node = this,
args = arguments, args = arguments;
o = node[name];
// remove the old listener, if any (using the previously-set capture) onRemove.call(this);
if (o) { this.addEventListener(type, this[name] = wrapper, wrapper.$ = capture);
node.removeEventListener(type, o, o.$); wrapper._ = listener;
delete node[name];
}
// add the new listener, if any (remembering the capture flag) function wrapper(e) {
if (listener) {
node.addEventListener(type, node[name] = l, l.$ = capture);
l._ = listener; // stash the unwrapped listener for get
}
// wrapped event listener that propagates data changes
function l(e) {
var o = d3.event; // Events can be reentrant (e.g., focus). var o = d3.event; // Events can be reentrant (e.g., focus).
d3.event = e; d3.event = e;
args[0] = node.__data__; args[0] = node.__data__;
@ -39,5 +52,7 @@ d3_selectionPrototype.on = function(type, listener, capture) {
d3.event = o; d3.event = o;
} }
} }
}); }
};
return listener ? onAdd : onRemove;
}

Просмотреть файл

@ -1,23 +1,41 @@
d3_selectionPrototype.property = function(name, value) { d3_selectionPrototype.property = function(name, value) {
if (arguments.length < 2) {
// If no value is specified, return the first value. // For property(string), return the property value for the first node.
if (arguments.length < 2) return this.node()[name]; if (typeof name === "string") return this.node()[name];
// For property(object), the object specifies the names and values of the
// properties to set or remove. The values may be functions that are
// evaluated for each element.
for (value in name) this.each(d3_selection_property(value, name[value]));
return this;
}
// Otherwise, both a name and a value are specified, and are handled as below.
return this.each(d3_selection_property(name, value));
};
function d3_selection_property(name, value) {
// For property(name, null), remove the property with the specified name.
function propertyNull() { function propertyNull() {
delete this[name]; delete this[name];
} }
// For property(name, string), set the property with the specified name.
function propertyConstant() { function propertyConstant() {
this[name] = value; this[name] = value;
} }
// For property(name, function), evaluate the function for each element, and
// set or remove the property as appropriate.
function propertyFunction() { function propertyFunction() {
var x = value.apply(this, arguments); var x = value.apply(this, arguments);
if (x == null) delete this[name]; if (x == null) delete this[name];
else this[name] = x; else this[name] = x;
} }
return this.each(value == null return value == null
? propertyNull : (typeof value === "function" ? propertyNull : (typeof value === "function"
? propertyFunction : propertyConstant)); ? propertyFunction : propertyConstant);
}; }

Просмотреть файл

@ -1,26 +1,55 @@
d3_selectionPrototype.style = function(name, value, priority) { d3_selectionPrototype.style = function(name, value, priority) {
if (arguments.length < 3) priority = ""; var n = arguments.length;
if (n < 3) {
// If no value is specified, return the first value. // For style(object) or style(object, string), the object specifies the
if (arguments.length < 2) return window // names and values of the attributes to set or remove. The values may be
.getComputedStyle(this.node(), null) // functions that are evaluated for each element. The optional string
.getPropertyValue(name); // specifies the priority.
if (typeof name !== "string") {
if (n < 2) value = "";
for (priority in name) this.each(d3_selection_style(priority, name[priority], value));
return this;
}
// For style(string), return the computed style value for the first node.
if (n < 2) return window
.getComputedStyle(this.node(), null)
.getPropertyValue(name);
// For style(string, string) or style(string, function), use the default
// priority. The priority is ignored for style(string, null).
priority = "";
}
// Otherwise, a name, value and priority are specified, and handled as below.
return this.each(d3_selection_style(name, value, priority));
};
function d3_selection_style(name, value, priority) {
// For style(name, null) or style(name, null, priority), remove the style
// property with the specified name. The priority is ignored.
function styleNull() { function styleNull() {
this.style.removeProperty(name); 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.
function styleConstant() { function styleConstant() {
this.style.setProperty(name, value, priority); this.style.setProperty(name, value, priority);
} }
// For style(name, function) or style(name, function, priority), evaluate the
// function for each element, and set or remove the style property as
// appropriate. When setting, use the specified priority.
function styleFunction() { function styleFunction() {
var x = value.apply(this, arguments); var x = value.apply(this, arguments);
if (x == null) this.style.removeProperty(name); if (x == null) this.style.removeProperty(name);
else this.style.setProperty(name, x, priority); else this.style.setProperty(name, x, priority);
} }
return this.each(value == null return value == null
? styleNull : (typeof value === "function" ? styleNull : (typeof value === "function"
? styleFunction : styleConstant)); ? styleFunction : styleConstant);
}; }

Просмотреть файл

@ -1,5 +1,14 @@
d3_transitionPrototype.attr = function(name, value) { d3_transitionPrototype.attr = function(name, value) {
return this.attrTween(name, d3.tween(value, d3_interpolateByName(name))); 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 name) this.attrTween(value, d3_tweenByName(name[value], value));
return this;
}
return this.attrTween(name, d3_tweenByName(value, name));
}; };
d3_transitionPrototype.attrTween = function(nameNS, tween) { d3_transitionPrototype.attrTween = function(nameNS, tween) {

Просмотреть файл

@ -1,6 +1,24 @@
d3_transitionPrototype.style = function(name, value, priority) { d3_transitionPrototype.style = function(name, value, priority) {
if (arguments.length < 3) priority = ""; var n = arguments.length;
return this.styleTween(name, d3.tween(value, d3_interpolateByName(name)), priority); 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.styleTween(priority, d3_tweenByName(name[priority], 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 = "";
}
// Otherwise, a name, value and priority are specified, and handled as below.
return this.styleTween(name, d3_tweenByName(value, name), priority);
}; };
d3_transitionPrototype.styleTween = function(name, tween, priority) { d3_transitionPrototype.styleTween = function(name, tween, priority) {

Просмотреть файл

@ -21,3 +21,7 @@ var d3_tweenRemove = {};
function d3_tweenNull(d, i, a) { function d3_tweenNull(d, i, a) {
return a != "" && d3_tweenRemove; return a != "" && d3_tweenRemove;
} }
function d3_tweenByName(b, name) {
return d3.tween(b, d3_interpolateByName(name));
}

Просмотреть файл

@ -38,6 +38,15 @@ suite.addBatch({
body.data(["orange"]).attr("xlink:href", function(d, i) { return d + "-" + i; }); body.data(["orange"]).attr("xlink:href", function(d, i) { return d + "-" + i; });
assert.equal(document.body.getAttributeNS("http://www.w3.org/1999/xlink", "href"), "orange-0"); assert.equal(document.body.getAttributeNS("http://www.w3.org/1999/xlink", "href"), "orange-0");
}, },
"sets attributes as a map of constants": function(body) {
body.attr({bgcolor: "white", "xlink:href": "url.png"});
assert.equal(document.body.getAttribute("bgcolor"), "white");
assert.equal(document.body.getAttributeNS("http://www.w3.org/1999/xlink", "href"), "url.png");
},
"sets attributes as a map of functions": function(body) {
body.data(["orange"]).attr({"xlink:href": function(d, i) { return d + "-" + i + ".png"; }});
assert.equal(document.body.getAttributeNS("http://www.w3.org/1999/xlink", "href"), "orange-0.png");
},
"gets an attribute value": function(body) { "gets an attribute value": function(body) {
document.body.setAttribute("bgcolor", "yellow"); document.body.setAttribute("bgcolor", "yellow");
assert.equal(body.attr("bgcolor"), "yellow"); assert.equal(body.attr("bgcolor"), "yellow");
@ -62,6 +71,20 @@ suite.addBatch({
body.attr("xlink:href", "url").attr("xlink:href", function() { return null; }); body.attr("xlink:href", "url").attr("xlink:href", function() { return null; });
assert.equal(body.attr("xlink:href"), ""); assert.equal(body.attr("xlink:href"), "");
}, },
"removes attributes as a map of null": function(body) {
document.body.setAttribute("bgcolor", "white");
document.body.setAttributeNS("http://www.w3.org/1999/xlink", "href", "foo.png");
body.attr({bgcolor: null, "xlink:href": null});
assert.equal(document.body.getAttribute("bgcolor"), "");
assert.equal(document.body.getAttributeNS("http://www.w3.org/1999/xlink", "href"), "");
},
"removes attribtues as a map of functions that return null": function(body) {
document.body.setAttribute("bgcolor", "white");
document.body.setAttributeNS("http://www.w3.org/1999/xlink", "href", "foo.png");
body.attr({bgcolor: function() {}, "xlink:href": function() {}});
assert.equal(document.body.getAttribute("bgcolor"), "");
assert.equal(document.body.getAttributeNS("http://www.w3.org/1999/xlink", "href"), "");
},
"returns the current selection": function(body) { "returns the current selection": function(body) {
assert.isTrue(body.attr("foo", "bar") === body); assert.isTrue(body.attr("foo", "bar") === body);
} }

Просмотреть файл

@ -17,13 +17,6 @@ suite.addBatch({
body.classed("bar", true); body.classed("bar", true);
assert.equal(document.body.className, "foo bar"); assert.equal(document.body.className, "foo bar");
}, },
"adds a missing class as a function": function(body) {
body.attr("class", null);
body.classed("foo", function() { return true; });
assert.equal(document.body.className, "foo");
body.classed("bar", function() { return true; });
assert.equal(document.body.className, "foo bar");
},
"removes an existing class as false": function(body) { "removes an existing class as false": function(body) {
body.attr("class", "bar foo"); body.attr("class", "bar foo");
body.classed("foo", false); body.classed("foo", false);
@ -31,13 +24,6 @@ suite.addBatch({
body.classed("bar", false); body.classed("bar", false);
assert.equal(document.body.className, ""); assert.equal(document.body.className, "");
}, },
"removes an existing class as a function": function(body) {
body.attr("class", "bar foo");
body.classed("foo", function() { return false; });
assert.equal(document.body.className, "bar");
body.classed("bar", function() { return false; });
assert.equal(document.body.className, "");
},
"preserves an existing class as true": function(body) { "preserves an existing class as true": function(body) {
body.attr("class", "bar foo"); body.attr("class", "bar foo");
body.classed("foo", true); body.classed("foo", true);
@ -45,13 +31,6 @@ suite.addBatch({
body.classed("bar", true); body.classed("bar", true);
assert.equal(document.body.className, "bar foo"); assert.equal(document.body.className, "bar foo");
}, },
"preserves an existing class as a function": function(body) {
body.attr("class", "bar foo");
body.classed("foo", function() { return true; });
assert.equal(document.body.className, "bar foo");
body.classed("bar", function() { return true; });
assert.equal(document.body.className, "bar foo");
},
"preserves a missing class as false": function(body) { "preserves a missing class as false": function(body) {
body.attr("class", "baz"); body.attr("class", "baz");
body.classed("foo", false); body.classed("foo", false);
@ -60,14 +39,6 @@ suite.addBatch({
body.classed("bar", false); body.classed("bar", false);
assert.equal(document.body.className, ""); assert.equal(document.body.className, "");
}, },
"preserves a missing class as a function": function(body) {
body.attr("class", "baz");
body.classed("foo", function() { return false; });
assert.equal(document.body.className, "baz");
body.attr("class", null);
body.classed("bar", function() { return false; });
assert.equal(document.body.className, "");
},
"gets an existing class": function(body) { "gets an existing class": function(body) {
body.attr("class", " foo\tbar baz"); body.attr("class", " foo\tbar baz");
assert.isTrue(body.classed("foo")); assert.isTrue(body.classed("foo"));
@ -80,27 +51,101 @@ suite.addBatch({
assert.isFalse(body.classed("bare")); assert.isFalse(body.classed("bare"));
assert.isFalse(body.classed("rbaz")); assert.isFalse(body.classed("rbaz"));
}, },
"returns the current selection": function(body) { "accepts a name with whitespace, collapsing it": function(body) {
assert.isTrue(body.classed("foo", true) === body); body.attr("class", null);
body.classed(" foo\t", true);
assert.equal(document.body.className, "foo");
body.classed("\tfoo ", false);
assert.equal(document.body.className, "");
}, },
"adds missing classes as true": function(body) { "accepts a name with multiple classes separated by whitespace": function(body) {
body.attr("class", null); body.attr("class", null);
body.classed("foo bar", true); body.classed("foo bar", true);
assert.equal(document.body.className, "foo bar"); assert.equal(document.body.className, "foo bar");
},
"gets existing classes": function(body) {
body.attr("class", " foo\tbar baz");
assert.isTrue(body.classed("foo"));
assert.isTrue(body.classed("foo bar")); assert.isTrue(body.classed("foo bar"));
assert.isTrue(body.classed("bar baz")); assert.isTrue(body.classed("bar foo"));
assert.isTrue(body.classed("foo bar baz")); assert.isFalse(body.classed("foo bar baz"));
},
"does not get missing classes": function(body) {
body.attr("class", " foo\tbar baz");
assert.isFalse(body.classed("foob"));
assert.isFalse(body.classed("foob bar")); assert.isFalse(body.classed("foob bar"));
assert.isFalse(body.classed("bar baz blah")); body.classed("bar foo", false);
assert.isFalse(body.classed("foo bar baz moo")); assert.equal(document.body.className, "");
},
"accepts a silly class name with unsafe characters": function(body) {
body.attr("class", null);
body.classed("foo.bar", true);
assert.equal(document.body.className, "foo.bar");
assert.isTrue(body.classed("foo.bar"));
assert.isFalse(body.classed("foo"));
assert.isFalse(body.classed("bar"));
body.classed("bar.foo", false);
assert.equal(document.body.className, "foo.bar");
body.classed("foo.bar", false);
assert.equal(document.body.className, "");
},
"accepts a name with duplicate classes, ignoring them": function(body) {
body.attr("class", null);
body.classed(" foo\tfoo ", true);
assert.equal(document.body.className, "foo");
body.classed("\tfoo foo ", false);
assert.equal(document.body.className, "");
},
"accepts a value function returning true or false": function(body) {
body.attr("class", null);
body.classed("foo", function() { return true; });
assert.equal(document.body.className, "foo");
body.classed("foo bar", function() { return true; });
assert.equal(document.body.className, "foo bar");
body.classed("foo", function() { return false; });
assert.equal(document.body.className, "bar");
},
"accepts a name object containing true or false": function(body) {
body.attr("class", null);
body.classed({foo: true});
assert.equal(document.body.className, "foo");
body.classed({bar: true, foo: false});
assert.equal(document.body.className, "bar");
},
"accepts a name object containing a function returning true or false": function(body) {
body.attr("class", null);
body.classed({foo: function() { return true; }});
assert.equal(document.body.className, "foo");
},
"accepts a name object containing a mix of functions and non-functions": function(body) {
body.attr("class", "foo");
body.classed({foo: false, bar: function() { return true; }});
assert.equal(document.body.className, "bar");
},
"the value may be truthy or falsey": function(body) {
body.attr("class", "foo");
body.classed({foo: null, bar: function() { return 1; }});
assert.equal(document.body.className, "bar");
},
"keys in the name object may contain whitespace": function(body) {
body.attr("class", null);
body.classed({" foo\t": function() { return true; }});
assert.equal(document.body.className, "foo");
body.attr("class", null);
},
"keys in the name object may reference multiple classes": function(body) {
body.attr("class", null);
body.classed({"foo bar": function() { return true; }});
assert.equal(document.body.className, "foo bar");
body.attr("class", null);
},
"keys in the name object may contain duplicates": function(body) {
body.attr("class", null);
body.classed({"foo foo": function() { return true; }});
assert.equal(document.body.className, "foo");
body.attr("class", null);
},
"value functions are only evaluated once when used for multiple classes": function(body) {
var count = 0;
body.attr("class", null);
body.classed({"foo bar": function() { return ++count; }});
assert.equal(document.body.className, "foo bar");
assert.equal(count, 1);
},
"returns the current selection": function(body) {
assert.isTrue(body.classed("foo", true) === body);
} }
} }
}); });

Просмотреть файл

@ -48,11 +48,21 @@ suite.addBatch({
"observes the specified namespace": function(body) { "observes the specified namespace": function(body) {
var form = body.append("form"), foo = 0, bar = 0; var form = body.append("form"), foo = 0, bar = 0;
form.on("submit.foo", function() { ++foo; }); form.on("submit.foo", function() { ++foo; });
form.on("submit.bar", function() { ++bar; }); form.on({"submit.bar": function() { ++bar; }});
form.append("input").attr("type", "submit").node().click(); form.append("input").attr("type", "submit").node().click();
assert.equal(foo, 1); assert.equal(foo, 1);
assert.equal(bar, 1); assert.equal(bar, 1);
}, },
"can register listeners as a map": function(body) {
var form = body.append("form"), count = 0, fail = 0;
form.on({submit: function() { ++fail; }});
form.on({submit: function() { ++count; }});
form.append("input").attr("type", "submit").node().click();
assert.equal(count, 1);
assert.equal(fail, 0);
form.on({submit: null});
assert.isUndefined(form.on("submit"));
},
/* Not really sure how to test this one /* Not really sure how to test this one
"observes the specified capture flag": function(body) { "observes the specified capture flag": function(body) {
}, },

Просмотреть файл

@ -22,6 +22,16 @@ suite.addBatch({
body.property("bgcolor", function() { return "orange"; }); body.property("bgcolor", function() { return "orange"; });
assert.equal(document.body.bgcolor, "orange"); assert.equal(document.body.bgcolor, "orange");
}, },
"sets properties as a map of constants": function(body) {
body.property({bgcolor: "purple", opacity: .41});
assert.equal(document.body.bgcolor, "purple");
assert.equal(document.body.opacity, .41);
},
"sets properties as a map of functions": function(body) {
body.data(["cyan"]).property({bgcolor: String, opacity: function(d, i) { return i; }});
assert.equal(document.body.bgcolor, "cyan");
assert.equal(document.body.opacity, 0);
},
"gets a property value": function(body) { "gets a property value": function(body) {
document.body.bgcolor = "yellow"; document.body.bgcolor = "yellow";
assert.equal(body.property("bgcolor"), "yellow"); assert.equal(body.property("bgcolor"), "yellow");
@ -34,6 +44,16 @@ suite.addBatch({
body.property("bgcolor", "yellow").property("bgcolor", function() { return null }); body.property("bgcolor", "yellow").property("bgcolor", function() { return null });
assert.isFalse("bgcolor" in document.body); assert.isFalse("bgcolor" in document.body);
}, },
"removes properties as a map of nulls": function(body) {
document.body.bgcolor = "red";
body.property({bgcolor: null});
assert.isFalse("bgcolor" in document.body);
},
"removes properties as a map of functions that return null": function(body) {
document.body.bgcolor = "red";
body.property({bgcolor: function() {}});
assert.isFalse("bgcolor" in document.body);
},
"returns the current selection": function(body) { "returns the current selection": function(body) {
assert.isTrue(body.property("bgcolor", "yellow") === body); assert.isTrue(body.property("bgcolor", "yellow") === body);
} }

Просмотреть файл

@ -22,6 +22,16 @@ suite.addBatch({
body.style("background-color", function() { return "orange"; }); body.style("background-color", function() { return "orange"; });
assert.equal(document.body.style["background-color"], "orange"); assert.equal(document.body.style["background-color"], "orange");
}, },
"sets properties as a map of constants": function(body) {
body.style({"background-color": "white", opacity: .42});
assert.equal(document.body.style["background-color"], "white");
assert.equal(document.body.style["opacity"], "0.42");
},
"sets properties as a map of functions": function(body) {
body.data(["orange"]).style({"background-color": String, opacity: function(d, i) { return i; }});
assert.equal(document.body.style["background-color"], "orange");
assert.equal(document.body.style["opacity"], "0");
},
"gets a property value": function(body) { "gets a property value": function(body) {
document.body.style.setProperty("background-color", "yellow", ""); document.body.style.setProperty("background-color", "yellow", "");
assert.equal(body.style("background-color"), "yellow"); assert.equal(body.style("background-color"), "yellow");
@ -29,6 +39,10 @@ suite.addBatch({
"observes the specified priority": function(body) { "observes the specified priority": function(body) {
body.style("background-color", "green", "important"); body.style("background-color", "green", "important");
assert.equal(document.body.style.getPropertyPriority("background-color"), "important"); assert.equal(document.body.style.getPropertyPriority("background-color"), "important");
body.style({opacity: .52}, "important");
assert.equal(document.body.style.getPropertyPriority("opacity"), "important");
body.style({visibility: function() { return "visible"; }}, "important");
assert.equal(document.body.style.getPropertyPriority("visibility"), "important");
}, },
"removes a property as null": function(body) { "removes a property as null": function(body) {
body.style("background-color", "green").style("background-color", null); body.style("background-color", "green").style("background-color", null);
@ -38,6 +52,16 @@ suite.addBatch({
body.style("background-color", "green").style("background-color", function() { return null; }); body.style("background-color", "green").style("background-color", function() { return null; });
assert.equal(body.style("background-color"), ""); assert.equal(body.style("background-color"), "");
}, },
"removes properties as a map of nulls": function(body) {
document.body.style.setProperty("background-color", "purple");
body.style({"background-color": null});
assert.equal(body.style("background-color"), "");
},
"removes properties as a map of functions that return null": function(body) {
document.body.style.setProperty("background-color", "purple");
body.style({"background-color": function() {}});
assert.equal(body.style("background-color"), "");
},
"returns the current selection": function(body) { "returns the current selection": function(body) {
assert.isTrue(body.style("background-color", "green") === body); assert.isTrue(body.style("background-color", "green") === body);
} }