Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge branch '2.9.7'

  • Loading branch information...
commit 108d65da0eebd431425bf3aa51f0ed234d04975e 2 parents fb86373 + 540d3ac
@mbostock authored
Showing with 10,319 additions and 12,496 deletions.
  1. +4 −2 Makefile
  2. +6,661 −9,171 d3.v2.js
  3. +4 −4 d3.v2.min.js
  4. +1 −1  examples/area/area-radial.html
  5. +1 −1  examples/clock/clock.js
  6. +3,185 −3,215 examples/data/us-counties.json
  7. +22 −0 examples/transform/null-matrix.html
  8. +22 −0 examples/transform/null.html
  9. +23 −16 examples/transform/test-rotate.html
  10. +1 −1  package.json
  11. +9 −6 src/behavior/zoom.js
  12. +2 −2 src/core/bisect.js
  13. +1 −1  src/core/core.js
  14. +114 −6 src/core/interpolate.js
  15. +5 −3 src/core/selection-classed.js
  16. +5 −3 src/core/selection-on.js
  17. +4 −4 src/core/transform.js
  18. +19 −0 src/core/transition-filter.js
  19. +5 −5 src/layout/pack.js
  20. +6 −6 src/svg/line.js
  21. +4 −2 src/time/day.js
  22. +3 −3 src/time/format.js
  23. +3 −1 src/time/month.js
  24. +3 −1 src/time/year.js
  25. +66 −0 test/core/bisect-test.js
  26. +84 −0 test/core/transition-test-filter.js
  27. +2 −1  test/core/transition-test.js
  28. +2 −2 test/layout/pack-test.js
  29. +3 −0  test/time/day-test.js
  30. +22 −0 test/time/dayOfYear-test.js
  31. +8 −8 test/time/format-test.js
  32. +4 −4 test/time/hour-test.js
  33. +2 −18 test/time/hours-test.js
  34. +3 −0  test/time/month-test.js
  35. +10 −9 test/time/time.js
  36. +3 −0  test/time/week-test.js
  37. +3 −0  test/time/year-test.js
