2 回答

TA貢獻1943條經(jīng)驗 獲得超7個贊
首先,此解決方案使用您在 HTML 中引用的 D3 v5,而不是 D3 v2(已有 9 年歷史)。
回到你的問題,你說:
我希望能夠觸發(fā)它們的事件并傳播到它們下面的元素,直到SVG本身被觸發(fā)。
好吧,這不是傳播的意思。冒泡意味著在DOM樹中上升,但這些圓圈不是父/子,它們只是兄弟姐妹。因此,你想要的與傳播無關,所以我們需要一種不同的方法。
我在這里建議的方法使用 ,獲取您單擊的坐標下的所有元素,并結(jié)合用于調(diào)度單擊(我在這里找到了該函數(shù),并對其進行了修改以用于 D3)。最后,我需要標志,因為指針事件設置為 的元素被 忽略(順便說一句,它是 ,不是)。elementFromPoint
d3.dispatch
getAllElements
clicked
none
elementFromPoint
pointer-events
pointer-event
這是演示:
let clicked;
var svg = d3.select("body").append("svg")
.style("float", "left")
.attr("width", 480)
.attr("height", 480)
.attr('pointer-event', 'all');
svg.append("circle")
.attr('pointer-event', 'all')
.attr("cx", 240)
.attr("cy", 240)
.attr("r", 200)
.on("click", function() {
if (!clicked) return;
log("OUTER")
});
svg.append("circle")
.attr('pointer-event', 'all')
.attr("cx", 240)
.attr("cy", 240)
.attr("r", 100)
.on("click", function() {
if (!clicked) return;
log("INNER")
});
var div = d3.select("body").append("div")
.style("float", "left");
function log(message) {
div.append("p")
.text(message)
.style("background", "#ff0")
.transition()
.duration(2500)
.style("opacity", 1e-6)
.remove();
}
d3.select("svg").on("click", function() {
clicked = true;
getAllElements(...d3.mouse(this));
log("SVG")
clicked = false;
function getAllElements(x, y) {
const elements = [];
let thisElement = document.elementFromPoint(x, y);
while (thisElement && thisElement.nearestViewportElement) {
elements.push(thisElement);
d3.select(thisElement).style("display", "none");
thisElement = document.elementFromPoint(x, y);
}
elements.forEach(function(elm) {
d3.select(elm).style("display", null)
.dispatch("click");
});
};
})
<!DOCTYPE html>
<style>
circle {
fill: lightgreen;
stroke: #000;
}
</style>
<body>
<script src="https://d3js.org/d3.v5.min.js"></script>

TA貢獻1829條經(jīng)驗 獲得超13個贊
解決方案將取決于控制 svg 元素大小的形狀類型和參數(shù)。如果需要非最優(yōu)但通用的解決方案,可以使用元素的邊界框。使用邊界框,可以通過針對 [x,y] 目標測試 x 和 y 范圍來確定是否有任何對象超過 [x,y]。
您可以優(yōu)化以下代碼并將其插入到任何 d3 功能塊中:
<d3 function block>((shape)=>{
let bbox = this.getBBox();
let minX=bbox.x;
let maxX=minX+bbox.width;
let minY=bbox.y;
let maxY=minY+bbox.width;
let isOver=shape.x>minX && shape.x < maxX && shape.y > minY && shape.y < maxY;
//..do something depending on the value of isOver
})
添加回答
舉報