From df77d81b10e3ad8b767ac79216014be824b63c4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Rivi=C3=A8re?= Date: Mon, 13 Jul 2020 09:59:45 +0200 Subject: [PATCH] zoom.center() defines a center function for the reference point of the wheel event; defaults to d3.pointer fixes https://github.com/d3/d3-zoom/issues/211 --- README.md | 12 ++++++++++++ src/zoom.js | 14 ++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a1aba131..2b332ba7 100644 --- a/README.md +++ b/README.md @@ -168,6 +168,18 @@ function constrain(transform, extent, translateExtent) { The constraint function must return a [*transform*](#zoom-transforms) given the current *transform*, [viewport extent](#zoom_extent) and [translate extent](#zoom_translateExtent). The default implementation attempts to ensure that the viewport extent does not go outside the translate extent. +# zoom.center([center]) · [Source](https://github.com/d3/d3-zoom/blob/main/src/zoom.js), [Examples](https://observablehq.com/@d3/zoom-center-212) + +If *center* is a function, sets the center to the specified function, and returns the zoom behavior. If *center* is an array, sets the center to a constant function that returns the specified array. If *center* is not specified, returns the current center, which defaults to the pointer’s position relative to the current DOM element: + +```js +function center(event) { + return d3.pointer(event, this); +} +``` + +The center is passed the current event (`event`) and datum `d`, with the `this` context as the current DOM element. It must return the reference position as [*x*, *y*]. + # zoom.filter([filter]) · [Source](https://github.com/d3/d3-zoom/blob/main/src/zoom.js) If *filter* is specified, sets the filter to the specified function and returns the zoom behavior. If *filter* is not specified, returns the current filter, which defaults to: diff --git a/src/zoom.js b/src/zoom.js index d5643882..fb3ff5b3 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) { @@ -52,6 +56,7 @@ function defaultConstrain(transform, extent, translateExtent) { export default function() { var filter = defaultFilter, + center = defaultCenter, extent = defaultExtent, constrain = defaultConstrain, wheelDelta = defaultWheelDelta, @@ -243,6 +248,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 +258,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; @@ -406,6 +412,10 @@ 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.extent = function(_) { return arguments.length ? (extent = typeof _ === "function" ? _ : constant([[+_[0][0], +_[0][1]], [+_[1][0], +_[1][1]]]), zoom) : extent; };