检测HTML画布中某些点的鼠标悬停?

rya*_*nki 32 javascript canvas

我已经为Canvas构建了一个分析数据可视化引擎,并且已经被要求在数据元素上添加类似工具提示的悬停,以显示光标下数据点的详细度量.

对于简单的条形图和Gaant图表,具有简单方形区域或特定兴趣点的树形图和节点图,我能够通过将绝对定位的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();
Run Code Online (Sandbox Code Playgroud)

绑定到这样的对象在Flash或Silverlight中实现几乎是微不足道的,因为当前的Canvas实现具有直接使用我们现有的Javascript API并与其他Ajax元素集成的优势,我们希望避免将Flash置于混合中.

有任何想法吗?

Sam*_*ler 21

您可以处理mousemove事件并从事件中获取x,y坐标.然后,您可能必须遍历所有路径以测试该点是否在路径上.我有一个类似的问题,可能有一些你可以使用的代码.

以这种方式循环事物可能会很慢,尤其是在IE上.一种方法可以加速它 - 这是一个黑客,但它会非常有效 - 将改变每个路径绘制的颜色,以便人类不会注意到但是每个路径都被绘制成不同的颜色.有一个表来查找路径的颜色,只需查看鼠标下的像素颜色.

  • 我喜欢颜色的想法,但这种可视化使用了大量的渐变来指示各种活动点.我在http://twitpic.com/cqam4找到了一张图片,展示了我的意思.对于每个彩色区域,我希望鼠标悬停按名称识别它并显示有关该点的一些数字统计数据. (2认同)
  • 我真的很喜欢颜色的想法.现在,每个渐变在特定的色调范围内是不同的,所以我可以解码回HSV并以这种方式进行映射!我试试看. (2认同)
  • 精度太低了.对于类似颜色的区域,我会得到颜色范围的消失.相反,我想我会渲染一个单独的不可见阴影画布,其中包含直接映射的非渐变颜色值,并在那里执行像素颜色索引查找. (2认同)

jca*_*lly 13

阴影画布

我在其他地方看到的用于鼠标悬停检测的最佳方法是将要检测的图形部分重复到隐藏的清除画布上.然后存储ImageData对象.然后,您可以检查ImageData数组中的感兴趣像素,如果alpha值大于0,则返回true.

// 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
  ...
}
Run Code Online (Sandbox Code Playgroud)

好处

  • 您可以检测任何您想要的内容,因为您只是重复上下文方法.这适用于PNG alpha,疯狂复合形状,文本等.
  • 如果您的图像是相当静态的,那么您只需要每个感兴趣的区域执行一次此操作.
  • "面具"很慢,但查找像素很便宜.因此,"快速部分"非常适合鼠标悬停检测.

缺点

  • 这是一个记忆猪.每个掩模是W*H*4值.如果你有一个小的帆布区域或几个区域来掩盖,它并没有那么糟糕.使用chrome的任务管理器来监控内存使用情况.
  • 目前Chrome和Firefox中存在getImageData的已知问题.如果你使变量无效,结果不会立即收集垃圾,所以如果你经常这样做,你会看到内存迅速上升.它最终会收集垃圾并且它不应该崩溃浏览器,但它可能会在具有少量RAM的机器上征税.

拯救记忆的黑客

我们可以只记住哪些像素具有alpha值,而不是存储整个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]) {
  ...
}
Run Code Online (Sandbox Code Playgroud)


Fab*_*ger 7

这可以使用方法ctx.isPointInPath完成,但它不是在ExCanvas for IE中实现的.但另一个解决方案是使用HTML地图,就像我为这个小库所做的那样:http://phenxdesign.net/projects/phenx-web/graphics/example.htm你可以从中获得灵感,但它仍然是一点点越野车.