通过遮挡SVG元素阻止Mousemove事件

时间:2017-07-05 00:09:55

标签: javascript svg snap.svg

我有一个带有mousemove事件的SVG元素,显示指针的坐标。当鼠标移动到遮挡元素上时,将阻止mousemove事件。我需要将事件传播到原始元素。

我尝试更改pointer-events属性,但这会影响所有鼠标事件,我需要遮挡元素来响应其他事件。有什么建议。

2 个答案:

答案 0 :(得分:1)

也许解决这个问题的方法是将你的所有事件绑定到你的svg和遮挡元素所在的容器/ parentNode中 - 将'mouse'元素记录在'{{}}'的''外部'元素中其中子元素的属性。

如果没有问题中的代码示例,很难确切地知道需要什么,但原则可能遵循这些原则......

<!-- HTML sample -->
<div id="container">
    <div id="elem1" class="occluded">Element #1</div>
    <div id="elem2" class="occluded">Element #2</div>
    <div class="fullWidthHeightOverlay"></div>
</div>
<div id="eventLog"></div>

假设#container具有宽度和高度,.occluded元素在该图层中浮动,但位于.fullWidthHeightOverly元素下方(如果我理解了您的问题正确起作用)你的SVG)。 #eventLog可以将行为附加到以后。

我们还假设我们想要相对于外部#container图层记录鼠标位置,以便在鼠标位于.occluded元素之一时使“点击”行为可用。 (我希望这很清楚?)

首先,我们需要将一些事件附加到#container - 在这种情况下,一个用于鼠标位置,一个用于点击。

/* SIMPLE SELECTOR - '#id' */
function $(a){
    $.b = $.b || {};
    if (void 0 === $.b[a]) $.b[a] = document.getElementById(a.slice(1));
    return $.b[a];
}

var elem1, elem2;

/* ! */
function addEvents() {
    $('#container').addEventListener('mousemove', logMousePos, false);
    $('#container').addEventListener('click', occludedClick, false);
}

您会看到我还创建了一些我们可以将.occluded元素分配给的变量。

接下来,我们需要logMousePos()occludedClick()函数来记录相对于.occluded图层上鼠标位置的两个.fullWidthHeightOverly元素的位置属性在他们之上,然后发起一些简单的行为,EG ..

function logMousePos(e) {
    var e1 = elem1.getBoundingClientRect(),
        e2 = elem2.getBoundingClientRect(),
        e1CL = elem1.classList,
        e2CL = elem2.classList;

    /* is mouse inside #elem1 ? */
    if (check.X(e.clientX, e1) && check.Y(e.clientY, e1)) {
        /* if no 'over' class add it... */
        if (!e1CL.contains('over')) e1CL.add('over');
    } else {
        /* ...if 'over' class remove it */
        if (e1CL.contains('over')) e1CL.remove('over');
    }

    /* is mouse inside #elem2 ? */
    if (check.X(e.clientX, e2) && check.Y(e.clientY, e2)) {
        if (!e2CL.contains('over')) e2CL.add('over');
    } else {
        if (e2CL.contains('over')) e2CL.remove('over');
    }
}

function occludedClick(e) {
    var e1 = elem1.getBoundingClientRect(),
        e2 = elem2.getBoundingClientRect(),
        e1CL = elem1.classList,
        e2CL = elem2.classList;

    /* was mouse clicked inside #elem1 or #elem2 or not ? */
    if (check.X(e.clientX, e1) && check.Y(e.clientY, e1)) {
        $('#eventLog').textContent = 'Element #1 pseudo-Clicked';
    } else if (check.X(e.clientX, e2) && check.Y(e.clientY, e2)) {
        $('#eventLog').textContent = 'Element #2 pseudo-Clicked';
    } else {
        $('#eventLog').textContent = '';
    }
 }

..在那里你会注意到我指的是一些check()对象方法,嗯,检查鼠标是否在.occluded元素的'boundingClientRect'内。

var check = {
    X: function(x, el) {
        return (x > el.left && x < el.right);
    },
    Y: function(y, el) {
        return (y > el.top && y < el.bottom);
    }
};

然后只需初始化变量并添加事件监听器......

(function init() {
    addEvents();
    elem1 = $('#elem1');
    elem2 = $('#elem2');
}());

您可以找到整个事件bounding Client Rectangles的JSFIDDLE。

我希望这足以让你能够在你的特定情况下应用这个原则。

:)

答案 1 :(得分:0)

总结Brian Peacock的优秀和详细建议的主要观点: 似乎问题是svg元素的图形顺序(背后的内容)不遵循DOM层次结构,因此不能直接使用正常的事件冒泡。因此,必须在共同的高点捕获事件并实际搜索该点下的元素。

作为一般性的讨论点(请原谅我这里),应该注意到在许多情况下这不是最佳解决方案。例如,当捕获快速发生的事件时,例如mousemove,当SVG中存在许多元素时,并且当平滑GUI需要快速响应时,该策略可能计算成本太高。如果更好的事件处理系统包含在SVG规范中并包含在浏览器中,那么一切都可以由引擎完成,这将是很棒的。这将显着提高具有纯SVG GUI的能力。