I’m currently working on a candlestick chart with D3 in a NextJS app.I have some basic zoom/pan working. What I need ,however, is to “fix” the chart on one side(right) so that when I zoom, the data points are only moving left. Right now the chart moves away from the mouse position.
I’ve tried changing the translate values in zoomed function, but could not manage to make it “fixed”. Instead it moved to the right(I need to the left).
I’ve tried to set className(using tailwind) to ‘origin-right’, which I’ve found in some other (similar, not the same) stack overflow question – did not work.
One thing I’ve come to realize is that the zoom distorts/moves the center of the svg(which makes sense since it changes the range of the scale), this I believe is the cause(another side-effect of this is a off-set I see in my crosshair I draw based on the same scale)?
function zoomed(event) {
const { k: newK, x: newX, y: newY } = event.transform;
const { k: prevK, x: prevX, y: prevY } = currentGlobalZoomState;
setCurrentXZoomState(
currentXZoomState.translate((newX - prevX) / prevK, 0).scale(newK / prevK)
);
setCurrentYZoomState(
currentYZoomState.translate(0, (newY - prevY) / prevK).scale(newK / prevK)
);
setCurrentGlobalZoomState(event.transform);
}
useEffect(() => {
const zoomGlobal = d3
.zoom()
.translateExtent([
[0, 0],
[width, height],
])
.scaleExtent([1, 16])
.extent([
[0, 0],
[width, height],
]);
zoomGlobal.wheelDelta((e) => {
return (e.deltaY * (e.deltaMode ? 120 : 1)) / 1500;
});
zoomGlobal.on("zoom", zoomed);
const svg = d3.select(svgRef.current);
svg.call(zoomGlobal);
const resetListener = d3.select("#reset-listening-rect");
resetListener.on("contextmenu", (e) => {
e.preventDefault();
svg.call(zoomGlobal.transform, d3.zoomIdentity);
setCurrentGlobalZoomState(d3.zoomIdentity);
setCurrentXZoomState(d3.zoomIdentity);
setCurrentYZoomState(d3.zoomIdentity);
});
return () => {
resetListener.on("contextmenu", null);
};
}, [
data,
newDimensions,
currentXZoomState,
currentYZoomState,
currentGlobalZoomState,
]);
if (currentXZoomState) {
xScale.range(
[
newDimensions.marginLeft,
newDimensions.width - newDimensions.marginRight,
].map((d) => currentXZoomState.applyX(d))
);
}
Is there something I’m missing here ? I’ve only provided the code pertaining to the zoom.
1