d3 / d3-zoom

Pan and zoom SVG, HTML or Canvas using mouse or touch input.
https://d3js.org/d3-zoom
ISC License
501 stars 144 forks source link

Default zoom tween for translation animation surprising / More control over zoom animation tweens wanted #252

Closed curiouserrandy closed 2 years ago

curiouserrandy commented 2 years ago

When doing an animation between two zoom transforms that have no scaling factor involved the zoom tween created zooms out and back in. An example of this can be found in https://observablehq.com/@curiouserrandy/example-funny-zoom-behavior; the initial transform is translate(-74, 300).scale(1), and the target transform translate(-5114, 275).scale(1) but as is visible when visiting or reloading the above page, the transition between the two involves a zoom out and back again (also, the intermediate transforms are logged to the console). (Note that the location of the example sketch is translated at the same time so that it's visible in the viewport during the animation.)

This may be considered intended and reasonable behavior; most graphics that have something visible in the two specified translations might be aided by a zoom out during the translation to provide the user more context for the translation. However, for my use case the change in zoom during the animation is a distraction. Would it be possible to make animations between transforms that have the same scale not alter the scale during the animation, or alternatively, to give the user more control over the nature of the tween generated for animating zoom changes to support use cases like mine?

Use case background: I am displaying different sections of a larger graph and navigating through that graph via clicks. When those clicks change the portion of the graph that is being displayed, I send the new graph through a layout engine, and animate the transition from one graph to another. The layout engine can produce very different coordinates for the same node depending on how many other nodes are being added/taken away from the displayed graph by the transition, so keeping a particular node in the same or a similar position on the screen can require transform changes as large as the one described above. You can see https://observablehq.com/@curiouserrandy/initial-interactive-graph-explorer if you'd like more context; the animation described above was copied directly from one generated there by a layout change that resulted in a large change in the number of displayed nodes.

Fil commented 2 years ago

I think the option you want is zoom.interpolate, see https://github.com/d3/d3-zoom/blob/main/README.md#zoom_interpolate and https://observablehq.com/@d3/d3-interpolatezoom for details.

d3.zoom().interpolate(d3.interpolate).on("zoom", (event) => { … })
curiouserrandy commented 2 years ago

That works beautifully! Thanks, and sorry I didn't notice before filing the issue.