Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
lukicenturi opened this issue Jun 19, 2023 · 2 comments · Fixed by #811
Closed

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

lukicenturi opened this issue Jun 19, 2023 · 2 comments · Fixed by #811

Comments

@lukicenturi
Copy link

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
Copy link

jcphill commented Sep 26, 2023

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.

export function computeDragRect(chart, mode, beginPointEvent, endPointEvent) {
const xEnabled = directionEnabled(mode, 'x', chart);
const yEnabled = directionEnabled(mode, 'y', chart);
let {top, left, right, bottom, width: chartWidth, height: chartHeight} = chart.chartArea;
const beginPoint = getRelativePosition(beginPointEvent, chart);
const endPoint = getRelativePosition(endPointEvent, chart);
if (xEnabled) {
left = Math.min(beginPoint.x, endPoint.x);
right = Math.max(beginPoint.x, endPoint.x);
}
if (yEnabled) {
top = Math.min(beginPoint.y, endPoint.y);
bottom = Math.max(beginPoint.y, endPoint.y);
}
const width = right - left;
const height = bottom - top;
return {
left,
top,
right,
bottom,
width,
height,
zoomX: xEnabled && width ? 1 + ((chartWidth - width) / chartWidth) : 1,
zoomY: yEnabled && height ? 1 + ((chartHeight - height) / chartHeight) : 1
};
}
export function mouseUp(chart, event) {
const state = getState(chart);
if (!state.dragStart) {
return;
}
removeHandler(chart, 'mousemove');
const {mode, onZoomComplete, drag: {threshold = 0}} = state.options.zoom;
const rect = computeDragRect(chart, mode, state.dragStart, event);

@sqlAlchemyNoob2004
Copy link

sqlAlchemyNoob2004 commented Dec 21, 2023

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:

  • I have a 500px height canvas
  • I'm trying to select from the middle (250), to the end (500)
  • I drag from the middle to one pixel outside of the canvas, 1px into some sibling element
  • e.target is now that sibling element, so offsetY becomes 1
  • I now have start.y = 250 and end.y = 1 which just gets flipped further down the call chain
  • on mouseUp I've selected selected the first half of the chart (1-250) instead of the last half (250-500) like I intended.

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants