Commit 4b3795e1 authored by Jason Davies's avatar Jason Davies
Browse files

Support simultaneous zooming on multiple targets.

Fixes #1497, where a zoom gesture would break if a touch was started
outside the target during a gesture.

Each zoom gesture now only considers touches that were started on its
associated target element.  This allows multiple zoom gestures to occur
at once without conflicts.
parent fc5a5864
......@@ -1205,7 +1205,7 @@ d3 = function() {
x: 0,
y: 0,
k: 1
}, translate0, center, size = [ 960, 500 ], scaleExtent = d3_behavior_zoomInfinity, mousedown = "mousedown.zoom", mousemove = "mousemove.zoom", mouseup = "mouseup.zoom", mousewheelTimer, touchstart = "touchstart.zoom", touchmove = "touchmove.zoom", touchend = "touchend.zoom", touchtime, event = d3_eventDispatch(zoom, "zoomstart", "zoom", "zoomend"), x0, x1, y0, y1;
}, translate0, center, size = [ 960, 500 ], scaleExtent = d3_behavior_zoomInfinity, mousedown = "mousedown.zoom", mousemove = "mousemove.zoom", mouseup = "mouseup.zoom", mousewheelTimer, touchstart = "touchstart.zoom", touchtime, event = d3_eventDispatch(zoom, "zoomstart", "zoom", "zoomend"), x0, x1, y0, y1;
function zoom(g) {
g.on(mousedown, mousedowned).on(d3_behavior_zoomWheel + ".zoom", mousewheeled).on(mousemove, mousewheelreset).on("dblclick.zoom", dblclicked).on(touchstart, touchstarted);
}
......@@ -1355,21 +1355,24 @@ d3 = function() {
}
}
function touchstarted() {
var target = this, event_ = event.of(target, arguments), locations0, distance0 = 0, scale0, w = d3.select(d3_window).on(touchmove, moved).on(touchend, ended), t = d3.select(target).on(mousedown, null).on(touchstart, started), dragRestore = d3_event_dragSuppress();
var target = this, event_ = event.of(target, arguments), locations0 = {}, distance0 = 0, scale0, eventId = d3.event.changedTouches[0].identifier, touchmove = "touchmove.zoom-" + eventId, touchend = "touchend.zoom-" + eventId, w = d3.select(d3_window).on(touchmove, moved).on(touchend, ended), t = d3.select(target).on(mousedown, null).on(touchstart, started), dragRestore = d3_event_dragSuppress();
d3_selection_interrupt.call(target);
started();
zoomstarted(event_);
function relocate() {
var touches = d3.touches(target);
scale0 = view.k;
locations0 = {};
touches.forEach(function(t) {
locations0[t.identifier] = location(t);
if (t.identifier in locations0) locations0[t.identifier] = location(t);
});
return touches;
}
function started() {
var now = Date.now(), touches = relocate();
var changed = d3.event.changedTouches;
for (var i = 0, n = changed.length; i < n; ++i) {
locations0[changed[i].identifier] = null;
}
var touches = relocate(), now = Date.now();
if (touches.length === 1) {
if (now - touchtime < 500) {
var p = touches[0], l = locations0[p.identifier];
......@@ -1385,9 +1388,16 @@ d3 = function() {
}
}
function moved() {
var touches = d3.touches(target), p0 = touches[0], l0 = locations0[p0.identifier];
if (p1 = touches[1]) {
var p1, l1 = locations0[p1.identifier], scale1 = d3.event.scale;
var touches = d3.touches(target), p0, l0, p1, l1;
for (var i = 0, n = touches.length; i < n; ++i, l1 = null) {
p1 = touches[i];
if (l1 = locations0[p1.identifier]) {
if (l0) break;
p0 = p1, l0 = l1;
}
}
if (l1) {
var scale1 = d3.event.scale;
if (scale1 == null) {
var distance1 = (distance1 = p1[0] - p0[0]) * distance1 + (distance1 = p1[1] - p0[1]) * distance1;
scale1 = distance0 && Math.sqrt(distance1 / distance0);
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -19,8 +19,6 @@ d3.behavior.zoom = function() {
mouseup = "mouseup.zoom",
mousewheelTimer,
touchstart = "touchstart.zoom",
touchmove = "touchmove.zoom",
touchend = "touchend.zoom",
touchtime, // time of last touchstart (to detect double-tap)
event = d3_eventDispatch(zoom, "zoomstart", "zoom", "zoomend"),
x0,
......@@ -186,9 +184,12 @@ d3.behavior.zoom = function() {
function touchstarted() {
var target = this,
event_ = event.of(target, arguments),
locations0, // touchstart locations
locations0 = {}, // touchstart locations
distance0 = 0, // distance² between initial touches
scale0, // scale when we started touching
eventId = d3.event.changedTouches[0].identifier,
touchmove = "touchmove.zoom-" + eventId,
touchend = "touchend.zoom-" + eventId,
w = d3.select(d3_window).on(touchmove, moved).on(touchend, ended),
t = d3.select(target).on(mousedown, null).on(touchstart, started), // prevent duplicate events
dragRestore = d3_event_dragSuppress();
......@@ -197,18 +198,26 @@ d3.behavior.zoom = function() {
started();
zoomstarted(event_);
// Updates locations of any touches in locations0.
function relocate() {
var touches = d3.touches(target);
scale0 = view.k;
locations0 = {};
touches.forEach(function(t) { locations0[t.identifier] = location(t); });
touches.forEach(function(t) {
if (t.identifier in locations0) locations0[t.identifier] = location(t);
});
return touches;
}
// Temporarily override touchstart while gesture is active.
function started() {
var now = Date.now(),
touches = relocate();
// Only track touches started on the target element.
var changed = d3.event.changedTouches;
for (var i = 0, n = changed.length; i < n; ++i) {
locations0[changed[i].identifier] = null;
}
var touches = relocate(),
now = Date.now();
if (touches.length === 1) {
if (now - touchtime < 500) { // dbltap
......@@ -228,12 +237,18 @@ d3.behavior.zoom = function() {
function moved() {
var touches = d3.touches(target),
p0 = touches[0],
l0 = locations0[p0.identifier];
p0, l0,
p1, l1;
for (var i = 0, n = touches.length; i < n; ++i, l1 = null) {
p1 = touches[i];
if (l1 = locations0[p1.identifier]) {
if (l0) break;
p0 = p1, l0 = l1;
}
}
if (p1 = touches[1]) {
var p1, l1 = locations0[p1.identifier],
scale1 = d3.event.scale;
if (l1) {
var scale1 = d3.event.scale;
if (scale1 == null) {
var distance1 = (distance1 = p1[0] - p0[0]) * distance1 + (distance1 = p1[1] - p0[1]) * distance1;
scale1 = distance0 && Math.sqrt(distance1 / distance0);
......
Supports Markdown
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