我在nvd3中使用了对焦图表(View Finder)示例。这意味着在图表上绘制了3或4行(系列)。当我将鼠标悬停在任何一条线上时,我想要找回给定x轴位置的所有线的所有y值(大多数情况下,这些线将是每行的y值插值)。
我在nv.models.lineWithFocusChart
源代码中看到,使用elementMouseover.tooltip
事件的回调,我可以为行上的数据点获取数据的x值。
我想要的最接近的源代码部分是interactiveGuideline
code for the lineChart examples。但是,我不想使用<rect>
互动创建elementMousemove
叠加层。我想我可以修改这段代码来过滤我的数据并得到每一行的y值,但我确信这是一种我没有看到的更简单的方法。
我认为我走在正确的轨道上,但只是想知道是否有人之前有这种需要,并找到了比兔子洞更快的路线。我想跳进去。
感谢您的反馈
答案 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
,
xScale
和yScale
可以在lines
,
我必须选择工具提示,而不是将其放在变量
使用自定义事件调用它们的函数作为已计算鼠标坐标的e
参数,我必须自己计算它们。
他们的一个计算使用了一个函数(nv.nearestValueIndex
),只有在创建交互层时才会初始化,所以我不得不将该函数定义复制到我的。
我认为这涵盖了它。如果您还有其他任何事情可以关注,请发表评论。