Commit fa55eead authored by Mike Bostock's avatar Mike Bostock
Browse files

Merge branch '3.4.4'

parents adeaf201 994235b3
{ {
"name": "d3", "name": "d3",
"version": "3.4.3", "version": "3.4.4",
"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.3", "version": "3.4.4",
"main": "d3.js", "main": "d3.js",
"scripts": [ "scripts": [
"d3.js" "d3.js"
......
This diff is collapsed.
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.3", "version": "3.4.4",
"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",
......
d3.ascending = function(a, b) { d3.ascending = d3_ascending;
function d3_ascending(a, b) {
return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN; return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
}; }
d3.bisector = function(f) { import "ascending";
function d3_bisector(compare) {
return { return {
left: function(a, x, lo, hi) { left: function(a, x, lo, hi) {
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 (compare(a[mid], x) < 0) lo = mid + 1;
else hi = mid; else hi = mid;
} }
return lo; return lo;
...@@ -15,14 +17,20 @@ d3.bisector = function(f) { ...@@ -15,14 +17,20 @@ d3.bisector = function(f) {
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 (compare(a[mid], x) > 0) hi = mid;
else lo = mid + 1; else lo = mid + 1;
} }
return lo; return lo;
} }
}; };
}; }
var d3_bisector = d3.bisector(function(d) { return d; }); var d3_bisect = d3_bisector(d3_ascending);
d3.bisectLeft = d3_bisector.left; d3.bisectLeft = d3_bisect.left;
d3.bisect = d3.bisectRight = d3_bisector.right; d3.bisect = d3.bisectRight = d3_bisect.right;
d3.bisector = function(f) {
return d3_bisector(f.length === 1
? function(d, x) { return d3_ascending(f(d), x); }
: f);
};
...@@ -5,5 +5,5 @@ import "quantile"; ...@@ -5,5 +5,5 @@ import "quantile";
d3.median = function(array, f) { d3.median = function(array, f) {
if (arguments.length > 1) array = array.map(f); if (arguments.length > 1) array = array.map(f);
array = array.filter(d3_number); array = array.filter(d3_number);
return array.length ? d3.quantile(array.sort(d3.ascending), .5) : undefined; return array.length ? d3.quantile(array.sort(d3_ascending), .5) : undefined;
}; };
...@@ -9,60 +9,60 @@ import "behavior"; ...@@ -9,60 +9,60 @@ import "behavior";
d3.behavior.drag = function() { d3.behavior.drag = function() {
var event = d3_eventDispatch(drag, "drag", "dragstart", "dragend"), var event = d3_eventDispatch(drag, "drag", "dragstart", "dragend"),
origin = null, origin = null,
mousedown = dragstart(d3_noop, d3.mouse, "mousemove", "mouseup"), mousedown = dragstart(d3_noop, d3.mouse, d3_behavior_dragMouseSubject, "mousemove", "mouseup"),
touchstart = dragstart(touchid, touchposition, "touchmove", "touchend"); touchstart = dragstart(d3_behavior_dragTouchId, d3.touch, d3_behavior_dragTouchSubject, "touchmove", "touchend");
function drag() { function drag() {
this.on("mousedown.drag", mousedown) this.on("mousedown.drag", mousedown)
.on("touchstart.drag", touchstart); .on("touchstart.drag", touchstart);
} }
function touchid() { function dragstart(id, position, subject, move, end) {
return d3.event.changedTouches[0].identifier;
}
function touchposition(parent, id) {
return d3.touches(parent).filter(function(p) { return p.identifier === id; })[0];
}
function dragstart(id, position, move, end) {
return function() { return function() {
var target = this, var that = this,
parent = target.parentNode, target = d3.event.target,
event_ = event.of(target, arguments), parent = that.parentNode,
eventTarget = d3.event.target, dispatch = event.of(that, arguments),
eventId = id(),
drag = eventId == null ? "drag" : "drag-" + eventId,
origin_ = position(parent, eventId),
dragged = 0, dragged = 0,
offset, dragId = id(),
w = d3.select(d3_window).on(move + "." + drag, moved).on(end + "." + drag, ended), dragName = ".drag" + (dragId == null ? "" : "-" + dragId),
dragRestore = d3_event_dragSuppress(); dragOffset,
dragSubject = d3.select(subject()).on(move + dragName, moved).on(end + dragName, ended),
dragRestore = d3_event_dragSuppress(),
position0 = position(parent, dragId);
if (origin) { if (origin) {
offset = origin.apply(target, arguments); dragOffset = origin.apply(that, arguments);
offset = [offset.x - origin_[0], offset.y - origin_[1]]; dragOffset = [dragOffset.x - position0[0], dragOffset.y - position0[1]];
} else { } else {
offset = [0, 0]; dragOffset = [0, 0];
} }
event_({type: "dragstart"}); dispatch({type: "dragstart"});
function moved() { function moved() {
var p = position(parent, eventId), var position1 = position(parent, dragId), dx, dy;
dx = p[0] - origin_[0], if (!position1) return; // this touch didn’t move
dy = p[1] - origin_[1];
dx = position1[0] - position0[0];
dy = position1[1] - position0[1];
dragged |= dx | dy; dragged |= dx | dy;
origin_ = p; position0 = position1;
event_({type: "drag", x: p[0] + offset[0], y: p[1] + offset[1], dx: dx, dy: dy}); dispatch({
type: "drag",
x: position1[0] + dragOffset[0],
y: position1[1] + dragOffset[1],
dx: dx,
dy: dy
});
} }
function ended() { function ended() {
w.on(move + "." + drag, null).on(end + "." + drag, null); if (!position(parent, dragId)) return; // this touch didn’t end
dragRestore(dragged && d3.event.target === eventTarget); dragSubject.on(move + dragName, null).on(end + dragName, null);
event_({type: "dragend"}); dragRestore(dragged && d3.event.target === target);
dispatch({type: "dragend"});
} }
}; };
} }
...@@ -75,3 +75,21 @@ d3.behavior.drag = function() { ...@@ -75,3 +75,21 @@ d3.behavior.drag = function() {
return d3.rebind(drag, event, "on"); return d3.rebind(drag, event, "on");
}; };
// While it is possible to receive a touchstart event with more than one changed
// touch, the event is only shared by touches on the same target; for new
// touches targetting different elements, multiple touchstart events are
// received even when the touches start simultaneously. Since multiple touches
// cannot move the same target to different locations concurrently without
// tearing the fabric of spacetime, we allow the first touch to win.
function d3_behavior_dragTouchId() {
return d3.event.changedTouches[0].identifier;
}
function d3_behavior_dragTouchSubject() {
return d3.event.target;
}
function d3_behavior_dragMouseSubject() {
return d3_window;
}
...@@ -36,13 +36,13 @@ d3.behavior.zoom = function() { ...@@ -36,13 +36,13 @@ d3.behavior.zoom = function() {
zoom.event = function(g) { zoom.event = function(g) {
g.each(function() { g.each(function() {
var event_ = event.of(this, arguments), var dispatch = event.of(this, arguments),
view1 = view; view1 = view;
if (d3_transitionInheritId) { if (d3_transitionInheritId) {
d3.select(this).transition() d3.select(this).transition()
.each("start.zoom", function() { .each("start.zoom", function() {
view = this.__chart__ || {x: 0, y: 0, k: 1}; // pre-transition state view = this.__chart__ || {x: 0, y: 0, k: 1}; // pre-transition state
zoomstarted(event_); zoomstarted(dispatch);
}) })
.tween("zoom:zoom", function() { .tween("zoom:zoom", function() {
var dx = size[0], var dx = size[0],
...@@ -56,17 +56,17 @@ d3.behavior.zoom = function() { ...@@ -56,17 +56,17 @@ d3.behavior.zoom = function() {
return function(t) { return function(t) {
var l = i(t), k = dx / l[2]; var l = i(t), k = dx / l[2];
this.__chart__ = view = {x: cx - l[0] * k, y: cy - l[1] * k, k: k}; this.__chart__ = view = {x: cx - l[0] * k, y: cy - l[1] * k, k: k};
zoomed(event_); zoomed(dispatch);
}; };
}) })
.each("end.zoom", function() { .each("end.zoom", function() {
zoomended(event_); zoomended(dispatch);
}); });
} else { } else {
this.__chart__ = view; this.__chart__ = view;
zoomstarted(event_); zoomstarted(dispatch);
zoomed(event_); zoomed(dispatch);
zoomended(event_); zoomended(dispatch);
} }
}); });
} }
...@@ -142,65 +142,65 @@ d3.behavior.zoom = function() { ...@@ -142,65 +142,65 @@ d3.behavior.zoom = function() {
if (y1) y1.domain(y0.range().map(function(y) { return (y - view.y) / view.k; }).map(y0.invert)); if (y1) y1.domain(y0.range().map(function(y) { return (y - view.y) / view.k; }).map(y0.invert));
} }
function zoomstarted(event) { function zoomstarted(dispatch) {
event({type: "zoomstart"}); dispatch({type: "zoomstart"});
} }
function zoomed(event) { function zoomed(dispatch) {
rescale(); rescale();
event({type: "zoom", scale: view.k, translate: [view.x, view.y]}); dispatch({type: "zoom", scale: view.k, translate: [view.x, view.y]});
} }
function zoomended(event) { function zoomended(dispatch) {
event({type: "zoomend"}); dispatch({type: "zoomend"});
} }
function mousedowned() { function mousedowned() {
var target = this, var that = this,
event_ = event.of(target, arguments), target = d3.event.target,
eventTarget = d3.event.target, dispatch = event.of(that, arguments),
dragged = 0, dragged = 0,
w = d3.select(d3_window).on(mousemove, moved).on(mouseup, ended), subject = d3.select(d3_window).on(mousemove, moved).on(mouseup, ended),
l = location(d3.mouse(target)), location0 = location(d3.mouse(that)),
dragRestore = d3_event_dragSuppress(); dragRestore = d3_event_dragSuppress();
d3_selection_interrupt.call(target); d3_selection_interrupt.call(that);
zoomstarted(event_); zoomstarted(dispatch);
function moved() { function moved() {
dragged = 1; dragged = 1;
translateTo(d3.mouse(target), l); translateTo(d3.mouse(that), location0);
zoomed(event_); zoomed(dispatch);
} }
function ended() { function ended() {
w.on(mousemove, d3_window === target ? mousewheelreset : null).on(mouseup, null); subject.on(mousemove, d3_window === that ? mousewheelreset : null).on(mouseup, null);
dragRestore(dragged && d3.event.target === eventTarget); dragRestore(dragged && d3.event.target === target);
zoomended(event_); zoomended(dispatch);
} }
} }
// These closures persist for as long as at least one touch is active. // These closures persist for as long as at least one touch is active.
function touchstarted() { function touchstarted() {
var target = this, var that = this,
event_ = event.of(target, arguments), dispatch = event.of(that, arguments),
locations0 = {}, // touchstart locations locations0 = {}, // touchstart locations
distance0 = 0, // distance² between initial touches distance0 = 0, // distance² between initial touches
scale0, // scale when we started touching scale0, // scale when we started touching
eventId = d3.event.changedTouches[0].identifier, zoomName = ".zoom-" + d3.event.changedTouches[0].identifier,
touchmove = "touchmove.zoom-" + eventId, touchmove = "touchmove" + zoomName,
touchend = "touchend.zoom-" + eventId, touchend = "touchend" + zoomName,
w = d3.select(d3_window).on(touchmove, moved).on(touchend, ended), target = d3.select(d3.event.target).on(touchmove, moved).on(touchend, ended),
t = d3.select(target).on(mousedown, null).on(touchstart, started), // prevent duplicate events subject = d3.select(that).on(mousedown, null).on(touchstart, started), // prevent duplicate events
dragRestore = d3_event_dragSuppress(); dragRestore = d3_event_dragSuppress();
d3_selection_interrupt.call(target); d3_selection_interrupt.call(that);
started(); started();
zoomstarted(event_); zoomstarted(dispatch);
// Updates locations of any touches in locations0. // Updates locations of any touches in locations0.
function relocate() { function relocate() {
var touches = d3.touches(target); var touches = d3.touches(that);
scale0 = view.k; scale0 = view.k;
touches.forEach(function(t) { touches.forEach(function(t) {
if (t.identifier in locations0) locations0[t.identifier] = location(t); if (t.identifier in locations0) locations0[t.identifier] = location(t);
...@@ -225,7 +225,7 @@ d3.behavior.zoom = function() { ...@@ -225,7 +225,7 @@ d3.behavior.zoom = function() {
scaleTo(view.k * 2); scaleTo(view.k * 2);
translateTo(p, l); translateTo(p, l);
d3_eventPreventDefault(); d3_eventPreventDefault();
zoomed(event_); zoomed(dispatch);
} }
touchtime = now; touchtime = now;
} else if (touches.length > 1) { } else if (touches.length > 1) {
...@@ -236,7 +236,7 @@ d3.behavior.zoom = function() { ...@@ -236,7 +236,7 @@ d3.behavior.zoom = function() {
} }
function moved() { function moved() {
var touches = d3.touches(target), var touches = d3.touches(that),
p0, l0, p0, l0,
p1, l1; p1, l1;
for (var i = 0, n = touches.length; i < n; ++i, l1 = null) { for (var i = 0, n = touches.length; i < n; ++i, l1 = null) {
...@@ -257,7 +257,7 @@ d3.behavior.zoom = function() { ...@@ -257,7 +257,7 @@ d3.behavior.zoom = function() {
touchtime = null; touchtime = null;
translateTo(p0, l0); translateTo(p0, l0);
zoomed(event_); zoomed(dispatch);
} }
function ended() { function ended() {
...@@ -275,24 +275,24 @@ d3.behavior.zoom = function() { ...@@ -275,24 +275,24 @@ d3.behavior.zoom = function() {
} }
} }
// Otherwise, remove touchmove and touchend listeners. // Otherwise, remove touchmove and touchend listeners.
w.on(touchmove, null).on(touchend, null); target.on(zoomName, null);
t.on(mousedown, mousedowned).on(touchstart, touchstarted); subject.on(mousedown, mousedowned).on(touchstart, touchstarted);
dragRestore(); dragRestore();
zoomended(event_); zoomended(dispatch);
} }
} }
function mousewheeled() { function mousewheeled() {
var event_ = event.of(this, arguments); var dispatch = event.of(this, arguments);
if (mousewheelTimer) clearTimeout(mousewheelTimer); if (mousewheelTimer) clearTimeout(mousewheelTimer);
else d3_selection_interrupt.call(this), zoomstarted(event_); else d3_selection_interrupt.call(this), zoomstarted(dispatch);
mousewheelTimer = setTimeout(function() { mousewheelTimer = null; zoomended(event_); }, 50); mousewheelTimer = setTimeout(function() { mousewheelTimer = null; zoomended(dispatch); }, 50);
d3_eventPreventDefault(); d3_eventPreventDefault();
var point = center || d3.mouse(this); var point = center || d3.mouse(this);
if (!translate0) translate0 = location(point); if (!translate0) translate0 = location(point);
scaleTo(Math.pow(2, d3_behavior_zoomDelta() * .002) * view.k); scaleTo(Math.pow(2, d3_behavior_zoomDelta() * .002) * view.k);
translateTo(point, translate0); translateTo(point, translate0);
zoomed(event_); zoomed(dispatch);
} }
function mousewheelreset() { function mousewheelreset() {
...@@ -300,15 +300,15 @@ d3.behavior.zoom = function() { ...@@ -300,15 +300,15 @@ d3.behavior.zoom = function() {
} }
function dblclicked() { function dblclicked() {
var event_ = event.of(this, arguments), var dispatch = event.of(this, arguments),
p = d3.mouse(this), p = d3.mouse(this),
l = location(p), l = location(p),
k = Math.log(view.k) / Math.LN2; k = Math.log(view.k) / Math.LN2;
zoomstarted(event_); zoomstarted(dispatch);
scaleTo(Math.pow(2, d3.event.shiftKey ? Math.ceil(k) - 1 : Math.floor(k) + 1)); scaleTo(Math.pow(2, d3.event.shiftKey ? Math.ceil(k) - 1 : Math.floor(k) + 1));
translateTo(p, l); translateTo(p, l);
zoomed(event_); zoomed(dispatch);
zoomended(event_); zoomended(dispatch);
} }
return d3.rebind(zoom, event, "on"); return d3.rebind(zoom, event, "on");
......
...@@ -69,7 +69,7 @@ function d3_rgb_parse(format, rgb, hsl) { ...@@ -69,7 +69,7 @@ function d3_rgb_parse(format, rgb, hsl) {
b = 0, // blue channel; int in [0, 255] b = 0, // blue channel; int in [0, 255]
m1, // CSS color specification match m1, // CSS color specification match
m2, // CSS color specification type (e.g., rgb) m2, // CSS color specification type (e.g., rgb)
name; color;
/* Handle hsl, rgb. */ /* Handle hsl, rgb. */
m1 = /([a-z]+)\((.*)\)/i.exec(format); m1 = /([a-z]+)\((.*)\)/i.exec(format);
...@@ -94,22 +94,19 @@ function d3_rgb_parse(format, rgb, hsl) { ...@@ -94,22 +94,19 @@ function d3_rgb_parse(format, rgb, hsl) {
} }
/* Named colors. */ /* Named colors. */
if (name = d3_rgb_names.get(format)) return rgb(name.r, name.g, name.b); if (color = d3_rgb_names.get(format)) return rgb(color.r, color.g, color.b);
/* Hexadecimal colors: #rgb and #rrggbb. */ /* Hexadecimal colors: #rgb and #rrggbb. */
if (format != null && format.charAt(0) === "#") { if (format != null && format.charAt(0) === "#" && !isNaN(color = parseInt(format.substring(1), 16))) {
if (format.length === 4) { if (format.length === 4) {
r = format.charAt(1); r += r; r = (color & 0xf00) >> 4; r = (r >> 4) | r;
g = format.charAt(2); g += g; g = (color & 0xf0); g = (g >> 4) | g;
b = format.charAt(3); b += b; b = (color & 0xf); b = (b << 4) | b;
} else if (format.length === 7) { } else if (format.length === 7) {
r = format.substring(1, 3); r = (color & 0xff0000) >> 16;
g = format.substring(3, 5); g = (color & 0xff00) >> 8;
b = format.substring(5, 7); b = (color & 0xff);
} }
r = parseInt(r, 16);
g = parseInt(g, 16);
b = parseInt(b, 16);
} }