Closed NJRBailey closed 5 years ago
I think (though I'm not sure at all) that this is caused by the zoom behaviour's transform not updating when the window is resized.
Yes, this is exactly it. You must update the state yourself. Something like:
function onResize() {
// start/end is the start date and end date of the current zoom
var s = [startDate, endDate].map(xScale2)
// timeline.select(".zoom").call(...) in your case
svg.select(".zoom").call(zoom.transform, d3.zoomIdentity
//.translate(paddingLeft, 0)) // uncomment in case the svg has some internal padding (i.e for a yAxis)
// if there's paddingLeft then this would be ((width - paddingLeft) / (s[1] - s[0]))
.scale(width / (s[1] - s[0]))
.translate(-s[0], 0));
}
It's the same as in the brush/zoom example, those two must be kept in sync when one of them change.
However, it isn't possible to change the scale and translate accordingly without also triggering the zoom operations
Yes, It is by replacing the selection.node().__zoom
instance. However that's not recommended according to the docs, but it's documented. Otherwise, you may just detach the zoom listener before the transform call and then attach it later again or wrap the scale/translate call in a "lock". Not sure if you actually need to do this in your case.
this means that the operation will just be carried out with the offset, and doesn't get us anywhere).
No, there is no offset, as long as you keep the state in sync.
@nitely’s answer is correct. This isn’t a problem with the zoom behavior, but inconsistent state created as a side-effect of your resize event listener.
What is happening
We have a chart with a d3.scaleTime as the x-axis, and a d3.scaleBand as the y-axis. We only zoom on the x-axis. When we zoom the chart, there is a 1:1 movement with the mouse cursor. When the window is resized horizontally, the x-axis range is recalculated, so that the chart will shrink or expand to fill the space - however, this results in the zoom having an offset (the mouse moves a longer or shorter distance than the chart when panning, and when zooming, the zoom will focus in on a point to the left or right of the mouse cursor). A block to demonstrate this can be found here: https://bl.ocks.org/NJRBailey/3d555173b13cd1de71f101885f16dba4/442012d6d3de6f6fca81ef1deb605f39878fff29
What should be happening
The zoom should stay 1:1 with the mouse (move the same distance, zoom in/out on the mouse position) after window resize.
How to reproduce
Notes
This is a question that has been asked on Stack Overflow (https://stackoverflow.com/questions/39735367/d3-zoom-behavior-when-window-is-resized) but which has no answers, so I thought I'd post it as an issue here, as I haven't been able to find a solution in about five days of searching and trying.
I think (though I'm not sure at all) that this is caused by the zoom behaviour's transform not updating when the window is resized. For example, if the window is made wider (and the range is updated to fill the new space), the scale and translate will stay the same, but the zoom operations will still act as though the range was spread across the same amount of pixels. However, it isn't possible to change the scale and translate accordingly without also triggering the zoom operations (e.g. if we try to set the zoom scale to a specific number in an attempt to counteract the resize error, by using zoom.scaleTo() or zoom.scaleBy(), or by setting the whole zoom.transform(), it will perform the scaling operation instead of just updating the numbers - this means that the operation will just be carried out with the offset, and doesn't get us anywhere).