I'm coding a super basic canvas-based image viewer. I'm trying to implement image panning. I want to be able to hold my mouse button down and move the mouse to pan the image around. I'm using the mouse up and down events to enter and leave a "panning mode". My mouse move handler never seems to see that the panning boolean changes from false to true, though.
I've tried writing my functions as arrow functions instead, thinking maybe it was something to do with the fact that these are DOM handlers (issues with this
or something), but that didn't seem to make any difference.
I have a heads-up display that shows the panning state and it updates accordingly, but my console logs within the mouse move handler always show the variable as false.
How can I get this panning boolean value to update as you'd expect within my mouse move handler?
Here is my trimmed down code, which is testable in my codepen link further down ...
import * as React from "https://cdn.skypack.dev/react@17.0.1";
import * as ReactDOM from "https://cdn.skypack.dev/react-dom@17.0.1";
type PropsType = {
url: string;
};
function ImageViewer(props: PropsType) {
const imgRef = React.useRef(null);
const canvasRef = React.useRef(null);
const [isDragging, setIsDragging] = React.useState(false);
function imageUrlChangeEffect() {
imgRef.current.src = props.url;
}
function componentMountEffect() {
imgRef.current.onload = handleImageLoad;
canvasRef.current.onmouseup = handleMouseUp;
canvasRef.current.onmousedown = handleMouseDown;
canvasRef.current.onmousemove = handleMouseMove;
}
function handleMouseUp() {
setIsDragging(false);
}
function handleMouseDown() {
setIsDragging(true);
}
function handleMouseMove(ev) {
const {x, y} = ev;
console.log({x, y, isDragging});
}
function handleImageLoad() {
clearCanvas();
drawImage();
}
function clearCanvas() {
const context = canvasRef.current.getContext("2d");
context.clearRect(0, 0, canvasRef.current.width, canvasRef.current.height);
}
function drawImage() {
const context = canvasRef.current.getContext("2d");
context.drawImage(imgRef.current, 0, 0, imgRef.current.width, imgRef.current.height);
}
React.useEffect(componentMountEffect, []);
React.useEffect(imageUrlChangeEffect, [props.url]);
return (
<div className="image-viewer">
<p>is dragging: {isDragging.toString()}</p>
<canvas ref={canvasRef} width="600" height="200"></canvas>
<img ref={imgRef} />
</div>
);
}
ReactDOM.render(
<ImageViewer url="https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png" />,
document.getElementById("container"));
Here is a testable code sample. You have to bring up the console to see the console logs of the variable never changing to true as you move your mouse and hold down the mouse button. You see though that the text above the canvas changes to show that it's changing from false to true ...
you have at least two solutions here:
Solution 1:
declare listener on canvas:
<canvas ref={canvasRef} width="600" height="200" onMouseMove={handleMouseMove}></canvas>
and use native event in the handleMouseMove
:
const {x, y} = ev.nativeEvent;
Solution 2:
instruct useEffect
to update value of isDragging
:
React.useEffect(componentMountEffect, [isDragging]);