当鼠标在折线图上的任何位置时显示提示
display tip when mouse is anywhere over line chart
我有一个复合折线图。
当我将鼠标悬停在图表的任何位置时,如何显示相应的值(日期和值),如下所示:
var composechart = dc.compositeChart("#test_composed");
composechart
.width(990)
.height(450)
.margins({ top: 50, right: 40, left: 50, bottom: 50 })
.x(d3.scaleTime().domain([new Date(2017, 0, 1), new Date(2019, 10, 30)]))
.rangeChart(xChart)
.elasticY(true)
.xUnits(d3.timeMonths)
.legend(dc.legend().x(80).y(20).itemHeight(13).gap(5))
.renderHorizontalGridLines(true)
.brushOn(false)
.compose([
dc.lineChart(composechart)
.dimension(salesgrafikDim)
.group(salesgrafikGroup,"Sales"),
dc.lineChart(composechart)
.dimension(satisgrafikDim)
.colors('red')
.group(quantitygrafikGroup,"Quantity")
])
xChart
.width(990)
.height(40)
.margins({top: 0, right: 50, bottom: 20, left: 50})
.dimension(salesgrafikDim)
.group(salesgrafikGroup)
.x(d3.scaleTime().domain([new Date(2017, 0, 1), new Date(2019, 10, 30)]))
.xUnits(d3.timeMonths);
xChart.yAxis().ticks(0);
基本上想要像下面的屏幕截图一样显示工具提示,其中鼠标不需要悬停在一个点上即可显示。
我可以直接使用 D3、svg 和 append 等等。但是我有其他图表和数据表的维度,所以我想将它与 dc.js.
一起使用
如果您不必将鼠标悬停在圆点上即可看到提示,将会更加用户友好且易于理解。
我的图表如下:
由于 dc.js 不直接支持此功能,您将最终进入 D3 以实现此功能。
首先,我们需要禁用现有的标题:
.title(() => '')
和悬停事件:
composite.on('pretransition', chart => {
chart.children().forEach(
child => child.selectAll('circle.dot')
.on('mousemove', null)
.on('mouseout', null)
);
})
然后我们可以添加一个处理程序,将鼠标处理程序放在 SVG 本身上
composite.on('postRender', chart => {
chart.svg().on('mousemove', () => { // 2
// find closest data point
const x = chart.x().invert(d3.mouse(chart.svg().node())[0] - chart.margins().left),
xs = chart.children()[0].group().all().map(kv => kv.key),
right = d3.bisectLeft(xs, x);
let closest = right;
if(right >= xs.length)
closest = right - 1;
else if(right > 0) {
// see if point to the left is closer
if(x - xs[right-1] < xs[right] - x)
closest = right - 1;
}
//console.log('closest', new Date(x), closest, xs[closest])
chart.children().forEach(child => { // 3
child.g().selectAll('circle.dot').each(function(d) {
if(d.x === xs[closest]) {
child._showDot(d3.select(this));
child.g().select('text.data-tip')
.attr('visibility', 'visible')
.attr('x', child.x()(d.x))
.attr('y', child.y()(d.y))
.text(tooltip_text(d.data))
} else
child._hideDot(d3.select(this));
});
})
})
chart.svg().on('mouseout', () => { // 4
chart.children().forEach(child => {
child.selectAll('circle.dot').each(function(d) {
child._hideDot(d3.select(this));
});
})
})
chart.children().forEach(child => child.g() // 1
.append('text')
.attr('class', 'data-tip')
.attr('fill', 'black')
.attr('alignment-baseline', 'top')
.attr('text-anchor', 'begin')
.attr('visibility', 'hidden')
)
});
我不打算深入细节,但是这个
- 向每个 child 图表添加一个文本元素,这将显示提示
- 侦听 mousemove 并找到最近的点
- 显示每个 child
中所选点的点和文本
- 当鼠标离开图表时隐藏所有点和文本
我 运行 没有时间考虑这个,所以我没有尝试让文本正确定位或使其看起来漂亮。
线性刻度
时间尺度
正如我在评论中提到的,如果线条靠得太近,您将 运行 遇到此设计的麻烦。你可以在这个例子的第一点看到这个问题。
我有一个复合折线图。
当我将鼠标悬停在图表的任何位置时,如何显示相应的值(日期和值),如下所示:
var composechart = dc.compositeChart("#test_composed");
composechart
.width(990)
.height(450)
.margins({ top: 50, right: 40, left: 50, bottom: 50 })
.x(d3.scaleTime().domain([new Date(2017, 0, 1), new Date(2019, 10, 30)]))
.rangeChart(xChart)
.elasticY(true)
.xUnits(d3.timeMonths)
.legend(dc.legend().x(80).y(20).itemHeight(13).gap(5))
.renderHorizontalGridLines(true)
.brushOn(false)
.compose([
dc.lineChart(composechart)
.dimension(salesgrafikDim)
.group(salesgrafikGroup,"Sales"),
dc.lineChart(composechart)
.dimension(satisgrafikDim)
.colors('red')
.group(quantitygrafikGroup,"Quantity")
])
xChart
.width(990)
.height(40)
.margins({top: 0, right: 50, bottom: 20, left: 50})
.dimension(salesgrafikDim)
.group(salesgrafikGroup)
.x(d3.scaleTime().domain([new Date(2017, 0, 1), new Date(2019, 10, 30)]))
.xUnits(d3.timeMonths);
xChart.yAxis().ticks(0);
基本上想要像下面的屏幕截图一样显示工具提示,其中鼠标不需要悬停在一个点上即可显示。
我可以直接使用 D3、svg 和 append 等等。但是我有其他图表和数据表的维度,所以我想将它与 dc.js.
一起使用如果您不必将鼠标悬停在圆点上即可看到提示,将会更加用户友好且易于理解。
我的图表如下:
由于 dc.js 不直接支持此功能,您将最终进入 D3 以实现此功能。
首先,我们需要禁用现有的标题:
.title(() => '')
和悬停事件:
composite.on('pretransition', chart => {
chart.children().forEach(
child => child.selectAll('circle.dot')
.on('mousemove', null)
.on('mouseout', null)
);
})
然后我们可以添加一个处理程序,将鼠标处理程序放在 SVG 本身上
composite.on('postRender', chart => {
chart.svg().on('mousemove', () => { // 2
// find closest data point
const x = chart.x().invert(d3.mouse(chart.svg().node())[0] - chart.margins().left),
xs = chart.children()[0].group().all().map(kv => kv.key),
right = d3.bisectLeft(xs, x);
let closest = right;
if(right >= xs.length)
closest = right - 1;
else if(right > 0) {
// see if point to the left is closer
if(x - xs[right-1] < xs[right] - x)
closest = right - 1;
}
//console.log('closest', new Date(x), closest, xs[closest])
chart.children().forEach(child => { // 3
child.g().selectAll('circle.dot').each(function(d) {
if(d.x === xs[closest]) {
child._showDot(d3.select(this));
child.g().select('text.data-tip')
.attr('visibility', 'visible')
.attr('x', child.x()(d.x))
.attr('y', child.y()(d.y))
.text(tooltip_text(d.data))
} else
child._hideDot(d3.select(this));
});
})
})
chart.svg().on('mouseout', () => { // 4
chart.children().forEach(child => {
child.selectAll('circle.dot').each(function(d) {
child._hideDot(d3.select(this));
});
})
})
chart.children().forEach(child => child.g() // 1
.append('text')
.attr('class', 'data-tip')
.attr('fill', 'black')
.attr('alignment-baseline', 'top')
.attr('text-anchor', 'begin')
.attr('visibility', 'hidden')
)
});
我不打算深入细节,但是这个
- 向每个 child 图表添加一个文本元素,这将显示提示
- 侦听 mousemove 并找到最近的点
- 显示每个 child 中所选点的点和文本
- 当鼠标离开图表时隐藏所有点和文本
我 运行 没有时间考虑这个,所以我没有尝试让文本正确定位或使其看起来漂亮。
线性刻度
时间尺度
正如我在评论中提到的,如果线条靠得太近,您将 运行 遇到此设计的麻烦。你可以在这个例子的第一点看到这个问题。