常规更新模式D3-重绘未更改的节点

时间:2019-03-04 15:57:37

标签: javascript d3.js

我正在根据时间序列数据制作d3图表。我想根据用户实时指定的时间窗口绘制移动平均值。 所有行将共享相同的数据集。 我正在实现常规更新模式(我相信),但是,当我更改数据集时,除非显式调用更新函数,否则不会发生更新。但是,这可以为数组中的每个元素创建一个节点(在旧元素之上创建一个新的DOM元素),而不是仅添加更新的元素。我觉得我对D3或javascript本身有一些根本性的误解。这是我的代码的最小工作示例:

简而言之,我的图表具有setInterval方法,该方法可添加到数据集中并更新图表上的所有折线。每行共享图表数据,但是将以不同的方式转换数据。

window.onload = function() {
  let mychart = chart( '#chart' );
  let props1 = {
    'className': 'line-1',
    'Color': 'red',
    'y': function( d ) { return d + 25; }
  }

  let line1 = line( mychart, props1 );

  mychart.addPlot( line1 );
  mychart.stream();
}

//need to find best way to share data across all indicators 
var chart = function(svg_id) {
  let data = [ 0, 1, 2, 3, 4, 5];
  let plots = [];
  let svg = ( function(  ) {
    return d3.select( svg_id + '-container' ).append( 'svg' )
      .attr( 'height', 500 )
      .attr( 'width', 1000 )
      .attr( 'id', svg_id.replace('#', '' ))
  })();

  let xscale = d3.scaleLinear()
                  .domain( [0, 100] )
                  .range( [10, 990] )

  let addPlot = function( plot ) {
    plots.push( plot );
  }

  let stream = function() {
    setInterval( function() {
      data.push( Math.random(0, 1) * 100);
      for( var i = 0; i < plots.length; i++ ) {
        plots[i].update();
      }
    }, 1000);
  }
  return {
    'svg': svg,
    'xscale': xscale,
    'data': data,
    'addPlot': addPlot,
    'stream': stream,
  }

}

var line = function( chart, props ) {
  let data = chart.data;
  let xscale = chart.xscale;
  let svg = chart.svg;

  let buildLine = d3.line()
    .x( function(d, i ) { return xscale( i ) + i*1; })
    .y( function(d) { return props.y( d ); })

  let update = function() {
    let line = svg.selectAll( props.className ).data( data );

    line.enter()
      .append( 'path' )
      .attr( 'stroke', props.Color )
      .attr( 'stroke-width', 2 )
      .attr( 'class', props.className )
      .attr( 'fill', 'none' )
      .merge( line )
        .attr( 'd', buildLine( data ))

    line.exit().remove();
  }


  return {
    'update': update,
  }
}

我在网上发现了很多关于没有添加节点的信息,但是关于每次迭代都重新绘制d3以及每次迭代都添加节点的事情却一无所获。谢谢。

2 个答案:

答案 0 :(得分:0)

我不确定,但是也许您可以看一下:Key functions

作为.data( data )的第二个参数,您可以提供一个唯一标识数据点的函数。像.data( data, function(d) { return d.someUniqueId; })

D3可以使用此密钥来更新DOM元素,而不必重新生成它们,据我所知from Mike Bostock's post

答案 1 :(得分:0)

我在d3路径https://www.dashingd3js.com/svg-paths-and-d3js上使用本教程解决了此问题。关键是selectAll不适用于路径,因为一行仅是一个“路径”元素,因此仅需添加。我正在使用jquery删除该行,因此仍然有点hacky,因为我确定D3可以做到这一点。但是这里有一个更新的初始化和更新功能。

  let init = function() {
    svg.append( 'path' )
      .attr( 'd', buildLine( data ))
      .attr( 'stroke', props.Color )
      .attr( 'stroke-width', 2 )
      .attr( 'class', props.className )
      .attr( 'fill', 'none' )

  }



  let update = function( newdata ) {
    data.push( newdata );
    $( '.' + props.className ).remove();
    init();