草庐IT

javascript - HTML5 canvas 的三种鼠标检测技术,都不够

coder 2024-05-12 原文

我已经构建了一个 Canvas 库来管理一些工作项目的形状场景。每个形状都是一个对象,具有与之关联的绘图方法。在刷新 Canvas 期间,绘制堆栈中的每个形状。形状可能绑定(bind)了典型的鼠标事件,这些事件都包裹在 Canvas 自己的 DOM 鼠标事件周围。

我在野外发现了一些检测鼠标悬停在单个形状上的技术,每一种都有效,但有一些非常严重的警告。

  1. 清除的幽灵 Canvas 用于单独绘制一个单独的形状。然后,我使用 getImageData() 存储了 ghost Canvas 的副本。可以想象,当有许多点绑定(bind)了鼠标事件时,这会占用大量内存(960x800 Canvas 上的 100 个可点击形状大约需要 300MB 内存)。

  2. 为了回避内存问题,我开始遍历像素数据并仅存储具有非零 alpha 的像素的地址。这对于减少内存很有效,但会显着增加 CPU 负载。我只对每 4 个索引 (RGBA) 进行迭代,并且任何具有非零 alpha 的像素地址都存储为哈希键,以便在鼠标移动期间进行快速查找。它仍然会使 Linux 上的移动浏览器和 Firefox 重载 10 秒以上。

  3. 我读到过一种技术,在这种技术中,所有形状都将绘制到一个幽灵 Canvas 上,使用颜色来区分哪个形状拥有每个像素。我对这个想法非常满意,因为理论上它应该能够区分数百万种形状。

    不幸的是,这被抗锯齿破坏了,抗锯齿在大多数 Canvas 实现中都无法禁用。每个模糊边缘都会产生数十种颜色,除了/它们可以与重叠的形状边缘混合/之外,可以安全地忽略这些颜色。当有人将鼠标悬停在形状边界上时,我最不希望发生的事情是为不相关的形状触发半随机鼠标悬停事件,这些形状与由于 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 似乎根本没有根据所需的像素区域进行优化。也许在内部它会获取整个 Canvas ,然后返回您的像素区域。

此处的代码和原始输出:http://pastebin.com/aW3xr2eB .

最佳答案

如果我对问题的理解正确,您想检测鼠标何时进入/离开 Canvas 上的形状,对吗?

如果是这样,那么您可以使用简单的几何计算,这比在像素数据上循环要简单和快速得多。您的渲染算法已经有了所有可见形状的列表,因此您知道每个形状的位置、尺寸和类型。

假设您有某种形状列表,类似于@Benjammmin' 所描述的,您可以遍历可见形状并进行多边形内点检查:

// Track which shape is currently under the mouse cursor, and raise
// mouse enter/leave events
function trackHoverShape(mousePos) {
    var shape;
    for (var i = 0, len = visibleShapes.length; i < len; i++) {
        shape = visibleShapes[i];
        switch (shape.type ) {
            case 'arc':
                if (pointInCircle(mousePos, shape) &&
                    _currentHoverShape !== shape) {
                        raiseEvent(_currentHoverShape, 'mouseleave');
                        _currentHoverShape = shape;
                        raiseEvent(_currentHoverShape, 'mouseenter');
                    return;
                }
                break;
            case 'rect':
                if (pointInRect(mousePos, shape) &&
                    _currentHoverShape !== shape) {
                       raiseEvent(_currentHoverShape, 'mouseleave');
                       _currentHoverShape = shape;
                       raiseEvent(_currentHoverShape, 'mouseenter');
                }
                break;
        }
    }
}

function raiseEvent(shape, eventName) {
    var handler = shape.events[eventName];
    if (handler)
        handler();
}

// Check if the distance between the point and the shape's
// center is greater than the circle's radius. (Pythagorean theroem)
function pointInCircle(point, shape) {
    var distX = Math.abs(point.x - shape.center.x),
        distY = Math.abs(point.y - shape.center.y),
        dist = Math.sqrt(distX * distX + distY * distY);
    return dist < shape.radius;
}

因此,只需调用 Canvas 中的 trackHoverShape mousemove 事件,它就会跟踪当前鼠标下的形状。

希望对您有所帮助。

关于javascript - HTML5 canvas 的三种鼠标检测技术,都不够,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7799466/

