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

#javascript #canvas #html5-canvas

#javascript #холст #html5-холст

Вопрос:

У меня возникли некоторые проблемы с реализацией пользовательского масштабирования.

У меня работает большая часть функций масштабирования, однако она масштабирует «вокруг» начала координат, в данном случае верхнего левого угла сетки. Вместо этого я хочу, чтобы он увеличивал масштаб вокруг курсора.

Холст такой же большой, как окно (я добавлю пользовательский интерфейс поверх холста, вроде как photoshop), и я рисую сетку на холсте размером в пиксели ШИРИНЫ x ВЫСОТЫ, «увеличенную» с коэффициентом PIXEL_SIZE.

Важная часть этого, этот обработчик событий прямо здесь

 const WIDTH = 32;
const HEIGHT = 24;
const PIXEL_SIZE = 10;
...
// controls how big the grid is
let scale = 1.5;

// controls where the grid is drawn, 
// starts exactly in the middle of the screen
let originX = canvas.width / 2 - (WIDTH * PIXEL_SIZE * scale) / 2;
let originY = canvas.height / 2 - (HEIGHT * PIXEL_SIZE * scale) / 2;

function zoom(event) {
  event.preventDefault();

  const wheel = event.deltaY < 0 ? 1 : -1;
  const z = Math.exp(wheel * 0.05);

  scale *= z;

  // this adjusts the scale just fine-ish
  // however, the origin needs to move in relation
  // to the cursor position
}

window.addEventListener("wheel", zoom, { passive: false });
 

Я пробовал несколько вещей, но по какой-то причине мой мозг на данный момент не может выполнить математику. Я пробовал использовать ctx.translate и ctx.scale , но ни один из них, похоже, не делает то, что я хочу сделать (хотя я мог бы использовать их неправильно).

Вот JSFiddle с тем, что у меня есть на данный момент. Если бы кто-нибудь мог взглянуть, это было бы потрясающе.

Ответ №1:

Довольно классный код. Масштабирование в определенной точке может быть сложным и может быть выполнено несколькими способами. Основная проблема заключается в том, где именно вы хотите увеличить масштаб и в каком масштабе / как быстро при приближении к максимальному масштабированию.

Я бы предложил начать с определения смещения

 ...
// starts exactly in the middle of the screen
let originX = canvas.width / 2 - (WIDTH * PIXEL_SIZE * scale) / 2;
let originY = canvas.height / 2 - (HEIGHT * PIXEL_SIZE * scale) / 2;

let offsetX = originX;
let offsetY = originY;
...
 

А затем вычислить смещение с использованием event.x и event.y MouseEvent в zoom обратном вызове, аналогично:

   function zoom(event) {
      ...

      // event.x and event.y returns the position relative to ...something
      // To properly scale the values, you could get the relative position
      // and size of the canvas and find your offset, for example
      // (viwportsizeX - canvasSizeX)   event.X / (scaleX) and the same for Y 
      // when the position is realtive to the viewport
      offsetX = event.x;
      offsetY = event.y;
  }
 

И, конечно, обновите смещение в главном цикле анимации:

 function animate() {
    requestAnimationFrame(animate);
    ctx.clearRect(0, 0, canvas.width, canvas.height);

    bufferCtx.putImageData(data, 0, 0);

    ctx.drawImage(
        bufferCanvas,
        originX - offsetX,
        originY - offsetY,
        WIDTH * PIXEL_SIZE * scale,
        HEIGHT * PIXEL_SIZE * scale
    );
 }
 

Увеличение точно в точке курсора возможно путем вычисления смещений относительно элемента холста, на котором выполняется масштабирование.

JSFiddle

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

1. Ваш пример действует довольно хаотично.

2. @RokoC. Buljan Это подразумевается как пример, а не как полное решение. Однако вы можете улучшить его, я с радостью приму улучшения