d3.js - 鼠标悬停事件在 svg 组上无法正常工作 [英] d3.js - mouseover event not working properly on svg group

查看:59
本文介绍了d3.js - 鼠标悬停事件在 svg 组上无法正常工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

这是我的代码:

test.html

<头><script src="jquery.js"><script src="d3.v2.js"><script src="retest.js"><style type="text/css">.g_main {游标:指针;}.axis 路径,.axis 线 {笔画:#DBDBDB;/* 形状渲染:crispEdges;*/}.y g:第一个子文本{显示:无;}.y g:第一个子行{中风:#989898;描边宽度:2.5px;}/*.x g:第一个子行{笔画:黑色;描边宽度:2.5px;}*/.y 路径 {中风:#989898;描边宽度:2.5px;}</风格><身体><中心><button id="reload" onclick="loadViz();">负载图<div id="viz" class="viz">

</中心><脚本>加载可视化();

重新测试.js

var 系列,分类,最小值,最大值,SVGW = 600,svgH = 600,//w = 1200,//h = 1200,vizPadding = {顶部:120,右:30,底部:120,左:50},yAxMin_PA = 0,yAxMax_PA = 50,xAxMin_PA = 2002,xAxMax_PA = 2008,areaStrokeColors = ['#FF6600', '#3366FF', '#B8860B', '#458B00', '白色'];var loadViz = 函数 () {颜色 = d3.scale.category10();数据 = {行":[{线": [{X":2002,是":42}, {X":2003,Y":45},{X":2005,是":47},{X":2007,是":41}]}, {线": [{X":2003,是":33}, {X":2005,是":38}, {"Y": 36,X":2008}]}, {线": [{X":2004,是":13}, {X":2005,是":19}, {X":2008,Y":21}]}, {线": [{X":2003,Y":20}, {X":2005,Y":27}, {X":2008,是":29}]}]};$("#viz").html("");构建基础();//setScales();};var buildBase = 函数 () {边距 = {顶部:80,右:120,底部:40,左:40},宽度 = 960 - margin.left - margin.right,高度 = 550 - margin.top - margin.bottom;t2 = 高度 + margin.top + margin.bottom;x = d3.scale.linear().domain([xAxMin_PA, xAxMax_PA]).range([0, 宽度]);y = d3.scale.linear().domain([yAxMin_PA, yAxMax_PA]).range([高度, 0]);tickSizeToApplyX = 5;tickSizeToApplyY = 10;//绘制X轴的函数xAxis = d3.svg.axis().scale(x).ticks(tickSizeToApplyX).tickSize(-height, 0, 0)//.tickSize(10).orient("底部").tickPadding(5);//绘制Y轴的函数yAxis = d3.svg.axis().scale(y).ticks(tickSizeToApplyY).tickSize(-width, 0, 0)//.tickSize(0).orient("左").tickPadding(5);//定义行var valueline = d3.svg.line().x(function (d) {/*console.log(d.X);*/返回 x(d.X);}).y(function (d) {/*console.log(d.Y);*/返回 y(d.Y);});//定义行var 参考线 = d3.svg.line().x(function (dx) {/*console.log(d.X);*/返回 dx;}).y(function (dy) {/*console.log(d.Y);*/返回 dy;});//将 SVG 附加到 html 中var viz = d3.select("#viz").append("svg").attr("宽度", 宽度 + 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(鼠标移动",函数(){cx = d3.mouse(this)[0];cy = d3.mouse(this)[1];console.log("xx=>" + cx + "yy=>" + cy);重绘线(cx,cy);}).on(鼠标悬停",函数(){d3.selectAll('.line_over').style("display", "block");}).on("mouseout", function () {d3.selectAll('.line_over').style("display", "none");});//console.log(this);viz.append("行")//d3.select("svg").append("line").attr("class", 'line_over').attr("x1", 0).attr("y1", 0).attr("x2", x(xAxMax_PA)).attr("y2", 0).style("笔画", "灰色").attr("stroke-dasharray", ("5,5")).style("笔画宽度", "1.5").style("显示", "无");//绘制X轴viz.append("g").attr("class", "x 轴").attr("transform", "translate(0," + height + ")").call(xAxis);//绘制Y轴viz.append("g").attr("class", function (d, i) {返回y轴"}).call(yAxis);功能重绘线(cx,cy){d3.selectAll('.line_over').attr("x1", 0).attr("y1", cy).attr("x2", x(xAxMax_PA)).attr("y2", cy).style("显示", "块");}};

解决方案

g 元素只是一个无法捕获点击事件的空容器(请参阅 pointer-events 属性 的文档以了解详细信息).

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

.g_main {//..指针事件:全部;}

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

viz.on("mousemove", function () {cx = d3.mouse(this)[0];cy = d3.mouse(this)[1];重绘线(cx,cy);}).on(鼠标悬停",函数(){d3.selectAll('.line_over').style("display", "block");}).on("mouseout", function () {d3.selectAll('.line_over').style("display", "none");}).append('rect').attr('class', '点击捕获').style('可见性','隐藏').attr('x', 0).attr('y', 0).attr('宽度', 宽度).attr('身高', 身高);

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

至于为什么它们适用于 svg 元素(来自文档):

<块引用>

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

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 ?

Here is my code :

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>

retest.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");
    }
};

解决方案

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

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

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

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

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.

这篇关于d3.js - 鼠标悬停事件在 svg 组上无法正常工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