Search code examples
konvajs

React konva custom shape drag


How to update position of a custom shape after drag? With other shapes e.target.position() works, but with custom shapes it returns position relative to original position when drawing the shape.

I tried to update position by adding new coordinates to the original position but shape goes to wrong position.


Solution

  • Here is your old code of the shape:

    <Shape
      sceneFunc={(context, shape) => {
        context.beginPath();
        context.moveTo(pos.x, pos.y);
    
        for (let i = 0; i < pos.points.length; i++) {
          context.lineTo(pos.x + pos.points[i].x, pos.y + pos.points[i].y);
        }
        context.stroke();
        // (!) Konva specific method, it is very important
        context.fillStrokeShape(shape);
      }}
      stroke="black"
      strokeWidth={4}
      draggable={true}
      onDragEnd={handleDrag}
    />
    

    Here you are using the position of the node pos.x and pos.y inside sceneFunc. You don't need to do that! Konva automatically applies transform into 2D context before calling sceneFunc.

    Here is fixed version of full code:

    export default function App() {
      const [pos, setPos] = useState({
        x: 20,
        y: 50,
        points: [
          { x: 200, y: 60 },
          { x: 300, y: 200 }
        ]
      });
    
      const handleDrag = (e) => {
        setPos((prev) => ({ ...prev, x: e.target.x(), y: e.target.y() }));
      };
    
      return (
        <Stage width={window.innerWidth} height={window.innerHeight}>
          <Layer>
            <Shape
              sceneFunc={(context, shape) => {
                context.beginPath();
                context.moveTo(0, 0);
    
                for (let i = 0; i < pos.points.length; i++) {
                  context.lineTo(pos.points[i].x, pos.points[i].y);
                }
                // (!) Konva specific method, it is very important
                context.fillStrokeShape(shape);
              }}
              stroke="black"
              strokeWidth={4}
              draggable={true}
              onDragEnd={handleDrag}
            />
          </Layer>
        </Stage>
      );
    }
    

    Demo: https://codesandbox.io/s/react-konva-custom-shape-with-drag-9f78lr?file=/src/App.js