Commit 92c9d9d8 authored by Mike Bostock's avatar Mike Bostock
Browse files

Merge branch '3.4.5'

parents fa55eead 378526d9
{ {
"name": "d3", "name": "d3",
"version": "3.4.4", "version": "3.4.5",
"main": "d3.js", "main": "d3.js",
"scripts": [ "scripts": [
"d3.js" "d3.js"
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
"animation", "animation",
"canvas" "canvas"
], ],
"version": "3.4.4", "version": "3.4.5",
"main": "d3.js", "main": "d3.js",
"scripts": [ "scripts": [
"d3.js" "d3.js"
......
!function() { !function() {
var d3 = { var d3 = {
version: "3.4.4" version: "3.4.5"
}; };
if (!Date.now) Date.now = function() { if (!Date.now) Date.now = function() {
return +new Date(); return +new Date();
...@@ -3224,7 +3224,6 @@ ...@@ -3224,7 +3224,6 @@
clip.lineEnd = ringEnd; clip.lineEnd = ringEnd;
segments = []; segments = [];
polygon = []; polygon = [];
listener.polygonStart();
}, },
polygonEnd: function() { polygonEnd: function() {
clip.point = point; clip.point = point;
...@@ -3233,13 +3232,15 @@ ...@@ -3233,13 +3232,15 @@
segments = d3.merge(segments); segments = d3.merge(segments);
var clipStartInside = d3_geo_pointInPolygon(rotatedClipStart, polygon); var clipStartInside = d3_geo_pointInPolygon(rotatedClipStart, polygon);
if (segments.length) { if (segments.length) {
if (!polygonStarted) listener.polygonStart(), polygonStarted = true;
d3_geo_clipPolygon(segments, d3_geo_clipSort, clipStartInside, interpolate, listener); d3_geo_clipPolygon(segments, d3_geo_clipSort, clipStartInside, interpolate, listener);
} else if (clipStartInside) { } else if (clipStartInside) {
if (!polygonStarted) listener.polygonStart(), polygonStarted = true;
listener.lineStart(); listener.lineStart();
interpolate(null, null, 1, listener); interpolate(null, null, 1, listener);
listener.lineEnd(); listener.lineEnd();
} }
listener.polygonEnd(); if (polygonStarted) listener.polygonEnd(), polygonStarted = false;
segments = polygon = null; segments = polygon = null;
}, },
sphere: function() { sphere: function() {
...@@ -3267,7 +3268,7 @@ ...@@ -3267,7 +3268,7 @@
line.lineEnd(); line.lineEnd();
} }
var segments; var segments;
var buffer = d3_geo_clipBufferListener(), ringListener = clipLine(buffer), polygon, ring; var buffer = d3_geo_clipBufferListener(), ringListener = clipLine(buffer), polygonStarted = false, polygon, ring;
function pointRing(λ, φ) { function pointRing(λ, φ) {
ring.push([ λ, φ ]); ring.push([ λ, φ ]);
var point = rotate(λ, φ); var point = rotate(λ, φ);
...@@ -3288,9 +3289,12 @@ ...@@ -3288,9 +3289,12 @@
if (clean & 1) { if (clean & 1) {
segment = ringSegments[0]; segment = ringSegments[0];
var n = segment.length - 1, i = -1, point; var n = segment.length - 1, i = -1, point;
listener.lineStart(); if (n > 0) {
while (++i < n) listener.point((point = segment[i])[0], point[1]); if (!polygonStarted) listener.polygonStart(), polygonStarted = true;
listener.lineEnd(); listener.lineStart();
while (++i < n) listener.point((point = segment[i])[0], point[1]);
listener.lineEnd();
}
return; return;
} }
if (n > 1 && clean & 2) ringSegments.push(ringSegments.pop().concat(ringSegments.shift())); if (n > 1 && clean & 2) ringSegments.push(ringSegments.pop().concat(ringSegments.shift()));
...@@ -5617,71 +5621,38 @@ ...@@ -5617,71 +5621,38 @@
} }
d3.interpolateString = d3_interpolateString; d3.interpolateString = d3_interpolateString;
function d3_interpolateString(a, b) { function d3_interpolateString(a, b) {
var m, i, j, s0 = 0, s1 = 0, s = [], q = [], n, o; var bi = d3_interpolate_numberA.lastIndex = d3_interpolate_numberB.lastIndex = 0, am, bm, bs, i = -1, s = [], q = [];
a = a + "", b = b + ""; a = a + "", b = b + "";
d3_interpolate_number.lastIndex = 0; while ((am = d3_interpolate_numberA.exec(a)) && (bm = d3_interpolate_numberB.exec(b))) {
for (i = 0; m = d3_interpolate_number.exec(b); ++i) { if ((bs = bm.index) > bi) {
if (m.index) s.push(b.substring(s0, s1 = m.index)); bs = b.substring(bi, bs);
q.push({ if (s[i]) s[i] += bs; else s[++i] = bs;
i: s.length,
x: m[0]
});
s.push(null);
s0 = d3_interpolate_number.lastIndex;
}
if (s0 < b.length) s.push(b.substring(s0));
for (i = 0, n = q.length; (m = d3_interpolate_number.exec(a)) && i < n; ++i) {
o = q[i];
if (o.x == m[0]) {
if (o.i) {
if (s[o.i + 1] == null) {
s[o.i - 1] += o.x;
s.splice(o.i, 1);
for (j = i + 1; j < n; ++j) q[j].i--;
} else {
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;
}
} else {
if (s[o.i + 1] == null) {
s[o.i] = o.x;
} else {
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--;
}
}
q.splice(i, 1);
n--;
i--;
} else {
o.x = d3_interpolateNumber(parseFloat(m[0]), parseFloat(o.x));
} }
} if ((am = am[0]) === (bm = bm[0])) {
while (i < n) { if (s[i]) s[i] += bm; else s[++i] = bm;
o = q.pop();
if (s[o.i + 1] == null) {
s[o.i] = o.x;
} else { } else {
s[o.i] = o.x + s[o.i + 1]; s[++i] = null;
s.splice(o.i + 1, 1); q.push({
i: i,
x: d3_interpolateNumber(am, bm)
});
} }
n--; bi = d3_interpolate_numberB.lastIndex;
} }
if (s.length === 1) { if (bi < b.length) {
return s[0] == null ? (o = q[0].x, function(t) { bs = b.substring(bi);
return o(t) + ""; if (s[i]) s[i] += bs; else s[++i] = bs;
}) : function() {
return b;
};
} }
return function(t) { return s.length < 2 ? q[0] ? (b = q[0].x, function(t) {
for (i = 0; i < n; ++i) s[(o = q[i]).i] = o.x(t); return b(t) + "";
}) : function() {
return b;
} : (b = q.length, function(t) {
for (var i = 0, o; i < b; ++i) s[(o = q[i]).i] = o.x(t);
return s.join(""); return s.join("");
}; });
} }
var d3_interpolate_number = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g; var d3_interpolate_numberA = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g, d3_interpolate_numberB = new RegExp(d3_interpolate_numberA.source, "g");
d3.interpolate = d3_interpolate; d3.interpolate = d3_interpolate;
function d3_interpolate(a, b) { function d3_interpolate(a, b) {
var i = d3.interpolators.length, f; var i = d3.interpolators.length, f;
......
This source diff could not be displayed because it is too large. You can view the blob instead.
{ {
"name": "d3", "name": "d3",
"version": "3.4.4", "version": "3.4.5",
"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",
......
...@@ -18,7 +18,6 @@ function d3_geo_clip(pointVisible, clipLine, interpolate, clipStart) { ...@@ -18,7 +18,6 @@ function d3_geo_clip(pointVisible, clipLine, interpolate, clipStart) {
clip.lineEnd = ringEnd; clip.lineEnd = ringEnd;
segments = []; segments = [];
polygon = []; polygon = [];
listener.polygonStart();
}, },
polygonEnd: function() { polygonEnd: function() {
clip.point = point; clip.point = point;
...@@ -28,13 +27,15 @@ function d3_geo_clip(pointVisible, clipLine, interpolate, clipStart) { ...@@ -28,13 +27,15 @@ function d3_geo_clip(pointVisible, clipLine, interpolate, clipStart) {
segments = d3.merge(segments); segments = d3.merge(segments);
var clipStartInside = d3_geo_pointInPolygon(rotatedClipStart, polygon); var clipStartInside = d3_geo_pointInPolygon(rotatedClipStart, polygon);
if (segments.length) { if (segments.length) {
if (!polygonStarted) listener.polygonStart(), polygonStarted = true;
d3_geo_clipPolygon(segments, d3_geo_clipSort, clipStartInside, interpolate, listener); d3_geo_clipPolygon(segments, d3_geo_clipSort, clipStartInside, interpolate, listener);
} else if (clipStartInside) { } else if (clipStartInside) {
if (!polygonStarted) listener.polygonStart(), polygonStarted = true;
listener.lineStart(); listener.lineStart();
interpolate(null, null, 1, listener); interpolate(null, null, 1, listener);
listener.lineEnd(); listener.lineEnd();
} }
listener.polygonEnd(); if (polygonStarted) listener.polygonEnd(), polygonStarted = false;
segments = polygon = null; segments = polygon = null;
}, },
sphere: function() { sphere: function() {
...@@ -61,6 +62,7 @@ function d3_geo_clip(pointVisible, clipLine, interpolate, clipStart) { ...@@ -61,6 +62,7 @@ function d3_geo_clip(pointVisible, clipLine, interpolate, clipStart) {
var buffer = d3_geo_clipBufferListener(), var buffer = d3_geo_clipBufferListener(),
ringListener = clipLine(buffer), ringListener = clipLine(buffer),
polygonStarted = false,
polygon, polygon,
ring; ring;
...@@ -96,9 +98,12 @@ function d3_geo_clip(pointVisible, clipLine, interpolate, clipStart) { ...@@ -96,9 +98,12 @@ function d3_geo_clip(pointVisible, clipLine, interpolate, clipStart) {
var n = segment.length - 1, var n = segment.length - 1,
i = -1, i = -1,
point; point;
listener.lineStart(); if (n > 0) {
while (++i < n) listener.point((point = segment[i])[0], point[1]); if (!polygonStarted) listener.polygonStart(), polygonStarted = true;
listener.lineEnd(); listener.lineStart();
while (++i < n) listener.point((point = segment[i])[0], point[1]);
listener.lineEnd();
}
return; return;
} }
......
...@@ -3,86 +3,52 @@ import "number"; ...@@ -3,86 +3,52 @@ import "number";
d3.interpolateString = d3_interpolateString; d3.interpolateString = d3_interpolateString;
function d3_interpolateString(a, b) { function d3_interpolateString(a, b) {
var m, // current match var bi = d3_interpolate_numberA.lastIndex = d3_interpolate_numberB.lastIndex = 0, // scan index for next number in b
i, // current index am, // current match in a
j, // current index (for coalescing) bm, // current match in b
s0 = 0, // start index of current string prefix bs, // string preceding current number in b, if any
s1 = 0, // end index of current string prefix i = -1, // index in s
s = [], // string constants and placeholders s = [], // string constants and placeholders
q = [], // number interpolators q = []; // number interpolators
n, // q.length
o;
// Coerce inputs to strings. // Coerce inputs to strings.
a = a + "", b = b + ""; a = a + "", b = b + "";
// Reset our regular expression! // Interpolate pairs of numbers in a & b.
d3_interpolate_number.lastIndex = 0; while ((am = d3_interpolate_numberA.exec(a))
&& (bm = d3_interpolate_numberB.exec(b))) {
// Find all numbers in b. if ((bs = bm.index) > bi) { // a string precedes the next number in b
for (i = 0; m = d3_interpolate_number.exec(b); ++i) { bs = b.substring(bi, bs);
if (m.index) s.push(b.substring(s0, s1 = m.index)); if (s[i]) s[i] += bs; // coalesce with previous string
q.push({i: s.length, x: m[0]}); else s[++i] = bs;
s.push(null);
s0 = d3_interpolate_number.lastIndex;
}
if (s0 < b.length) s.push(b.substring(s0));
// 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 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 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;
}
} 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 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--;
}
}
q.splice(i, 1);
n--;
i--;
} else {
o.x = d3_interpolateNumber(parseFloat(m[0]), parseFloat(o.x));
} }
} if ((am = am[0]) === (bm = bm[0])) { // numbers in a & b match
if (s[i]) s[i] += bm; // coalesce with previous string
// Remove any numbers in b not found in a. else s[++i] = bm;
while (i < n) { } else { // interpolate non-matching numbers
o = q.pop(); s[++i] = null;
if (s[o.i + 1] == null) { // This match is followed by another number. q.push({i: i, x: d3_interpolateNumber(am, bm)});
s[o.i] = o.x;
} 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);
} }
n--; bi = d3_interpolate_numberB.lastIndex;
} }
// Special optimization for only a single match. // Add remains of b.
if (s.length === 1) { if (bi < b.length) {
return s[0] == null bs = b.substring(bi);
? (o = q[0].x, function(t) { return o(t) + ""; }) if (s[i]) s[i] += bs; // coalesce with previous string
: function() { return b; }; else s[++i] = bs;
} }
// Special optimization for only a single match.
// Otherwise, interpolate each of the numbers and rejoin the string. // Otherwise, interpolate each of the numbers and rejoin the string.
return function(t) { return s.length < 2
for (i = 0; i < n; ++i) s[(o = q[i]).i] = o.x(t); ? (q[0] ? (b = q[0].x, function(t) { return b(t) + ""; })
return s.join(""); : function() { return b; })
}; : (b = q.length, function(t) {
for (var i = 0, o; i < b; ++i) s[(o = q[i]).i] = o.x(t);
return s.join("");
});
} }
var d3_interpolate_number = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g; var d3_interpolate_numberA = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g,
d3_interpolate_numberB = new RegExp(d3_interpolate_numberA.source, "g");
!function(){ !function(){
var d3 = {version: "3.4.4"}; // semver var d3 = {version: "3.4.5"}; // semver
...@@ -386,6 +386,10 @@ suite.addBatch({ ...@@ -386,6 +386,10 @@ suite.addBatch({
"renders a small circle of 120°": function(p) { "renders a small circle of 120°": function(p) {
p(_.geo.circle().angle(120)()); p(_.geo.circle().angle(120)());
assert.deepEqual(testContext.buffer().filter(function(d) { return d.type === "moveTo"; }), [{type: "moveTo", x: 87, y: 700}]); assert.deepEqual(testContext.buffer().filter(function(d) { return d.type === "moveTo"; }), [{type: "moveTo", x: 87, y: 700}]);
},
"degenerate polygon": function(p) {
p({type: "Polygon", coordinates: [[[0, 0], [0, 0], [0, 0], [0, 0]]]});
assert.deepEqual(testContext.buffer(), []);
} }
}, },
......
#!/usr/bin/env node
var d3 = require("../../");
var n = +process.argv[2],
p = +process.argv[3],
k = +process.argv[4];
var formatTime = d3.format(".3s"),
formatNumber = d3.format(",.0f");
// Returns the time required to construct a string interpolator
// for two strings with n numbers, separated by commas,
// with probability p that the corresponding numbers in a & b are different.
// The test is run k times, and the mean result is returned.
function observeConstruction(n, p, k) {
if (arguments.length < 3) k = 1;
for (var i = 0, sum = 0; i < k; ++i) {
var a = d3.range(n).map(function() { return Math.random() * 1000; }),
b = d3.range(n).map(function(i) { return Math.random() < p ? Math.random() * 1000 : a[i]; });
var start = process.hrtime();
d3.interpolateString(a, b);
var elapsed = process.hrtime(start);
sum += elapsed[0] + elapsed[1] / 1e9;
process.stdout.write(".");
}
console.log("");
return sum / k;
}
console.log(formatTime(observeConstruction(n, p, k)) + "s\tn=" + formatNumber(n) + "\tp=" + p);
...@@ -36,6 +36,16 @@ suite.addBatch({ ...@@ -36,6 +36,16 @@ suite.addBatch({
assert.strictEqual(interpolate("-1.e-3", "-1.e-4")(.5), "-0.00055"); assert.strictEqual(interpolate("-1.e-3", "-1.e-4")(.5), "-0.00055");
assert.strictEqual(interpolate("+1.e-3", "+1.e-4")(.5), "0.00055"); assert.strictEqual(interpolate("+1.e-3", "+1.e-4")(.5), "0.00055");
assert.strictEqual(interpolate(".1e-2", ".1e-3")(.5), "0.00055"); assert.strictEqual(interpolate(".1e-2", ".1e-3")(.5), "0.00055");
},
"with no numbers, returns the target string": function(interpolate) {
assert.strictEqual(interpolate("foo", "bar")(.5), "bar");
assert.strictEqual(interpolate("foo", "")(.5), "");
assert.strictEqual(interpolate("", "bar")(.5), "bar");
assert.strictEqual(interpolate("", "")(.5), "");
},
"with two numerically-equivalent numbers, returns the default format": function(interpolate) {
assert.strictEqual(interpolate("top: 1000px;", "top: 1e3px;")(.5), "top: 1000px;");
assert.strictEqual(interpolate("top: 1e3px;", "top: 1000px;")(.5), "top: 1000px;");
} }
} }
}); });
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment