【问题标题】:D3 hover chart - thousands of x entries - mouse sensitivityD3 悬停图表 - 数千个 x 条目 - 鼠标灵敏度
【发布时间】:2014-09-16 15:27:45
【问题描述】:

我使用 D3 创建了以下图表:
(来源:envhealthatlas.co.uk

这是为了可视化 3 个变量按升序排列的分布,并识别小于和大于 1 的值。

垂直条同步 3 个图表,并在鼠标悬停时相应移动。下面代码中的 mousemove 函数获取特定鼠标坐标对应的 x 值,然后从查找中我可以获得标识符,它允许我将条形移动与所有 3 个图表同步。

 var xS = d3.scale.linear()
  .range( [ 0, this.width ] )//width 400
  .domain( [1,  options.data.length]); 

var yS = d3.scale.linear()
  .range( [ this.height, 0 ] )
  .domain( [ 0, this.maxDataPoint ] );


var linename =  this.name + "_line";


this.area = d3.svg.area()
  //.interpolate( "monotone" )
  .x( function( d ) {
    return xS( +d[xOrder] );
  } )
  .y0( function( d ) {
    if ( d[ localName ] < 1 ) {
      return yS( d[ localName ] );
    } else {
      return yS( 1 )
    }

  } )
  .y1( function( d ) {
    if ( d[ localName ] < 1 ) {
      return yS( 1 );
    } else {
      return yS( d[ localName ] )
    }
  } );


this.chartContainer = svg.append( "g" )
  .attr( 'class', this.name.toLowerCase() )
  .attr( "transform", "translate(" + this.margin.left + "," + ( this.margin.top + ( this.height * this.id ) + ( 10 * this.id ) ) + ")" );

/* We've created everything, let's actually add it to the page */
this.chartContainer.append( "path" )
  .data( [ options.data ] )
  .attr( "class", "chart unadj " + this.name.toLowerCase() )
  .attr( "clip-path", "url(#clip-" + this.id + ")" )
  .attr( "d", this.area );


var mousemove = function( d ) {

    var xValue = Math.round(xS.invert(d3.mouse(this)[0])) ,
        gid = null;

    var update = function( xVal , txt, set ){
        lines[set]
          .attr("transform","translate(" + xS(xVal) + "," + 0 + ")");
        texts[set]
          .text( txt );
    };

    if( typeof dataSets[localName][xValue] !== 'undefined'){
        gid =  dataSets[localName][xValue]["gid"];// Sync with other area charts
    };      

    for (var set in dataSets){ 
        var dataLength = dataSets[set].length ;
        while(dataLength--){
            if(dataSets[set][dataLength]["gid"] === gid){
                var xVal =  +dataSets[set][dataLength][xOrder],// xOrder is an auto increment field used for sync purpose and for the xs linear scale
                    yVal = dataSets[set][dataLength][set];
                update(xVal, yVal, set);  
            };      
        };
    };  
};

this.chartContainer.append( "rect" )
    .attr( "class", "overlayHover" )
    .attr( "width", width)
    .attr( "height", chartHeight )
    .on( "mousemove", mousemove );

/* Highlighter */
lines[localName] = this.chartContainer.append("line")
    .attr("class", "lineHover")
    .attr("x1", 0)
    .attr("y1", 0)
    .attr("x2", 0)
    .attr("y2", chartHeight)
    .attr("height", 2 )
    .attr("height", chartHeight )
    .attr("id", linename );


this.yAxis = d3.svg.axis().scale( yS ).orient( "left" ).tickValues( [ 0, 1, this.maxDataPoint ]);

this.chartContainer.append( "g" )
  .attr( "class", "y axis" )
  .attr( "transform", "translate(0,0)" )
  .call( this.yAxis );

this.chartContainer.append( "text" )
  .attr( "class", "country-title" )
  .attr( "transform", "translate(10,20)" )
  .text( this.name  );

texts[localName] = this.chartContainer.append( "text" )
  .attr( "class","areaValue")
  .attr ( "id", localName + "_text"  )
  .attr( "transform", "translate(10,32)" )
  .text("0.00");    

};

