Skip to content Skip to sidebar Skip to footer

Konva.js: [free Drawing & Drag & Zoom] Can't Draw Correctly With Pointer After Drag Or Zoom

Any discussion is welcomed. Thanks for reading! What I am trying to do I'm trying to implement simple paper(whiteboard) using Konva.js. So far I've implemented Drag, Zoom and Free

Solution 1:

stage.getPointerPosition() returns absolute position of pointer (related top-left corner of canvas container).

As you are transforming (moving and scaling a stage) you need to find a relative position, so you can use it for the line.

Relative mouse position demo demonstrates how to do that:

functiongetRelativePointerPosition(node) {
  // the function will return pointer position relative to the passed nodevar transform = node.getAbsoluteTransform().copy();
  // to detect relative position we need to invert transform
  transform.invert();

  // get pointer (say mouse or touch) positionvar pos = node.getStage().getPointerPosition();

  // now we find a relative pointreturn transform.point(pos);
}

/* ---- Mode management ---- */let modeSelector = document.getElementById('mode-selector');
let mode = modeSelector.value;
modeSelector.addEventListener('change', () => {
  // Discaed event handlers used by old modeswitch (mode) {
    case'Hand': {
      endHand();
      break;
    }
    case'Pen': {
      endPen();
      break;
    }
  }

  // Set event handlers for new mode
  mode = modeSelector.value;
  switch (mode) {
    case'Hand': {
      useHand();
      break;
    }
    case'Pen': {
      usePen();
      break;
    }
  }
});


/* ---- Konva Objects ---- */let stage = newKonva.Stage({
  container: 'container',
  width: window.innerWidth,
  height: window.innerHeight
});

// A layer that is only used for background colorlet backgroundLayer = newKonva.Layer();
let backgroundColor = newKonva.Image({
  width: window.innerWidth,
  height: window.innerHeight,
  fill: 'rgb(242,233,226)'
}) 
backgroundLayer.add(backgroundColor);
stage.add(backgroundLayer);
backgroundLayer.draw();

// A layer for free drawinglet drawLayer = newKonva.Layer();
stage.add(drawLayer);


/* ---- Functions for mode change ----*/functionuseHand () {
  // Make stage draggable
  stage.draggable(true);

  // Make stage zoomable// *** Code is copy and pasted from// *** https://konvajs.org/docs/sandbox/Zooming_Relative_To_Pointer.htmlhttps://konvajs.org/docs/sandbox/Zooming_Relative_To_Pointer.htmllet scaleBy = 1.3;
  stage.on('wheel', (evt) => {
    evt.evt.preventDefault();
    let oldScale = stage.scaleX();

    let mousePointTo = {
      x: stage.getPointerPosition().x / oldScale - stage.x() / oldScale,
      y: stage.getPointerPosition().y / oldScale - stage.y() / oldScale
    };

    let newScale = evt.evt.deltaY > 0 ? oldScale * scaleBy : oldScale / scaleBy;
    stage.scale({ x: newScale, y: newScale });

    let newPos = {
      x: -(mousePointTo.x - stage.getPointerPosition().x / newScale) * newScale,
      y: -(mousePointTo.y - stage.getPointerPosition().y / newScale) * newScale
    };
    stage.position(newPos);
    stage.batchDraw();
  });
}

functionendHand () {
  stage.draggable(false);
  stage.off('wheel');
}

functiongetRelativePointerPosition(node) {
    // the function will return pointer position relative to the passed nodevar transform = node.getAbsoluteTransform().copy();
    // to detect relative position we need to invert transform
    transform.invert();

    // get pointer (say mouse or touch) positionvar pos = node.getStage().getPointerPosition();

    // now we find relative pointreturn transform.point(pos);
  }
functionusePen () {
  let isDrawing = false;
  let currentLine;
  stage.on('mousedown', (evt) => {
    // Start drawing
    isDrawing = true;
    // Create new line objectlet pos = getRelativePointerPosition(stage);
    currentLine = newKonva.Line({
      stroke: 'black',
      strokeWidth: 3,
      points: [pos.x, pos.y]
    });
    drawLayer.add(currentLine);
  });

  stage.on('mousemove', (evt) => {
    if (!isDrawing) {
      return;
    }
    
    // If drawing, add new point to the current line objectlet pos = getRelativePointerPosition(stage);
    let newPoints = currentLine.points().concat([pos.x, pos.y]);
    currentLine.points(newPoints);
    drawLayer.batchDraw();
  });

  stage.on('mouseup', (evt) => {
    // End drawing
    isDrawing = false;
  });
}

functionendPen () {
  stage.off('mousedown');
  stage.off('mousemove');
  stage.off('mouseup');
}


/* ---- Init ---- */useHand();
<!DOCTYPE html><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width, initial-scale=1.0"><title>Paper</title></head><body><selectid="mode-selector"><optionvalue="Hand">Hand</option><optionvalue="Pen">Pen</option></select><divid="container"></div><scriptsrc="https://unpkg.com/konva@4.0.0/konva.min.js"></script><!-- <script src="konvaTest.js"></script> --><scriptsrc="buggyPaper.js"></script></body></html>

Post a Comment for "Konva.js: [free Drawing & Drag & Zoom] Can't Draw Correctly With Pointer After Drag Or Zoom"