如何在D3中鼠标悬停到线图交互 [英] How to as mouseover to Line Graph Interactive in D3

查看:261
本文介绍了如何在D3中鼠标悬停到线图交互的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是D3的新手,试图制作一个简单的交互式线形图。我当前的代码: http://jsfiddle.net/9xske0m1/
基于一个找到的on bl.ocks.org



我正在考虑在这里添加一条垂直线: http://bl.ocks.org/benjchristensen/2657838 ,但是在鼠标悬停时将线条的值显示为图例,而不是将它们显示在底部的图表,和我当我徘徊在一条线。
所以我想知道我会怎么做。
我假设我在这里添加了一些东西:

  data = data.map(function {
return {
CAUSES:d.CAUSES,
YEAR:parseDate(d.YEAR.toString()),
VALUE:+ d.VALUE};
});


//然后我们需要将数据嵌套在CAUSES上,因为我们只想每个CAUSES绘制一个
//行
data = d3.nest() .key(function(d){return d.CAUSES;})。entries(data);


x.domain([d3.min(data,function(d){return d3.min(d.values,function(d){return d.YEAR;}); }),
d3.max(data,function(d){return d3.max(d.values,function(d){return d.YEAR;});})]);
y.domain([0,d3.max(data,function(d){return d3.max(d.values,function(d){return d.VALUE;});})]);

// var path1 = svg.append(g)。append(path)。data([data1])。attr(class,line1);


svg.append(g)
.attr(class,x axis)
.attr(transform,translate 0,+ height +))
.call(xAxis);

svg.append(g)
.attr(class,y axis)
.call(yAxis);

var causation = svg.selectAll(。CAUSES)
.data(data,function(d){return d.key;})
.enter append(g)
.attr(class,CAUSES);

causation.append(path)
.attr(class,line)
.attr(d,function(d){return line d.values);})
.style(stroke,function(d){return color(d.key);});


解决方案

EDITS >

对于通过搜索找到此答案的用户,还请参阅我在此写的答案。这是一个非常类似的问题,具有更干净的实现。






我没有看到链接示例的实现,重新创建效果。我在这里玩了一下,所以在这里解释更新的小提琴



本质上,我添加了一条垂直线来跟随鼠标。我还添加了 g 文本元素。当鼠标悬停在绘图上时,我将垂直线更新为鼠标位置,找出垂直线在x轴上的位置,并确定它与每个绘制的路径相交的位置。最后,我更新了圆的位置,并用插入的x,y位置更新了文本元素。



这里是添加代码的注释说明:

  svg.append(path)//这是跟随鼠标的黑色垂直线
.attr(class mouseLine)
.style(stroke,black)
.style(stroke-width,1px)
.style(opacity );

var mouseCircle = causation.append(g)//为每一行添加组来保存文本和圆
.attr(class,mouseCircle);

mouseCircle.append(circle)//添加一个圆圈以跟随路径
.attr(r,7)
.style (fill,none)
.style(stroke-width, 1px);

mouseCircle.append(text)
.attr(transform,translate(10,3) // text to hold coordinates

var bisect = d3.bisector(function(d){return d.YEAR;})right; //可重用的bisect在之前/之后找到点

svg.append('svg:rect')//附加一个rect来捕捉canvas上的鼠标移动
.attr('width' ,width)//不能在ag元素上捕获鼠标事件
.attr('height',height)
.attr('fill','none')
.attr指针事件','所有')
.on('mouseout',function(){//鼠标移出时隐藏线,圆和文本
d3.select(mouseLine)
.style(opacity,0);
d3.selectAll(mouseCircle circle)
.style(opacity,0);
d3。 selectAll(。mouseCircle text)
.style(opacity,0);
})
.on('mouseover',function显示线,圆和文本
d3.select(。mouseLine)
.style(opacity,1);
d3.selectAll(mouseCircle circle)
.style(opacity,1);
d3.selectAll(mouseCircle text)
.style )
.on('mousemove',function(){//鼠标移动到画布上
d3.select(mouseLine)
.attr(d,function
yRange = y.range(); // y轴范围
var xCoor = d3.mouse(this)[0]; //鼠标在x中的位置
var xDate = x.invert(xCoor); //对应于鼠标的日期x
d3.selectAll('。mouseCircle')//对于每个圆形组
.each(function(d,i){
var rightIdx = bisect [1] .values,xDate); //在鼠标右键的数据中找到日期
var interSect = get_line_intersection(xCoor,//获取垂直线和数据线的交叉
yRange [0 ],
xCoor,
yRange [1],
x(data [i] .values [rightIdx-1] .YEAR),
y(data [i] .values [rightIdx -1] .VALUE),
x(data [i] .values [rightIdx] .YEAR),
y(data [i] .values [rightIdx] .VALUE));

d3.select(this)//将圆移动到交集
.attr('transform','translate('+ interSect.x +','+ interSect.y +')');

d3.select(this.children [1])//写坐标出
.text(xDate.toLocaleDateString()+,+ y.invert(interSect.y).toFixed 0));

});

returnM+ xCoor +,+ yRange [0] +L+ xCoor +,+ yRange [1] // position vertical line
});
});

