I put some ChartJS graphs in Rnd and it’s mostly great but if I want to pan around in the graph, it also moves the window. Here’s an example…
My current code is
<>
<Rnd
style={style}
default={{
x: 0,
y: 0,
width: 600,
height: 200,
}}
>
<Chart type="line" ref={chartRef} data={data} options={options} />
</Rnd>
</>
What I want to do is have it so that it will ignore the area of its div that is overlaid by the canvas. I think then I’d have to add another child to Rnd to be like a windows top bar and only dragging that drags the window.
The only thing I can think of is having a useEffect tracking the mouse position over the canvas so when the mouse is over the canvas it’s true and false otherwise and then have disableDragging
take that state variable. I haven’t tried that yet because I’m hoping there’s a better way as I suspect that approach would come with a lot of hair with all the rerenders that would cause.
Here’s the disableDragging
approach. The first thing is to put a small Box (I’m using MUI, so just a div really) at the top of the Rnd
and then put a mouse listener on the Box so that anytime the mouse goes over the box or leaves the box, it sets a State variable. Use that State variable for the disableDragging
parameter in Rnd
. I’m not noticing real world performance issues with my small site but it seems like the rerenders induced by moving the mouse are not the best way.
const handleMouseMove = (
e: MouseEvent,
chartRef: MutableRefObject<null | HTMLDivElement>,
setDisableDragging: Dispatch<SetStateAction<boolean>>
) => {
if (
chartRef.current != undefined &&
'getBoundingClientRect' in chartRef.current
) {
const rect = (chartRef.current as HTMLDivElement).getBoundingClientRect()
const isInChart =
e.clientX >= rect.left &&
e.clientX <= rect.right &&
e.clientY >= rect.top &&
e.clientY <= rect.bottom
setDisableDragging(!isInChart)
}
}
const Graph: FC<GraphTprops> = () => {
const [disableDragging, setDisableDragging] = useState(false)
const containerRef = useRef<HTMLDivElement | null>(null)
useEffect(() => {
// Add global mousemove listener
window.addEventListener('mousemove', (e: MouseEvent) =>
handleMouseMove(e, containerRef, setDisableDragging)
)
return () => {
// Clean up listener on component unmount
window.removeEventListener('mousemove', (e: MouseEvent) =>
handleMouseMove(e, containerRef, setDisableDragging)
)
}
}, [containerRef])
const chartRef = useRef(null)
const options = ...
const data = ...
return (
<>
<Rnd
disableDragging={disableDragging}
>
<Box
ref={containerRef}
sx={{
height: '15px',
width: '100%',
display: 'block',
top: '0',
left: '0',
}}
/>
<Chart type="line" ref={chartRef} data={data} options={options} />
</Rnd>
</>
)
}