Konva.js:[自由绘图和拖动和缩放]拖动或缩放后无法用指针正确绘图

dyn*_*dle 5 javascript konvajs

欢迎任何讨论。谢谢阅读!

我正在尝试做什么

我正在尝试使用 Konva.js 实现简单的纸张(白板)。

到目前为止,我已经在纸上实现了拖动、缩放和自由绘图。

我提到

  1. https://konvajs.org/docs/sandbox/Zooming_Relative_To_Pointer.html用于缩放
  2. https://konvajs.org/docs/sandbox/Free_Drawing.html免费绘图

我只想在米色背景的区域上绘制,并且我想精确地在指针下方绘制,即使它被缩放或拖动。

但自由绘图以及拖动和缩放功能不能很好地协同工作。

漏洞

拖动或缩放后无法正确绘制。

我认为发生了错误的事情,但无法修复

我认为以下两部分有问题。

  1. 缩放的实现
  2. 我如何在绘图实现中使用stage.getPointerPosition()
  3. 或者这两个的实现不适合在一起

代码

最低代码在这里。

/* ---- Mode management ---- */
let modeSelector = document.getElementById('mode-selector');
let mode = modeSelector.value;
modeSelector.addEventListener('change', () => {
  // Discaed event handlers used by old mode
  switch (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 = new Konva.Stage({
  container: 'container',
  width: window.innerWidth,
  height: window.innerHeight
});

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

// A layer for free drawing
let drawLayer = new Konva.Layer();
stage.add(drawLayer);


/* ---- Functions for mode change ----*/
function useHand () {
  // 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.html
  let 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();
  });
}

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

function usePen () {
  let isDrawing = false;
  let currentLine;
  stage.on('mousedown', (evt) => {
    // Start drawing
    isDrawing = true;
    // Create new line object
    let pos = stage.getPointerPosition();
    currentLine = new Konva.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 object
    let pos = stage.getPointerPosition();
    let newPoints = currentLine.points().concat([pos.x, pos.y]);
    currentLine.points(newPoints);
    drawLayer.batchDraw();
  });

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

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


/* ---- Init ---- */
useHand();
Run Code Online (Sandbox Code Playgroud)
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Paper</title>
</head>
<body>
  <select id="mode-selector">
    <option value="Hand">Hand</option>
    <option value="Pen">Pen</option>
  </select>
  <div id="container"></div>

  <script src="https://unpkg.com/konva@4.0.0/konva.min.js"></script>
  <!-- <script src="konvaTest.js"></script> -->
  <script src="buggyPaper.js"></script>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)

lav*_*ton 7

stage.getPointerPosition()返回指针的绝对位置(画布容器的相关左上角)。

当您进行变换(移动和缩放舞台)时,您需要找到相对位置,以便可以将其用于线条。

相对鼠标位置演示演示了如何做到这一点:

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

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

  // now we find a relative point
  return transform.point(pos);
}
Run Code Online (Sandbox Code Playgroud)

/* ---- Mode management ---- */
let modeSelector = document.getElementById('mode-selector');
let mode = modeSelector.value;
modeSelector.addEventListener('change', () => {
  // Discaed event handlers used by old mode
  switch (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 = new Konva.Stage({
  container: 'container',
  width: window.innerWidth,
  height: window.innerHeight
});

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

// A layer for free drawing
let drawLayer = new Konva.Layer();
stage.add(drawLayer);


/* ---- Functions for mode change ----*/
function useHand () {
  // 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.html
  let 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();
  });
}

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

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

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

    // now we find relative point
    return transform.point(pos);
  }
function usePen () {
  let isDrawing = false;
  let currentLine;
  stage.on('mousedown', (evt) => {
    // Start drawing
    isDrawing = true;
    // Create new line object
    let pos = getRelativePointerPosition(stage);
    currentLine = new Konva.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 object
    let 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;
  });
}

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


/* ---- Init ---- */
useHand();
Run Code Online (Sandbox Code Playgroud)
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Paper</title>
</head>
<body>
  <select id="mode-selector">
    <option value="Hand">Hand</option>
    <option value="Pen">Pen</option>
  </select>
  <div id="container"></div>

  <script src="https://unpkg.com/konva@4.0.0/konva.min.js"></script>
  <!-- <script src="konvaTest.js"></script> -->
  <script src="buggyPaper.js"></script>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)