当鼠标在折线图上的任意位置时显示提示 [英] display tip when mouse is anywhere over line chart

查看:70
本文介绍了当鼠标在折线图上的任意位置时显示提示的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个综合折线图.

当我将鼠标悬停在图表的任何位置时,如何显示相应的值(日期和值):

  var composechart = dc.compositeChart(#test_composed");组成图.width(990).height(450).margins({top:50,right:40,left:50,bottom:50}).x(d3.scaleTime().domain([新日期(2017,0,1),新日期(2019,10,30)])).rangeChart(xChart).elasticY(true).xUnits(d3.timeMonths).legend(dc.legend().x(80).y(20).itemHeight(13).gap(5)).renderHorizo​​ntalGridLines(true).brushOn(假).撰写([dc.lineChart(composechart).dimension(salesgrafikDim).group(salesgrafikGroup,销售"),dc.lineChart(composechart).dimension(satisgrafikDim).colors('红色').group(quantitygrafikGroup,数量")])图表.width(990).height(40).margins({top:0,right:50,bottom:20,left:50}).dimension(salesgrafikDim).group(salesgrafikGroup).x(d3.scaleTime().domain([新日期(2017,0,1),新日期(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.selectAll('circle.dot').on('mousemove',null).on('mouseout',null));}) 

然后我们可以添加一个处理程序,将鼠标处理程序放置在SVG本身上

  composite.on('postRender',chart => {chart.svg().on('mousemove',()=> {//2//查找最近的数据点const x = chart.x().invert(d3.mouse(chart.svg().node())[0]-chart.margins().left),xs = chart.children()[0] .group().all().map(kv => kv.key),右= d3.bisectLeft(xs,x);让最接近=正确;if(正确> = xs.length)最接近=右-1;否则if(right> 0){//查看左侧的点是否更近if(x-xs [right-1]< xs [right]-x)最接近=右-1;}//console.log('closest',new Date(x),最接近的xs [closest])chart.children().forEach(child => {//3child.g().selectAll('circle.dot').each(function(d){if(d.x === xs [closest]){child._showDot(d3.select(this));child.g().select('text.data-tip').attr('可见性','可见').attr('x',child.x()(d.x)).attr('y',child.y()(d.y)).text(tooltip_text(d.data))} 别的child._hideDot(d3.select(this));});})})chart.svg().on('mouseout',()=> {//4chart.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('填充','黑色').attr('alignment-baseline','top').attr('text-anchor','begin').attr('可见性','隐藏'))}); 

我不会详细介绍,但这

  1. 在每个子图表中添加一个文本元素,该文本元素将显示提示
  2. 侦听鼠标移动并找到最近的点
  3. 显示每个孩子中所选点的点和文本
  4. 当鼠标离开图表时隐藏所有点和文本

我没有时间考虑这个问题,所以我没有尝试正确放置文本或使文本看起来不错.

线性比例

时间刻度小提琴.

正如我在评论中提到的那样,如果线条之间的距离太近,您将在设计中遇到麻烦.您可以在此示例的第一点看到此问题.

I have a composite line chart.

How can I display the respective values (date and value) when i hover on any place of the chart like below:

                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);

Basically want to display a tooltip like in the screenshot below, where the mouse should not need to be over a dot for it to display.

I can do it with straight D3, with svg and append and so on. But i have dimension with other charts and dataTable, so I want to use this with dc.js.

It would be much more user friendly and easy to understand if you don't have to hover over the dots to see the tip.

My chart is below :

解决方案

Since dc.js doesn't support this directly, you're going to end up dropping down into D3 in order to implement this.

First, we need to disable the existing titles:

.title(() => '')

and hover events:

composite.on('pretransition', chart => {
  chart.children().forEach(
    child => child.selectAll('circle.dot')
      .on('mousemove', null)
      .on('mouseout', null)
    );
})

Then we can add a handler to put mouse handlers on the SVG itself

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')
    )
});  

I'm not going to get into the details, but this

  1. adds a text element to each child chart, which will display the tip
  2. listens for mousemove and finds the nearest point
  3. shows the dots and text for the selected point in each child
  4. hides all dots and text when the mouse leaves the chart

I ran out of time to think about this, so I didn't try to get the text positioned correctly or make it look nice.

linear scale

Linear scale fiddle.

time scale

Time scale fiddle.

As I mentioned in the comments, you're going to run into trouble with this design, if the lines get too close together. You can see this problem with the first point in this example.

这篇关于当鼠标在折线图上的任意位置时显示提示的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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