Html d3.js - 鼠标悬停事件在 svg 组上无法正常工作

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16918194/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-29 09:02:44  来源:igfitidea点击:

d3.js - mouseover event not working properly on svg group

javascripthtmld3.js

提问by user2339182

I have a graph for which I need a reference line everywhere the mouse-cursor is inside this graph. And this reference line will follow the mouse movements inside the graph.

我有一个图形,我需要一个参考线,鼠标光标在这个图形内的任何地方。这条参考线将跟随图形内的鼠标移动。

But this doesn't seems to work fine. It works only on the axis and the ticks (.axis lines) of the axis. On debugging, I found that mouse event works fine when applied over SVG but not on the group, why so ?

但这似乎不起作用。它仅适用于轴和轴的刻度线(.axis 线)。在调试时,我发现鼠标事件在应用于 SVG 而不是在组上时工作正常,为什么会这样?

Here is my code :

这是我的代码:

test.html

测试.html

<html>
<head>
<script src="jquery.js">
</script>
<script src="d3.v2.js">
</script>
<script src="retest.js">
</script>
<style type="text/css">
  .g_main {
    cursor:pointer;
  }

  .axis path, .axis line {
    stroke: #DBDBDB;
    /*shape-rendering: crispEdges;
    */
  }

  .y g:first-child text {
    display:none;
  }

  .y g:first-child line {
    stroke: #989898  ;
    stroke-width: 2.5px;
  }

  /*.x g:first-child line {
  stroke: black  ;
  stroke-width: 2.5px;
}
  */

  .y path {
    stroke: #989898  ;
    stroke-width: 2.5px;
  }

</style>
</head>
<body>  
<center>
  <button id="reload" onclick="loadViz();">
    load Graph
  </button>
  <div id="viz" class="viz">
  </div>    
</center>
<script>
  loadViz();
</script>
</body>
</html>

retest.js

重新测试.js

var series,
classifications,
minVal,
maxVal,

svgW = 600,
svgH = 600,
//w = 1200,
//h = 1200,

vizPadding = {
    top: 120,
    right: 30,
    bottom: 120,
    left: 50
},

yAxMin_PA = 0,
yAxMax_PA = 50,
xAxMin_PA = 2002,
xAxMax_PA = 2008,
areaStrokeColors = ['#FF6600', '#3366FF', '#B8860B', '#458B00', 'white'];

var loadViz = function () {

    color = d3.scale.category10();

    data = {
        "lines": [{
                "line": [{
                        "X": 2002,
                        "Y": 42
                    }, {
                        "X": 2003,
                        "Y": 45
                    },

                    {
                        "X": 2005,
                        "Y": 47
                    },

                    {
                        "X": 2007,
                        "Y": 41
                    }
                ]
            }, {
                "line": [{
                        "X": 2003,
                        "Y": 33
                    }, {
                        "X": 2005,
                        "Y": 38
                    }, {
                        "Y": 36,
                        "X": 2008
                    }
                ]
            }, {

                "line": [{
                        "X": 2004,
                        "Y": 13
                    }, {
                        "X": 2005,
                        "Y": 19
                    }, {
                        "X": 2008,
                        "Y": 21
                    }
                ]
            }, {

                "line": [{
                        "X": 2003,
                        "Y": 20
                    }, {
                        "X": 2005,
                        "Y": 27
                    }, {
                        "X": 2008,
                        "Y": 29
                    }
                ]
            }
        ]
    };


    $("#viz").html("");
    buildBase();
    //setScales();
};

