Commit 108d65da authored by Mike Bostock's avatar Mike Bostock

Merge branch '2.9.7'

parents fb86373a 540d3ace
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
NODE_PATH ?= ./node_modules NODE_PATH ?= ./node_modules
JS_COMPILER = $(NODE_PATH)/uglify-js/bin/uglifyjs JS_COMPILER = $(NODE_PATH)/uglify-js/bin/uglifyjs
JS_BEAUTIFIER = $(NODE_PATH)/uglify-js/bin/uglifyjs -b -i 2 -nm -ns
JS_TESTER = $(NODE_PATH)/vows/bin/vows JS_TESTER = $(NODE_PATH)/vows/bin/vows
all: \ all: \
...@@ -74,6 +75,7 @@ d3.core.js: \ ...@@ -74,6 +75,7 @@ d3.core.js: \
src/core/formatPrefix.js \ src/core/formatPrefix.js \
src/core/ease.js \ src/core/ease.js \
src/core/event.js \ src/core/event.js \
src/core/transform.js \
src/core/interpolate.js \ src/core/interpolate.js \
src/core/uninterpolate.js \ src/core/uninterpolate.js \
src/core/rgb.js \ src/core/rgb.js \
...@@ -107,6 +109,7 @@ d3.core.js: \ ...@@ -107,6 +109,7 @@ d3.core.js: \
src/core/transition.js \ src/core/transition.js \
src/core/transition-select.js \ src/core/transition-select.js \
src/core/transition-selectAll.js \ src/core/transition-selectAll.js \
src/core/transition-filter.js \
src/core/transition-attr.js \ src/core/transition-attr.js \
src/core/transition-style.js \ src/core/transition-style.js \
src/core/transition-text.js \ src/core/transition-text.js \
...@@ -116,7 +119,6 @@ d3.core.js: \ ...@@ -116,7 +119,6 @@ d3.core.js: \
src/core/transition-each.js \ src/core/transition-each.js \
src/core/transition-transition.js \ src/core/transition-transition.js \
src/core/timer.js \ src/core/timer.js \
src/core/transform.js \
src/core/mouse.js \ src/core/mouse.js \
src/core/touches.js \ src/core/touches.js \
src/core/noop.js src/core/noop.js
...@@ -225,7 +227,7 @@ test: all ...@@ -225,7 +227,7 @@ test: all
d3%.js: Makefile d3%.js: Makefile
@rm -f $@ @rm -f $@
cat $(filter %.js,$^) > $@ cat $(filter %.js,$^) | $(JS_BEAUTIFIER) > $@
@chmod a-w $@ @chmod a-w $@
package.json: src/package.js package.json: src/package.js
......
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -33,7 +33,7 @@ var angle = d3.scale.linear() ...@@ -33,7 +33,7 @@ var angle = d3.scale.linear()
.range([0, 2 * Math.PI]); .range([0, 2 * Math.PI]);
var line = d3.svg.line.radial() var line = d3.svg.line.radial()
.interpolate("basis-closed") .interpolate("linear-closed")
.radius(radius) .radius(radius)
.angle(function(d, i) { return angle(i); }); .angle(function(d, i) { return angle(i); });
......
...@@ -14,7 +14,7 @@ var width = 960, ...@@ -14,7 +14,7 @@ var width = 960,
var fill = d3.scale.linear() var fill = d3.scale.linear()
.range(["hsl(-180, 50%, 50%)", "hsl(180, 50%, 50%)"]) .range(["hsl(-180, 50%, 50%)", "hsl(180, 50%, 50%)"])
.interpolate(d3.interpolateHsl); .interpolate(d3.interpolateString);
var arc = d3.svg.arc() var arc = d3.svg.arc()
.startAngle(0) .startAngle(0)
......
This diff is collapsed.
<!DOCTYPE html>
<body>
<script src="../../d3.v2.js"></script>
<script>
var svg = d3.select("body").append("svg")
.attr("width", 960)
.attr("height", 500);
var g = svg.append("g")
.attr("transform", "translate(100,100)")
.append("g");
var rect = g.append("rect")
.attr("x", -25)
.attr("y", -50)
.attr("width", 50)
.attr("height", 100);
g.transition()
.duration(3000)
.attr("transform", "matrix(1 0 0 1 100 100)rotate(360)");
</script>
<!DOCTYPE html>
<body>
<script src="../../d3.v2.js"></script>
<script>
var svg = d3.select("body").append("svg")
.attr("width", 960)
.attr("height", 500);
var g = svg.append("g")
.attr("transform", "translate(100,100)")
.append("g");
var rect = g.append("rect")
.attr("x", -25)
.attr("y", -50)
.attr("width", 50)
.attr("height", 100);
g.transition()
.duration(3000)
.attr("transform", "translate(100,100)rotate(360)");
</script>
...@@ -51,13 +51,14 @@ var tests = [ ...@@ -51,13 +51,14 @@ var tests = [
{start: 225, end: 170, expected: [-135.00, -148.75, -162.50, -176.25, 170.00]}, {start: 225, end: 170, expected: [-135.00, -148.75, -162.50, -176.25, 170.00]},
{start: -170, end: -225, expected: [-170.00, 176.25, 162.50, 148.75, 135.00]}, {start: -170, end: -225, expected: [-170.00, 176.25, 162.50, 148.75, 135.00]},
{start: -225, end: -170, expected: [ 135.00, 148.75, 162.50, 176.25, -170.00]}, {start: -225, end: -170, expected: [ 135.00, 148.75, 162.50, 176.25, -170.00]},
{start: -170, end: 170, expected: [-170.00, -175.00, 180.00, 175.00, 170.00]}, {start: -170, end: 170, expected: [-170.00, -85.00, 0.00, 85.00, 170.00]},
{start: -170, end: 0, expected: [-170.00, -127.50, -85.00, -42.50, 0.00]}, {start: -170, end: 0, expected: [-170.00, -127.50, -85.00, -42.50, 0.00]},
{start: 170, end: 0, expected: [ 170.00, 127.50, 85.00, 42.50, 0.00]}, {start: 170, end: 0, expected: [ 170.00, 127.50, 85.00, 42.50, 0.00]},
{start: -180, end: 90, expected: [ 180.00, 157.50, 135.00, 112.50, 90.00]}, {start: -180, end: 90, expected: [-180.00, -112.50, -45.00, 22.50, 90.00]},
{start: 180, end: 90, expected: [ 180.00, 157.50, 135.00, 112.50, 90.00]}, {start: 180, end: 90, expected: [ 180.00, 157.50, 135.00, 112.50, 90.00]},
{start: -180, end: -90, expected: [-180.00, -157.50, -135.00, -112.50, -90.00]}, {start: -180, end: -90, expected: [-180.00, -157.50, -135.00, -112.50, -90.00]},
{start: 180, end: -90, expected: [ 180.00, -157.50, -135.00, -112.50, -90.00]} {start: 180, end: -90, expected: [ 180.00, 112.50, 45.00, -22.50, -90.00]},
{start: 780, end: -90, expected: [ 60.00, -157.50, -15.00, 127.50, -90.00]}
]; ];
var tr = d3.select("tbody").selectAll("tr") var tr = d3.select("tbody").selectAll("tr")
...@@ -84,35 +85,41 @@ tr.selectAll(".actual") ...@@ -84,35 +85,41 @@ tr.selectAll(".actual")
.text(function(d, i) { return format(d.actual); }) .text(function(d, i) { return format(d.actual); })
.attr("class", function(d) { return Math.abs(d.actual - d.expected) < .01 ? "success" : "fail"; }); .attr("class", function(d) { return Math.abs(d.actual - d.expected) < .01 ? "success" : "fail"; });
tr.append("td").attr("width", 40).append("svg") var ga = tr.append("td").attr("width", 40).append("svg")
.attr("width", 40) .attr("width", 40)
.attr("height", 20) .attr("height", 20)
.append("g") .append("g")
.attr("transform", "translate(20,10)") .attr("transform", "translate(20,10)")
.append("path") .append("g")
.attr("d", d3.svg.symbol().type("cross").size(120))
.each(animateExpected); .each(animateExpected);
tr.append("td").attr("width", 40).append("svg") ga.append("path")
.attr("d", d3.svg.symbol().type("cross").size(120));
ga.append("circle")
.attr("cx", 8)
.attr("r", 4);
var gb = tr.append("td").attr("width", 40).append("svg")
.attr("width", 40) .attr("width", 40)
.attr("height", 20) .attr("height", 20)
.append("g") .append("g")
.attr("transform", "translate(20,10)") .attr("transform", "translate(20,10)")
.append("path") .append("g")
.attr("d", d3.svg.symbol().type("cross").size(120))
.each(animateActual); .each(animateActual);
gb.append("path")
.attr("d", d3.svg.symbol().type("cross").size(120));
gb.append("circle")
.attr("cx", 8)
.attr("r", 4);
function animateExpected(d) { function animateExpected(d) {
d3.select(this).transition() d3.select(this).transition()
.duration(2500) .duration(2500)
.attrTween("transform", rotateTween) .attrTween("transform", function(d) { return d3.interpolateString("rotate(" + d.start + ")", "rotate(" + d.end + ")"); })
.each("end", animateExpected); .each("end", animateExpected);
function rotateTween(d) {
if (d.start - d.end > 180) d.end += 360;
else if (d.end - d.start > 180) d.start += 360;
return d3.interpolateString("rotate(" + d.start + ")", "rotate(" + d.end + ")");
}
} }
function animateActual(d) { function animateActual(d) {
......
{ {
"name": "d3", "name": "d3",
"version": "2.9.6", "version": "2.9.7",
"description": "A small, free JavaScript library for manipulating documents based on data.", "description": "A small, free JavaScript library for manipulating documents based on data.",
"keywords": [ "keywords": [
"dom", "dom",
......
...@@ -136,13 +136,15 @@ d3.behavior.zoom = function() { ...@@ -136,13 +136,15 @@ d3.behavior.zoom = function() {
touches.forEach(function(t) { translate0[t.identifier] = location(t); }); touches.forEach(function(t) { translate0[t.identifier] = location(t); });
d3_eventCancel(); d3_eventCancel();
if ((touches.length === 1) && (now - touchtime < 500)) { // dbltap if (touches.length === 1) {
var p = touches[0], l = location(touches[0]); if (now - touchtime < 500) { // dbltap
scaleTo(scale * 2); var p = touches[0], l = location(touches[0]);
translateTo(p, l); scaleTo(scale * 2);
dispatch(event.of(this, arguments)); translateTo(p, l);
dispatch(event.of(this, arguments));
}
touchtime = now;
} }
touchtime = now;
} }
function touchmove() { function touchmove() {
...@@ -156,6 +158,7 @@ d3.behavior.zoom = function() { ...@@ -156,6 +158,7 @@ d3.behavior.zoom = function() {
scaleTo(d3.event.scale * scale0); scaleTo(d3.event.scale * scale0);
} }
translateTo(p0, l0); translateTo(p0, l0);
touchtime = null;
dispatch(event.of(this, arguments)); dispatch(event.of(this, arguments));
} }
......
...@@ -4,7 +4,7 @@ d3.bisector = function(f) { ...@@ -4,7 +4,7 @@ d3.bisector = function(f) {
if (arguments.length < 3) lo = 0; if (arguments.length < 3) lo = 0;
if (arguments.length < 4) hi = a.length; if (arguments.length < 4) hi = a.length;
while (lo < hi) { while (lo < hi) {
var mid = lo + hi >> 1; var mid = lo + hi >>> 1;
if (f.call(a, a[mid], mid) < x) lo = mid + 1; if (f.call(a, a[mid], mid) < x) lo = mid + 1;
else hi = mid; else hi = mid;
} }
...@@ -14,7 +14,7 @@ d3.bisector = function(f) { ...@@ -14,7 +14,7 @@ d3.bisector = function(f) {
if (arguments.length < 3) lo = 0; if (arguments.length < 3) lo = 0;
if (arguments.length < 4) hi = a.length; if (arguments.length < 4) hi = a.length;
while (lo < hi) { while (lo < hi) {
var mid = lo + hi >> 1; var mid = lo + hi >>> 1;
if (x < f.call(a, a[mid], mid)) hi = mid; if (x < f.call(a, a[mid], mid)) hi = mid;
else lo = mid + 1; else lo = mid + 1;
} }
......
d3 = {version: "2.9.6"}; // semver d3 = {version: "2.9.7"}; // semver
...@@ -17,7 +17,7 @@ d3.interpolateRound = function(a, b) { ...@@ -17,7 +17,7 @@ d3.interpolateRound = function(a, b) {
d3.interpolateString = function(a, b) { d3.interpolateString = function(a, b) {
var m, // current match var m, // current match
i, // current index i, // current index
j, // current index (for coallescing) j, // current index (for coalescing)
s0 = 0, // start index of current string prefix s0 = 0, // start index of current string prefix
s1 = 0, // end index of current string prefix s1 = 0, // end index of current string prefix
s = [], // string constants and placeholders s = [], // string constants and placeholders
...@@ -40,13 +40,13 @@ d3.interpolateString = function(a, b) { ...@@ -40,13 +40,13 @@ d3.interpolateString = function(a, b) {
// Find all numbers in a. // Find all numbers in a.
for (i = 0, n = q.length; (m = d3_interpolate_number.exec(a)) && i < n; ++i) { for (i = 0, n = q.length; (m = d3_interpolate_number.exec(a)) && i < n; ++i) {
o = q[i]; o = q[i];
if (o.x == m[0]) { // The numbers match, so coallesce. if (o.x == m[0]) { // The numbers match, so coalesce.
if (o.i) { if (o.i) {
if (s[o.i + 1] == null) { // This match is followed by another number. if (s[o.i + 1] == null) { // This match is followed by another number.
s[o.i - 1] += o.x; s[o.i - 1] += o.x;
s.splice(o.i, 1); s.splice(o.i, 1);
for (j = i + 1; j < n; ++j) q[j].i--; for (j = i + 1; j < n; ++j) q[j].i--;
} else { // This match is followed by a string, so coallesce twice. } else { // This match is followed by a string, so coalesce twice.
s[o.i - 1] += o.x + s[o.i + 1]; s[o.i - 1] += o.x + s[o.i + 1];
s.splice(o.i, 2); s.splice(o.i, 2);
for (j = i + 1; j < n; ++j) q[j].i -= 2; for (j = i + 1; j < n; ++j) q[j].i -= 2;
...@@ -54,7 +54,7 @@ d3.interpolateString = function(a, b) { ...@@ -54,7 +54,7 @@ d3.interpolateString = function(a, b) {
} else { } else {
if (s[o.i + 1] == null) { // This match is followed by another number. if (s[o.i + 1] == null) { // This match is followed by another number.
s[o.i] = o.x; s[o.i] = o.x;
} else { // This match is followed by a string, so coallesce twice. } else { // This match is followed by a string, so coalesce twice.
s[o.i] = o.x + s[o.i + 1]; s[o.i] = o.x + s[o.i + 1];
s.splice(o.i + 1, 1); s.splice(o.i + 1, 1);
for (j = i + 1; j < n; ++j) q[j].i--; for (j = i + 1; j < n; ++j) q[j].i--;
...@@ -73,7 +73,7 @@ d3.interpolateString = function(a, b) { ...@@ -73,7 +73,7 @@ d3.interpolateString = function(a, b) {
o = q.pop(); o = q.pop();
if (s[o.i + 1] == null) { // This match is followed by another number. if (s[o.i + 1] == null) { // This match is followed by another number.
s[o.i] = o.x; s[o.i] = o.x;
} else { // This match is followed by a string, so coallesce twice. } else { // This match is followed by a string, so coalesce twice.
s[o.i] = o.x + s[o.i + 1]; s[o.i] = o.x + s[o.i + 1];
s.splice(o.i + 1, 1); s.splice(o.i + 1, 1);
} }
...@@ -93,6 +93,8 @@ d3.interpolateString = function(a, b) { ...@@ -93,6 +93,8 @@ d3.interpolateString = function(a, b) {
}; };
d3.interpolateTransform = function(a, b) { d3.interpolateTransform = function(a, b) {
if ((n = d3_interpolateTransformSimilar(a, b))) return n;
var s = [], // string constants and placeholders var s = [], // string constants and placeholders
q = [], // number interpolators q = [], // number interpolators
n, n,
...@@ -144,6 +146,112 @@ d3.interpolateTransform = function(a, b) { ...@@ -144,6 +146,112 @@ d3.interpolateTransform = function(a, b) {
}; };
}; };
var d3_interpolateTransformTypes = [
"",
"",
"translate",
"scale",
"rotate",
"skewX",
"skewY"
];
// If both the ‘from’ and ‘to’ transforms have the same number of transform
// functions and corresponding functions in each transform list are of the same
// type, each transform function is animated with its corresponding destination
// function in isolation using the rules described above. The individual values
// are then applied as a list to produce resulting transform value.
var d3_interpolateTransformSimilar = function(a, b) {
var ga = document.createElementNS(d3.ns.prefix.svg, "g"),
gb = document.createElementNS(d3.ns.prefix.svg, "g");
return (d3_interpolateTransformSimilar = function(a, b) {
ga.setAttribute("transform", a);
gb.setAttribute("transform", b);
a = ga.transform.baseVal;
b = gb.transform.baseVal;
var sa = [],
sb = [],
i = -1,
n = a.numberOfItems,
m = b.numberOfItems,
ta,
tb,
type;
// If one of the ‘from’ or ‘to’ transforms is "none", the ‘none’ is replaced
// by an equivalent identity function list for the corresponding transform
// function list. Otherwise, if the transform function lists do not have the
// same number of items, the transforms are each converted into the
// equivalent matrix value and animation proceeds using the rule for a
// single function above.
if (m !== n) {
if (!m) b = d3_interpolateTransformIdentity(a);
else if (!n) a = d3_interpolateTransformIdentity(b), n = m;
else return;
}
// If both the ‘from’ and ‘to’ transforms are "none", there is no
// interpolation necessary.
else if (!m) return;
while (++i < n) {
ta = a.getItem(i);
tb = b.getItem(i);
type = ta.type;
// If the transform functions are not the same type, or the type is
// unknown, fallback to the decomposed transform transition.
if (type !== tb.type || !type) return; // unknown
switch (type) {
// For matrix, the matrix is decomposed using the method described by
// unmatrix into separate translation, scale, rotation and skew
// matrices, then each decomposed matrix is interpolated numerically,
// and finally combined in order to produce a resulting 3x2 matrix.
case 1: { // matrix
sa.push(new d3_transform(ta.matrix));
sb.push(new d3_transform(tb.matrix));
continue;
}
// For translate, scale, rotate and skew functions the individual
// components of the function are interpolated numerically.
case 2: { // translate
ra = ta.matrix.e + "," + ta.matrix.f;
rb = tb.matrix.e + "," + tb.matrix.f;
break;
}
case 3: { // scale
ra = ta.matrix.a + "," + ta.matrix.d;
rb = tb.matrix.a + "," + tb.matrix.d;
break;
}
default: { // rotate, skew
ra = ta.angle;
rb = tb.angle;
}
}
sa.push(type = d3_interpolateTransformTypes[type], "(", ra, ")");
sb.push(type, "(", rb, ")");
}
return d3.interpolateString(sa.join(""), sb.join(""));
})(a, b);
};
function d3_interpolateTransformIdentity(a) {
return {
getItem: function(i) {
return {
type: a.getItem(i).type,
angle: 0,
matrix: d3_transformIdentity
};
}
};
}
d3.interpolateRgb = function(a, b) { d3.interpolateRgb = function(a, b) {
a = d3.rgb(a); a = d3.rgb(a);
b = d3.rgb(b); b = d3.rgb(b);
...@@ -213,7 +321,7 @@ d3.interpolateObject = function(a, b) { ...@@ -213,7 +321,7 @@ d3.interpolateObject = function(a, b) {
for (k in i) c[k] = i[k](t); for (k in i) c[k] = i[k](t);
return c; return c;
}; };
} };
var d3_interpolate_number = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g; var d3_interpolate_number = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g;
......
...@@ -41,9 +41,11 @@ function d3_selection_classed(name, value) { ...@@ -41,9 +41,11 @@ function d3_selection_classed(name, value) {
var c = this.className, var c = this.className,
cb = c.baseVal != null, cb = c.baseVal != null,
cv = cb ? c.baseVal : c; cv = cb ? c.baseVal : c;
cv = d3_collapse(cv.replace(re, " ")); if (cv) {
if (cb) c.baseVal = cv; cv = d3_collapse(cv.replace(re, " "));
else this.className = cv; if (cb) c.baseVal = cv;
else this.className = cv;
}
} }
function classedFunction() { function classedFunction() {
......
...@@ -11,8 +11,9 @@ d3_selectionPrototype.on = function(type, listener, capture) { ...@@ -11,8 +11,9 @@ d3_selectionPrototype.on = function(type, listener, capture) {
if (arguments.length < 2) return (i = this.node()[name]) && i._; if (arguments.length < 2) return (i = this.node()[name]) && i._;
// remove the old event listener, and add the new event listener // remove the old event listener, and add the new event listener
return this.each(function(d, i) { return this.each(function() {
var node = this, var node = this,
args = arguments,
o = node[name]; o = node[name];
// remove the old listener, if any (using the previously-set capture) // remove the old listener, if any (using the previously-set capture)
...@@ -27,12 +28,13 @@ d3_selectionPrototype.on = function(type, listener, capture) { ...@@ -27,12 +28,13 @@ d3_selectionPrototype.on = function(type, listener, capture) {
l._ = listener; // stash the unwrapped listener for get l._ = listener; // stash the unwrapped listener for get
} }
// wrapped event listener that preserves i // wrapped event listener that propagates data changes
function l(e) { 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__;
try { try {
listener.call(node, node.__data__, i); listener.apply(node, args);
} finally { } finally {
d3.event = o; d3.event = o;
} }
......
d3.transform = function(string) { d3.transform = function(string) {
var g = document.createElementNS(d3.ns.prefix.svg, "g"), var g = document.createElementNS(d3.ns.prefix.svg, "g");
identity = {a: 1, b: 0, c: 0, d: 1, e: 0, f: 0};
return (d3.transform = function(string) { return (d3.transform = function(string) {
g.setAttribute("transform", string); g.setAttribute("transform", string);
var t = g.transform.baseVal.consolidate(); var t = g.transform.baseVal.consolidate();
return new d3_transform(t ? t.matrix : identity); return new d3_transform(t ? t.matrix : d3_transformIdentity);
})(string); })(string);
}; };
...@@ -57,4 +56,5 @@ function d3_transformCombine(a, b, k) { ...@@ -57,4 +56,5 @@ function d3_transformCombine(a, b, k) {
return a; return a;
} }
var d3_transformDegrees = 180 / Math.PI; var d3_transformDegrees = 180 / Math.PI,
d3_transformIdentity = {a: 1, b: 0, c: 0, d: 1, e: 0, f: 0};
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, node.node.__data__, i)) {
subgroup.push(node);
}
}
}
return d3_transition(subgroups, this.id, this.time).ease(this.ease());
};
...@@ -181,11 +181,11 @@ function d3_layout_packPlace(a, b, c) { ...@@ -181,11 +181,11 @@ function d3_layout_packPlace(a, b, c) {
dy = b.y - a.y; dy = b.y - a.y;
if (db && (dx || dy)) { if (db && (dx || dy)) {
var da = b.r + c.r, var da = b.r + c.r,
dc = Math.sqrt(dx * dx + dy * dy),