Создание пользовательских путей

Пользовательские пути (custom paths) — ключевой инструмент для построения произвольной графики в библиотеке Two.js. В отличие от стандартных примитивов (прямоугольников, окружностей, линий), пути позволяют создавать сложные формы с точным контролем над каждой вершиной и кривой.

В основе лежит объект Two.Path, который представляет собой последовательность точек (vertices), соединённых линиями или кривыми Безье.


Структура объекта Path

Объект пути создаётся с использованием массива вершин:

const path = new Two.Path([
  new Two.Anchor(0, 0),
  new Two.Anchor(100, 0),
  new Two.Anchor(100, 100),
  new Two.Anchor(0, 100)
], true);

Ключевые параметры:

  • массив vertices — точки пути

  • второй аргумент (true) — замкнутость пути (closed)

  • дополнительные свойства:

    • fill — цвет заливки
    • stroke — цвет обводки
    • linewidth — толщина линии

Вершины и Two.Anchor

Каждая точка пути — это объект Two.Anchor. Он может представлять как обычную точку, так и управляющую точку для кривых.

const anchor = new Two.Anchor(x, y, lx, ly, rx, ry, command);

Параметры:

  • x, y — координаты точки
  • lx, ly — левая контрольная точка (для кривой)
  • rx, ry — правая контрольная точка
  • command — тип сегмента (move, line, curve)

Типы сегментов пути

Каждая вершина может иметь команду, определяющую способ соединения:

  • Two.Commands.move — перемещение без рисования
  • Two.Commands.line — прямая линия
  • Two.Commands.curve — кривая Безье
  • Two.Commands.close — замыкание пути

Пример:

const path = new Two.Path([
  new Two.Anchor(0, 0, null, null, null, null, Two.Commands.move),
  new Two.Anchor(100, 0, null, null, null, null, Two.Commands.line),
  new Two.Anchor(100, 100, 80, 20, 120, 80, Two.Commands.curve)
], false);

Кривые Безье

Для создания плавных линий используются кубические кривые Безье. Управление осуществляется через контрольные точки.

const curved = new Two.Path([
  new Two.Anchor(0, 0),
  new Two.Anchor(100, 100, 50, 0, 150, 100)
], false);

curved.vertices[1].command = Two.Commands.curve;

Особенности:

  • контрольные точки задают направление касательной
  • чем дальше контрольная точка — тем сильнее изгиб

Замкнутые и незамкнутые пути

Путь может быть:

  • замкнутым (closed = true) — последняя точка соединяется с первой
  • открытым (closed = false)
path.closed = true;

Замкнутые пути используются для заливки фигур, открытые — для линий и контуров.


Динамическое изменение пути

Вершины можно изменять после создания:

path.vertices[0].x = 50;
path.vertices[0].y = 50;
path._flagVertices = true;

Флаг _flagVertices сообщает системе о необходимости обновления геометрии.


Добавление и удаление вершин

path.vertices.push(new Two.Anchor(200, 200));
path.vertices.splice(1, 1);
path._flagVertices = true;

Это позволяет динамически изменять форму, например, при анимации.


Интерполяция (автоматическое сглаживание)

Two.js может автоматически рассчитывать кривые между точками:

path.curved = true;

При этом:

  • не требуется вручную задавать контрольные точки
  • создаётся плавная линия через все вершины

Ручное управление сглаживанием

Для отключения автоматического сглаживания:

path.curved = false;

После этого каждая вершина должна иметь явно заданный command.


Преобразования пути

Любой путь поддерживает стандартные трансформации:

path.translation.set(200, 200);
path.rotation = Math.PI / 4;
path.scale = 1.5;

Работа с сегментами

Каждый сегмент — это связь между двумя вершинами. Управление осуществляется через:

path.vertices[i].command = Two.Commands.line;

Изменение типа сегмента позволяет динамически менять форму.


Построение сложных форм

Пример создания произвольной фигуры:

const shape = new Two.Path([
  new Two.Anchor(0, 0, null, null, null, null, Two.Commands.move),
  new Two.Anchor(50, -100, null, null, null, null, Two.Commands.line),
  new Two.Anchor(100, 0, 75, -50, 125, -50, Two.Commands.curve),
  new Two.Anchor(0, 0, null, null, null, null, Two.Commands.close)
], true);

shape.fill = 'orange';
shape.stroke = 'black';
shape.linewidth = 2;

Анимация путей

Пути удобно использовать для анимаций:

two.bind('upd ate', function(frameCount) {
  path.vertices.forEach((v, i) => {
    v.y += Math.sin(frameCount * 0.05 + i) * 0.5;
  });
  path._flagVertices = true;
});

Оптимизация производительности

При работе с большим количеством путей важно учитывать:

  • минимизация изменения _flagVertices
  • использование curved вместо ручных кривых (при возможности)
  • уменьшение количества вершин

Использование масок и клиппинга

Пути можно применять как маски:

shape.mask = anotherPath;

Это позволяет создавать сложные визуальные эффекты.


Работа с прозрачностью и стилями

path.opacity = 0.5;
path.dashes = [5, 3];
path.linecap = 'round';
path.linejoin = 'bevel';

Композиция путей

Несколько путей можно объединять в группы:

const group = two.makeGroup(path1, path2);
group.translation.se t(100, 100);

Практические сценарии применения

  • рисование пользовательских иконок
  • построение графиков и диаграмм
  • анимация волн, линий, контуров
  • генеративная графика
  • интерактивные интерфейсы

Ограничения и особенности

  • отсутствие нативной поддержки булевых операций (объединение, пересечение)
  • необходимость ручного управления контрольными точками
  • чувствительность к количеству вершин при анимации

Внутренние механизмы обновления

Two.js использует флаги (_flag*) для отслеживания изменений:

  • _flagVertices
  • _flagFill
  • _flagStroke

Это позволяет минимизировать перерасчёт сцены.


Расширение функциональности

Пути можно комбинировать с:

  • пользовательскими шейдерами (в WebGL-режиме)
  • событиями мыши
  • физическими движками

Контроль точности

Для высокоточной графики важно:

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

Сериализация и восстановление путей

Пути можно сохранять:

const data = JSON.stringify(path.vertices);

И восстанавливать:

const vertices = JSON.parse(data).map(v => new Two.Anchor(v.x, v.y));
const newPath = new Two.Path(vertices);

Связь с SVG

Two.js может импортировать SVG, преобразуя его в пути:

two.load('shape.svg', function(group) {
  two.add(group);
});

Каждый SVG-путь превращается в Two.Path, что позволяет редактировать его программно.


Управление порядком отрисовки

Пути отрисовываются в порядке добавления:

path1.addTo(two);
path2.addTo(two);

Позднее добавленные элементы находятся выше.


Тонкая настройка геометрии

Для сложных форм используется комбинация:

  • ручных контрольных точек
  • смешанных типов сегментов
  • динамических обновлений

Это делает Two.Path универсальным инструментом для любой 2D-графики.