Вычисление позиций

Interact.js предоставляет гибкий механизм для управления позиционированием элементов на странице через drag-and-drop, масштабирование и другие интерактивные действия. В основе этого механизма лежат координаты мыши, позиция элемента в DOM и трансформации CSS.

Координаты события

Каждое интерактивное событие (dragmove, resize, gesturemove) содержит объект события с несколькими ключевыми свойствами для определения положения:

  • event.pageX и event.pageY — координаты курсора относительно страницы.
  • event.clientX и event.clientY — координаты относительно видимой области браузера.
  • event.dx и event.dy — смещение курсора с предыдущего события. Полезно для инкрементного перемещения.

Использование этих координат позволяет точно вычислять новые позиции элемента, независимо от его начального положения.

Позиционирование через CSS трансформации

Interact.js по умолчанию работает через CSS transform: translate(), что обеспечивает плавное и высокопроизводительное перемещение. Для отслеживания позиции элемента используется собственный объект data, где хранятся текущие координаты:

target.dataset.x = (parseFloat(target.dataset.x) || 0) + event.dx;
target.dataset.y = (parseFloat(target.dataset.y) || 0) + event.dy;

target.style.transform =
  `translate(${target.dataset.x}px, ${target.dataset.y}px)`;

Ключевые моменты:

  • dataset позволяет хранить абсолютные координаты без постоянного чтения CSS стилей.
  • Смещение dx/dy применяется инкрементно.
  • transform гарантирует аппаратное ускорение и минимизирует сдвиг макета страницы.

Вычисление позиции относительно родителя

В случаях, когда элемент находится внутри контейнера с собственным позиционированием, важно учитывать смещение родительского блока:

const rect = parent.getBoundingClientRect();
const offsetX = event.clientX - rect.left;
const offsetY = event.clientY - rect.top;
  • getBoundingClientRect() возвращает текущие координаты контейнера относительно окна браузера.
  • offsetX и offsetY позволяют вычислять локальные координаты внутри родителя.
  • Эти координаты особенно важны при реализации ограничений движения (restrict) и сетки (snapGrid).

Применение сетки и ограничений

Interact.js поддерживает ограничения движения с помощью метода modifiers. Для позиционирования на сетке используется snap:

interact(target).draggable({
  modifiers: [
    interact.modifiers.snap({
      targets: [
        interact.snappers.grid({ x: 50, y: 50 })
      ],
      range: Infinity,
      relativePoints: [{ x: 0, y: 0 }]
    })
  ]
});
  • snap.targets определяет точки, к которым элемент будет притягиваться.
  • grid({ x, y }) задает шаг сетки по горизонтали и вертикали.
  • relativePoints определяет точку элемента, к которой применяется притяжение.

Актуализация позиции после трансформаций

После изменения масштаба (scale) или вращения (rotate) элемент может иметь нестандартные координаты в системе страницы. Для корректного вычисления применяются методы:

const rect = target.getBoundingClientRect();
const style = window.getComputedStyle(target);
const matrix = new DOMMatrixReadOnly(style.transform);

const x = matrix.m41; // трансляция по X
const y = matrix.m42; // трансляция по Y
  • DOMMatrixReadOnly позволяет извлечь текущие значения translate, scale, rotate.
  • Это важно для точного расчета позиции элемента после сложных трансформаций.

Инкрементное и абсолютное позиционирование

Interact.js поддерживает два подхода:

  1. Инкрементное — добавление dx/dy к текущим координатам (плавное перемещение).
  2. Абсолютное — установка позиции по фиксированным координатам страницы или родителя.

Пример абсолютного позиционирования:

target.style.left = `${event.pageX - offsetX}px`;
target.style.top = `${event.pageY - offsetY}px`;
  • Используется, когда необходимо позиционировать элемент без CSS-трансформаций.
  • Требует, чтобы элемент имел position: absolute или relative в родительском контейнере.

Синхронизация с другими событиями

Для сложных интерфейсов часто требуется вычислять позицию с учётом нескольких интерактивных действий одновременно (drag + resize). Interact.js предоставляет объект interaction:

interact(target).on('dragmove resize', event => {
  const x = (parseFloat(target.dataset.x) || 0) + event.dx;
  const y = (parseFloat(target.dataset.y) || 0) + event.dy;
  target.dataset.x = x;
  target.dataset.y = y;
  target.style.transform = `translate(${x}px, ${y}px)`;
});
  • interaction объединяет события и позволяет применять общую логику смещения.
  • Поддерживает вычисление позиции в реальном времени с учётом ограничений и сеток.

Итоговые рекомендации

  • Хранение координат в dataset позволяет легко комбинировать смещения и трансформации.
  • Использование transform: translate() обеспечивает производительное позиционирование.
  • Учет смещений родителя через getBoundingClientRect() необходим для корректной работы с контейнерами.
  • Применение modifiers позволяет легко реализовать сетки, ограничения и притяжение к точкам.
  • Для сложных трансформаций важно использовать DOMMatrixReadOnly для точного получения координат после масштабирования и вращения.

Такой подход позволяет реализовать точное, плавное и управляемое позиционирование элементов в любых интерактивных интерфейсах на базе Interact.js.