Search code examples
javascriptreactjskonvajsreact-konva

How to reset position of a dragged canvas on react-konva?


I have a react konva project where you can load an image into a canvas and then move around dragging the canvas. If you load a different image, then it appears on the position where the previous image was dragged to. I am guessing if there is any way to reset this "dragged" position on the stage (the draggable component). The only thing I can think of,because I'm using react, is to re-render the entire component, which is not a problem right now, but I want to have alternatives.

The reason why I made the stage draggable instead of the image itself it's because I have a series of points that I want to be moved along with the image. Sure I can add both points and image to a group, but that will introduce some complexity that it's probably not worth it.

The code that I have now looks something like this:

  <Stage draggable width={canvasWidth} height={canvasHeight}>
        <Layer ref={layerRef}>
          {imageInfo.loaded && (
            <Image
              image={image}
              onClick={addPoint}
              onTap={addPoint}
              width={imageInfo.targetWidth}
              height={imageInfo.targetHeight}
            />
          )}
          {points.map((p, idx) => (
            <Circle
              key={pointId(p)}
              x={p.x}
              y={p.y}
              fill={color}
              radius={size}
              onClick={() => setPoints(points => removePos(idx, points))}
            />
          ))}
        </Layer>
      </Stage>

Solution

  • If you want to reset stage position when a new image is loaded you can:

    1. reset the position of the stage manually if ref access
    const App = () => {
      const stageRef = React.useRef();
      const [image] useImage(url);
    
      // every time an images is changed we should reset position of the stage
      React.useEffect(() => {
         stageRef.current.position({ x: 0, y: 0});
      }, [image])
    
      return <Stage ref={stageRef} draggable width={canvasWidth} height={canvasHeight} />;
    };
    
    1. Or you can reset the position in the state (and it is important to save position changes in dragmove or dragend events):
    const App = () => {
      const [pos, setPos] = React.useState({x : 0, y: 0 });
    
      const handleDragEnd = (e) => {
         setPos({
           x: e.target.x(),
           y: e.target.y(),
         });
      };
    
      // every time an images is changed we should reset position of the stage
      React.useEffect(() => {
         setPos({ x: 0, y: 0});
      }, [image])
    
      return <Stage onDragEnd={handleDragEnd} draggable width={canvasWidth} height={canvasHeight} />;
    };