【发布时间】:2011-10-17 20:55:19
【问题描述】:
我已经构建了一个画布库,用于管理一些工作项目的形状场景。每个形状都是一个对象,具有与之关联的绘图方法。在刷新画布期间,将绘制堆栈上的每个形状。一个形状可能绑定了典型的鼠标事件,这些事件都包裹在画布自己的 DOM 鼠标事件周围。
我在野外发现了一些用于检测单个形状上的鼠标悬停的技术,每种技术都有效,但有一些非常严重的警告。
-
清除的幽灵画布用于自行绘制单个形状。然后我用
getImageData()存储一个幽灵画布的副本。正如您可以想象的那样,当有很多点与鼠标事件绑定时,这会占用大量内存(960x800 画布上的 100 个可点击形状在内存中约为 300MB)。 -
为了回避内存问题,我开始循环遍历像素数据并仅将地址存储到具有非零 alpha 的像素。这对于减少内存非常有效,但会显着增加 CPU 负载。我只在每 4 个索引 (RGBA) 上进行迭代,并且任何具有非零 alpha 的像素地址都存储为哈希键,以便在鼠标移动期间快速查找。它仍然会使 Linux 上的移动浏览器和 Firefox 过载 10 多秒。
-
我读到了一种技术,可以使用颜色将所有形状绘制到一个幻影画布上,以区分哪个形状拥有每个像素。我对这个想法非常满意,因为理论上它应该能够区分数百万种形状。
不幸的是,这被抗锯齿破坏了,在大多数画布实现中都无法禁用它。每个模糊边缘都会创建数十种颜色,这些颜色可以安全地忽略,除非/它们可以混合/与重叠的形状边缘。当有人将鼠标越过形状边界时,我最不想发生的事情是为与由于 AA 混合而出现的颜色相关的不相关形状触发半随机鼠标悬停事件。
我知道这对视频游戏开发者来说并不是一个新问题,而且必须有快速算法来解决这类问题。如果有人知道一种算法可以解决(实际上)数百个形状,而不会占用 CPU 超过几秒钟或显着增加 RAM 消耗,我将非常感激。
还有两个关于鼠标悬停检测的 Stack Overflow 主题,它们都讨论了这个主题,但它们仅比我描述的 3 种方法更进一步。 Detect mouseover of certain points within an HTML canvas? 和 mouseover circle HTML5 canvas.
编辑:2011/10/21
我测试了另一种更动态且不需要存储任何内容的方法,但它因 Firefox 中的性能问题而瘫痪。该方法基本上是循环形状和:1)在鼠标下清除1x1像素,2)绘制形状,3)在鼠标下获得1x1像素。令人惊讶的是,这在 Chrome 和 IE 中运行良好,但在 Firefox 下却很糟糕。
如果您只想要一个小像素区域,显然 Chrome 和 IE 能够进行优化,但 Firefox 似乎根本没有根据所需的像素区域进行优化。也许在内部它会获取整个画布,然后返回您的像素区域。
此处的代码和原始输出:http://pastebin.com/aW3xr2eB。
【问题讨论】:
-
就我个人而言,我只想改用 SVG。它更多的是它的目的。但是,可能值得查看 EaselJS (easeljs.com) 源代码。有一个方法
Stage.getObjectUnderPoint(),他们的演示似乎工作得很好。
标签: javascript algorithm graphics html5-canvas