Обнаружить наведение курсора мыши на определенные точки внутри HTML-холста?

StackOverflow https://stackoverflow.com/questions/1221347

  •  10-07-2019
  •  | 
  •  

Вопрос

Я создал механизм аналитической визуализации данных для Canvas, и меня попросили добавить всплывающую подсказку в виде наведения курсора мыши на элементы данных, чтобы отобразить подробные показатели для точки данных под курсором.

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

Возможно ли каким-то образом прикрепить наложение или вызвать событие, когда пользователь наводит курсор мыши на определенный замкнутый путь?

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

context.beginPath();
context.moveTo(segmentRight, prevTop);
context.bezierCurveTo(segmentRight, prevTop, segmentLeft, thisTop, segmentLeft, thisTop);
context.lineTo(segmentLeft, thisBottom);
context.bezierCurveTo(segmentLeft, thisBottom, segmentRight, prevBottom, segmentRight, prevBottom);
/*
 * ...define additional segments...
 */
// <dream> Ideally I would like to attach to events on each path:
context.setMouseover(function(){/*Show hover content*/});
// </dream>
context.closePath();

Привязку к объекту, подобному этому, почти тривиально реализовать во Flash или Silverlight, поскольку, хотя текущая реализация Canvas имеет преимущество прямого использования нашего существующего Javascript API и интеграции с другими элементами Ajax, мы надеемся избежать использования Flash в сочетании.

Есть какие-нибудь идеи?

Это было полезно?

Решение

Вы можете обработать событие mousemove и получить координаты x, y из события. Тогда вам, вероятно, придется перебирать все ваши пути, чтобы проверить, находится ли точка на пути. У меня была похожая проблема , которая могла некоторый код, который вы могли бы использовать.

Циклы по таким вещам могут быть медленными, особенно в IE. Один из способов, которыми вы могли бы ускорить его - и это хак, но это было бы весьма эффективно - это изменить цвет, которым нарисован каждый путь, чтобы он не был заметен для людей, но чтобы каждый путь был нарисован в другой цвет. Подготовьте таблицу для поиска цветов путей и просто найдите цвет пикселя под мышкой.

Другие советы

Теневой холст

Лучший метод, который я видел в других местах для обнаружения наведения курсора мыши, - это повторить часть вашего рисунка, которую вы хотите обнаружить, на скрытом, очищенном холсте.Затем сохраните объект ImageData.Затем вы можете проверить массив ImageData на наличие интересующего пикселя и вернуть true, если альфа-значение больше 0.

// slow part
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.fillRect(100,100,canvas.width-100,canvas.height-100);
var pixels = ctx.getImageData(0,0,canvas.width,canvas.height).data;

// fast part
var idx = 4 * (mouse_x + mouse_y * canvas.width) + 3;
if (pixels[idx]) { // alpha > 0
  ...
}

Преимущества

  • Вы можете обнаружить все, что захотите, поскольку вы просто повторяете контекстные методы.Это работает с PNG alpha, сумасшедшими составными фигурами, текстом и т.д.
  • Если ваше изображение достаточно статично, то вам нужно сделать это только один раз для каждой области интереса.
  • "Маска" работает медленно, но поиск пикселя обходится очень дешево.Таким образом, "быстрая часть" отлично подходит для обнаружения наведения курсора мыши.

Недостатки

  • Это боров памяти.Каждая маска имеет 4 значения W * H*.Если у вас есть небольшая область холста или несколько областей для маскировки, это не так уж плохо.Используйте диспетчер задач Chrome для отслеживания использования памяти.
  • В настоящее время известна проблема с getImageData в Chrome и Firefox.Результаты не будут собраны сразу, если вы обнулите переменную, поэтому, если вы будете делать это слишком часто, вы увидите, что объем памяти быстро увеличивается.В конечном итоге происходит сбор мусора, и это не должно привести к сбою браузера, но это может быть обременительно для машин с небольшим объемом оперативной памяти.

Взлом для экономии памяти

Вместо того чтобы хранить весь массив ImageData целиком, мы можем просто запомнить, какие пиксели имеют альфа-значения.Это экономит много памяти, но добавляет цикл к процессу маски.

var mask = {};
var len = pixels.length;
for (var i=3;i<len;i+=4) if ( pixels[i] ) mask[i] = 1;

// this works the same way as the other method
var idx = 4 * (mouse_x + mouse_y * canvas.width) + 3;
if (mask[idx]) {
  ...
}

Это можно сделать с помощью метода ctx.isPointInPath, но это не реализовано в ExCanvas для IE. Но другим решением было бы использовать карты HTML, как я сделал для этой маленькой библиотеки: http : //phenxdesign.net/projects/phenx-web/graphics/example.htm вы можете черпать вдохновение из этого, но он все еще немного глючит.

Я бы предложил наложить карту изображения с правильными координатами, установленными в областях, соответствующих элементам, нарисованным на холсте. Таким образом, вы получаете подсказки и множество других функций DOM / Browser бесплатно.

Мне нужно было обнаружить щелчки мышью для сетки квадратов (например, ячеек таблицы Excel). Чтобы ускорить его, я разделил сетку на регионы, которые рекурсивно делятся пополам до тех пор, пока не останется небольшое количество ячеек, например, для сетки 100x100, первые 4 области могут быть сетками 50x50, содержащими четыре квадранта. Затем они могут быть разделены на еще 4 каждый (следовательно, давая 16 областей 25x25 каждый). Это требует небольшого количества сравнений, и, наконец, сетка 25x25 может быть протестирована для каждой ячейки (625 сравнений в этом примере).

Есть книга Эрика Роуэлла "HTML5 CANVAS COOKBOOK". В этой книге есть глава под названием «Взаимодействие с Canvas: присоединение слушателей событий к фигурам и областям». Могут быть реализованы события mousedown, mouseup, mouseover, mouseout, mousemove, touchstart, touchend и touchmove. Я настоятельно рекомендую вам прочитать это.

Этого нельзя сделать (ну, по крайней мере, не так просто), потому что объекты, которые вы рисуете на холсте (пути), не представлены как те же самые объекты на холсте. Я имею в виду, что это простой 2D-контекст, и как только вы на нем что-то рисуете, он полностью забывает, как он был нарисован. Это просто набор пикселей для него.

Для того, чтобы наблюдать за наведением мыши и тому подобным, вам нужен какой-нибудь холст с векторной графикой, то есть SVG, или реализовать свой собственный поверх существующего (что и предложил Сэм Хаслер)

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top