Use dispatchEvent to invoke multiple Chartjs line charts tooltips but not worked with large width
Expected behavior
I had multiple Line Charts in a React project and wanted to have a common vertical Crosshairs and display tooltip in the corresponding position. because the actual situation was more complex, I simplified this part and built a demo.
There is NO Crosshair in the demo, but essentially a transparent Div that covers all the charts is placed at the top level and all the onMouseMove, onMouseLeave and onMouseEnter methods are passed to the parent component.
Current behavior
Here are some of the core code:
onMouseMove={(event) => {
handleMoveEventWithAllCanvas(event);
setCrosshairXIndex(event.nativeEvent.offsetX);
}}
function handleMoveEventWithAllCanvas(event) {
refCanvases.current.forEach((canvas,i) => {
// Get the point where the mouse is
let rect = canvas.current.getBoundingClientRect();
let newEvent = new MouseEvent(event.type, {
clientX: rect.left + event.nativeEvent.offsetX,
clientY: rect.top + height/2,
})
canvas.current.dispatchEvent(newEvent);
})
}
This method worked well when this chart was relatively small (not quite sure of the exact numbers)! But when the chart is wider, the tooltip will not be triggered on the right side of the chart. I used afterEventhook to check what events the chart was receiving, and I found that y and/or x could become negative numbers.
Reproducible sample
https://codepen.io/chengs-u/pen/oNdYNoG?editors=1111
Optional extra steps/info to reproduce
This is the log output from the console:
// Tooltips worked
newEvent clientX: 1630 clientY: 345
customEventListener: evt.type: mousemove
customEventListener: clientX: 1630 offsetX: 0 pageX: 1630 X: 407
customEventListener: clientY: 345 offsetY: -49 pageY: 345 Y: 49
// Tooltips stuck from this event
newEvent clientX: 1631 clientY: 345
customEventListener: evt.type: mousemove
customEventListener: clientX: 1631 offsetX: 1 pageX: 1631 X: 1
customEventListener: clientY: 345 offsetY: -49 pageY: 345 Y: -49
I've been stuck in this problem for a long time, my Chart is set up in responsive mode according to this document, and I've checked the source code of Chartjs for event handling, but I couldn't find the answer
Possible solution
I'm not sure if this issue is a bug or a problem with some part of the setup, so I'll set it up as a bug tag for now, thanks!
Context
No response
chart.js version
v3.9.1
Browser name and version
No response
Link to your project
No response
Tooltips seem to be working fine for me, even if I increase the canvas width to 2000
Tooltips seem to be working fine for me, even if I increase the canvas width to 2000
Thanks for your reply. This seems strange, according to the Log can see that from clientX 1631, afterEventhook received event has started to use offsetX as x coordinate, in the method getCanvasPosition, there is a useOffsetPos method, not quite sure what the purpose of this method is. Thanks
After more research, I found that the problem is that the offsetX and offsetY of the mouse events received by Chart are different from the actual dispatched events.
// Tooltip worked here, not using offsetX or offsetY
newEvent clientX: 1629 clientY: 299 offsetX: 1630 offsetY: 300
customEventListener: evt.type: mousemove
customEventListener: clientX: 1629 offsetX: -1 pageX: 1629 X: 406
customEventListener: clientY: 299 offsetY: -33 pageY: 299 Y: 49
customEventListener: evt.event.native.target: <canvas height="409" style="display: block; box-sizing: border-box; height: 306.75px; width: 699.75px;" width="933">
customEventListener: rect.left: 1222.751953125 rect.top: 249.521484375
customEventListener:
evt.event.native.clientX - rect.left: 406.248046875
evt.event.native.clientY - rect.top: 49.478515625
Math.round((x - xOffset) / width * canvas.width / currentDevicePixelRatio): 406
***********************
// Tooltip NOT worked here, using offsetX or offsetY as event x or y
newEvent clientX: 1633 clientY: 299 offsetX: 1634 offsetY: 300
customEventListener: evt.type: mousemove
customEventListener: clientX: 1633 offsetX: 3 pageX: 1633 X: 3
customEventListener: clientY: 299 offsetY: -33 pageY: 299 Y: -33
customEventListener: evt.event.native.target: <canvas height="409" style="display: block; box-sizing: border-box; height: 306.75px; width: 699.75px;" width="933">
customEventListener: rect.left: 1222.751953125 rect.top: 249.521484375
customEventListener:
evt.event.native.clientX - rect.left: 410.248046875
evt.event.native.clientY - rect.top: 49.478515625
Math.round((x - xOffset) / width * canvas.width / currentDevicePixelRatio): 410
***********************
Hope this helps to find the cause, thank you!