chartjs / chartjs-plugin-zoom

Zoom and pan plugin for Chart.js
MIT License
598 stars 327 forks source link

Drag to the outside of the chart doesn't work correctly #770

Closed lukicenturi closed 2 weeks ago

lukicenturi commented 1 year ago

Drag to the outside of the chart doesn't work correctly It's only happen in 2.0.1. I downgrade to 2.0.0, it works fine.

image In 2.0.1, it seems that it calculated the length between mousedown and mouseup, so it shows longer range than expected. (I expect the range starts on the mousedown point, till the end of the chart)

jcphill commented 1 year ago

I see this same issue (with chart.js 3.9.1 and react 17.0.2) and can confirm that downgrading from 2.0.1 to 2.0.0 fixes it.

I believe the cause is that getRelativePosition (called in computeDragRect, which is called in mouseUp) is returning a position relative to whatever element the mouse was over when the endPointEvent mouseup happened rather than the position relative to the chart canvas.

https://github.com/chartjs/chartjs-plugin-zoom/blob/bfd207d9108cbcd612b8f4c2b0221ef8e7ed373b/src/handlers.js#L80-L120

sqlAlchemyNoob2004 commented 11 months ago

I was just about to create an issue for this. Unsure if there is active development on this plugin, but I think you should follow the chartjs core implementation of getRelativePosition and write your own.

The reason theirs doesn't work for you is because they seem to assume that any events passed to that method have an equivalent target and currentTarget, i.e. they all originate from the canvas. This isn't the case for the zoom plugin because the mouseUp listener for drag detection is attached to the canvas.ownerDocument.

This gets you into situations where, when dragging out of the canvas, your start and end points get flipped. For example:

Another method to get canvas position would be to, instead of relying on offsetY/X, use canvas.getBoundingClientRect(). Then just subtract clientX/Y by left/top.

You do need to clamp though, because while start and end won't flip accidentally, you could get an end position that is greater than the actual height or width of the canvas. In practice this just means that you will zoom slightly further past the current scale.