javascript - 通过重叠的 svg 元素传播事件

标签 javascript svg d3.js

我有两个重叠的 svg.g 组,它们具有不同的 onclick 事件。我定期使用 opacity 属性将组混合进或出可视化效果。目前,仅调用顶部呈现的组的 onclick 事件,但我想调用当前可见的组的事件。或者,我始终可以调用这两个事件,并在被调用函数内使用条件语句,该语句取决于 opacity 属性。

这是一个例子

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>

</head>
<body>
    <div id="body"></div>
    <script type="text/javascript">

    var canvas_w = 1280 - 80,
        canvas_h = 800 - 180;

    var svg = d3.select("#body").append("div")
        .append("svg:svg")
        .attr("width", canvas_w)
        .attr("height", canvas_h)   

    var visible_group = svg.append("g")
        .attr("opacity", 1)
        .on("click", function(d){console.log("Click")})
        .append("rect")
        .attr("x", 0)
        .attr("y", 0)
        .attr("width", 100)
        .attr("height", 100)
        .style("fill", "blue");

    var invisible_group = svg.append("g")
        .attr("opacity", 0)
        .on("click", function(d){console.log("Invisiclick")})
        .append("rect")
        .attr("x", 0)
        .attr("y", 0)
        .attr("width", 100)
        .attr("height", 100)
        .style("fill", "red");


    </script>
</body>
</html>

此代码将渲染一个蓝色矩形,即可见组。带有红色矩形的组被隐藏。如果单击蓝色矩形,控制台将打印“Invisiclick”,即隐藏组的 onclick 事件。我想将“Click”打印到控制台,或者同时打印“Invisiclick”和“Click”。

我该怎么做?

最佳答案

不透明度确实使元素半透明,但不会使它们消失。正如您可以点击一 block 玻璃一样,您可以点击 opacity:0 的元素。

现在,有两个选项,具体取决于两个 View 中的形状是否不同。如果它们不是(例如,您正在绘制世界地图,国家/地区保持不变,只是颜色发生变化),那么最简单的方法可能是监听最顶层,然后运行 ​​if -声明要执行哪一部分。像这样

    var state = "blue";


    var clickHandler = function() {
        if(state === "blue") {
            console.log("Blue clicked");
        } else {
            console.log("Red clicked");
        }
    }


    var toggleState = function() {
        state = (state === "blue") ? "red" : "blue";
    }

    var updateDisplay = function() {
        blueGroup
            .transition()
            .duration(400)
            .attr("opacity", state === "blue" ? 1 : 0);
        redGroup
            .transition()
            .duration(400)
            .attr("opacity", state === "red" ? 1 : 0);
    }

    var canvas_w = 1280 - 80,
        canvas_h = 120;

    var svg = d3.select("#body").append("div")
        .append("svg:svg")
        .attr("width", canvas_w)
        .attr("height", canvas_h)   

    var blueGroup = svg.append("g")
        .append("rect")
        .attr("opacity", 1)
        .attr("x", 0)
        .attr("y", 0)
        .attr("width", 100)
        .attr("height", 100)
        .style("fill", "blue");

    var redGroup = svg.append("g")
        .on("click", clickHandler)
        .append("rect")
        .attr("opacity", 0)
        .attr("x", 0)
        .attr("y", 0)
        .attr("width", 100)
        .attr("height", 100)
        .style("fill", "red");



    d3.select("button").on("click", function() {
        toggleState();
        updateDisplay();
    });
<script src="https://samizdat.cz/tools/d3/3.5.3.min.js" charset="utf-8"></script>
<div id="body"></div>
<button>change!</button>

如果形状发生变化,您需要首先使用 opacity:0 使元素半透明,然后然后使它们消失display:none(否则,它们会立即闪出)。另一种选择是 pointer-events ,但前提是您不需要支持 old browsers 。 转换将如下所示:

var state = "blue";

var toggleState = function() {
    state = (state === "blue") ? "red" : "blue";
}

var updateDisplay = function() {
    blueGroup
        .style("display", state === "blue" ? "block" : "none")
        .transition()
        .duration(400)
        .attr("opacity", state === "blue" ? 1 : 0)
        .each("end", function() {
            blueGroup.style("display", state === "blue" ? "block" : "none");
        });
        
    redGroup
        .style("display", state === "red" ? "block" : "none")
        .transition()
        .duration(400)
        .attr("opacity", state === "red" ? 1 : 0)
        .each("end", function() {
            redGroup.style("display", state === "red" ? "block" : "none");
        });
}

var canvas_w = 1280 - 80,
    canvas_h = 120;

var svg = d3.select("#body").append("div")
    .append("svg:svg")
    .attr("width", canvas_w)
    .attr("height", canvas_h)   

var blueGroup = svg.append("g")
    .on("click", function() {
        console.log("Blue clicked");
    })
    .append("rect")
    .attr("opacity", 1)
    .attr("x", 0)
    .attr("y", 0)
    .attr("width", 150)
    .attr("height", 100)
    .style("fill", "blue");

var redGroup = svg.append("g")
    .on("click", function() {
        console.log("Red clicked");
    })
    .append("rect")
    .attr("opacity", 0)
    .style("display", "none")
    .attr("x", 0)
    .attr("y", 0)
    .attr("width", 100)
    .attr("height", 120)
    .style("fill", "red");



d3.select("button").on("click", function() {
    toggleState();
    updateDisplay();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div id="body"></div>
<button>change!</button>

请注意,在每次转换时,我们现在必须以正确的顺序处理不透明度显示。另请注意,现在我们在 both rect 上都有监听器。

如果该示例可以与 .enter().exit() 选择一起使用,那么它会更简单,因为您可以取消 .on("end") 并在退出转换上使用 .remove()

更新:实际上与display:none相同也是visibility:hidden

关于javascript - 通过重叠的 svg 元素传播事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29704936/

相关文章:

d3.js - D3 v4 : element 'snaps' to previous translate after programmatic transform

css - 如何用透明文字制作文字描边

javascript - 如何在点上应用渐变蒙版

javascript - 在字符串中最后一次出现特定字符之前插入

javascript - 在 Protractor 中测试模板?

java - Batik - 将 SVG 置于图像之上

javascript - 在 Firefox 中将 SVG 绘制到 Canvas 时出现 InvalidStateError(适用于 Chrome)

javascript - D3 V4 : Updated data is being seen as new data?(更新功能)

javascript - 可以使用 Backbone 模型的 cid 作为 html id 属性吗?它保证是唯一的吗?

javascript - 解码 ReadableByteStreams