Konva. js: [Свободное рисование и перетаскивание и масштабирование] Не удается правильно нарисовать с указателем после перетаскивания или масштабирования - PullRequest
0 голосов
/ 14 марта 2020

Любая дискуссия приветствуется. Спасибо за чтение!

Что я пытаюсь сделать

Я пытаюсь реализовать простую бумагу (доску), используя Konva. js.

Итак До сих пор я реализовал Drag, Zoom и Free рисование на бумаге.

Я ссылался на

  1. https://konvajs.org/docs/sandbox/Zooming_Relative_To_Pointer.html для Zoom
  2. https://konvajs.org/docs/sandbox/Free_Drawing.html для свободного рисования

Я хочу рисовать только на области с бежевым цветным фоном , а Я хочу рисовать точно под указатель, даже если он увеличен или перетащен.

Но функции «Свободное рисование» и «Перетаскивание» и «Масштаб» не работают вместе.

Ошибка

Не может рисовать правильно после перетаскивания или масштабирования.

Там, где я думаю, что происходит что-то не так, но не могу исправить

Я думаю, что что-то не так в 2 частях ниже.

  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();
<!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>

1 Ответ

0 голосов
/ 14 марта 2020

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);
}

/* ---- 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();
<!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>
...