Home > database >  Change zooming from geometric to sementic ( zooming only on x-axis )
Change zooming from geometric to sementic ( zooming only on x-axis )

Time:12-16

I have a graph of lines paths . Actually when I zoom it applies a transform attribute.

I would like to make a semantic zoom by zooming only on the x-axis.

Here's the code for zooming

private manageZoom(svgs: AllSvg, allAxis: AllAxis, dimension: Dimension): D3ZoomBehavior {
    const zoom: D3ZoomBehavior = d3
        .zoom()
        .scaleExtent([1, 40])
        .translateExtent([
            [0, 0],
            [dimension.width, dimension.height]
        ])
        .on('zoom', zoomed.bind(null, allAxis));

    svgs.svgContainer.call(zoom);
    return zoom;

    function zoomed({ xAxis, xAxisBottom, yAxis }: AllAxis, { transform }: any) {
        svgs.sillons.attr('transform', transform);
        xAxisBottom.axisContainer.call(xAxisBottom.axis.scale(transform.rescaleX(xAxisBottom.scale)) as any);
    }
}

the sillons object is an array of paths text circles enter image description here

enter image description here

I would that the lines get re-drawed in the right position as the x-axis get larger, but not zoom sillons on y-axis.

I have checked many posts but can't repoduce them to solve my issue. for example

CodePudding user response:

When you set up something along the lines of

svg.call(
  d3.zoom()
   .on("zoom", zoom)
)

the zoom function can be just about anything that you want. The first argument of zoom is the zoom event itself. Let's denote it by evt. Then

  • evt.transform.k tells you the scale factor,
  • evt.transform.x tells you the horizontal translation, and
  • evt.transform.y tells you the vertical translation.

You don't have to use all of those, though. Rather, you can redraw your image however you want.

Here's a slightly cute example that rescales the image only horizontally.

  let w = 500;
  let h = 100;
  let svg = d3
    .select("#container")
    .append("svg")
    .attr("width", w)
    .attr("height", h)
    .style("border", "solid 1px black");

  let n = 500;
  let pts0 = d3.range(n).map((_) => [d3.randomNormal(w / 2, w / 20)(), 0]);
  let pts1 = pts0.map((pt) => [w - pt[0], h]);

  let g = svg.append("g");
  let link_group = g.append("g");
  link_group
    .selectAll("path")
    .data(d3.range(n))
    .join("path")
    .attr("d", (i) => d3.linkVertical()({ source: pts0[i], target: pts1[i] }))
    .attr("fill", "none")
    .attr("stroke", "#000")
    .attr("stroke-opacity", 0.1)
    .attr("stroke-width", 1.5);

  let all_pts = pts0.concat(pts1);
  let circle_group = g.append("g");
  let circles = circle_group
    .attr("fill", "black")
    .attr("fill-opacity", 0.2)
    .selectAll("circle")
    .data(all_pts)
    .join("circle")
    .attr("cx", (d) => d[0])
    .attr("cy", (d) => d[1])
    .attr("data-x", (d) => d[0])
    .attr("r", 4);

  svg.call(
    d3
      .zoom()
      .scaleExtent([1 / 4, 20])
      .duration(500)
      .on("zoom", function (evt) {
        let k = evt.transform.k;
        link_group.selectAll("path").attr("d", function (i) {
          let x00 = pts0[i][0];
          let x01 = k * (x00 - w / 2)   w / 2;
          let x10 = pts1[i][0];
          let x11 = k * (x10 - w / 2)   w / 2;
          return d3.linkVertical()({ source: [x01, 0], target: [x11, h] });
        });
        circle_group
          .selectAll("circle")
          .nodes()
          .forEach(function (c) {
            let x0 = c.getAttribute("data-x");
            let k = evt.transform.k;
            let x1 = k * (x0 - w / 2)   w / 2;
            c.setAttribute("cx", x1);
          });
      })
  );
<script src="https://d3js.org/d3.v7.min.js"></script>
<div id="container"></div>

  • Related