HTML Canvas:鼠标点击命中测试使用ghost canvas - 抗锯齿麻烦

时间:2013-05-01 15:52:23

标签: javascript canvas html5-canvas

我正在编写一个JavaScript应用程序,它在HTML画布上绘制任意形状的对象。用户应该能够通过单击选择任何对象。

为了使这成为一个O(1)操作,我使用了一个阴影画布,即一个没有显示的画布,它具有完全相同的大小,在普通画布上绘制的每个对象也在那里绘制 - 但是颜色为代表它是ID 因此,一个简单的ghostContex.getImageData()和鼠标单击坐标一起给出了该像素的颜色,从而得到了点击对象的ID

所有这一切都运行正常 - 除非我点击对象的确切边框。

因为在鬼画布上使用抗锯齿绘制,我得到的颜色错误(因为该颜色是之前绘制的对象下正确的IDID之间的混合...)。这种错误的颜色表示错误ID,因此我选择了一个完全不同的对象:(

我该如何解决这个问题?

注意#1:我已经在使用translate(0.5,0.5)技巧来防止大多数抗锯齿 注意#2:我之前尝试用SVG编写这个应用程序,但是特别是这个对象选择非常慢,因为我猜它是用于碰撞检测的太多对象。这就是为什么我现在想要一个O(1)方法的主要原因......哦,这样我就可以轻松地在幽灵画布上绘制比在普通画布上绘制线条更大的线条,使拾取更容易。<登记/> 注意#3:相关浏览器是Firefox,Chrome,Android 2.3+原生和iOS原生

3 个答案:

答案 0 :(得分:1)

我无法接受任何答案的原因很简单而且非常悲伤:它不存在...... :(

抗锯齿无法切换,标准没有办法解决。但是该标准确实有一个命中测试函数(http://www.w3.org/html/wg/drafts/2dcontext/html5_canvas_CR/#hit-regions),它可以完全满足此处的需要。即使以一种很好的方式隐藏了开发人员讨厌的细节 - 但它现在还没有在任何浏览器中实现。
并且实施期望远远不可能(参见https://code.google.com/p/chromium/issues/detail?id=328961处的评论#6)。但显然它在上个月获得了动力......

那么平均时间可以做些什么呢?我做了什么?

在我的代码中,我可以为每个形状实现isPointInShape()方法。因此,我使用鬼画布技巧来获得形状,并使用isPointInShape()验证我确实选择了正确的形状。这有助于消除锯齿的像素不要选择错误的形状(只想到点击形状#2的边界,我们有50%的抗锯齿透明度 - 这会错误地告诉你选择形状#1 ......)。

如果你的形状很难实现通用isPointInShape(),你可以尝试一下我在其他地方读到的技巧(我没有尝试过它,所以我还没有测试过它...):
创建一个大小为1x1像素的额外幽灵画布,该画布正好位于鼠标位置。然后绘制感兴趣的形状 - 当RGBA的A更改时,此形状确实属于该像素。

答案 1 :(得分:0)

我编造了幽灵语境!你在用我的旧教程吗? :)

在那个旧教程中,我不会在每个对象被绘制后清除ghost上下文。在您的情况下,为了解决您的问题,您可能需要在测试ghost上下文中的每个对象后清除。

当然要确保您正在以相同的数量翻译幽灵上下文和正常上下文。 (并将其翻译回来,或者之后重置转换)。

答案 2 :(得分:0)

我知道这是一个老帖子,但最近我遇到了类似的问题。我解决“两种颜色的缝隙”问题的方法是对辅助画布进行10x10像素采样而不是单个像素。然后我将RGB值字符串化并将它们用作映射到颜色所代表的对象的地图中的键。因此,最初使用1像素采样我立即使用地图来确定关联对象,但抗锯齿创建了地图中不存在的中途颜色。 10x10方法通过循环返回的100个RGB值并创建“计数映射”来解决此问题。此贴图使用字符串化颜色并将它们映射到计数,但仅包括计数中第一个贴图的有效颜色。所以你最终会得到一张地图,说你计算了65个红色像素和23个蓝色像素(剩下的12个像素是一些奇怪的抗锯齿混合)。在我计算颜色的同一循环中,我还为当前最大计数和与该最大计数相关联的当前颜色维护了一个变量(以避免再次循环遍历此新映射)。现在最后你得到的颜色在10x10采样中计算得最多,并且可以使用它来映射回与之关联的对象。如果在10x10样本中找不到有效颜色,您将只能得到一个未定义的结果,您可以合理地假设这意味着单击了“背景”。