将工具提示添加到D3线性图

时间:2014-02-10 17:58:38

标签: graph d3.js tooltip

我对如何将工具提示添加到我的线性d3图表感到疯狂,以便用户可以看到多年来的性能特定值。 这是小提琴:http://jsfiddle.net/d9Lya/ 这个代码

    // define dimensions of graph
    var m = [20, 80, 80, 80]; // margins
    var w = 650 - m[1] - m[3]; // width
    var h = 500 - m[0] - m[2]; // height


    var data = [30, 28, 33] ;
    var years = [2010, 2011, 2012] ;

    var data2 = [100, 200, 200] ;
    var years2 = [2009, 2010, 2011] ;
    var alldata = data.concat(data2);
    var allyears = years.concat(years2);

    var data3 = [200, 220, 300] ;
    var years3 = [2011, 2012, 2013] ;
    var alldata = data.concat(data2, data3);
    var allyears = years.concat(years2, years3);


    //unique vals functin
    var unique = function(origArr) {
        var newArr = [],
            origLen = origArr.length,
            found,
            x, y;
        for ( x = 0; x < origLen; x++ ) {
            found = undefined;
            for ( y = 0; y < newArr.length; y++ ) {
                if ( origArr[x] === newArr[y] ) {
                  found = true;
                  break;
                }
            }
            if ( !found) newArr.push( origArr[x] );   
        }
       return newArr;
    };


    allyears = unique(allyears);


    var x = d3.scale.linear().domain([d3.min(allyears), d3.max(allyears)]).range([0,w]);


    var y = d3.scale.linear().domain([0, (d3.max(alldata))*1.3]).range([h, 0]);


    var line = d3.svg.line()

        .x(function(d,i) { 

            return x(years[i]); 
        })

        .y(function(d) { 

            return y(d); 
        })


    var line2 = d3.svg.line()

        .x(function(d,i) { 
            return x(years2[i]); 
        })

        .y(function(d) { 

            return y(d); 
        })          

    var line3 = d3.svg.line()
        .x(function(d,i) { 
            return x(years3[i]); 
        })

        .y(function(d) { 

            return y(d); 
        })          

    // Add an SVG element with the desired dimensions and margin.
    var graph = d3.select("#graph").append("svg:svg")
        .attr("width", w + m[1] + m[3])
        .attr("height", h + m[0] + m[2])
        .append("svg:g")
        .attr("transform", "translate(" + m[3] + "," + m[0] + ")");

    // create xAxis
    var xAxis = d3.svg.axis().scale(x).ticks(allyears.length).tickSize(-h).tickSubdivide(true);
    // Add the x-axis.
    graph.append("svg:g")
          .attr("class", "x axis")
          .attr("transform", "translate(0," + h + ")")
          .call(xAxis);


    // create left yAxis
    var yAxisLeft = d3.svg.axis().scale(y).ticks(8).orient("left");
    // Add the y-axis to the left
    graph.append("svg:g")
          .attr("class", "y axis")
          .attr("transform", "translate(-25,0)")
          .call(yAxisLeft);


    graph.append("svg:text")
        .attr("class", "title1")
        .attr("x", (w/2))
        .attr("y", 0)
        .text("Performance")
        .style({ "stroke": "Black", "fill": "Black", "stroke-width": "1px"})
        .attr("text-anchor", "middle")  
        .style("font-size", "16px") ;   



    graph.append("svg:path").attr("d", line(data)).style("stroke", "steelblue");
    graph.append("svg:text")
        .attr("class", "title1")
        .attr("x", 0)
        .attr("y", 30)
        .text("TEAM A")
        .style({ "stroke": "steelblue", "fill": "steelblue", "stroke-width": "0px"});       
    graph.append("svg:path")
    .attr("d", line2(data2)).style("stroke", "green")
    ;




        graph.append("svg:text")
                        .attr("class", "title2")
                        .attr("x", 0)
                        .attr("y", 50)
                        .text("TEAM B")
                        .style({ "stroke": "Green", "fill": "Green", "stroke-width": "0px"});         
            graph.append("svg:path").attr("d", line3(data3)).style("stroke", "red");
                graph.append("svg:text")
                        .attr("class", "title3")
                        .attr("x", 0)
                        .attr("y", 70)
                        .text("team C")
                        .style({ "stroke": "Red", "fill": "Red", "stroke-width": "0px"});

我实际上是D3的新手,我已经看到了其他样本,我无法在我的js代码上重现它们。谁能帮我? 此致

1 个答案:

答案 0 :(得分:2)

我在评论中提到&#34;线的数据是完整的数组,并且弄清楚用户鼠标在线的位置需要额外的计算&#34;。这是使用&#34;隐形圈&#34;的一个原因。在数据点上抓取鼠标事件。另一个原因是,您可以使圆的半径远大于笔划宽度,以便为鼠标事件创建更大的区域。第三个是你可以在鼠标悬停时装饰圆圈,就像在NVD3 line charts

中一样

但是,如果你不想要额外的圈子挤占你的DOM,那该怎么办?或者,如果您希望鼠标悬停事件在线路上任何地方触发,而不仅仅是在点上?您仍然可以确定鼠标相对于该行的位置,并可以使用它来查找该行的数据数组中的正确点。

d3.selectAll("path")
    .on("mouseover", findValue);

function findValue(d, i) {
    var mouseX = d3.mouse(this.parentNode)[0];
    //find the mouse's horizontal coordinate relative to the drawing container

    var dataX = x.invert(mouseX); 
       //invert the scale to find the x value at the mouse point

    //scan through the data array to find the value closest to the mouse
    var j = d.length;
    while ((j--) && (d[j].x > dataX)); //repeat until false

    var datapoint;
    if (j >= 0) {
        //d[j] will now be the first datapoint *less than* the mousepoint
        //compare it with d[j+1] to see which is closer to the mouse:
        if ( isNaN(d[j+1]) || (dataX - d[j].x < d[j+1].x - dataX) )
            datapoint = d[j];
        else
            datapoint = d[j+1];
    } else {
        //all the values in the array were greater than the mouse point, 
        //so return the first point
        datapoint = d[0];
    }

    //Do something with your datapoint value:
    alert("Crossed line " + i + " near " + [datapoint.x, datapoint.y]);
}

此处的实例:http://fiddle.jshell.net/c2mru/8/

传递给事件处理函数的d值是附加到<path>元素的数据对象。这通常是线上的点数组,尽管有时它是包含点数组作为属性的对象,在这种情况下,您必须修改它以适应。使用d3.mouse(container)可以找出鼠标在相关SVG坐标系中的位置,并使用比例的反转方法可以计算出鼠标相对于水平轴的位置。然后,假设您的数据是不重复x值的法线图,那么滚动点数组就可以找到最接近鼠标的点数。

请注意,此方法无法使用@ picus&#39;原始代码,因为该代码实际上没有使用d3方法将数据链接到元素。 (@picus,查看Tutorials page了解如何更轻松地使用d3!)