#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
на нем есть состояние, которое выглядит так:
Поэтому я вернулся и попробовал это вот так:
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 снова