HitTest и определение попадания

HitTest — это механизм, который позволяет определить, находится ли точка на холсте в пределах какой-либо графической фигуры, пути или слоя. Он широко используется для обработки кликов, наведения мыши и взаимодействия с объектами в Paper.js. Метод hitTest вызывается на объекте project или view, и возвращает объект HitResult, содержащий подробную информацию о том, что именно было «попаданием».

var hitResult = project.hitTest(point, options);
  • point — объект типа Point, координаты которого проверяются на попадание.
  • options — объект, который задаёт условия поиска попаданий.

Опции HitTest

Объект options позволяет гибко настроить поведение hitTest. Основные свойства:

  • segmentstrue, если нужно проверять попадание по сегментам путей.
  • stroketrue, если проверять попадание по контуру (stroke) объекта.
  • filltrue, если проверять попадание по заливке (fill).
  • tolerance — число, задающее допустимое расстояние до линии или сегмента для признания попадания.
  • class — фильтр по классу объекта (Path, Shape, Raster, TextItem).
  • match — функция обратного вызова для дополнительной фильтрации объектов.

Пример использования:

var hit = project.hitTest(new Point(50, 50), {
    segments: true,
    stroke: true,
    fill: true,
    tolerance: 5
});
if (hit) {
    console.log(hit.item); // объект, в который попали
    console.log(hit.point); // точка попадания
    console.log(hit.location); // локализация на пути
}

Свойства HitResult

Объект HitResult содержит набор свойств, которые дают полную информацию о попадании:

  • item — объект Paper.js (Path, Shape, Raster), в который произошло попадание.
  • point — точка типа Point, где произошло попадание.
  • location — объект PathLocation, если попадание произошло на пути.
  • segment — сегмент пути, если попадание произошло на сегменте.
  • curve — кривизна, если попадание на кривой Безье.
  • distance — расстояние до объекта.

Примеры различных сценариев

Попадание по заливке

var circle = new Path.Circle({
    center: [100, 100],
    radius: 50,
    fillColor: 'red'
});

var hit = project.hitTest(new Point(120, 120), { fill: true });
if (hit) {
    console.log('Попадание по заливке круга');
}

Попадание по контуру

var rectangle = new Path.Rectangle({
    point: [200, 200],
    size: [100, 50],
    strokeColor: 'blue'
});

var hit = project.hitTest(new Point(250, 220), { stroke: true, tolerance: 2 });
if (hit) {
    console.log('Попадание по контуру прямоугольника');
}

Попадание на сегмент

var line = new Path.Line({
    from: [300, 300],
    to: [400, 400],
    strokeColor: 'green'
});

var hit = project.hitTest(new Point(350, 350), { segments: true, tolerance: 5 });
if (hit) {
    console.log('Попадание на сегмент линии');
}

Использование функции match

Функция match позволяет фильтровать объекты перед возвратом результата. Например, только объекты с определённым цветом заливки:

var hit = project.hitTest(new Point(120, 120), {
    fill: true,
    match: function(item) {
        return item.fillColor && item.fillColor.toCSS(true) === '#ff0000';
    }
});
if (hit) {
    console.log('Попадание по красной заливке');
}

HitTest для слоёв и групп

hitTest работает не только с отдельными элементами, но и с группами (Group) и слоями (Layer). В случае групп, Paper.js проверяет все дочерние элементы. Это позволяет организовать сложные структуры и всё равно определять попадания:

var group = new Group([circle, rectangle]);
var hit = project.hitTest(new Point(250, 220), { fill: true });
if (hit) {
    console.log('Попадание на один из элементов группы');
}

Практические рекомендации

  • Точность: использовать свойство tolerance для небольших объектов или тонких линий, чтобы не пропускать попадания.
  • Оптимизация: при большом количестве объектов фильтровать по классу через class или функцию match.
  • Комбинация опций: можно комбинировать segments, stroke и fill, чтобы получать более точные результаты.
  • События мыши: hitTest удобно использовать внутри обработчиков событий onMouseDown, onMouseMove, onMouseUp для интерактивных интерфейсов.

Особенности работы с кривыми и сегментами

Когда hitTest используется с segments: true, результат возвращает объект segment и location. Свойство location предоставляет методы для дальнейшего анализа кривой: вычисление угла касательной, длины до сегмента, позиции на кривой. Это особенно полезно для анимаций и сложных интерактивных сценариев, где важно точное позиционирование.

if (hit && hit.location) {
    console.log(hit.location.offset); // смещение по пути
    console.log(hit.location.curve);  // кривая Безье на которой попадание
}

HitTest для растровых изображений

Для объектов Raster метод hitTest ограничен проверкой по прямоугольной области (bounds) и прозрачности пикселей при pixelHitTest: true:

var raster = new Raster('image.png');
var hit = project.hitTest(new Point(150, 150), { pixel: true });
if (hit) {
    console.log('Попадание на непустой пиксель растрового изображения');
}
  • pixel: true — проверяет прозрачность пикселя. Если пиксель прозрачный, попадание не фиксируется.