Pointer events в Popmotion построены вокруг унифицированной модели обработки ввода, которая абстрагирует мышь, сенсорные экраны и стилусы в единый поток координатных событий. В основе лежит реактивная модель: движение указателя превращается в последовательность значений, которые можно преобразовывать, комбинировать и связывать с анимациями.
Pointer API в Popmotion предоставляет поток координат x,
y, а также дополнительные метаданные события. Внутренне
используется подписочная модель, где каждое движение указателя
становится новым значением потока.
Ключевая идея — отказ от императивной обработки событий в пользу декларативного описания реакции на ввод.
import { pointer } from 'popmotion';
const pointerTracker = pointer();
pointerTracker.start((v) => {
console.log(v.x, v.y);
});
Каждое значение v представляет текущее состояние
указателя:
{
x: number,
y: number,
deltaX: number,
deltaY: number,
velocityX: number,
velocityY: number,
pressure?: number,
point?: number
}
Событие указателя в Popmotion расширяет базовую координатную модель дополнительными параметрами, которые позволяют строить инерционные и физически правдоподобные анимации.
Основные поля:
x, y — абсолютные координаты
указателяdeltaX, deltaY — смещение относительно
предыдущего событияvelocityX, velocityY — скорость движения
по осямpressure — давление (для устройств, поддерживающих
stylus)point — идентификатор активного указателяСкорость вычисляется на основе временного интервала между событиями, что позволяет использовать данные напрямую для инерционных эффектов.
Pointer поток проходит три ключевые стадии: старт, обновление и завершение.
Запуск начинается с фиксации начальной точки:
const pointerTracker = pointer();
pointerTracker.start({
start: (v) => {
console.log('start', v.x, v.y);
}
});
На этом этапе фиксируется начальная позиция и сбрасываются внутренние значения скорости.
Основной поток значений формируется при движении:
pointerTracker.start({
update: (v) => {
element.style.transform = `translate(${v.x}px, ${v.y}px)`;
}
});
Каждое обновление содержит дифференциальные изменения, что позволяет строить трансформации без дополнительного вычисления дельт.
Финальное событие фиксирует завершение жеста:
pointerTracker.start({
end: (v) => {
console.log('end velocity:', v.velocityX, v.velocityY);
}
});
Значения скорости на момент завершения используются для инерционных анимаций и продолжения движения.
Pointer поток может быть ограничен конкретной областью взаимодействия. Это позволяет отслеживать движение внутри элемента без ручной работы с DOM-событиями.
const box = document.querySelector('.box');
const tracker = pointer({
target: box
});
tracker.start((v) => {
box.style.transform = `translate(${v.x}px, ${v.y}px)`;
});
В этом режиме Popmotion автоматически рассчитывает координаты относительно элемента-цели.
Pointer API работает в пикселях, но часто требуется нормализация значений в диапазон 0–1. Это используется для адаптивных интерфейсов и анимационных кривых.
tracker.start((v) => {
const normalizedX = v.x / window.innerWidth;
const normalizedY = v.y / window.innerHeight;
});
Нормализованные значения удобно связывать с анимационными функциями.
Pointer API поддерживает несколько одновременных указателей через
идентификатор point. Это позволяет отслеживать независимые
жесты.
tracker.start((v) => {
if (v.point === 0) {
// первый палец
}
if (v.point === 1) {
// второй палец
}
});
Каждый активный pointer сохраняет собственное состояние скорости и координат.
Одно из ключевых применений pointer API — управление анимациями в реальном времени. Данные потока напрямую передаются в функции трансформации.
import { animate } from 'popmotion';
const tracker = pointer();
tracker.start((v) => {
animate({
from: v.x,
to: v.x + v.velocityX * 20
});
});
Такой подход позволяет создавать инерционные эффекты без ручного расчёта физики.
Pointer поток можно комбинировать с функциями ограничения значений. Это полезно для drag-интерфейсов.
tracker.start((v) => {
const x = Math.max(0, Math.min(300, v.x));
const y = Math.max(0, Math.min(500, v.y));
element.style.transform = `translate(${x}px, ${y}px)`;
});
Ограничение координат часто используется в интерфейсах перетаскивания и слайдерах.
Pointer поток возвращает объект управления подпиской, позволяющий завершать прослушивание событий.
const subscription = tracker.start((v) => {
console.log(v.x, v.y);
});
subscription.stop();
Остановка потока освобождает обработчики событий и прекращает вычисление значений.
Pointer API становится более мощным при использовании вместе с функциями преобразования потоков: фильтрацией, интерполяцией и сглаживанием.
import { pointer, transformMap } from 'popmotion';
const smooth = transformMap({
x: (v) => v * 0.1,
y: (v) => v * 0.1
});
pointer().start((v) => {
const transformed = smooth(v);
element.style.transform =
`translate(${transformed.x}px, ${transformed.y}px)`;
});
Такой подход снижает шум движения и делает взаимодействие более плавным.
Velocity в pointer API рассчитывается динамически и отражает реальную скорость перемещения. Это позволяет строить инерционные траектории без дополнительных таймеров.
pointer().start((v) => {
const projectedX = v.x + v.velocityX * 100;
const projectedY = v.y + v.velocityY * 100;
});
Скорость обновляется на каждом кадре, что делает данные пригодными для физически корректных анимаций.
Pointer поток обычно синхронизируется с requestAnimationFrame внутри Popmotion. Это обеспечивает стабильную частоту обновлений независимо от частоты событий браузера.
События указателя агрегируются и нормализуются перед передачей в подписчиков, что предотвращает избыточные обновления UI.
При резких скачках координат Popmotion использует сглаживание значений скорости, чтобы избежать выбросов. Это особенно важно для сенсорных экранов с низкой частотой обновления.
Дельты ограничиваются внутренними фильтрами, что делает движение предсказуемым даже при нестабильном вводе.
Pointer API является основой для реализации drag-and-drop логики. Поток координат напрямую связывается с позиционированием элемента.
pointer().start((v) => {
element.style.left = `${v.x}px`;
element.style.top = `${v.y}px`;
});
При этом сохраняется непрерывность движения без ручной обработки событий mousedown, mousemove и mouseup.
Pointer данные часто используются как входные параметры для моделей пружин, трения и импульса. Velocity становится основным источником энергии движения, а координаты — состоянием системы.
Такой подход позволяет строить интерфейсы, где движение продолжается после завершения жеста, постепенно затухая под действием коэффициента трения.