diff --git a/src/zoom.js b/src/zoom.js index d56438823b2882856f156b0915ccbac038d6923e..50936066a3597c46ad65f690e9c8417e9d3375f8 100644 --- a/src/zoom.js +++ b/src/zoom.js @@ -14,6 +14,10 @@ function defaultFilter(event) { return (!event.ctrlKey || event.type === 'wheel') && !event.button; } +function defaultCenter(event) { + return pointer(event, this); +} + function defaultExtent() { var e = this; if (e instanceof SVGElement) { @@ -27,6 +31,10 @@ function defaultExtent() { return [[0, 0], [e.clientWidth, e.clientHeight]]; } +function defaultCentroid(extent) { + return [(+extent[0][0] + +extent[1][0]) / 2, (+extent[0][1] + +extent[1][1]) / 2]; +} + function defaultTransform() { return this.__zoom || identity; } @@ -52,7 +60,9 @@ function defaultConstrain(transform, extent, translateExtent) { export default function() { var filter = defaultFilter, + center = defaultCenter, extent = defaultExtent, + centroid = defaultCentroid, constrain = defaultConstrain, wheelDelta = defaultWheelDelta, touchable = defaultTouchable, @@ -148,9 +158,6 @@ export default function() { return x === transform.x && y === transform.y ? transform : new Transform(transform.k, x, y); } - function centroid(extent) { - return [(+extent[0][0] + +extent[1][0]) / 2, (+extent[0][1] + +extent[1][1]) / 2]; - } function schedule(transition, transform, point, event) { transition @@ -243,6 +250,7 @@ export default function() { if (g.wheel) { if (g.mouse[0][0] !== p[0] || g.mouse[0][1] !== p[1]) { g.mouse[1] = t.invert(g.mouse[0] = p); + g.mouse[2] = center.apply(this, arguments); } clearTimeout(g.wheel); } @@ -252,14 +260,14 @@ export default function() { // Otherwise, capture the mouse point and location at the start. else { - g.mouse = [p, t.invert(p)]; + g.mouse = [p, t.invert(p), center.apply(this, arguments)]; interrupt(this); g.start(); } noevent(event); g.wheel = setTimeout(wheelidled, wheelDelay); - g.zoom("mouse", constrain(translate(scale(t, k), g.mouse[0], g.mouse[1]), g.extent, translateExtent)); + g.zoom("mouse", constrain(translate(scale(t, k), g.mouse[2], t.invert(g.mouse[2])), g.extent, translateExtent)); function wheelidled() { g.wheel = null; @@ -278,7 +286,7 @@ export default function() { dragDisable(event.view); nopropagation(event); - g.mouse = [p, this.__zoom.invert(p)]; + g.prev = p; interrupt(this); g.start(); @@ -288,8 +296,10 @@ export default function() { var dx = event.clientX - x0, dy = event.clientY - y0; g.moved = dx * dx + dy * dy > clickDistance2; } + var p = pointer(event, currentTarget); g.event(event) - .zoom("mouse", constrain(translate(g.that.__zoom, g.mouse[0] = pointer(event, currentTarget), g.mouse[1]), g.extent, translateExtent)); + .zoom("mouse", constrain(translate(g.that.__zoom, p, g.that.__zoom.invert(g.prev)), g.extent, translateExtent)); + g.prev = p; } function mouseupped(event) { @@ -303,7 +313,7 @@ export default function() { function dblclicked(event, ...args) { if (!filter.apply(this, arguments)) return; var t0 = this.__zoom, - p0 = pointer(event.changedTouches ? event.changedTouches[0] : event, this), + p0 = center.call(this, event.changedTouches ? event.changedTouches[0] : event), p1 = t0.invert(p0), k1 = t0.k * (event.shiftKey ? 0.5 : 2), t1 = constrain(translate(scale(t0, k1), p0, p1), extent.apply(this, args), translateExtent); @@ -322,7 +332,7 @@ export default function() { nopropagation(event); for (i = 0; i < n; ++i) { - t = touches[i], p = pointer(t, this); + t = touches[i], p = center.call(this, t); p = [p, this.__zoom.invert(p), t.identifier]; if (!g.touch0) g.touch0 = p, started = true, g.taps = 1 + !!touchstarting; else if (!g.touch1 && g.touch0[2] !== p[2]) g.touch1 = p, g.taps = 0; @@ -345,7 +355,7 @@ export default function() { noevent(event); for (i = 0; i < n; ++i) { - t = touches[i], p = pointer(t, this); + t = touches[i], p = center.call(this, t); if (g.touch0 && g.touch0[2] === t.identifier) g.touch0[0] = p; else if (g.touch1 && g.touch1[2] === t.identifier) g.touch1[0] = p; } @@ -406,6 +416,14 @@ export default function() { return arguments.length ? (touchable = typeof _ === "function" ? _ : constant(!!_), zoom) : touchable; }; + zoom.center = function(_) { + return arguments.length ? (center = typeof _ === "function" ? _ : constant([+_[0], +_[1]]), zoom) : center; + }; + + zoom.centroid = function(_) { + return arguments.length ? (centroid = typeof _ === "function" ? _ : constant([+_[0], +_[1]]), zoom) : centroid; + }; + zoom.extent = function(_) { return arguments.length ? (extent = typeof _ === "function" ? _ : constant([[+_[0][0], +_[0][1]], [+_[1][0], +_[1][1]]]), zoom) : extent; };