Как я могу рассчитать новое положение курсора относительно моего холста после увеличения масштаба?

#javascript #reactjs #canvas

Вопрос:

Контекст:

Я пытаюсь создать игру с раскраской пикселей с помощью холста. На данный момент я визуализирую несколько прямых линий strokeRect , которые можно нарисовать при помощи fillRect клика .

Поскольку холст не является полноэкранным, а просто фиксированного размера, мне нужно рассчитать смещение. Когда у меня есть координаты, я просто делю x на ширину прямой (10).

Вот код, который у меня есть.

Сначала я получаю правильное положение курсора:

 function getCursorPosition(canvas, event) {
    const rect = canvas.getBoundingClientRect();

    const x = event.clientX - rect.left
    const y = event.clientY - rect.top

   
    return { x: x, y: y };
  }
 

Затем я рассчитаю, куда нужно fillRect , чтобы казалось, что я заполнил strokeRect именно эту позицию:

 const paint = (e, isClick) => {
    if (!isDrawing amp;amp; !isClick) {
      return;
    }

    const coordinates = getCursorPosition(canvas, e);

    let rectX = Math.floor(coordinates.x / 10);
    let rectY = Math.floor(coordinates.y / 10);
    // stop drawing when it's outside of the bounds (i have a grid 100 x 100)
    if (rectX > 99 || rectY > 99) {
      return;
    }

    ctx.fillStyle = "black";
    ctx.fillRect(rectX * 10, rectY * 10, 10, 10);
  };
 

Проблема:

Так что это работает как заклинание. Но сегодня я установил React-zoom-pan-pinch

Очевидно, что после того, как я увеличу масштаб холста, все испортится, так getCursorPosition как функция должна выполнять больше работы. Мне нужно рассчитать новое правильное положение после масштабирования. Но я не могу понять, как это сделать.

Поэтому после того, как я увеличу масштаб и нажму на прямоугольники (пиксели), цветная прямая появится в крайнем правом и дальнем нижнем углу. Так что сейчас все очень не так.

Пакет предоставляет мне эту функцию onZoom , которая получает следующие параметры: ReactZoomPanPinchRef и event . У них есть много атрибутов, например x , y , offsetX , .. и многое другое.

Я попробовал несколько комбинаций, но не могу заставить их работать.

Вопрос:

Как я могу рассчитать новое положение курсора относительно моего холста, чтобы я мог рисовать на нем прямоугольники? Каков расчет, который мне нужно сделать, учитывая все атрибуты, которые onZoom дает мне событие/реквизит.

Вот все атрибуты из этого пакета:

https://prc5.github.io/react-zoom-pan-pinch/?path=/story/docs-props—page

К сожалению, я не смог найти список реквизита, который ReactZoomPanPinchRef и event дает мне. Я мог бы сделать скриншоты, но это длинный список.

Что я выяснил до сих пор:

Я нашел репо react для рисования кабана, сделанное с помощью react canvas. Он использует функцию «колесо мыши», которую вы можете увидеть здесь:

https://github.com/dilidili/react-drawing-board/blob/master/src/SketchPad.tsx#L858

Также эту матрицу я мог бы найти здесь:

https://github.com/dilidili/react-drawing-board/blob/master/src/utils.ts#L4

Никогда об этом не слышал. Но, может быть, мне нужно что-то подобное. Также пакет react-zoom-pan-pinch предоставляет в onZoom функции этот параметр:

ReactZoomPanPinchRef на нем есть состояние, которое выглядит так:

https://imgur.com/a/8t1FpJR

Поэтому я вернулся и попробовал это вот так:

  let rectX = Math.floor((coordinates.x   zoomState.offsetX) / rectSize);
    let rectY = Math.floor((coordinates.y   zoomState.offsetY) / rectSize);
 

Теперь это намного лучше, но чем дальше я увеличиваю масштаб, тем хуже становится.

И последнее, но не менее важное: вот кодовое поле, в котором вы можете все это попробовать:

https://codesandbox.io/s/dark-darkness-iqwku?file=/src/components/canvas.js:2023-2171

Соответствующие файлы: index.js componentscanvas.js

Если вам нужна дополнительная информация, пожалуйста, дайте мне знать.

Ребята, спасибо вам за это.

Ответ №1:

До сих пор, похоже, вы возились со смещением состояния масштабирования. Смещение, однако, отлично фиксируется, canvas.getBoundingClientRect() поскольку оно по-прежнему возвращает положение верхнего левого угла даже после преобразования CSS.

Проблема заключается в вашем преобразовании в rectX и rectY : при увеличении или уменьшении размера ваших прямоугольников изменяется размер, который еще не отражен в ваших расчетах. Следующий фрагмент кода решает эту проблему:

 const scale = zoomState?.scale ?? 1;
let rectX = Math.floor(coordinates.x / (rectSize * scale));
let rectY = Math.floor(coordinates.y / (rectSize * scale));
 

Рабочий пример можно увидеть в этой ветке вашего CodeSandbox.

Комментарии:

1. В качестве дополнительного несвязанного бонусного совета return { x: x, y: y } можно записать как return { x, y } . Если переменная, которую вы хотите использовать в качестве значения во вновь созданном объекте, имеет то же имя, что и нужный ключ, вы можете записать ее следующим образом.

2. Да return { x, y } Я знал об этом. Я просто был небрежен с этим 😀 Thx снова