3

Note: (Similar to question here D3.js Set initial zoom level. However their answer is for v3, and the v4 answer in the comment doesn't work.)

I'm trying to setup initial pan/zoom of a d3 animation. As per the answer above, I've setup my SVG zoom with the appropriate translations.

var svg = d3.select("#chart").append("svg")
    .on("touchmove mousemove", moved)
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
    .call(zoom)
    .append ("g")
    .attr("transform","translate(400,200) scale(.4,.4)");

svg.call(zoom.transform, d3.zoomIdentity.translate(400, 200).scale(0.4))
.call(zoom);

The graph loads fine as intended. However, the initial zooming action breaks the translation/scale, going back to the zoom identity. I have reviewed the docs and numerous zoom examples, but can't pin down this d3 V4 behavior.

Does anyone know what is going on? Feels like a bug.

  • 2
    Can you provide a Fiddle with more of the code to help me tinker? I've experienced something similar in a current project. It could be due to the fact that you're currently setting the variable `svg` to the group element as soon as you use `.append(g)`. In effect, your initial zoom call is on the svg element whereas all future zoom call are on the g element. Instead, start a new variable (e.g., `var group = svg.append("g")...`. But again, a fiddle would help! – Nick Sep 09 '17 at 03:14
  • Ok I'll try to make a fiddle. Thanks for the explanation, that makes the most sense. I'll study it. – Courtney Kristensen Sep 09 '17 at 03:35
  • Ok I've been trying to make fiddles but they crash...I just went through more examples and copied and pasted until things worked. Answer below. – Courtney Kristensen Sep 10 '17 at 03:34

1 Answers1

3

The following seems to work as desired

var zoom = d3.zoom().on("zoom", zoomed).scaleExtent([1 / 2, 8]);

function zoomed() {
  g.attr("transform", d3.event.transform); // updated for d3 v4
}

var svg = d3.select("#chart").append("svg")
    .on("touchmove mousemove", moved)
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)


var g = svg.append("g");

svg.call(zoom).call(zoom.transform, d3.zoomIdentity.translate(400, 200).scale(0.4));

I'm still not sure what the problem was. Going back to the original code, the transform was correctly applied to g and the transformation erased this without explanation.

One difference is that I define g seperately, maybe that is related.

  • 1
    The last line of your code is now calling zoom on the svg element rather than the g element – Nick Sep 10 '17 at 18:11
  • Interesting, firstly, so despite the fact in my original code zoom is earlier in the chain than the append, d3 interprets the zoom as called on the `g`? (`.call(zoom).append ("g")`). Secondly, I actually _want_ zoom applied to `g`, not the SVG element. The new code does this in the `zoomed()` function. I guess I don't understand d3! – Courtney Kristensen Sep 10 '17 at 20:50