score:2

Accepted answer

Two initial considerations: d3.create("svg") is rarely used in real D3 codes. Also, you don't have data appended to the DOM, just SVG elements you loaded (unless you're calling that "data").

Back to your question, you don't need path.bounds to make your code work, actually you don't even need d3.zoom. All you need is get the element's box (with getBBox) and do the appropriate transform.

The real problem, though, is that you need to wrap all the elements in a <g>, because you cannot apply the transform to the root SVG in SVG 1.1 (apparently this is possible in SVG 2).

Here is a basic demo. In this demo I'm using an external SVG made with different elements (circle, rectangle, text...), which represents the SVG you're appending. You get this SVG with:

const svg = d3.select("svg");

Then, considering you somehow manage to fix the <g> problem I mentioned, you get that group...

const g = svg.select("g");

... and you select the elements you want to zoom in (here, everything), binding an event listener:

const elements = g.selectAll("*")
    .on("click", clicked);

In this demo I'm using Bostock's math, to save (my) time, but you can change it. Click the element to zoom in, click it again to zoom out.

const width = 500,
  height = 400;
const svg = d3.select("svg");
const g = svg.select("g");
const elements = g.selectAll("*")
  .each(function() {
    d3.select(this).datum({})
  })
  .on("click", clicked);

function clicked(d) {
  d.clicked = !d.clicked;
  const bounds = this.getBBox();
  const x0 = bounds.x;
  const x1 = bounds.x + bounds.width;
  const y0 = bounds.y;
  const y1 = bounds.y + bounds.height;
  g.transition().duration(1000).attr("transform", d.clicked ? "translate(" + (width / 2) + "," + (height / 2) + ") scale(" + (1 / Math.max((x1 - x0) / width, (y1 - y0) / height)) + ") translate(" + (-(x0 + x1) / 2) + "," + (-(y0 + y1) / 2) + ")" : "transform(0,0) scale(1)");
}
<svg width="500" height="400">
<g>
<circle cx="50" cy="50" r="30" stroke="black" stroke-width="3" fill="teal"></circle>
<rect x="300" y="20" rx="20" ry="20" width="150" height="150" style="fill:tomato;stroke:black;stroke-width:3"/>
<polygon points="200,100 250,190 160,210" style="fill:lavender;stroke:purple;stroke-width:3" />
<path d="M 140 350 q 150 -200 350 0" stroke="blue" stroke-width="5" fill="none" />
<text x="30" y="300" transform="rotate(-30, 30, 300)">Foo Bar Baz</text>
</g>
</svg>
<script src="https://d3js.org/d3.v5.min.js"></script>


Related Query

More Query from same tag