Popmotion использует унифицированную модель указателей (pointer
model), которая объединяет мышь, касания и перо в единый поток событий.
Это устраняет необходимость отдельно обрабатывать
mousedown, touchstart,
pointerdown и связанные с ними события низкого уровня.
Основной принцип — работа не с типом устройства ввода, а с абстрактным указателем, обладающим координатами, скоростью и фазой взаимодействия.
pointerФункция pointer создаёт поток координат, который
реагирует на начало взаимодействия и отслеживает движение вплоть до
завершения.
import { pointer } from 'popmotion';
const track = pointer({
x: 0,
y: 0
});
const subscription = track.start((v) => {
console.log(v.x, v.y);
});
Каждое событие возвращает объект состояния указателя:
x, y — текущие координатыdeltaX, deltaY — смещение с предыдущего
кадраvelocityX, velocityY — скорость
движенияpoint — исходные координаты взаимодействияМодель потоковая: при старте взаимодействия Popmotion сам подписывается на DOM-события и обновляет значения до момента завершения жеста.
Указатель проходит через несколько фаз:
Внутри Popmotion эти состояния агрегируются в единый поток значений, что позволяет абстрагироваться от различий между браузерами и устройствами.
Одной из ключевых задач библиотеки является приведение входных данных к единому формату.
Для каждого кадра вычисляются:
{
x: 240,
y: 120,
deltaX: 4,
deltaY: -2,
velocityX: 0.32,
velocityY: -0.18
}
Скорость не берётся напрямую из событий браузера, а вычисляется через дифференцирование позиций с последующим фильтром сглаживания, что снижает шум при резких движениях пальца.
Поверх pointer-модели строится поведение drag. Popmotion реализует его как композицию фильтров и ограничений.
import { pointer, listen, value } from 'popmotion';
const position = value({ x: 0, y: 0 });
pointer()
.start((pointerValue) => {
position.update(pointerValue);
});
Перетаскивание фактически представляет собой непрерывное присваивание координат состояния.
В сенсорных интерфейсах часто требуется ограничение перемещения объекта.
Popmotion использует трансформации данных потока:
import { pointer, transform } from 'popmotion';
const { clamp } = transform;
const xClamp = clamp(0, 300);
pointer().start((v) => {
const x = xClamp(v.x);
console.log(x);
});
Ограничения применяются не к DOM, а к потоку данных, что делает систему декларативной.
Для сенсорных экранов критична поддержка multitouch. Popmotion предоставляет механизм отслеживания нескольких указателей одновременно.
Каждое касание получает собственный идентификатор, позволяющий различать независимые потоки.
import { multitouch } from 'popmotion';
multitouch().start((points) => {
points.forEach((p) => {
console.log(p.x, p.y);
});
});
Структура данных представляет массив активных точек:
[
{ id: 0, x: 120, y: 80 },
{ id: 1, x: 200, y: 140 }
]
Это позволяет реализовывать жесты масштабирования, вращения и сложных манипуляций.
При наличии двух точек касания можно вычислять геометрию взаимодействия.
Основные параметры:
Расстояние вычисляется через евклидову метрику:
genui{“math_block_widget_always_prefetch_v2”:{“content”:“d = ”}}
Изменение расстояния используется для масштабирования, а изменение угла — для поворота.
Сырые данные касаний часто содержат шум, особенно при медленных движениях. Popmotion применяет сглаживание через фильтрацию значений скорости и позиции.
Используется принцип экспоненциального сглаживания:
s_t = x_t + (1 - ) s_{t-1}
где:
x_t — текущее значениеs_t — сглаженное значениеα — коэффициент сглаживанияЭто уменьшает резкие скачки координат при работе на сенсорных экранах.
Popmotion строится вокруг идеи связывания ввода и анимации в одной системе значений. Поток касаний может напрямую управлять анимационными значениями.
import { pointer, animate } from 'popmotion';
const x = pointer();
x.start((v) => {
animate({
from: v.x,
to: v.x + v.velocityX * 20,
duration: 100
});
});
Движение пальца становится источником параметров для кинетической анимации.
После события end часто применяется инерционная модель
движения. Popmotion использует скорость последнего кадра как основу для
продолжения движения.
Основная идея:
Математически это можно представить как экспоненциальное затухание скорости:
genui{“math_block_widget_always_prefetch_v2”:{“content”:“v(t) = v_0 e^{-kt}”}}
где скорость постепенно стремится к нулю.
Popmotion не привязывает сенсорные события напрямую к DOM-обработчикам. Вместо этого используется подписочная модель.
Это позволяет:
DOM становится лишь потребителем вычисленного состояния, а не источником логики.
Сложные взаимодействия строятся через композицию простых потоков:
Каждый слой преобразует входные данные, не изменяя базовую модель указателя.
Так формируется цепочка:
input → normalization → gesture recognition → state update → animation
Разделение этапов позволяет масштабировать систему взаимодействия без усложнения базового кода.