Подтвердить что ты не робот

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

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

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

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

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

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 в смесь.

Любые идеи?

4b9b3361

Ответ 1

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

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

Ответ 2

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

Лучший метод, который я видел в другом месте для обнаружения мыши, - это повторить часть вашего чертежа, которую вы хотите обнаружить, на скрытый, очищенный холст. Затем сохраните объект 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, сумасшедшими составными фигурами, текстом и т.д.
  • Если ваше изображение довольно статично, вам нужно сделать это только один раз для интересующей области.
  • "Маска" медленная, но поиск пикселя - это дешево. Таким образом, "быстрая часть" отлично подходит для обнаружения мыши.

Недостатки

  • Это борода. Каждая маска имеет значения W * H * 4. Если у вас есть небольшая область холста или несколько областей для маскировки, это не так уж плохо. Используйте диспетчер задач 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]) {
  ...
}

Ответ 3

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

Ответ 4

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

Ответ 5

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

Ответ 6

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

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

Ответ 7

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