Анимация путей и якорных точек

Для работы с Two.js необходимо сначала инициализировать сцену, на которой будут размещаться все графические объекты. Основным объектом является Two, который создаёт канвас и управляет рендерингом:

const elem = document.getElementById('draw-shapes');
const two = new Two({ width: 800, height: 600 }).appendTo(elem);

После создания сцены можно добавлять базовые фигуры: линии, прямоугольники, круги, полигоны и кривые. Основное внимание в анимации путей уделяется Path и Anchor, которые позволяют управлять формой кривых и их движением.

const path = two.makePath(50, 50, 150, 50, 150, 150, 50, 150, true); // замкнутый путь
path.fill = 'rgba(0, 200, 255, 0.5)';
path.stroke = 'black';
path.linewidth = 2;

Каждый путь состоит из якорных точек (anchors), каждая из которых имеет координаты x, y и опционально управляющие точки controls.left и controls.right, которые определяют кривизну сегментов.


Работа с якорными точками

Якорные точки являются фундаментом анимации в Two.js. Они дают возможность изменять форму кривой без пересоздания объекта.

Основные свойства Anchor:

  • anchor.x и anchor.y — координаты точки.
  • anchor.controls.left и anchor.controls.right — векторы управляющих точек для кривой Безье.
  • anchor.command — тип сегмента ('M' — move, 'L' — line, 'C' — bezier curve, 'Z' — close).

Пример изменения координат якорных точек для анимации кривой:

two.bind('upd ate', function(frameCount) {
  path.vertices[1].x = 150 + 50 * Math.sin(frameCount * 0.05);
  path.vertices[2].y = 150 + 30 * Math.cos(frameCount * 0.05);
}).play();

В этом примере используются vertices, которые являются массивом Anchor объектов. Изменение координат вершин в каждом кадре создаёт плавную анимацию.


Анимация кривых Безье

Кривые Безье создаются с помощью управляющих точек каждого Anchor. Для сложных анимаций важно правильно синхронизировать движение основной точки и её контроллеров:

path.vertices[1].controls.right.x = 100 + 40 * Math.cos(frameCount * 0.05);
path.vertices[1].controls.right.y = 50 + 40 * Math.sin(frameCount * 0.05);

Такой подход позволяет создать динамические изгибы и волнообразные движения, при этом сама структура пути остаётся одной и той же.

Для более плавного эффекта можно использовать функции интерполяции, например Two.Utils.interpolate, которая линейно или криволинейно изменяет значения между двумя состояниями:

anchor.x = Two.Utils.interpolate(anchor.x, targetX, 0.1);
anchor.y = Two.Utils.interpolate(anchor.y, targetY, 0.1);

Последовательная анимация вдоль пути

Анимация объектов вдоль заданного пути требует вычисления позиции на основе сегмента кривой. Two.js не предоставляет готового метода, поэтому используется метод чтения пути и интерполяции:

function getPointOnPath(vertices, t) {
  const n = vertices.length;
  const total = n - 1;
  const i = Math.floor(t * total);
  const frac = (t * total) - i;

  const x = vertices[i].x + frac * (vertices[i + 1].x - vertices[i].x);
  const y = vertices[i].y + frac * (vertices[i + 1].y - vertices[i].y);

  return { x, y };
}

const circle = two.makeCircle(0, 0, 10);
two.bind('update', function(frameCount) {
  const t = (frameCount % 200) / 200;
  const pos = getPointOnPath(path.vertices, t);
  circle.translation.se t(pos.x, pos.y);
}).play();

В этом примере объект circle плавно движется вдоль контура path. Для сложных кривых можно использовать кривые Безье с интерполяцией по сегментам.


Управление анимацией с использованием временных функций

Для естественной динамики движения применяются easing-функции. Two.js может использовать библиотеку Tween.js или встроенную интерполяцию для создания плавных переходов:

const anchor = path.vertices[2];
two.bind('update', function(frameCount) {
  const t = 0.5 + 0.5 * Math.sin(frameCount * 0.03);
  anchor.x = Two.Utils.interpolate(anchor.x, 200 + 50 * t, 0.1);
  anchor.y = Two.Utils.interpolate(anchor.y, 200 + 50 * (1 - t), 0.1);
}).play();

Такое управление позволяет делать ритмичные колебания, мягкие движения и волны, не прибегая к внешним библиотекам.


Практические советы

  • Для плавной анимации избегать прямого присваивания координат — лучше использовать интерполяцию.
  • Для сложных анимаций с большим количеством вершин рекомендуется хранить исходные координаты и состояния контроллеров, чтобы легко возвращать точки к базовой форме.
  • Использование two.update() вручную даёт полный контроль над кадрами и синхронизацией нескольких объектов.
  • Разделение логики движения и изменения формы кривой позволяет комбинировать анимации: объект может одновременно двигаться вдоль пути и менять форму самого пути.

Эти методы и приёмы позволяют создавать сложные динамические сцены, где пути и якорные точки анимируются в реальном времени, обеспечивая высокий уровень контроля над формой и движением объектов в Two.js.