有关javascript - HTML5 canvas 的三种鼠标检测技术,都不够的更多相关文章

  1. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

    我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

  2. ruby-on-rails - Rails HTML 请求渲染 JSON - 2

    在我的Controller中,我通过以下方式在我的index方法中支持HTML和JSON:respond_todo|format|format.htmlformat.json{renderjson:@user}end在浏览器中拉起它时,它会自然地以HTML呈现。但是,当我对/user资源进行内容类型为application/json的curl调用时(因为它是索引方法),我仍然将HTML作为响应。如何获取JSON作为响应?我还需要说明什么? 最佳答案 您应该将.json附加到请求的url,提供的格式在routes.rb的路径中定义。这

  3. ruby-on-rails - 使用 Sublime Text 3 突出显示 HTML 背景语法中的 ERB? - 2

    所以我在关注Railscast,我注意到在html.erb文件中,ruby代码有一个微弱的背景高亮效果,以区别于其他代码HTML文档。我知道Ryan使用TextMate。我正在使用SublimeText3。我怎样才能达到同样的效果?谢谢! 最佳答案 为SublimeText安装ERB包。假设您安装了SublimeText包管理器*,只需点击cmd+shift+P即可获得命令菜单,然后键入installpackage并选择PackageControl:InstallPackage获取包管理器菜单。在该菜单中,键入ERB并在看到包时选择

  4. ruby-on-rails - Ruby url 到 html 链接转换 - 2

    我正在使用Rails构建一个简单的聊天应用程序。当用户输入url时,我希望将其输出为html链接(即“url”)。我想知道在Ruby中是否有任何库或众所周知的方法可以做到这一点。如果没有,我有一些不错的正则表达式示例代码可以使用... 最佳答案 查看auto_linkRails提供的辅助方法。这会将所有URL和电子邮件地址变成可点击的链接(htmlanchor标记)。这是文档中的代码示例。auto_link("Gotohttp://www.rubyonrails.organdsayhellotodavid@loudthinking.

  5. ruby-on-rails - capybara ::ElementNotFound:无法找到 xpath "/html" - 2

    我正在学习http://ruby.railstutorial.org/chapters/static-pages上的RubyonRails教程并遇到以下错误StaticPagesHomepageshouldhavethecontent'SampleApp'Failure/Error:page.shouldhave_content('SampleApp')Capybara::ElementNotFound:Unabletofindxpath"/html"#(eval):2:in`text'#./spec/requests/static_pages_spec.rb:7:in`(root)'

  6. ruby - 如何使用 Ruby 将 CSV 文件读入 HTML 表格? - 2

    我正在尝试将一个简单的CSV文件读入HTML表格以在浏览器中显示,但我遇到了麻烦。这就是我正在尝试的:Controller:defshow@csv=CSV.open("file.csv",:headers=>true)end查看:输出:NameStartDateEndDateQuantityPostalCode基本上我只获取标题,而不会读取和呈现CSV正文。 最佳答案 这最终成为最终解决方案:Controller:defshow#OpenaCSVfile,andthenreaditintoaCSV::Tableobjectforda

  7. ruby - 如何使用 Nokogiri 解析纯 HTML 表格? - 2

    我想用Nokogiri解析HTML页面。页面的一部分有一个表,它没有使用任何特定的ID。是否可以提取如下内容:Today,3,455,34Today,1,1300,3664Today,10,100000,3444,Yesterday,3454,5656,3Yesterday,3545,1000,10Yesterday,3411,36223,15来自这个HTML:TodayYesterdayQntySizeLengthLengthSizeQnty345534345456563113003664354510001010100000344434113622315

  8. ruby-on-rails - 使用 javascript 更改数据方法不会更改 ajax 调用用户的什么方法? - 2

    我遇到了一个非常奇怪的问题,我很难解决。在我看来,我有一个与data-remote="true"和data-method="delete"的链接。当我单击该链接时,我可以看到对我的Rails服务器的DELETE请求。返回的JS代码会更改此链接的属性,其中包括href和data-method。再次单击此链接后,我的服务器收到了对新href的请求,但使用的是旧的data-method,即使我已将其从DELETE到POST(它仍然发送一个DELETE请求)。但是,如果我刷新页面,HTML与"new"HTML相同(随返回的JS发生变化),但它实际上发送了正确的请求类型。这就是这个问题令我困惑的

  9. ruby-on-rails - 连接字符串时如何在 <%=%> block 内输出 html_safe? - 2

    考虑一下:现在这些情况:#output:http://domain.com/?foo=1&bar=2#output:http://domain.com/?foo=1&bar=2#output:http://domain.com/?foo=1&bar=2#output:http://domain.com/?foo=1&bar=2我需要用其他字符串输出URL。我如何保证&符号不会被转义?由于我无法控制的原因,我无法发送&。求助!把我的头发拉到这里:\编辑:为了澄清,我实际上有一个像这样的数组:@images=[{:id=>"fooid",:url=>"http://

  10. ruby - Ruby 和 Ruby on Rails 中的三层架构 - 2

    我是一名决定学习Ruby和RubyonRails的ASP.NETMVC开发人员。我已经有所了解并在RoR上创建了一个网站。在ASP.NETMVC上开发,我一直使用三层架构:数据层、业务层和UI(或表示)层。尝试在RubyonRails应用程序中使用这种方法,我发现没有关于它的信息(或者也许我只是找不到它?)。也许有人可以建议我如何在RubyonRails上创建或使用三层架构?附言我使用ruby​​1.9.3和RubyonRails3.2.3。 最佳答案 我建议在制作RoR应用程序时遵循RubyonRails(RoR)风格。Rails

随机推荐