将工具提示添加到D3线性图 [英] Add tooltip to D3 linear graph

查看:125
本文介绍了将工具提示添加到D3线性图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

  //定义图形的尺寸
var m = [20,80,80,80] // marginins
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 (d){

return y(d);
})($ {
} b

$ b 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]);
})
b $ b .y(function(d){

return y(d);
})

//添加具有所需尺寸的SVG元素,保证金。
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] +));

//创建xAxis
var xAxis = d3.svg.axis()。scale(x).ticks(allyears.length).tickSize(-h).tickSubdivide(true);
//添加x轴。
graph.append(svg:g)
.attr(class,x axis)
.attr(transform ))
.call(xAxis);


// create left yAxis
var yAxisLeft = d3.svg.axis()。scale(y).ticks(8).orient(left);
//将y轴添加到左边
graph.append(svg:g)
.attr(class,y axis)
.attr (transform,translate(-25,0))
.call(yAxisLeft);


graph.append(svg:text)
.attr(class,title1)
.attr(x, / 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的新手,我已经看过seveal其他样本,能够在我的js代码上重现他们。谁能帮助我?
谨慎

解决方案

我在评论中提到行的数据是完整的数组,该行用户的鼠标将需要额外的计算。这是使用隐形圆在数据点上抓取鼠标事件的一个原因。另一个是,你可以使圆的半径大于笔画宽度,以使更大的面积为鼠标事件。第三个是,您可以在鼠标悬停时装饰圆形,如 NVD3折线图中所示。 / p>

但是如果你不想让额外的圈​​子拥挤你的DOM怎么办。或者,如果你想让鼠标悬停事件在任何地方上触发,而不只是在点上?你仍然可以知道鼠标相对于线的位置,并且可以使用它来为该线的数据数组中找到正确的点。

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

function findValue(d,i){
var mouseX = d3.mouse(this.parentNode)[0];
//找到鼠标相对于绘图容器的水平坐标

var dataX = x.invert(mouseX);
//转换缩放比例以在鼠标点找到x值

//扫描数据数组以找到最接近鼠标的值
var j = d。长度;
while((j--)&&(d [j] .x> dataX)); // repeat until false

var datapoint;
if(j> = 0){
// d [j]现在将是第一数据点*小于*指针
//将其与d [j + 1]以查看哪个更靠近鼠标:
if(isNaN(d [j + 1])||(dataX_d [j] .x datapoint = d [j];
else
datapoint = d [j + 1];
} else {
//数组中的所有值都大于鼠标点,
//因此返回第一个点
datapoint = d [0];
}

//使用数据点值执行某些操作:
alert(Crossed line+ i +near+ [datapoint.x,datapoint.y]);
}

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



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



请注意,此方法不能与@picus的原始代码一起工作,因为该代码实际上并不使用d3方法将数据链接到元素。 (@picus,请查看教程页面,了解如何使用d3更容易! )


I'm getting crazy on how to add tooltip to my linear d3 chart, so that the user can see the specific value of the performance along the years. This is the fiddle: http://jsfiddle.net/d9Lya/ and this the code

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

I'm actually new to D3 and I've seen seveal other samples around and I'm not able to reproduce them on my js code. Can anyone help me? Regards

解决方案

I mentioned in the comments that "the line's data is the complete array, and figuring out where on the line the user's mouse is would require extra calculation". That's one reason to use "invisible circles" to grab mouse events over datapoints. Another is that you can make the radius of the circle much larger than the stroke width to make a larger area for mouse events. A third is that you can then decorate the circles on mouseover, like in the NVD3 line charts.

But what if you don't want extra circles crowding up your DOM. Or what if you want the mouseover event to be triggered anywhere on the line, not just on the points? You can still figure out where the mouse is relative to the line, and can use that to find the correct point in the data array for that line.

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

Live example here: http://fiddle.jshell.net/c2mru/8/

The d value passed to the event handler function is the data object attached to the <path> element. That is normally the array of points on the line, although sometimes it is an object that contains the array of points as a property, in which case you'd have to amend this to suit. Using d3.mouse(container) you can figure out the position of the mouse in the relevant SVG coordinate system, and using the invert method of the scale you can figure out the position of the mouse relative to the horizontal axis. Then, assuming that your data is a normal line graph that doesn't repeat x-values, it's a simple matter of scrolling through the array of points to find the one closest to the mouse.

Note that this method won't work with @picus' original code, because that code doesn't actually use d3 methods to link data to the elements. (@picus, check out the Tutorials page for how to make working with d3 much easier!)

这篇关于将工具提示添加到D3线性图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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