问题: 图表似乎表现良好,但是通过使用包含几千条记录的当前数据集,我意识到某些值从未显示。例如,如果我将鼠标悬停在图表的最左侧或最右侧(最低或最高),我无法让鼠标坐标变为 0.00 和 400(图表宽度),因此无法获得数据集的极端值。

可用宽度和 x 条目数是否存在问题?

数据如下我有大约9000条记录:

gid,rr_unadj,x_order
948,0.751,1
947,0.751,2
6728,0.762,3
950,0.768,4

任何帮助表示赞赏, 谢谢!

【问题讨论】:

  • 听起来像 0 和 400 点,因为离边缘太近了,基本上落在用于捕获 mousemove 事件的矩形之外和/或完全在 SVG 之外。如果是这样,您需要使矩形稍微宽一些,以便它可以捕获 400 的 x 坐标(然后将 Math.min/Math.max 值保持在 0 到 400 之间)。而且,由于 SVG 边界会剪裁矩形,因此您还需要增加 SVG 的宽度以在其周围引入一些填充。
  • 最大的问题是可用的宽度有限。如果我的 X 是 400px 宽,但我有 8800 个条目,并且执行鼠标悬停效果的线当时只能移动 1px 如果 xS.invert(mouseX) 只能有 400 个唯一的 mouseX 坐标,它如何在整个数据集中移动价值观

标签: javascript d3.js charts


【解决方案1】:

没错,这主要是鼠标分辨率的问题。但即使使用无限灵敏的鼠标,您也不会期望人类用户能够如此精确地控制鼠标。使用我的鼠标,在屏幕上移动 400 像素等于在鼠标垫上移动约 7 厘米(= 70 毫米)。使用 8800 个点,每毫米大约有 125 个数据点。太多了。所以你必须想出另一种与图表交互的方式,这将涉及更多的工作。

我能想到的最简单的选择是在文档而不是矩形上监听 mousemove 事件:

d3.select(document) // Maybe "body" is better than document
  ...
  .on("mousemove", mousemove)

然后您将在整个窗口中获得鼠标值。然后你需要将xS 的范围定义为

xS.range([0, window.innerWidth])

这样,根据浏览器窗口的大小,您可以获得高达 4 倍的分辨率。显然,鼠标位置与图表上突出显示的位置不对应,但这不一定是问题。 的一个问题是,如果有 8800 条记录,鼠标分辨率仍然不足以满足您要求的精度。 (注意:我刚刚意识到,使用此方案,您还需要考虑鼠标 y 位置,确定哪个图表与其垂直对齐。)

另一种方法是使用箭头键或鼠标滚轮从一条记录移动到紧随其后或之前的一条记录。在这种情况下,您首先读取鼠标位置,就像您当前所做的一样,以查找它产生的任何记录。但是,只要鼠标保持不动,用户就可以使用滚轮或按键优化该位置。您的 gid 查找将如下所示:

gid =  dataSets[localName][xValue + refinement]

refinement 将被初始化为 0,但每次按下向上或向下时,您将其递增/递减 1。

【讨论】:

  • 伟大的建议和cmets!非常感谢。
  • 我会试试方向键的方法!
【解决方案2】:

根据建议,我已经实现了允许通过 X 轴上的每个条目的键盘方法,代码可以在这里找到: https://github.com/smallAreaHealthStatisticsUnit/rapidInquiryFacility/blob/master/rifWebPlatform/web/js/v2/components/chart/units/d3renderers/multipleAreaCharts.d3renderer.js

效果很好。

集成在以下疾病绘图平台中:
(来源:envhealthatlas.co.uk

【讨论】:

  • 再次感谢 meetamit 的尖锐建议(见下文)!
猜你喜欢
  • 1970-01-01
  • 2015-02-20
  • 2015-04-22
  • 1970-01-01
  • 2018-01-23
  • 2011-01-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多