因此,我有一个带有rect
覆盖层的d3图表,用于保存mouseover
事件中的十字线元素。在覆盖层下,我还有其他rect显示数据,这些数据也具有mouseover
事件处理程序,但是覆盖层阻止mouseover
了以下子区域上触发器触发的事件。
let chartWindow = svg
.append("g");
/* this holds axis groups, and cadlestick group*/
let candleStickWindow = chartWindow.append("g")
//this event never fires
.on('mousemove', ()=>console.log('mouse move'));
let candlesCrosshairWindow = chartWindow
.append("rect")
.attr("class", "overlay")
.attr("height", innerHeight)
.attr("width", innerWidth)
.on("mouseover", function() {
crosshair.style("display", null);
})
.on("mouseout", function() {
crosshair.style("display", "none");
removeAllAxisAnnotations();
})
.on("mousemove", mousemove);
在CrosshairWindow
具有CSS属性pointer-events: all
。如果我删除了该事件,则会在上触发事件,candleStickWindow
但不会触发CrosshairWindow
。如何使鼠标事件同时出现在这两个元素上?
谢谢你的帮助!
更新我将十字准线rect元素更改为在底部,这有点奏效,烛台条mouseover事件有效,但它阻止了十字准线起作用。
One solution that comes to mind might use event bubbling which, however, only works if the events can bubble up along the same DOM sub-tree. If, in your DOM structure, the crosshairs rectangle and the other elements do not share a common ancestor to which you could reasonably attach such listener, you need to either rethink your DOM or resort to some other solution. For this answer I will lay out an alternative approach which is more generally applicable.
You can position your full-size rect
at the very bottom of your SVG and have its pointer-events
set to all
. That way you can easily attach a mousemove
handler to it to control your crosshairs' movements spanning the entire viewport. As you have noticed yourself, however, this does not work if there are elements above which have listeners for that particular event type attached to them. Because in that case, once the event has reached its target, there is no way propagating it further to the underlying rectangle for handling the crosshairs component. The work-around is easy, though, since you can clone the event and dispatch that new one directly to your rectangle.
Cloning the event is done by using the MouseEvent()
constructor passing in the event's details from the d3.event
reference:
new MouseEvent(d3.event.type, d3.event)
然后,您可以rect
使用.dispatchEvent()
以下EventTarget
接口实现的方法将新创建的事件对象分派到crosshairs元素SVGRectElement
:
.dispatchEvent(new MouseEvent(d3.event.type, d3.event));
由于您的问题中没有完整的示例,因此我自己创建了一个工作示例来演示该方法。您可以拖动蓝色圆圈,它是十字准线组件的简化版本。请注意,即使在橙色矩形下方,圆也可以无缝移动。为了演示附加在这些小矩形上的事件处理程序,当使用鼠标指针进入或离开它们时,它们将转换为绿色,然后转换为橙色。
const width = 500;
const height = 500;
const radius = 10;
const orange = d3.hsl("orange");
const steelblue = d3.hsl("steelblue");
const limegreen = d3.hsl("limegreen");
const svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
const target = svg.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", width)
.attr("height", height)
.attr("fill", "none")
.attr("pointer-events", "all")
.on("mousemove", () => {
circle.attr("cx", d3.event.clientX - radius);
circle.attr("cy", d3.event.clientY - radius);
});
const circle = svg.append("circle")
.attr("r", radius)
.attr("fill", steelblue)
.attr("pointer-events", "none");
const rect = svg.selectAll(null)
.data(d3.range(3).map(d => [Math.random() * width, Math.random() * height]))
.enter().append("rect")
.attr("x", d => d[0])
.attr("y", d => d[1])
.attr("width", 50)
.attr("height", 50)
.attr("fill", orange)
.attr("opacity", 0.5)
.on("mouseover", function() {
d3.select(this).transition().attr("fill", limegreen);
})
.on("mousemove", function() {
target.node().dispatchEvent(new MouseEvent(d3.event.type, d3.event));
})
.on("mouseout", function() {
d3.select(this).transition().attr("fill", orange);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句