8

我正在尝试检测部分重叠的 SVG 元素上的 mousemove 事件,如图所示

在此处输入图像描述

小提琴

<svg>
    <rect id="red"    x=10 y=10 width=60 height=60 style="fill:#ff0000" />
    <rect id="orange" x=80 y=10 width=60 height=60 style="fill:#ffcc00" />
    <rect id="blue"   x=50 y=30 width=60 height=60 style="fill:#0000ff; fill-opacity: 0.8" />
</svg>

$('rect').on('mousemove', function()
{
    log(this.id);
});

现在,当将鼠标悬停在蓝色/红色交叉点上时,我想检测这两个元素上的鼠标事件,蓝色/橙色组合也是如此。正如您在日志中看到的那样,在这些情况下,当前仅针对位于顶部的蓝色框触发事件。

这与指针事件有关,因为我可以通过将蓝色元素的指针事件设置为 none来让红色和橙色元素在悬停蓝色元素时触发事件。但是我没有得到蓝色框的事件,所以这也不是一个可行的选择。

我将使用任何一个库来解决这个问题。我在这个 d3 示例中查看了事件冒泡,但这仅适用于嵌套在 DOM 中的元素。我有许多独立的元素,它们可能与许多其他元素重叠,因此不能以这种方式构建我的 DOM。

我猜最后的手段是找到当前鼠标位置的元素,并手动触发事件。因此,我查看了document.elementFromPoint(),但这只会产生 1 个元素(并且可能不适用于 SVG?)。我在 中找到了jQuerypp函数,该函数给定位置找到元素,请参见此处。这个例子看起来很棒,除了它是 DIV 而不是在 SVG 中。当用 svg 矩形元素替换 div 时,fiddle 似乎中断了。

我该怎么办?!

4

2 回答 2

7

这里的精彩评论给了我答案:可以通过在光标位置使用getIntersectionList()来手动将事件传播到底层元素。

$('svg').on('mousemove', function(evt)
{
    var root = $('svg')[0];
    var rpos = root.createSVGRect();
    rpos.x = evt.clientX;
    rpos.y = evt.clientY;
    rpos.width = rpos.height = 1;
    var list = root.getIntersectionList(rpos, null);

    for(var i = 0; i < list.length; i++)
    {
        if(list[i] != evt.target)
        {
            $(list[i]).mousemove();
        }
    }
});

工作示例:http: //jsfiddle.net/michaschwab/w0wufbtn/6/

如果其他侦听器需要原始事件对象,请查看http://jsfiddle.net/michaschwab/w0wufbtn/13/

非常感谢!!

于 2015-04-01T19:14:26.767 回答
0

对于仍在寻找的人,elementsFromPoint()返回鼠标光标下所有元素的节点列表。

注意:还有一种elementFromPoint()方法。

当您需要path在鼠标悬停时检测多个重叠的 SVG 元素时,这特别有用。

一个简单的例子:

从鼠标事件中获取 nodeList。

const _overlapped = document.elementsFromPoint(e.pageX, e.pageY)

根据某些标准过滤列表:

// Some list of element id's you're interested in
const _lines = ['elId1', 'elId2', 'elId3'] 

// Check to see if any element id matches an id in _lines   
const _included = _overlapped.filter(el => _lines.includes(el.id))

// Perform an action on each member in the list
_included.forEach(...) 
于 2022-02-25T15:58:23.317 回答