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

时间:2015-04-17 16:40:31

标签: 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”。

我该怎么做?

2 个答案:

答案 0 :(得分:2)

如果您使用样式visibility而不是属性opacity将组设置为隐藏或可见,您还可以使用样式pointer-events将事件限制为可见元素。

         

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")
    .style("visibility", "visible")
    .style("pointer-events", "visible")
    .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")
    .style("visibility", "hidden")
    .style("pointer-events", "visible")
    .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>

此示例将打印&#34;点击&#34;单击蓝色矩形时到控制台。

答案 1 :(得分:2)

不透明度确实使元素半透明,它不会使它们消失。就像您可以点击一块玻璃一样,您可以使用opacity:0单击一个元素。

现在,根据两个视图中形状是否不同,有两个选项。如果他们(比如说,您正在绘制世界地图,国家/地区保持不变,只是颜色发生变化),那么最容易听取最顶层和然后运行if语句执行哪一部分。喜欢这个

&#13;
&#13;
    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();
    });
&#13;
<script src="https://samizdat.cz/tools/d3/3.5.3.min.js" charset="utf-8"></script>
<div id="body"></div>
<button>change!</button>
&#13;
&#13;
&#13;

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

&#13;
&#13;
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();
});
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div id="body"></div>
<button>change!</button>
&#13;
&#13;
&#13;

请注意,在每次转换时,我们现在必须按正确顺序处理opacity display。另请注意,现在我们在两个 rect上都有听众。

如果可以与.enter().exit()选项一起使用,则示例会更简单,因为您可以使用.on("end")取而代之的是使用.remove()关于现有的过渡。

更新:与display:none几乎完全相同,也是visibility: hidden