【问题标题】:d3.js - mouseover event not working properly on svg groupd3.js - mouseover 事件在 svg 组上无法正常工作
【发布时间】:2013-06-04 12:44:38
【问题描述】:

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

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

这是我的代码:

test.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>

重新测试.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");
    }
};

【问题讨论】:

    标签: javascript html d3.js


    【解决方案1】:

    g 元素只是一个空容器,无法捕获点击事件(详情请参阅documentation for pointer-events property)。

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

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

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

    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);
    

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

    至于为什么它们在应用于svg 元素(from the docs)时起作用:

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

    【讨论】:

    • 这也可以通过viz.style('pointer-events', 'all')实现
    • 这个答案很好,但是是关于 D3 v3...2019 年的一些新闻?没有简单的方法来为事件设置“catch all”节点?我正在使用背景矩形,并且有同样的问题。
    • 我可以为 .g_main 和 .click-capture 类使用相同的矩形吗?
    • The g element is just an empty container which cannot capture click events - 不正确。您可以在 g 元素上设置 pointer-events: bounding-box,并在其上捕获单击事件,而不管其子元素如何。这个答案实际上花费了我 2 个小时,试图弄清楚当点击侦听器位于其祖先之一时如何将 g 元素作为目标。
    • 嗯,如果我这样做,鼠标悬停工作,但我不能再点击 svg 中的其他元素
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多