d3 / d3-transition

Animated transitions for D3 selections.
https://d3js.org/d3-transition
ISC License
224 stars 64 forks source link

Odd behavior using transition() while panning / zooming #83

Closed entiendoNull closed 5 years ago

entiendoNull commented 6 years ago

I am basically using this to pan and zoom to a svg node. It works great :)

this.container // a svg group acting as a wrapper
    .transition()
    .duration(1000)
    .call(
        this.zoom.transform,
        d3.zoomIdentity
             .translate(translate.x, translate.y)
             .scale(scale)
    );

However, in action it sort of zooms out before it's zooms back in to the new coordinates which is both cool and annoying at the same time. I have seen this behavior at several examples, like this one for example: https://bl.ocks.org/mbostock/b783fbb2e673561d214e09c7fb5cedee or https://bl.ocks.org/mbostock/6238040

But I have also seen examples where this behavior is not seen at all: https://bl.ocks.org/mbostock/9656675 (v3) or https://bl.ocks.org/iamkevinv/0a24e9126cd2fa6b283c6f2d774b69a2 (v4)

Notice how the it sort of zoom to fit without zooming out way too much? How do I achieve that? My first thought was that I could override that behavior with easings.

I've tried numerous different easings, which are all cool... but still the zoom is zooming out before heading towards the new translation and scale.

Here are som approaches:

this.container // a svg group acting as a wrapper
    .transition()
    .ease(d3.easeLinear)
    .duration(1000)
    .call(
        this.zoom.transform,
        d3.zoomIdentity
             .translate(translate.x, translate.y)
             .scale(scale)
    );

and

let t = d3.transition()
       .duration(1000)
       .ease(d3.easeLinear);

this.container // a svg group acting as a wrapper
    .transition(t)
    .call(
        this.zoom.transform,
        d3.zoomIdentity
             .translate(translate.x, translate.y)
             .scale(scale)
    );

What am I missing here? :)

mbostock commented 5 years ago

It sounds like you are describing the smooth zooming implemented by d3.interpolateZoom. As described in the d3-zoom documentation, that’s what zoom.transform uses internally. And, as the documentation goes on to say, you can use d3.interpolate instead of d3.interpolateZoom with zoom.interpolate if you prefer direct interpolation rather than trying to minimize apparent movement.