View
6 Makefile
@@ -2,6 +2,7 @@
NODE_PATH ?= ./node_modules
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
all: \
@@ -74,6 +75,7 @@ d3.core.js: \
src/core/formatPrefix.js \
src/core/ease.js \
src/core/event.js \
+ src/core/transform.js \
src/core/interpolate.js \
src/core/uninterpolate.js \
src/core/rgb.js \
@@ -107,6 +109,7 @@ d3.core.js: \
src/core/transition.js \
src/core/transition-select.js \
src/core/transition-selectAll.js \
+ src/core/transition-filter.js \
src/core/transition-attr.js \
src/core/transition-style.js \
src/core/transition-text.js \
@@ -116,7 +119,6 @@ d3.core.js: \
src/core/transition-each.js \
src/core/transition-transition.js \
src/core/timer.js \
- src/core/transform.js \
src/core/mouse.js \
src/core/touches.js \
src/core/noop.js
@@ -225,7 +227,7 @@ test: all
d3%.js: Makefile
@rm -f $@
- cat $(filter %.js,$^) > $@
+ cat $(filter %.js,$^) | $(JS_BEAUTIFIER) > $@
@chmod a-w $@
package.json: src/package.js
View
15,832 d3.v2.js
6,661 additions, 9,171 deletions not shown
View
8 d3.v2.min.js
4 additions, 4 deletions not shown
View
2  examples/area/area-radial.html
@@ -33,7 +33,7 @@
.range([0, 2 * Math.PI]);
var line = d3.svg.line.radial()
- .interpolate("basis-closed")
+ .interpolate("linear-closed")
.radius(radius)
.angle(function(d, i) { return angle(i); });
View
2  examples/clock/clock.js
@@ -14,7 +14,7 @@ var width = 960,
var fill = d3.scale.linear()
.range(["hsl(-180, 50%, 50%)", "hsl(180, 50%, 50%)"])
- .interpolate(d3.interpolateHsl);
+ .interpolate(d3.interpolateString);
var arc = d3.svg.arc()
.startAngle(0)
View
6,400 examples/data/us-counties.json
3,185 additions, 3,215 deletions not shown
View
22 examples/transform/null-matrix.html
@@ -0,0 +1,22 @@
+<!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>
View
22 examples/transform/null.html
@@ -0,0 +1,22 @@
+<!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>
View
39 examples/transform/test-rotate.html
@@ -51,13 +51,14 @@
{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: -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: -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, 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")
@@ -84,35 +85,41 @@
.text(function(d, i) { return format(d.actual); })
.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("height", 20)
.append("g")
.attr("transform", "translate(20,10)")
- .append("path")
- .attr("d", d3.svg.symbol().type("cross").size(120))
+ .append("g")
.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("height", 20)
.append("g")
.attr("transform", "translate(20,10)")
- .append("path")
- .attr("d", d3.svg.symbol().type("cross").size(120))
+ .append("g")
.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) {
d3.select(this).transition()
.duration(2500)
- .attrTween("transform", rotateTween)
+ .attrTween("transform", function(d) { return d3.interpolateString("rotate(" + d.start + ")", "rotate(" + d.end + ")"); })
.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) {
View
2  package.json
@@ -1,6 +1,6 @@
{
"name": "d3",
- "version": "2.9.6",
+ "version": "2.9.7",
"description": "A small, free JavaScript library for manipulating documents based on data.",
"keywords": [
"dom",
View
15 src/behavior/zoom.js
@@ -136,13 +136,15 @@ d3.behavior.zoom = function() {
touches.forEach(function(t) { translate0[t.identifier] = location(t); });
d3_eventCancel();
- if ((touches.length === 1) && (now - touchtime < 500)) { // dbltap
- var p = touches[0], l = location(touches[0]);
- scaleTo(scale * 2);
- translateTo(p, l);
- dispatch(event.of(this, arguments));
+ if (touches.length === 1) {
+ if (now - touchtime < 500) { // dbltap
+ var p = touches[0], l = location(touches[0]);
+ scaleTo(scale * 2);
+ translateTo(p, l);
+ dispatch(event.of(this, arguments));
+ }
+ touchtime = now;
}
- touchtime = now;
}
function touchmove() {
@@ -156,6 +158,7 @@ d3.behavior.zoom = function() {
scaleTo(d3.event.scale * scale0);
}
translateTo(p0, l0);
+ touchtime = null;
dispatch(event.of(this, arguments));
}
View
4 src/core/bisect.js
@@ -4,7 +4,7 @@ d3.bisector = function(f) {
if (arguments.length < 3) lo = 0;
if (arguments.length < 4) hi = a.length;
while (lo < hi) {
- var mid = lo + hi >> 1;
+ var mid = lo + hi >>> 1;
if (f.call(a, a[mid], mid) < x) lo = mid + 1;
else hi = mid;
}
@@ -14,7 +14,7 @@ d3.bisector = function(f) {
if (arguments.length < 3) lo = 0;
if (arguments.length < 4) hi = a.length;
while (lo < hi) {
- var mid = lo + hi >> 1;
+ var mid = lo + hi >>> 1;
if (x < f.call(a, a[mid], mid)) hi = mid;
else lo = mid + 1;
}
View
2  src/core/core.js
@@ -1 +1 @@
-d3 = {version: "2.9.6"}; // semver
+d3 = {version: "2.9.7"}; // semver
View
120 src/core/interpolate.js
@@ -17,7 +17,7 @@ d3.interpolateRound = function(a, b) {
d3.interpolateString = function(a, b) {
var m, // current match
i, // current index
- j, // current index (for coallescing)
+ j, // current index (for coalescing)
s0 = 0, // start index of current string prefix
s1 = 0, // end index of current string prefix
s = [], // string constants and placeholders
@@ -40,13 +40,13 @@ d3.interpolateString = function(a, b) {
// Find all numbers in a.
for (i = 0, n = q.length; (m = d3_interpolate_number.exec(a)) && i < n; ++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 (s[o.i + 1] == null) { // This match is followed by another number.
s[o.i - 1] += o.x;
s.splice(o.i, 1);
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.splice(o.i, 2);
for (j = i + 1; j < n; ++j) q[j].i -= 2;
@@ -54,7 +54,7 @@ d3.interpolateString = function(a, b) {
} else {
if (s[o.i + 1] == null) { // This match is followed by another number.
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.splice(o.i + 1, 1);
for (j = i + 1; j < n; ++j) q[j].i--;
@@ -73,7 +73,7 @@ d3.interpolateString = function(a, b) {
o = q.pop();
if (s[o.i + 1] == null) { // This match is followed by another number.
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.splice(o.i + 1, 1);
}
@@ -93,6 +93,8 @@ d3.interpolateString = function(a, b) {
};
d3.interpolateTransform = function(a, b) {
+ if ((n = d3_interpolateTransformSimilar(a, b))) return n;
+
var s = [], // string constants and placeholders
q = [], // number interpolators
n,
@@ -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) {
a = d3.rgb(a);
b = d3.rgb(b);
@@ -213,7 +321,7 @@ d3.interpolateObject = function(a, b) {
for (k in i) c[k] = i[k](t);
return c;
};
-}
+};
var d3_interpolate_number = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g;
View
8 src/core/selection-classed.js
@@ -41,9 +41,11 @@ function d3_selection_classed(name, value) {
var c = this.className,
cb = c.baseVal != null,
cv = cb ? c.baseVal : c;
- cv = d3_collapse(cv.replace(re, " "));
- if (cb) c.baseVal = cv;
- else this.className = cv;
+ if (cv) {
+ cv = d3_collapse(cv.replace(re, " "));
+ if (cb) c.baseVal = cv;
+ else this.className = cv;
+ }
}
function classedFunction() {
View
8 src/core/selection-on.js
@@ -11,8 +11,9 @@ d3_selectionPrototype.on = function(type, listener, capture) {
if (arguments.length < 2) return (i = this.node()[name]) && i._;
// remove the old event listener, and add the new event listener
- return this.each(function(d, i) {
+ return this.each(function() {
var node = this,
+ args = arguments,
o = node[name];
// remove the old listener, if any (using the previously-set capture)
@@ -27,12 +28,13 @@ d3_selectionPrototype.on = function(type, listener, capture) {
l._ = listener; // stash the unwrapped listener for get
}
- // wrapped event listener that preserves i
+ // wrapped event listener that propagates data changes
function l(e) {
var o = d3.event; // Events can be reentrant (e.g., focus).
d3.event = e;
+ args[0] = node.__data__;
try {
- listener.call(node, node.__data__, i);
+ listener.apply(node, args);
} finally {
d3.event = o;
}
View
8 src/core/transform.js
@@ -1,10 +1,9 @@
d3.transform = function(string) {
- var g = document.createElementNS(d3.ns.prefix.svg, "g"),
- identity = {a: 1, b: 0, c: 0, d: 1, e: 0, f: 0};
+ var g = document.createElementNS(d3.ns.prefix.svg, "g");
return (d3.transform = function(string) {
g.setAttribute("transform", string);
var t = g.transform.baseVal.consolidate();
- return new d3_transform(t ? t.matrix : identity);
+ return new d3_transform(t ? t.matrix : d3_transformIdentity);
})(string);
};
@@ -57,4 +56,5 @@ function d3_transformCombine(a, b, k) {
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};
View
19 src/core/transition-filter.js
@@ -0,0 +1,19 @@
+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());
+};
View
10 src/layout/pack.js
@@ -181,11 +181,11 @@ function d3_layout_packPlace(a, b, c) {
dy = b.y - a.y;
if (db && (dx || dy)) {
var da = b.r + c.r,
- dc = Math.sqrt(dx * dx + dy * dy),
- cos = Math.max(-1, Math.min(1, (db * db + dc * dc - da * da) / (2 * db * dc))),
- theta = Math.acos(cos),
- x = cos * (db /= dc),
- y = Math.sin(theta) * db;
+ dc = dx * dx + dy * dy;
+ da *= da;
+ db *= db;
+ var x = .5 + (db - da) / (2 * dc),
+ y = Math.sqrt(Math.max(0, 2 * da * (db + dc) - (db -= dc) * db - da * da)) / (2 * dc);
c.x = a.x + x * dx + y * dy;
c.y = a.y + x * dy - y * dx;
} else {
View
12 src/svg/line.js
@@ -86,6 +86,7 @@ var d3_svg_lineInterpolatorDefault = "linear";
// The various interpolators supported by the `line` class.
var d3_svg_lineInterpolators = d3.map({
"linear": d3_svg_lineLinear,
+ "linear-closed": d3_svg_lineLinearClosed,
"step-before": d3_svg_lineStepBefore,
"step-after": d3_svg_lineStepAfter,
"basis": d3_svg_lineBasis,
@@ -100,12 +101,11 @@ var d3_svg_lineInterpolators = d3.map({
// Linear interpolation; generates "L" commands.
function d3_svg_lineLinear(points) {
- var i = 0,
- n = points.length,
- p = points[0],
- path = [p[0], ",", p[1]];
- while (++i < n) path.push("L", (p = points[i])[0], ",", p[1]);
- return path.join("");
+ return points.join("L");
+}
+
+function d3_svg_lineLinearClosed(points) {
+ return d3_svg_lineLinear(points) + "Z";
}
// Step interpolation; generates "H" and "V" commands.
View
6 src/time/day.js
@@ -1,5 +1,7 @@
d3.time.day = d3_time_interval(function(date) {
- return new d3_time(date.getFullYear(), date.getMonth(), date.getDate());
+ var day = new d3_time(0, date.getMonth(), date.getDate());
+ day.setFullYear(date.getFullYear());
+ return day;
}, function(date, offset) {
date.setDate(date.getDate() + offset);
}, function(date) {
@@ -11,5 +13,5 @@ d3.time.days.utc = d3.time.day.utc.range;
d3.time.dayOfYear = function(date) {
var year = d3.time.year(date);
- return Math.floor((date - year) / 864e5 - (date.getTimezoneOffset() - year.getTimezoneOffset()) / 1440);
+ return Math.floor((date - year - (date.getTimezoneOffset() - year.getTimezoneOffset()) * 6e4) / 864e5);
};
View
6 src/time/format.js
@@ -215,11 +215,11 @@ function d3_time_parseFullYear(date, string, i) {
function d3_time_parseYear(date, string, i) {
d3_time_numberRe.lastIndex = 0;
var n = d3_time_numberRe.exec(string.substring(i, i + 2));
- return n ? (date.y = d3_time_century() + +n[0], i += n[0].length) : -1;
+ return n ? (date.y = d3_time_expandYear(+n[0]), i += n[0].length) : -1;
}
-function d3_time_century() {
- return ~~(new Date().getFullYear() / 1000) * 1000;
+function d3_time_expandYear(d) {
+ return d + (d > 68 ? 1900 : 2000);
}
function d3_time_parseMonthNumber(date, string, i) {
View
4 src/time/month.js
@@ -1,5 +1,7 @@
d3.time.month = d3_time_interval(function(date) {
- return new d3_time(date.getFullYear(), date.getMonth(), 1);
+ date = d3.time.day(date);
+ date.setDate(1);
+ return date;
}, function(date, offset) {
date.setMonth(date.getMonth() + offset);
}, function(date) {
View
4 src/time/year.js
@@ -1,5 +1,7 @@
d3.time.year = d3_time_interval(function(date) {
- return new d3_time(date.getFullYear(), 0, 1);
+ date = d3.time.day(date);
+ date.setMonth(0, 1);
+ return date;
}, function(date, offset) {
date.setFullYear(date.getFullYear() + offset);
}, function(date) {
View
66 test/core/bisect-test.js
@@ -5,6 +5,8 @@ var vows = require("vows"),
var suite = vows.describe("d3.bisect");
+var i30 = 1 << 30;
+
suite.addBatch({
"bisectLeft": {
topic: function() {
@@ -48,6 +50,22 @@ suite.addBatch({
assert.equal(bisect(array, 4, 2, 3), 3);
assert.equal(bisect(array, 5, 2, 3), 3);
assert.equal(bisect(array, 6, 2, 3), 3);
+ },
+ "large arrays": function(bisect) {
+ var array = [],
+ i = i30;
+ array[i++] = 1;
+ array[i++] = 2;
+ array[i++] = 3;
+ array[i++] = 4;
+ array[i++] = 5;
+ assert.equal(bisect(array, 0, i - 5, i), i - 5);
+ assert.equal(bisect(array, 1, i - 5, i), i - 5);
+ assert.equal(bisect(array, 2, i - 5, i), i - 4);
+ assert.equal(bisect(array, 3, i - 5, i), i - 3);
+ assert.equal(bisect(array, 4, i - 5, i), i - 2);
+ assert.equal(bisect(array, 5, i - 5, i), i - 1);
+ assert.equal(bisect(array, 6, i - 5, i), i - 0);
}
}
});
@@ -95,6 +113,22 @@ suite.addBatch({
assert.equal(bisect(array, 4, 2, 3), 3);
assert.equal(bisect(array, 5, 2, 3), 3);
assert.equal(bisect(array, 6, 2, 3), 3);
+ },
+ "large arrays": function(bisect) {
+ var array = [],
+ i = i30;
+ array[i++] = 1;
+ array[i++] = 2;
+ array[i++] = 3;
+ array[i++] = 4;
+ array[i++] = 5;
+ assert.equal(bisect(array, 0, i - 5, i), i - 5);
+ assert.equal(bisect(array, 1, i - 5, i), i - 4);
+ assert.equal(bisect(array, 2, i - 5, i), i - 3);
+ assert.equal(bisect(array, 3, i - 5, i), i - 2);
+ assert.equal(bisect(array, 4, i - 5, i), i - 1);
+ assert.equal(bisect(array, 5, i - 5, i), i - 0);
+ assert.equal(bisect(array, 6, i - 5, i), i - 0);
}
}
});
@@ -146,6 +180,22 @@ suite.addBatch({
assert.equal(bisect(array, 4, 2, 3), 3);
assert.equal(bisect(array, 5, 2, 3), 3);
assert.equal(bisect(array, 6, 2, 3), 3);
+ },
+ "large arrays": function(bisect) {
+ var array = [],
+ i = i30;
+ array[i++] = {key: 1};
+ array[i++] = {key: 2};
+ array[i++] = {key: 3};
+ array[i++] = {key: 4};
+ array[i++] = {key: 5};
+ assert.equal(bisect(array, 0, i - 5, i), i - 5);
+ assert.equal(bisect(array, 1, i - 5, i), i - 5);
+ assert.equal(bisect(array, 2, i - 5, i), i - 4);
+ assert.equal(bisect(array, 3, i - 5, i), i - 3);
+ assert.equal(bisect(array, 4, i - 5, i), i - 2);
+ assert.equal(bisect(array, 5, i - 5, i), i - 1);
+ assert.equal(bisect(array, 6, i - 5, i), i - 0);
}
},
"right": {
@@ -190,6 +240,22 @@ suite.addBatch({
assert.equal(bisect(array, 4, 2, 3), 3);
assert.equal(bisect(array, 5, 2, 3), 3);
assert.equal(bisect(array, 6, 2, 3), 3);
+ },
+ "large arrays": function(bisect) {
+ var array = [],
+ i = i30;
+ array[i++] = {key: 1};
+ array[i++] = {key: 2};
+ array[i++] = {key: 3};
+ array[i++] = {key: 4};
+ array[i++] = {key: 5};
+ assert.equal(bisect(array, 0, i - 5, i), i - 5);
+ assert.equal(bisect(array, 1, i - 5, i), i - 4);
+ assert.equal(bisect(array, 2, i - 5, i), i - 3);
+ assert.equal(bisect(array, 3, i - 5, i), i - 2);
+ assert.equal(bisect(array, 4, i - 5, i), i - 1);
+ assert.equal(bisect(array, 5, i - 5, i), i - 0);
+ assert.equal(bisect(array, 6, i - 5, i), i - 0);
}
}
}
View
84 test/core/transition-test-filter.js
@@ -0,0 +1,84 @@
+require("../env");
+
+var assert = require("assert");
+
+var datum = {};
+
+module.exports = {
+ topic: function() {
+ return d3.select("body").html("").selectAll("div")
+ .data([0, 1])
+ .enter().append("div")
+ .selectAll("span")
+ .data(function(d) { d <<= 1; return [d, d + 1]; })
+ .enter().append("span")
+ .classed("foo", function(d, i) { return d & 1; })
+ .transition()
+ .delay(100)
+ .duration(150)
+ .ease("bounce");
+ },
+
+ "preserves matching elements": function(span) {
+ var some = span.filter(function(d, i) { return i === 0; });
+ assert.isTrue(some[0][0] === span[0][0]);
+ assert.isTrue(some[1][0] === span[1][0]);
+ },
+ "removes non-matching elements": function(span) {
+ var some = d3.merge(span.filter(function(d, i) { return d & 1; }));
+ assert.equal(some.indexOf(span[0][0]), -1);
+ assert.equal(some.indexOf(span[1][0]), -1);
+ },
+ "preserves data": function(span) {
+ var some = span.filter(function(d, i) { return d & 1; });
+ assert.equal(some[0][0].node.__data__, 1);
+ assert.equal(some[1][0].node.__data__, 3);
+ },
+ "preserves grouping": function(span) {
+ var some = span.filter(function(d, i) { return d & 1; });
+ assert.equal(some.length, 2);
+ assert.equal(some[0].length, 1);
+ assert.equal(some[1].length, 1);
+ },
+ "preserves parent node": function(span) {
+ var some = span.filter(function(d, i) { return d & 1; });
+ assert.isTrue(some[0].parentNode === span[0].parentNode);
+ assert.isTrue(some[1].parentNode === span[1].parentNode);
+ },
+ "does not preserve index": function(span) {
+ var indexes = [];
+ span.filter(function(d, i) { return d & 1; }).each(function(d, i) { indexes.push(i); });
+ assert.deepEqual(indexes, [0, 0]);
+ },
+ "ignores null nodes": function() {
+ var span = d3.selectAll("span");
+ span[0][1] = null;
+ var some = span.filter(function(d, i) { return d & 1; });
+ assert.isTrue(some[0][0] === span[0][3]);
+ assert.equal(some.length, 1);
+ },
+ "can be specified as a selector": function(span) {
+ var some = span.filter(".foo");
+ assert.equal(some.length, 2);
+ assert.equal(some[0].length, 1);
+ assert.equal(some[1].length, 1);
+ },
+ "returns a new selection": function(span) {
+ assert.isFalse(span.filter(function() { return 1; }) === span);
+ },
+ "inherits the delay": function(t1) {
+ var t2 = t1.filter(function() { return 1; });
+ assert.equal(t2[0][0].delay, 100);
+ },
+ "inherits the duration": function(t1) {
+ var t2 = t1.filter(function() { return 1; });
+ assert.equal(t2[0][0].duration, 150);
+ },
+ "inherits easing": function(t1) {
+ // TODO how to test this?
+ },
+ "inherits the transition id": function(t1) {
+ var t2 = t1.filter(function() { return 1; });
+ assert.equal(t2.id, t1.id);
+ }
+};
View
3  test/core/transition-test.js
@@ -38,7 +38,8 @@ var suite = vows.describe("transition");
suite.addBatch({
"select": require("./transition-test-select"),
"selectAll": require("./transition-test-selectAll"),
- "transition": require("./transition-test-transition")
+ "transition": require("./transition-test-transition"),
+ "filter": require("./transition-test-filter")
});
// Content
View
4 test/layout/pack-test.js
@@ -33,7 +33,7 @@ suite.addBatch({
{y: 0.5084543199854831, x: 0.4682608366855136, value: 0.01, r: 0.016411496513964046, depth: 1},
{y: 0.5084543199854831, x: 0.7167659426883449, value: 2, r: 0.23209360948886723, depth: 1},
{y: 0.34256315498862167, x: 0.2832340573116551, value: 2, r: 0.23209360948886723, depth: 1},
- {y: 0.7254154893606051, x: 0.3852405506102519, value: 1, r: 0.16411496513964044, depth: 1}
+ {y: 0.7254154893606051, x: 0.38524055061025186, value: 1, r: 0.16411496513964044, depth: 1}
]);
assert.deepEqual(d3.layout.pack().sort(null).nodes({children: [
{value: 2},
@@ -45,7 +45,7 @@ suite.addBatch({
{y: 0.6274712284943809, x: 0.26624891409386664, value: 2, r: 0.23375108590613333, depth: 1},
{y: 0.6274712284943809, x: 0.7337510859061334, value: 2, r: 0.23375108590613333, depth: 1},
{y: 0.30406466355343187, x: 0.5, value: 1, r: 0.1652869779539461, depth: 1},
- {y: 0.3878967195987758, x: 0.3386645534068855, value: 0.01, r: 0.01652869779539461, depth: 1}
+ {y: 0.3878967195987758, x: 0.3386645534068854, value: 0.01, r: 0.01652869779539461, depth: 1}
]);
},
"can handle residual floating point error": function(pack) {
View
3  test/time/day-test.js
@@ -36,6 +36,9 @@ suite.addBatch({
assert.deepEqual(floor(utc(2011, 10, 06, 08)), local(2011, 10, 06));
assert.deepEqual(floor(utc(2011, 10, 06, 09)), local(2011, 10, 06));
assert.deepEqual(floor(utc(2011, 10, 06, 10)), local(2011, 10, 06));
+ },
+ "correctly handles years in the first century": function(floor) {
+ assert.deepEqual(floor(local(0011, 10, 06, 07)), local(0011, 10, 06));
}
},
"ceil": {
View
22 test/time/dayOfYear-test.js
@@ -0,0 +1,22 @@
+require("../env");
+
+var vows = require("vows"),
+ assert = require("assert"),
+ time = require("./time"),
+ local = time.local,
+ utc = time.utc;
+
+var suite = vows.describe("d3.time.dayOfYear");
+
+suite.addBatch({
+ "dayOfYear": {
+ topic: function() {
+ return d3.time.dayOfYear;
+ },
+ "no floating-point rounding error": function(dayOfYear) {
+ assert.equal(dayOfYear(new Date(2011, 4, 9)), 128);
+ }
+ }
+});
+
+suite.export(module);
View
16 test/time/format-test.js
@@ -317,14 +317,14 @@ suite.addBatch({
},
"parses numeric date": function(format) {
var p = format("%m/%d/%y").parse;
- assert.deepEqual(p("01/01/90"), local(2090, 0, 1));
- assert.deepEqual(p("02/03/91"), local(2091, 1, 3));
+ assert.deepEqual(p("01/01/90"), local(1990, 0, 1));
+ assert.deepEqual(p("02/03/91"), local(1991, 1, 3));
assert.isNull(p("03/10/2010"));
},
"parses locale date": function(format) {
var p = format("%x").parse;
- assert.deepEqual(p("01/01/90"), local(2090, 0, 1));
- assert.deepEqual(p("02/03/91"), local(2091, 1, 3));
+ assert.deepEqual(p("01/01/90"), local(1990, 0, 1));
+ assert.deepEqual(p("02/03/91"), local(1991, 1, 3));
assert.isNull(p("03/10/2010"));
},
"parses abbreviated month, date and year": function(format) {
@@ -398,14 +398,14 @@ suite.addBatch({
},
"parses numeric date": function(format) {
var p = format("%m/%d/%y").parse;
- assert.deepEqual(p("01/01/90"), utc(2090, 0, 1));
- assert.deepEqual(p("02/03/91"), utc(2091, 1, 3));
+ assert.deepEqual(p("01/01/90"), utc(1990, 0, 1));
+ assert.deepEqual(p("02/03/91"), utc(1991, 1, 3));
assert.isNull(p("03/10/2010"));
},
"parses locale date": function(format) {
var p = format("%x").parse;
- assert.deepEqual(p("01/01/90"), utc(2090, 0, 1));
- assert.deepEqual(p("02/03/91"), utc(2091, 1, 3));
+ assert.deepEqual(p("01/01/90"), utc(1990, 0, 1));
+ assert.deepEqual(p("02/03/91"), utc(1991, 1, 3));
assert.isNull(p("03/10/2010"));
},
"parses abbreviated month, date and year": function(format) {
View
8 test/time/hour-test.js
@@ -42,14 +42,14 @@ suite.addBatch({
assert.deepEqual(floor(utc(2011, 10, 06, 09, 01)), utc(2011, 10, 06, 09));
},
"NPT": {
- "observes 15-minute offset": time.zone("Asia/Kathmandu", function(floor) {
+ "observes 15-minute offset": time.zone(345, function(floor) {
assert.deepEqual(floor(local(2010, 11, 31, 23, 59, 59)), utc(2010, 11, 31, 17, 15));
assert.deepEqual(floor(local(2011, 00, 01, 00, 00, 00)), utc(2010, 11, 31, 18, 15));
assert.deepEqual(floor(local(2011, 00, 01, 00, 00, 01)), utc(2010, 11, 31, 18, 15));
})
},
"IST": {
- "observes 30-minute offset": time.zone("Asia/Calcutta", function(floor) {
+ "observes 30-minute offset": time.zone(330, function(floor) {
assert.deepEqual(floor(local(2010, 11, 31, 23, 59, 59)), utc(2010, 11, 31, 17, 30));
assert.deepEqual(floor(local(2011, 00, 01, 00, 00, 00)), utc(2010, 11, 31, 18, 30));
assert.deepEqual(floor(local(2011, 00, 01, 00, 00, 01)), utc(2010, 11, 31, 18, 30));
@@ -82,14 +82,14 @@ suite.addBatch({
assert.deepEqual(ceil(utc(2011, 10, 06, 09, 01)), utc(2011, 10, 06, 10));
},
"NPT": {
- "observes 15-minute offset": time.zone("Asia/Kathmandu", function(ceil) {
+ "observes 15-minute offset": time.zone(345, function(ceil) {
assert.deepEqual(ceil(local(2010, 11, 31, 23, 59, 59)), utc(2010, 11, 31, 18, 15));
assert.deepEqual(ceil(local(2011, 00, 01, 00, 00, 00)), utc(2010, 11, 31, 18, 15));
assert.deepEqual(ceil(local(2011, 00, 01, 00, 00, 01)), utc(2010, 11, 31, 19, 15));
})
},
"IST": {
- "observes 30-minute offset": time.zone("Asia/Calcutta", function(ceil) {
+ "observes 30-minute offset": time.zone(330, function(ceil) {
assert.deepEqual(ceil(local(2010, 11, 31, 23, 59, 59)), utc(2010, 11, 31, 18, 30));
assert.deepEqual(ceil(local(2011, 00, 01, 00, 00, 00)), utc(2010, 11, 31, 18, 30));
assert.deepEqual(ceil(local(2011, 00, 01, 00, 00, 01)), utc(2010, 11, 31, 19, 30));
View
20 test/time/hours-test.js
@@ -49,7 +49,7 @@ suite.addBatch({
]);
},
"NPT": {
- "observes 15-minute offset": tz("Asia/Kathmandu", function(range) {
+ "observes 15-minute offset": time.zone(345, function(range) {
assert.deepEqual(range(local(2011, 10, 7, 0), local(2011, 10, 7, 3)), [
utc(2011, 10, 6, 18, 15),
utc(2011, 10, 6, 19, 15),
@@ -58,7 +58,7 @@ suite.addBatch({
})
},
"IST": {
- "observes 30-minute offset": tz("Asia/Calcutta", function(range) {
+ "observes 30-minute offset": time.zone(330, function(range) {
assert.deepEqual(range(local(2011, 10, 7, 0), local(2011, 10, 7, 3)), [
utc(2011, 10, 6, 18, 30),
utc(2011, 10, 6, 19, 30),
@@ -109,20 +109,4 @@ suite.addBatch({
}
});
-function tz(tz, scope) {
- return function() {
- var o = process.env.TZ;
- try {
- process.env.TZ = tz;
- new Date(0).toString(); // invalidate node's dst cache
- new Date().toString();
- scope.apply(this, arguments);
- } finally {
- process.env.TZ = o;
- new Date(0).toString(); // invalidate node's dst cache
- new Date().toString();
- }
- };
-}
-
suite.export(module);
View
3  test/time/month-test.js
@@ -30,6 +30,9 @@ suite.addBatch({
},
"observes the end of the daylight savings time": function(floor) {
assert.deepEqual(floor(local(2011, 10, 06, 01)), local(2011, 10, 01));
+ },
+ "correctly handles years in the first century": function(floor) {
+ assert.deepEqual(floor(local(0011, 10, 06, 07)), local(0011, 10, 01));
}
},
"ceil": {
View
19 test/time/time.js
@@ -1,7 +1,9 @@
+var offset = 0;
+
exports.local = function(year, month, day, hours, minutes, seconds, milliseconds) {
var date = new Date();
date.setFullYear(year, month, day);
- date.setHours(hours || 0, minutes || 0, seconds || 0, milliseconds || 0);
+ date.setHours(hours || 0, offset + (minutes || 0), seconds || 0, milliseconds || 0);
return date;
};
@@ -12,18 +14,17 @@ exports.utc = function(year, month, day, hours, minutes, seconds, milliseconds)
return date;
};
-exports.zone = function(tz, scope) {
+exports.zone = function(tzOffset, scope) {
return function() {
- var o = process.env.TZ;
+ var o = Date.prototype.getTimezoneOffset;
try {
- process.env.TZ = tz;
- new Date(0).toString(); // invalidate node's dst cache
- new Date().toString();
+ // Note: assumes the dates are not in DST.
+ offset = -tzOffset - new Date(0).getTimezoneOffset();
+ Date.prototype.getTimezoneOffset = function() { return offset; };
scope.apply(this, arguments);
} finally {
- process.env.TZ = o;
- new Date(0).toString(); // invalidate node's dst cache
- new Date().toString();
+ offset = 0;
+ Date.prototype.getTimezoneOffset = o;
}
};
};
View
3  test/time/week-test.js
@@ -33,6 +33,9 @@ suite.addBatch({
},
"observes the end of the daylight savings time": function(floor) {
assert.deepEqual(floor(local(2011, 10, 06, 01)), local(2011, 10, 06));
+ },
+ "correctly handles years in the first century": function(floor) {
+ assert.deepEqual(floor(local(0011, 10, 06, 07)), local(0011, 10, 01));
}
},
"ceil": {
View
3  test/time/year-test.js
@@ -21,6 +21,9 @@ suite.addBatch({
assert.deepEqual(floor(local(2010, 11, 31, 23, 59, 59)), local(2010, 00, 01));
assert.deepEqual(floor(local(2011, 00, 01, 00, 00, 00)), local(2011, 00, 01));
assert.deepEqual(floor(local(2011, 00, 01, 00, 00, 01)), local(2011, 00, 01));
+ },
+ "correctly handles years in the first century": function(floor) {
+ assert.deepEqual(floor(local(0011, 10, 06, 07)), local(0011, 00, 01));
}
},
"ceil": {
Please sign in to comment.
Something went wrong with that request. Please try again.