我为此一直苦苦挣扎了几天,但看来我不会自己解决这个问题。我希望有人能帮忙...或者只是告诉我这根本不可能,我会找到另一种方式:)
这是我的问题的简化版本:
.left {
fill: yellow;
pointer-events: visible;
}
.left:hover {
opacity: 0.3;
}
.middle {
fill: red;
pointer-events: visible;
}
.middle:hover {
opacity: 0.8;
pointer-events: visible;
}
.right {
fill: blue;
}
.right:hover {
opacity: 0.6;
pointer-events: visible;
}
<svg class="test" width="500px" height="500px">
<g name="Layer" class="group">
<ellipse class="left" cx="120" cy="160" rx="80" ry="81" />
<ellipse class="right" cx="342" cy="271" rx="93" ry="97" />
<ellipse class="middle" cx="223" cy="176" rx="115" ry="153" />
</g>
</svg>
将鼠标悬停在椭圆上时,其不透明度会被修改。可以。
我要实现的是,将鼠标悬停在两个椭圆的交点上时,将触发相关的两个已定义的:hover。当前,当鼠标指针悬停在红色椭圆和蓝色椭圆(在相交处)上方时,悬停仅关注红色椭圆。
我无法将它们分组,因为:
我认为“指针事件”的重点是一次处理多个重叠的形状,但是我一直试图以各种可能的方式使用该属性,但没有成功。 我正在使用Reactjs,因此有关Javascript解决方案的任何可能提示都会有所帮助。
答案 0 :(得分:2)
我喜欢@Connum附带的解决方案,但我认为它可以简化:
let ellipses = document.querySelectorAll("ellipse")
function getAllElementsFromPoint(rootEl, x, y) {
var item = document.elementFromPoint(x, y);
//in this case is tagName == "ellipse" but you can find something else in commun, like a class - for example.
while (item && item.tagName == "ellipse") {
item.classList.add("hover")
item.style.pointerEvents = "none";
item = document.elementFromPoint(x, y);
}
}
var svg = document.querySelector('svg.test');
svg.addEventListener('mousemove', function(ev) {
// first add pointer-events:all and remove the class .hover from all elements
ellipses.forEach(e=> {
e.style.pointerEvents = "all";
e.classList.remove('hover');
});
// then get all elements at the mouse position
// and add the class "hover" to them
getAllElementsFromPoint(svg, ev.clientX, ev.clientY)
});
.left {
fill: yellow;
}
.left.hover {
opacity: 0.3;
}
.middle {
fill: red;
}
.middle.hover {
opacity: 0.8;
}
.right {
fill: blue;
}
.right.hover {
opacity: 0.6;
}
svg {
border: 1px solid;
}
<svg class="test" width="500px" height="500px">
<g name="Layer" class="group">
<ellipse class="left" cx="120" cy="160" rx="80" ry="81" />
<ellipse class="right" cx="342" cy="271" rx="93" ry="97" />
<ellipse class="middle" cx="223" cy="176" rx="115" ry="153" />
</g>
</svg>
答案 1 :(得分:1)
使用this very similar question中演示的getIntersectionList()
可能是最干净,性能最高的解决方案。但是,Firefox尚不支持它,因此我提出了一个基于this answer to another question的稍微改编的功能的解决方案。
但是请注意:由于mousemove
事件与两个在DOM元素上迭代的forEach
循环的组合,加上可能由于以下原因而导致的重新渲染,这可能会非常耗费性能在最短的时间内隐藏/显示元素,具体取决于客户端如何处理和优化它。因此,这可能会在较弱的设备上导致非常差的性能。话虽如此,它似乎可以在所有主流浏览器中运行(在Firefox,Chrome和Edge中进行了测试;不过我没有尝试过IE)。
在我提供的第二个链接的答案注释中,建议使用CSS'pointer-events
而不是隐藏元素来实现另一个功能。必须将这两种方法的性能进行比较,才能确定哪种方法最合适。
function getAllElementsFromPoint(rootEl, x, y) {
var elements = [];
var display = [];
var item = document.elementFromPoint(x, y);
while (item && item !== document.body && item !== window && item !== document && item !== document.documentElement && item !== rootEl) {
elements.push(item);
display.push(item.style.display);
item.style.display = "none";
item = document.elementFromPoint(x, y);
}
// restore display property
for (var i = 0; i < elements.length; i++) {
elements[i].style.display = display[i];
}
return elements;
}
var svg = document.querySelector('svg.test');
svg.addEventListener('mousemove', function(ev) {
// first remove the class .hover from all elements
svg.querySelectorAll('*').forEach(function(subEl) {
subEl.classList.remove('hover');
});
// then get all elements at the mouse position
// and add the class "hover" to them
getAllElementsFromPoint(svg, ev.clientX, ev.clientY).forEach(function(hoveredEl) {
hoveredEl.classList.add('hover');
})
});
.left {
fill: yellow;
pointer-events: visible;
}
.left:hover,
.left.hover {
opacity: 0.3;
}
.middle {
fill: red;
pointer-events: visible;
}
.middle:hover,
.middle.hover {
opacity: 0.8;
pointer-events: visible;
}
.right {
fill: blue;
}
.right:hover,
.right.hover {
opacity: 0.6;
pointer-events: visible;
}
<svg class="test" width="500px" height="500px">
<g name="Layer" class="group">
<ellipse class="left" cx="120" cy="160" rx="80" ry="81" />
<ellipse class="right" cx="342" cy="271" rx="93" ry="97" />
<ellipse class="middle" cx="223" cy="176" rx="115" ry="153" />
</g>
</svg>