D3:在鼠标悬停时从序数轴获取最接近的值 [英] D3: Get nearest value from ordinal axis on mouseover

查看:58
本文介绍了D3:在鼠标悬停时从序数轴获取最接近的值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的D3折线图中,我试图像以下示例一样创建鼠标悬停效果: http://bl.ocks.org/mbostock/3902569

In my D3 line chart, i´m trying to create a mouseover effect like in this example: http://bl.ocks.org/mbostock/3902569

在此示例中,作者使用了平分线函数,据我所知,该函数仅支持线性刻度.问题是,在我的图表中,我有一个序数x轴,具有不同的离散rangePoint元组.因此,如果在以下情况下(m =鼠标位置),我想获取最接近的x值的像素位置,在本示例中为x2.

In this example the author uses the bisector function, which is, as far as i understand, only supported for linear scales. The problem is, that in my chart i have an ordinal x axis with different, discrete rangePoint tuples. So if it is like in the situation below (m = mouse position), i want to get the pixel position of the closest x value which would be x2 in this example.

         m
         |
x1----------x2----------x3

有没有办法做到这一点?

Is there any way to do that?

推荐答案

使用您的链接示例,以下是 mousemove 函数的有序刻度的快速实现:

Using your linked example, here's a quick implementation of the mousemove function for an ordinal scale:

var tickPos = x.range();
function mousemove(d){
  var m = d3.mouse(this),
      lowDiff = 1e99,
      xI = null;
  // if you have a large number of ticks
  // this search could be optimized
  for (var i = 0; i < tickPos.length; i++){
    var diff = Math.abs(m[0] - tickPos[i]);
    if (diff < lowDiff){
      lowDiff = diff;
      xI = i;
    }
  }
  focus
    .select('text')
    .text(ticks[xI]);
  focus
    .attr("transform","translate(" + tickPos[xI] + "," + y(data[xI].y) + ")");
}


完整代码:


Full code:

<!DOCTYPE html>
<meta charset="utf-8">
<style>
  body {
    font: 10px sans-serif;
  }
  
  .axis path,
  .axis line {
    fill: none;
    stroke: #000;
    shape-rendering: crispEdges;
  }
  
  .line {
    fill: none;
    stroke: steelblue;
    stroke-width: 1.5px;
  }
  
  .overlay {
    fill: none;
    pointer-events: all;
  }
  
  .focus circle {
    fill: none;
    stroke: steelblue;
  }
</style>

<body>
  <script src="//d3js.org/d3.v3.min.js"></script>
  <script>
    var margin = {
        top: 20,
        right: 20,
        bottom: 30,
        left: 50
      },
      width = 960 - margin.left - margin.right,
      height = 500 - margin.top - margin.bottom;


    var x = d3.scale.ordinal()
      .rangeRoundPoints([0, width]);

    var y = d3.scale.linear()
      .range([height, 0]);

    var xAxis = d3.svg.axis()
      .scale(x)
      .orient("bottom");

    var yAxis = d3.svg.axis()
      .scale(y)
      .orient("left");

    var line = d3.svg.line()
      .x(function(d) {
        return x(d.x);
      })
      .y(function(d) {
        return y(d.y);
      });

    var svg = d3.select("body").append("svg")
      .attr("width", width + margin.left + margin.right)
      .attr("height", height + margin.top + margin.bottom)
      .append("g")
      .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

    var data = [{
      x: 'A',
      y: Math.random() * 10
    }, {
      x: 'B',
      y: Math.random() * 10
    }, {
      x: 'C',
      y: Math.random() * 10
    }, {
      x: 'D',
      y: Math.random() * 10
    }, {
      x: 'E',
      y: Math.random() * 10
    }, {
      x: 'F',
      y: Math.random() * 10
    }, {
      x: 'G',
      y: Math.random() * 10
    }, {
      x: 'H',
      y: Math.random() * 10
    }, {
      x: 'I',
      y: Math.random() * 10
    }, {
      x: 'J',
      y: Math.random() * 10
    }];

    var ticks = data.map(function(d) {
      return d.x
    });
    x.domain(ticks);
    y.domain(d3.extent(data, function(d) {
      return d.y;
    }));

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

    svg.append("g")
      .attr("class", "y axis")
      .call(yAxis)
      .append("text")
      .attr("transform", "rotate(-90)")
      .attr("y", 6)
      .attr("dy", ".71em");

    svg.append("path")
      .datum(data)
      .attr("class", "line")
      .attr("d", line);

    var focus = svg.append("g")
      .attr("class", "focus")
      .style("display", "none");

    focus.append("circle")
      .attr("r", 4.5);

    focus.append("text")
      .attr("x", 9)
      .attr("dy", ".35em")
      .style('')

    svg.append("rect")
      .attr("class", "overlay")
      .attr("width", width)
      .attr("height", height)
      .on("mouseover", function() {
        focus.style("display", null);
      })
      .on("mouseout", function() {
        focus.style("display", "none");
      })
      .on("mousemove", mousemove);
    
    var tickPos = x.range();
    function mousemove(d){
      var m = d3.mouse(this),
          lowDiff = 1e99,
          xI = null;
      for (var i = 0; i < tickPos.length; i++){
        var diff = Math.abs(m[0] - tickPos[i]);
        if (diff < lowDiff){
          lowDiff = diff;
          xI = i;
        }
      }
      focus
        .select('text')
        .text(ticks[xI]);
      focus
        .attr("transform","translate(" + tickPos[xI] + "," + y(data[xI].y) + ")");
    }
  </script>

这篇关于D3:在鼠标悬停时从序数轴获取最接近的值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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