NVD3.js给定X轴值,获取所有线的Y轴值

时间:2014-02-28 17:08:33

标签: javascript d3.js nvd3.js

我在nvd3中使用了对焦图表(View Finder)示例。这意味着在图表上绘制了3或4行(系列)。当我将鼠标悬停在任何一条线上时,我想要找回给定x轴位置的所有线的所有y值(大多数情况下,这些线将是每行的y值插值)。

我在nv.models.lineWithFocusChart源代码中看到,使用elementMouseover.tooltip事件的回调,我可以为行上的数据点获取数据的x值。

我想要的最接近的源代码部分是interactiveGuideline code for the lineChart examples。但是,我不想使用<rect>互动创建elementMousemove叠加层。我想我可以修改这段代码来过滤我的数据并得到每一行的y值,但我确信这是一种我没有看到的更简单的方法。

我认为我走在正确的轨道上,但只是想知道是否有人之前有这种需要,并找到了比兔子洞更快的路线。我想跳进去。

感谢您的反馈

1 个答案:

答案 0 :(得分:1)

这是您正在寻找的基本功能,它仍然需要一些技巧和造型的工具提示。 (现在工具提示会阻止点的视图......)

在绘制图表之后调用的密钥代码(例如,在NVD3实时代码网站上的nv.addGraph函数内):

 d3.selectAll("g.nv-focus g.nv-point-paths")
    .on("mouseover.mine", function(dataset){

      //console.log("Data: ", dataset);

      var singlePoint, pointIndex, pointXLocation, allData = [];
      var lines = chart.lines;

      var xScale = chart.xAxis.scale();
      var yScale = chart.yAxis.scale();
      var mouseCoords = d3.mouse(this);
      var pointXValue = xScale.invert(mouseCoords[0]);

      dataset
          .filter(function(series, i) {
            series.seriesIndex = i;
            return !series.disabled;
          })
          .forEach(function(series,i) { 
              pointIndex = nv.interactiveBisect(series.values, pointXValue, lines.x());
              lines.highlightPoint(i, pointIndex, true);

              var point = series.values[pointIndex];

              if (typeof point === 'undefined') return;
              if (typeof singlePoint === 'undefined') singlePoint = point;
              if (typeof pointXLocation === 'undefined')
                pointXLocation = xScale(lines.x()(point,pointIndex));

              allData.push({
                  key: series.key,
                  value: lines.y()(point, pointIndex),
                  color: lines.color()(series,series.seriesIndex)
              });
          }); 


      /*
      Returns the index in the array "values" that is closest to searchVal.
      Only returns an index if searchVal is within some "threshold".
      Otherwise, returns null.
      */
      nv.nearestValueIndex = function (values, searchVal, threshold) {
            "use strict";
            var yDistMax = Infinity, indexToHighlight = null;
            values.forEach(function(d,i) {
               var delta = Math.abs(searchVal - d);
               if ( delta <= yDistMax && delta < threshold) {
                  yDistMax = delta;
                  indexToHighlight = i;
               }
            });
            return indexToHighlight;
      };

     //Determine which line the mouse is closest to.
     if (allData.length > 2) {
            var yValue = yScale.invert( mouseCoords[1] );
            var domainExtent = Math.abs(yScale.domain()[0] - yScale.domain()[1]);
            var threshold = 0.03 * domainExtent;
            var indexToHighlight = nv.nearestValueIndex(
              allData.map(function(d){ return d.value}), yValue, threshold
            );
            if (indexToHighlight !== null)
              allData[indexToHighlight].highlight = true;
                //set a flag you can use when styling the tooltip
      }


      //console.log("Points for all series", allData);

      var xValue = chart.xAxis.tickFormat()( lines.x()(singlePoint,pointIndex) );

      d3.select("div.nvtooltip:last-of-type")
        .html(
          "Point: " + xValue + "<br/>" +

          allData.map(function(point){
            return "<span style='color:" + point.color + 
              (point.highlight? ";font-weight:bold" : "") + "'>" + 
              point.key + ": " + 
              chart.yAxis.tickFormat()(point.value) +
              "</span>";
          }).join("<br/><hr/>")
        );

    }).on("mouseout.mine", function(d,i){ 
          //select all the visible circles and remove the hover class

      d3.selectAll("g.nv-focus circle.hover").classed("hover", false);
    });

要弄清楚的第一件事是我应该将事件绑定到哪些对象?逻辑选择是Voronoi路径元素,但即使我将事件名称命名为避免冲突,内部事件处理程序也没有触发我的事件处理函数。看起来父<g>事件会在鼠标事件到达各个<path>元素之前捕获它们。但是,如果我将事件绑定到包含Voronoi路径的<g>元素,它可以正常工作,并且它还有一个额外的好处,就是当数据对象传递给我的函数时,可以直接访问整个数据集。这意味着即使数据稍后更新,该功能仍在使用活动数据。

其余代码基于Interactive Guideline code for the NVD3 line graphs,但我必须进行一些重要更改:

  • 他们的代码在图表函数的闭包内,可以访问私有变量,我不能。此外,上下文+焦点图表具有稍微不同的名称/功能,用于访问图表组件,因为它由两个图表组成。因为:

      内部代码中的
    • chart外部为chart.lines

    • 必须从图表轴访问
    • xScaleyScale

    • 可以在lines

    • 中访问色标和x和y访问器功能
    • 我必须选择工具提示,而不是将其放在变量

  • 使用自定义事件调用它们的函数作为已计算鼠标坐标的e参数,我必须自己计算它们。

  • 他们的一个计算使用了一个函数(nv.nearestValueIndex),只有在创建交互层时才会初始化,所以我不得不将该函数定义复制到我的。

我认为这涵盖了它。如果您还有其他任何事情可以关注,请发表评论。