Определение попадания курсора на объект

Для работы с библиотекой Two.js необходимо создать экземпляр Two и привязать его к контейнеру на странице. Это базовый шаг для отображения графики и обработки взаимодействия с пользователем:

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

Создание объектов происходит через методы two.makeRectangle, two.makeCircle, two.makePolygon и т.д. Каждый объект получает уникальные свойства, включая координаты центра, размеры и цвет:

const rect = two.makeRectangle(200, 150, 100, 80);
rect.fill = '#FF8000';
rect.stroke = '#000000';
rect.linewidth = 2;

const circle = two.makeCircle(400, 300, 50);
circle.fill = '#0080FF';
circle.stroke = '#000000';
circle.linewidth = 2;

После создания объектов необходимо вызвать two.update() для отрисовки сцены.


Отслеживание положения курсора

Для определения попадания курсора на объект нужно знать текущие координаты мыши относительно контейнера. Событие mousemove позволяет получить эти данные:

elem.addEventListener('mousemove', function(event) {
    const rect = elem.getBoundingClientRect();
    const mouseX = event.clientX - rect.left;
    const mouseY = event.clientY - rect.top;

    checkHit(mouseX, mouseY);
});

mouseX и mouseY представляют координаты курсора относительно верхнего левого угла области, в которой отображается Two.js.


Проверка попадания на прямоугольник

Простейший способ — проверка координат мыши относительно границ объекта:

function isMouseOverRectangle(mouseX, mouseY, rect) {
    const left = rect.translation.x - rect.width / 2;
    const right = rect.translation.x + rect.width / 2;
    const top = rect.translation.y - rect.height / 2;
    const bottom = rect.translation.y + rect.height / 2;

    return mouseX >= left && mouseX <= right && mouseY >= top && mouseY <= bottom;
}

Для каждого движения мыши можно использовать эту функцию, чтобы определить, находится ли курсор над объектом:

function checkHit(mouseX, mouseY) {
    if (isMouseOverRectangle(mouseX, mouseY, rect)) {
        rect.fill = '#FF0000'; // Изменение цвета при наведении
    } else {
        rect.fill = '#FF8000';
    }
    two.update();
}

Проверка попадания на круг

Для окружности необходимо использовать формулу расстояния между точкой и центром круга:

function isMouseOverCircle(mouseX, mouseY, circle) {
    const dx = mouseX - circle.translation.x;
    const dy = mouseY - circle.translation.y;
    const distance = Math.sqrt(dx * dx + dy * dy);

    return distance <= circle.radius;
}

Применение аналогично прямоугольнику:

if (isMouseOverCircle(mouseX, mouseY, circle)) {
    circle.fill = '#00FF00';
} else {
    circle.fill = '#0080FF';
}
two.update();

Проверка попадания на сложные фигуры

Для полигона или многоугольника используется алгоритм «луч-лучевая проверка» (ray-casting), который определяет, находится ли точка внутри контура:

function isPointInPolygon(x, y, vertices) {
    let inside = false;
    for (let i = 0, j = vertices.length - 1; i < vertices.length; j = i++) {
        const xi = vertices[i].x, yi = vertices[i].y;
        const xj = vertices[j].x, yj = vertices[j].y;

        const intersect = ((yi > y) !== (yj > y)) &&
                          (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
        if (intersect) inside = !inside;
    }
    return inside;
}

Для использования:

const poly = two.makePolygon(500, 400, 60, 5); // Пятиугольник
function isMouseOverPolygon(mouseX, mouseY, poly) {
    return isPointInPolygon(mouseX, mouseY, poly.vertices);
}

Оптимизация проверки попадания

  1. Сначала проверка bounding box: для сложных фигур сначала проверяется попадание в ограничивающий прямоугольник, чтобы не выполнять дорогостоящий алгоритм для каждой точки.
  2. Кэширование вычислений: хранение координат вершин в массиве для полигона уменьшает нагрузку при частом обновлении.
  3. События mouseenter и mouseleave: можно использовать переменную состояния, чтобы не менять цвет при каждом движении мыши, если состояние уже известно.

Интеграция с анимацией

Two.js позволяет анимировать объекты с помощью two.bind('update', callback):

two.bind('update', function(frameCount) {
    rect.rotation += 0.01;
    circle.rotation -= 0.02;
}).play();

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


Выводы по методам определения попадания

  • Прямоугольник — проверка координат по границам.
  • Круг — проверка расстояния до центра.
  • Полигон — алгоритм ray-casting.
  • Оптимизация — bounding box, кэширование вершин, минимизация обновлений цвета.

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