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
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, andevt.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>