如何防止多个SVG元素(文本标签)对不同SVG元素的鼠标悬停的干扰?

时间:2018-10-09 21:01:20

标签: html d3.js select svg

我知道SVG元素没有z索引。我也知道,定义SVG元素的顺序将决定其垂直顺序。我在类似问题上看到的解决方案通常是选择单个元素并执行以下操作: identifier.node()。parentNode.appendChild(identifier.node());

将其带到甲板的顶部。但是,当您有多个SVG元素需要移到顶部时,这将不起作用。

以下代码(也请参见底部的codepen链接)是一个简化的示例,由两个相邻的圆和一个位于其下方的正方形组成。每个圆圈都有鼠标悬停事件,它们的颜色不同。但是,最左边的圆圈具有当前不透明度为0的文本标签。当您将鼠标悬停在正方形上时,不透明度会发生变化。这些文本标签将鼠标悬停在其相应位置时会阻止圆圈的鼠标悬停事件。至关重要的是,当我将鼠标悬停在文本上时可以草率地更改最左边的圆圈的颜色时,某些文本标签与最右边的圆圈重叠,因此会在这些重叠的位置使圆圈的颜色不正确。我正在寻找的解决方案将更改所有文本标签的垂直顺序,以便将鼠标悬停在最左边的圆圈的所有点上时,圆圈变为绿色,同样,当将鼠标悬停在正方形上时,所有文本标签都将显示在顶部,以红色显示。如何选择所有这些人?

<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>D3: Adjusted radii</title>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.2.0/d3.min.js" type="text/javascript"></script>
        <style type="text/css"> 
        </style>
    </head>
    <body>
        <script type="text/javascript">
            //Width and height
            var w = 500;
            var h = 500;
            var padding = 20;

            var circleDataset1 = [
                [800, 1000]
              ];
            var circleDataset2 = [
                [900, 500]
              ];
            var squareDataset = [
                [800, 1200]
              ];    
            var labs = [[100,450],[200,450], [100,550],[200,650],[50,450], [200,750],[0,650],[200,550],[250,450], [60,650],[250,550],[0,550], [0,750], [50,750], [100,750],]
            //Create scale functions
            var xScale = d3.scale.linear()
                 .domain([0, d3.max(circleDataset1, function(d) { return d[0]; })])
                 .range([padding, w - padding * 2]);
            var yScale = d3.scale.linear()
                 .domain([0, d3.max(circleDataset1, function(d) { return d[1]; })])
                 .range([h - padding, padding]);
            var rScale = d3.scale.linear()
                 .domain([0, 2000 ])
                 .range([0.05, 25]);

            //Create SVG element
            var svg = d3.select("body")
                .append("svg")
                .attr("width", w)
                .attr("height", h);
            var svg2 = d3.select('body')
                .append("svg")
                .attr("width", w)
                .attr("height", h);
            //Create circles
            svg.selectAll("circle")
               .data(circleDataset1)
               .enter()
               .append("circle")
               .attr("cx", 100)
               .attr("cy", 200)
               .attr("r", 100)
               .on('mouseover',function(d) {    
                    d3.select(this)
                        .attr('fill','green');
               })
               .on("mouseout", function(d) {            
                    d3.select(this)
                        .attr('fill','black');
               })
            svg.selectAll("ellipse")
               .data(circleDataset2)
               .enter()
               .append("ellipse")
               .attr("cx", 200)
               .attr("cy", 200)
               .attr("rx", 100)
               .attr("ry", 100)
               .attr('fill','grey')
               .on('mouseover',function(d) {    
                    d3.select(this)
                        .attr('fill','blue');
               })
               .on("mouseout", function(d) {    
                    d3.select(this)
                        .attr('fill','grey');
               })

            svg.selectAll('rect')
               .data(squareDataset)
               .enter()
               .append("rect")
               .attr("x", 100)
               .attr("y", 400)
               .attr("width", 100)
               .attr('height',500)
               .attr('fill','red')
               .on('mouseover',function(d) {    
                    d3.select(this)
                        d3.selectAll('.textlabel').style({opacity:'1'});
               })
               .on('mouseout',function(d) { 
                    d3.select(this)
                        d3.selectAll('.textlabel').style({opacity:'0'});
               })

            //Create labels
            svg.selectAll("text")
               .data(labs)
               .enter()
               .append("text")
               .text(function(d) {
                    return d[0] + "," + d[1];
               })
               .attr("x", function(d) {
                    return xScale(d[0]);
               })
               .attr("y", function(d) {
                    return yScale(d[1]);
               })
               .attr("font-family", "sans-serif")
               .attr("font-size", "11px")
               .attr("fill", "red")
               .attr('class','textlabel')
               .style('opacity',0)

            //////////////////////
            // Even if I select all elements by a classname and , only 1 of the elements will move to the front
            // textLabs = d3.selectAll('.textlabel')
              // .style('opacity',1.0)
            // textLabs.node().parentNode.appendChild(textLabs.node());
            ///////////////////////

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

https://codepen.io/robfran4566/pen/VEpPRB

1 个答案:

答案 0 :(得分:2)

您不需要做任何事情的Javascript。

circle {
  fill: black;
}
circle:hover {
  fill: green;
}
ellipse {
  fill: grey;
}
ellipse:hover {
  fill: blue;
}
rect {
  fill: red;
}
g.textlabel {
  font-family: sans-serif;
  font-size: 11px;
  fill: red;
  opacity: 0;
  pointer-events: none;
}
rect:hover + g {
  opacity: 1;
}
<svg width="500" height="500">
  <circle cx="100" cy="200" r="100" fill="black"></circle>
  <ellipse cx="200" cy="200" rx="100" ry="100" fill="grey"></ellipse>
  <rect x="100" y="400" width="100" height="500" fill="red"></rect>
  <g class="textlabel">
    <text x="75" y="273">100,450</text>
    <text x="130" y="273">200,450</text>
    <text x="75" y="227">100,550</text>
    <text x="130" y="181">200,650</text>
    <text x="47.5" y="273">50,450</text>
    <text x="130" y="135">200,750</text>
    <text x="20" y="181">0,650</text>
    <text x="130" y="227">200,550</text>
    <text x="157.5" y="273">250,450</text>
    <text x="53" y="181">60,650</text>
    <text x="157.5" y="227">250,550</text>
    <text x="20" y="227">0,550</text>
    <text x="20" y="135">0,750</text>
    <text x="47.5">50,750</text>
    <text x="75" y="135">100,750</text>
  </g>
</svg>