- PVSM.RU - https://www.pvsm.ru -
Те, кто занимается разработкой графики с использованием JavaScript + Canvas давно заметили проблему обработки мышиных событий на каких-либо элементах графики.
Решений проблемы несколько:
Все эти способы имеют право на жизнь в определенных обстоятельствах, но когда события обнаруживать нужно (отметаем вариант 1), когда фигуры зачастую не являются прямоугольными, имеют повороты, и прочие трансформации (вариант 2 тоже не подходит), когда фигуры не являются геометрически правильными, как например, сглаженые сплайнами линии, многоугольники с вогнутими гранями (вариант 3 тоже забыли), а самое главное, когда этих фигур становится бесчисленное множество, и хранить координаты каждой, перебирая их на каждый MouseMove становится накладным, на помощь приходит другой способ.
Нам нужно до пикселя точно знать попал курсор на нашу фигуру или нет. Для этого предпримем следующее:
При создании фигуры присвоим ей уникальный числовой идентификатор, например, 1. Теперь преобразуем этот идентификатор цвет в RGB HEX нотации — #000001
.
Создадим новый элемент canvas для того слоя, на котором находится фигура, но не будем добавлять его в DOM, это наш фоновый холст.
Во время отрисовки фигуры на основном холсте, отрисуем ее же на фоновом, но тем цветом, что получился из ее идентификатора (в том числе и линии границ).
Теперь становится понятно, что при соблюдении порядка отрисовки, фигуры на фоновом холсте будут перекрывать друг друга в том порядке, что и на реальном, и при движении курсора мыши по основному холсту, можно по координатам узнать цвет пикселя фонового холста, который является идентификатором фигуры, что позволяет однозначно сказать что курсор зашел на фигуру или ушел с нее.
При движении мыши мы определяем цвет пикселя под ней, и если он непрозрачный (Alpha = 255)
, определяем идентификатор фигуры и работаем с событиями.
Но не все так радужно. Есть 3 основных проблемы:
Дело в том, что все браузеры по-умолчанию используют сглаживание при отрисовке, а значит, не все пиксели фигуры будут полностью непрозрачны и того цвета, что нам нужно.
Решение:
Нужно отрисовывать границы фигуры на 2 пикселя толще (или просто 2 пикселя при отсутствии этой самой границы). Это создаст дополнительный шум в окрестных пикселях, но так как для нас они не являются значимыми, а также не видны пользователю, можно этим пренебречь.
При пересечении 2 фигур, то же самое сглаживание может создать полностью непрозраные пиксели, цвет которых, будет переходным от цвета одной фигуры к цвету другой. При этом есть небольшая вероятность того, что этот цвет укажет на совершенно другую фигуру, которая находится в совершенно другом месте. В реально работающем приложении такая вероятность достаточно низка, но мы ведь хотим все предусмотреть?
Решение:
Для проверки достоверности идентификатора нужно узнать цвет 4 пикселей — сверху, снизу, справа и слева. Если каждый из них того же цвета или не полностью прозрачен, идентификатор достоверен.
В случае, когда мы работаем с изображениями, очевидно что необходимо создать некий обработчик изображения, который итеративно обрабатывает его пиксельные данные, полученые через getImageData
, и заменяет каждый непрозрачный пиксель цветом идентификатора фигуры, а каждый полупрозрачный заменяет прозрачным.
В этом случае нет четко поставленой прблемы, есть лишь 3 нюанса на которые стоит обратить внимание.
SECURITY_ERR
, и работать с изображением как с прямоугольником.Итак, мы уже имеем фоновый холст с отрисоваными нужными цветами фигурами. Как получить цвет пикселя под курсором? Ниже приведен абстрактный код, демонстрирующий как зная координаты курсора получить пиксель под ним:
//x, y - координаты мыши, полученые ранее
var ctx = bgCanvas.getContext("2d");
var pixel = ctx.getImageData(x, y, 1, 1).data; //массив из 4 элементов, каналы R, G, B и A, соответственно
var isOpaque = pixel[3] === 255; //Четвертый пиксель содержит альфа канал
Далее любым удобным способом нужно из каналов получить цвет, который можно сравнить с идентификатором фигуры.
Здесь специально не описаны тонкости реализации механизмов событий и хранения и обработки идентификаторов, так как вариантов бесчисленное множество.
В качестве источника использован следующий ресурс:
http://tschaub.net/blog/2011/03/31/canvas-hit-detection.html [1]
Статья не претендует на право быть переводом, однако в ней использована большая часть материалов исходного ресурса.
Автор: Xnoyer
Источник [2]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/javascript/44737
Ссылки в тексте:
[1] http://tschaub.net/blog/2011/03/31/canvas-hit-detection.html: http://tschaub.net/blog/2011/03/31/canvas-hit-detection.html
[2] Источник: http://habrahabr.ru/post/195966/
Нажмите здесь для печати.