//从这里开始:http://stackoverflow.com/a/1968345/16363
function get_line_intersection(p0_x,p0_y,p1_x,p1_y,
p2_x,p2_y,p3_x ,p3_y)
{
var rV = {};
var s1_x,s1_y,s2_x,s2_y;
s1_x = p1_x - p0_x; s1_y = p1_y-p0_y;
s2_x = p3_x - p2_x; s2_y = p3_y-p2_y;

var s,t;
s =(-s1_y *(p0_x-p2_x)+ s1_x *(p0_y-p2_y))/(-s2_x * s1_y + s1_x * s2_y)
t =(s2_x *(p0_y-p2_y)-s2_y *(p0_x-p2_x))/(-s2_x * s1_y + s1_x * s2_y)

if(s> = 0&& s< = 1&& t> = 0&& t< = 1)
{
//检测到碰撞
rV.x = p0_x +(t * s1_x);
rV.y = p0_y +(t * s1_y);
}

return rV;
}

屏幕截图:




I am new to D3 and was trying to make a simple Interactive Line Graph. My current code: http://jsfiddle.net/9xske0m1/ is based off of one found on bl.ocks.org

I was thinking about adding a vertical line like the one here: http://bl.ocks.org/benjchristensen/2657838 but with the values of the lines displayed as a legend in a hover over, as opposed to having them displayed on the bottom of the chart, and I when I hover over a line. So I was wondering how I would go about doing that. I am assuming I have so add some thing around here:

    data = data.map( function (d) { 
    return { 
      CAUSES: d.CAUSES,
      YEAR: parseDate(d.YEAR.toString()),
      VALUE: +d.VALUE }; 
});   


// then we need to nest the data on CAUSES since we want to only draw one
// line per CAUSES
  data = d3.nest().key(function(d) { return d.CAUSES; }).entries(data);


  x.domain([d3.min(data, function(d) { return d3.min(d.values, function (d) { return d.YEAR; }); }),
             d3.max(data, function(d) { return d3.max(d.values, function (d) { return d.YEAR; }); })]);
  y.domain([0, d3.max(data, function(d) { return d3.max(d.values, function (d) { return d.VALUE; }); })]);

  // var path1 = svg.append("g").append("path").data([data1]).attr("class", "line1");


  svg.append("g")
      .attr("class", "x axis")
      .attr("transform", "translate(0," + height + ")")
      .call(xAxis);

  svg.append("g")
      .attr("class", "y axis")
      .call(yAxis);

  var causation = svg.selectAll(".CAUSES")
      .data(data, function(d) { return d.key; })
    .enter().append("g")
      .attr("class", "CAUSES");

  causation.append("path")
      .attr("class", "line")
      .attr("d", function(d) { return line(d.values); })
      .style("stroke", function(d) { return color(d.key); });

解决方案

EDITS

For those finding this answer through a search, also see the answer I wrote here. It's a very similar question with a much cleaner implementation.


I didn't look at the implementation of the linked example but recreated the effect. I went a little over the top playing around with this, so before I explain here's the updated fiddle.

