Handles и управляющие точки

В основе векторной графики лежит представление кривых с помощью сегментов и управляющих точек. В библиотеке Paper.js каждая кривая строится из объектов Segment, которые содержат не только координаты самой точки, но и два вектора — handleIn и handleOut. Именно они определяют форму кривой между сегментами.


Структура сегмента

Каждый сегмент (Segment) включает три ключевых компонента:

  • point — основная точка (якорь)
  • handleIn — входящая управляющая точка
  • handleOut — исходящая управляющая точка
var segment = new Segment({
    point: [100, 100],
    handleIn: [-50, 0],
    handleOut: [50, 0]
});

Векторы handleIn и handleOut задаются относительно точки point, а не в абсолютных координатах.


Принцип работы handles

Handles управляют направлением и «силой» кривизны:

  • handleOut влияет на кривую, выходящую из текущего сегмента
  • handleIn влияет на кривую, входящую в сегмент

Если оба вектора равны [0, 0], сегмент соединяется с соседними прямой линией.


Связь с кривыми Безье

Paper.js использует кубические кривые Безье. Каждый отрезок между двумя сегментами определяется четырьмя точками:

  1. Текущая точка (point)
  2. Текущая handleOut
  3. Следующая handleIn
  4. Следующая точка (point)

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


Создание кривых с помощью handles

Пример создания простой кривой:

var path = new Path();
path.strokeColor = 'black';

path.add(new Segment({
    point: [100, 100],
    handleOut: [100, 0]
}));

path.add(new Segment({
    point: [300, 100],
    handleIn: [-100, 0]
}));

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


Симметричные и несвязанные handles

Симметричные handles

Когда handleIn и handleOut равны по длине и противоположны по направлению:

segment.handleIn = [-50, 0];
segment.handleOut = [50, 0];

Такая конфигурация обеспечивает плавный переход (smooth point).


Несвязанные handles

Handles можно задавать независимо:

segment.handleIn = [-30, -20];
segment.handleOut = [80, 40];

Это позволяет создавать острые изгибы и асимметричные кривые.


Автоматическое сглаживание

Paper.js предоставляет метод smooth() для автоматической настройки handles:

path.smooth();

Алгоритм анализирует соседние сегменты и выставляет управляющие точки так, чтобы кривая выглядела максимально плавной.

Варианты:

path.smooth({
    type: 'continuous'
});

Типы сглаживания:

  • continuous — плавный переход с сохранением формы
  • asymmetric — допускает асимметрию
  • geometric — учитывает геометрию сегментов

Работа с handles через API

Получение и изменение

var segment = path.segments[0];

segment.handleOut = new Point(50, 0);
segment.handleIn = new Point(-50, 0);

Удаление кривизны

segment.handleIn = new Point(0, 0);
segment.handleOut = new Point(0, 0);

Превращает участок в прямую линию.


Визуализация handles

Для отладки полезно отображать управляющие точки:

path.fullySelected = true;

Это включает отображение:

  • сегментов
  • линий handles
  • самих управляющих точек

Динамическое изменение handles

Handles можно изменять в реальном времени, например, при анимации:

function onFrame(event) {
    var segment = path.segments[0];
    segment.handleOut.x = Math.sin(event.time * 2) * 100;
}

Это создаёт эффект «живой» кривой.


Преобразования handles

Handles автоматически трансформируются при изменении пути:

path.scale(2);
path.rotate(45);

Все управляющие точки изменяются вместе с сегментами, сохраняя форму кривой.


Преобразование прямых в кривые

Даже если путь изначально состоит из прямых, можно добавить handles:

var segment = path.segments[1];
segment.handleIn = new Point(-50, 0);
segment.handleOut = new Point(50, 0);

Это мгновенно превращает прямой участок в кривую.


Работа с несколькими сегментами

Пример сложной кривой:

var path = new Path({
    strokeColor: 'black'
});

path.add(new Segment([100, 100], null, [50, 0]));
path.add(new Segment([200, 150], [-50, 0], [50, 50]));
path.add(new Segment([300, 100], [-50, -50], null));

Каждый сегмент влияет на форму всей кривой.


Разрыв связи handles

По умолчанию сглаженные точки могут вести себя как связанные. Для полного контроля:

segment.smooth({ type: 'asymmetric' });

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


Частые ошибки

1. Неправильное понимание координат handles Handles задаются относительно точки, а не в глобальных координатах.

2. Слишком длинные handles Могут приводить к неожиданным изгибам и самопересечениям.

3. Отсутствие балансировки между сегментами Резкие переходы возникают, если handles соседних сегментов не согласованы.


Практические приёмы

Создание плавных волн

for (var i = 0; i < path.segments.length; i++) {
    var segment = path.segments[i];
    segment.handleIn = new Point(-30, 0);
    segment.handleOut = new Point(30, 0);
}

Имитация острых углов

segment.handleIn = new Point(0, 0);
segment.handleOut = new Point(0, 0);

Управление формой через векторы

Handles — это обычные векторы, значит можно использовать:

segment.handleOut.length = 100;
segment.handleOut.angle = 45;

Это даёт удобный способ контролировать форму через длину и угол.


Взаимодействие с инструментами

При создании редакторов или интерактивных инструментов:

  • handles можно перетаскивать мышью
  • изменять в зависимости от пользовательского ввода
  • ограничивать длину или угол

Пример:

function onMouseDrag(event) {
    var segment = path.segments[0];
    segment.handleOut = event.point.subtract(segment.point);
}

Итоговая модель

  • Сегмент = точка + два управляющих вектора
  • Handles задают форму кривой
  • Взаимодействие между сегментами формирует непрерывную линию
  • Управление handles — ключ к точной работе с векторной графикой в Paper.js