var buildBase = function () {

    margin = {
        top: 80,
        right: 120,
        bottom: 40,
        left: 40
    },
    width = 960 - margin.left - margin.right,
    height = 550 - margin.top - margin.bottom;

    t2 = height + margin.top + margin.bottom;

    x = d3.scale.linear()
        .domain([xAxMin_PA, xAxMax_PA])
        .range([0, width]);

    y = d3.scale.linear()
        .domain([yAxMin_PA, yAxMax_PA])
        .range([height, 0]);

    tickSizeToApplyX = 5;

    tickSizeToApplyY = 10;

    // Function to draw X-axis
    xAxis = d3.svg.axis()
        .scale(x)
        .ticks(tickSizeToApplyX)
        .tickSize(-height, 0, 0)
    //.tickSize(10)
    .orient("bottom")
        .tickPadding(5);

    // Function to draw Y-axis
    yAxis = d3.svg.axis()
        .scale(y)
        .ticks(tickSizeToApplyY)
        .tickSize(-width, 0, 0)
    //.tickSize(0)
    .orient("left")
        .tickPadding(5);

    // Define the line
    var valueline = d3.svg.line()
        .x(function (d) { /*console.log(d.X);*/
            return x(d.X);
        })
        .y(function (d) { /*console.log(d.Y);*/
            return y(d.Y);
        });

    // Define the line
    var referline = d3.svg.line()
        .x(function (dx) { /*console.log(d.X);*/
            return dx;
        })
        .y(function (dy) { /*console.log(d.Y);*/
            return dy;
        });

    // Append SVG into the html
    var viz = d3.select("#viz")
        .append("svg")
        .attr("width", width + margin.left + margin.right + 10)
        .attr("height", height + margin.top + margin.bottom)
        .append("g")
        .attr("class", "g_main")
        .attr("transform", "translate(" + margin.left + "," + ((margin.top) - 30) + ")");

    viz.on("mousemove", function () {
        cx = d3.mouse(this)[0];
        cy = d3.mouse(this)[1];
        console.log("xx=>" + cx + "yy=>" + cy);
        redrawline(cx, cy);
    })
        .on("mouseover", function () {
            d3.selectAll('.line_over').style("display", "block");
        })
        .on("mouseout", function () {
            d3.selectAll('.line_over').style("display", "none");
        });

    //console.log(this);
    viz.append("line")
    //d3.select("svg").append("line")
    .attr("class", 'line_over')
        .attr("x1", 0)
        .attr("y1", 0)
        .attr("x2", x(xAxMax_PA))
        .attr("y2", 0)
        .style("stroke", "gray")
        .attr("stroke-dasharray", ("5,5"))
        .style("stroke-width", "1.5")
        .style("display", "none");

    // Draw X-axis
    viz.append("g")
        .attr("class", "x axis")
        .attr("transform", "translate(0," + height + ")")
        .call(xAxis);

    // Draw Y-axis
    viz.append("g")
        .attr("class", function (d, i) {
            return "y axis"
        })
        .call(yAxis);


    function redrawline(cx, cy) {
        d3.selectAll('.line_over')
            .attr("x1", 0)
            .attr("y1", cy)
            .attr("x2", x(xAxMax_PA))
            .attr("y2", cy)
            .style("display", "block");
    }
};

回答by musically_ut

The gelement is just an empty container which cannot capture click events (see documentation for pointer-eventspropertyfor details).

g元素只是一个无法捕获单击事件的空容器(有关详细信息,请参阅属性文档pointer-events)。

However, mouse events do bubble up to it. Hence, the effect you desire can be achieved by first making sure that the greceives all pointer events:

但是,鼠标事件确实会冒泡。因此,可以通过首先确保g接收所有指针事件来实现您想要的效果:

.g_main {
  // ..
  pointer-events: all;
}

And then appending an invisible rectangle to it as a place to hover over:

然后在它上面附加一个不可见的矩形作为悬停的地方:

viz.on("mousemove", function () {
        cx = d3.mouse(this)[0];
        cy = d3.mouse(this)[1];
        redrawline(cx, cy);
    })
    .on("mouseover", function () {
        d3.selectAll('.line_over').style("display", "block");
    })
    .on("mouseout", function () {
        d3.selectAll('.line_over').style("display", "none");
    })
  .append('rect')
  .attr('class', 'click-capture')
  .style('visibility', 'hidden')
  .attr('x', 0)
  .attr('y', 0)
  .attr('width', width)
  .attr('height', height);

Working example: http://jsfiddle.net/H3W3k/

工作示例:http: //jsfiddle.net/H3W3k/

As for why they work when applied to the svgelement (from the docs):

至于为什么它们在应用于svg元素时起作用(来自文档):

Note that the ‘svg' element is not a graphics element, and in a Conforming SVG Stand-Alone File a rootmost ‘svg' element will never be the target of pointer events, though events can bubble to this element. If a pointer event does not result in a positive hit-test on a graphics element, then it should evoke any user-agent-specific window behavior, such as a presenting a context menu or controls to allow zooming and panning of an SVG document fragment.

请注意,'svg' 元素不是图形元素,并且在符合标准的 SVG 独立文件中,最根的 'svg' 元素永远不会成为指针事件的目标,尽管事件可以冒泡到该元素。如果指针事件没有在图形元素上产生正面的命中测试,那么它应该唤起任何特定于用户代理的窗口行为,例如呈现上下文菜单或控件以允许缩放和平移 SVG 文档片段.