Essentially I added a vertical line to follow the mouse. I also added a g of a circle and text element for each plotted line. When you mouse over the plot, I update the vertical line to the mouse position, figure out where the vertical line is on the x-axis and determine where it intersects each plotted path. Finally, I updated the position of the circle and update the text elements with the interpolated x,y positions.

Here's a commented explanation of the added code:

svg.append("path") // this is the black vertical line to follow mouse
  .attr("class","mouseLine")  
  .style("stroke","black")
  .style("stroke-width", "1px")
  .style("opacity", "0");

var mouseCircle = causation.append("g") // for each line, add group to hold text and circle
      .attr("class","mouseCircle"); 

mouseCircle.append("circle") // add a circle to follow along path
  .attr("r", 7)
  .style("stroke", function(d) { console.log(d); return color(d.key); })
  .style("fill","none")
  .style("stroke-width", "1px"); 

mouseCircle.append("text")
  .attr("transform", "translate(10,3)"); // text to hold coordinates

var bisect = d3.bisector(function(d) { return d.YEAR; }).right; // reusable bisect to find points before/after line

svg.append('svg:rect') // append a rect to catch mouse movements on canvas
  .attr('width', width) // can't catch mouse events on a g element
  .attr('height', height)
  .attr('fill', 'none')
  .attr('pointer-events', 'all')
  .on('mouseout', function(){ // on mouse out hide line, circles and text
        d3.select(".mouseLine")
            .style("opacity", "0");
        d3.selectAll(".mouseCircle circle")
            .style("opacity", "0");
      d3.selectAll(".mouseCircle text")
            .style("opacity", "0");
  })
  .on('mouseover', function(){ // on mouse in show line, circles and text
        d3.select(".mouseLine")
            .style("opacity", "1");
         d3.selectAll(".mouseCircle circle")
            .style("opacity", "1");
        d3.selectAll(".mouseCircle text")
            .style("opacity", "1");
  })
  .on('mousemove', function() { // mouse moving over canvas
      d3.select(".mouseLine")
      .attr("d", function(){
          yRange = y.range(); // range of y axis
          var xCoor = d3.mouse(this)[0]; // mouse position in x
          var xDate = x.invert(xCoor); // date corresponding to mouse x 
          d3.selectAll('.mouseCircle') // for each circle group
              .each(function(d,i){
                 var rightIdx = bisect(data[1].values, xDate); // find date in data that right off mouse
                 var interSect = get_line_intersection(xCoor,  // get the intersection of our vertical line and the data line
                      yRange[0], 
                      xCoor, 
                      yRange[1],
                      x(data[i].values[rightIdx-1].YEAR),
                      y(data[i].values[rightIdx-1].VALUE),
                      x(data[i].values[rightIdx].YEAR),
                      y(data[i].values[rightIdx].VALUE));

              d3.select(this) // move the circle to intersection
                  .attr('transform', 'translate(' + interSect.x + ',' + interSect.y + ')');

              d3.select(this.children[1]) // write coordinates out
                  .text(xDate.toLocaleDateString() + "," + y.invert(interSect.y).toFixed(0));

              });

          return "M"+ xCoor +"," + yRange[0] + "L" + xCoor + "," + yRange[1]; // position vertical line
      });
  });

// from here: http://stackoverflow.com/a/1968345/16363
function get_line_intersection(p0_x, p0_y, p1_x, p1_y, 
    p2_x, p2_y, p3_x, p3_y)
{
    var rV = {};
    var s1_x, s1_y, s2_x, s2_y;
    s1_x = p1_x - p0_x;     s1_y = p1_y - p0_y;
    s2_x = p3_x - p2_x;     s2_y = p3_y - p2_y;

    var s, t;
    s = (-s1_y * (p0_x - p2_x) + s1_x * (p0_y - p2_y)) / (-s2_x * s1_y + s1_x * s2_y);
    t = ( s2_x * (p0_y - p2_y) - s2_y * (p0_x - p2_x)) / (-s2_x * s1_y + s1_x * s2_y);

    if (s >= 0 && s <= 1 && t >= 0 && t <= 1)
    {
        // Collision detected
        rV.x = p0_x + (t * s1_x);
        rV.y = p0_y + (t * s1_y);
    }

    return rV;
}

Screenshot:

这篇关于如何在D3中鼠标悬停到线图交互的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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