mardi 18 août 2015

D3 graph not updating range and domain on zoom for dynamic data

Graph works fine for first set of data. Plotting and zooming is good. When we change the data set, the graph will be re-plotted correctly. But on zooming, the scales still remain the same(so high), that the plotted line will turn out to be really small.

I guess it's the problem with setting the domain and range.

Also the init graph method is called only once - which is responsible for the domain and range update.

Below is my code,

App.ReportsGraphView = Ember.View.extend( {

  //... global Variables...

  didInsertElement: function () {
    this.initGraph();
  },

  initGraph: function () {
    var self = this,
      title = this.get( 'title' ),
      element = this.$().get( 0 ),
      graph = {
        margin: {
          top: 40,
          right: 80,
          bottom: 50,
          left: 50
        },

    bisectDate: d3.bisector( function ( d ) {
      return d[ self.get( 'xField' ) ];
    } ).left
  };

    graph.width = this.$().width() - graph.margin.left - graph.margin.right;
    graph.height = 400 - graph.margin.top - graph.margin.bottom;

    graph.x = d3.time.scale()
      .domain(d3.extent(self.get( 'dataSource' ), function(d) { return d[ self.get( 'xField' ) ]; }))
      .range( [0, graph.width] );


    graph.y = d3.scale.linear()
      .domain(d3.extent(self.get( 'dataSource' ), function(d) { return d[ self.get( 'yField' ) ]; }))
      .range( [graph.height, 0] );

   graph.xAxis = d3.svg.axis()
    .scale( graph.x )
    .tickSize(-graph.height, 0)
    .tickPadding(10)    
    .tickSubdivide(true)    
    .orient( 'bottom' );

  graph.yAxis = d3.svg.axis()
    .scale( graph.y )
    .ticks( 4 )
    .tickSize( -graph.width )
    .tickPadding(10)
    .tickSubdivide(true)
    .orient( 'left' );

  graph.line = d3.svg.line()
    .interpolate("linear")
    .x( function ( d ) {
      return graph.x( d[ self.get( 'xField' ) ] );
    } )
    .y( function ( d ) {
      return graph.y( d[ self.get( 'yField' ) ] );
    } );

var zoom = d3.behavior.zoom()
    .x(graph.x)
    .y(graph.y)
    .on("zoom", zoomed);

    var self = this;


    function zoomed() {
        //debugger;
        graph.node.select("g.x.axis").transition().call(graph.xAxis);
        graph.node.select("g.y.axis").transition().call(graph.yAxis);
        graph.node.select('path.line')
                .attr("d", graph.line(self.get( 'dataSource' )))
                .attr("clip-path", "url(#clip)");
    }

graph.node = d3.select( element ).append( 'svg' )
  .attr( 'width', graph.width + graph.margin.left + graph.margin.right )
  .attr( 'height', graph.height + graph.margin.top + graph.margin.bottom )
  .append( 'g' )
  .attr( 'transform', 'translate(' + graph.margin.left + ',' + graph.margin.top + ')' )
  .classed( 'empty', true )
  .call(zoom);


graph.node.append( 'g' )
  .attr( 'class', 'x axis' )
  .attr( 'transform', 'translate(0,' + graph.height + ')' )
  .call( graph.xAxis );

graph.node.append( 'g' )
  .attr( 'class', 'y axis' )
  .call( graph.yAxis );

graph.title = graph.node.append( 'text' )
  .attr( 'class', 'graph-title' )
  .attr( 'x', graph.width / 2 )
  .attr( 'y', graph.height + 40 )
  .style( 'text-anchor', 'middle' )
  .text( title );

graph.focus = graph.node.append( 'g' )
  .attr( 'class', 'focus' )
  .style( 'display', 'none' );


graph.overlay = graph.node.append( "rect" )
  .attr( 'class', 'overlay' )
  .attr( 'width', graph.width )
  .attr( 'height', graph.height )
  .style( 'display', 'none' )
  .on( 'mouseover', function () {
    graph.focus.style( 'display', null );
  } )
  .on( 'mouseout', function () {
    var node = graph.overlay.node(),
      pos = d3.mouse( node ),
      nodeSize = node.getBBox();
    if ( pos[0] < 0 || pos[0] > nodeSize.width || pos[1] < 0 || pos[1] > nodeSize.height ) {
      graph.focus.style( 'display', 'none' );          
    }
  } )
  .on( 'mousemove', function () {

        var x0 = graph.x.invert( d3.mouse( this )[ 0 ] ),
          i = graph.bisectDate( graph.data, x0, 1 ),
          d0 = graph.data[ i - 1 ],
          d1 = graph.data[ i ],
          xField = self.get( 'xField' ),
          yField = self.get( 'yField' );

          if(d0 && d1){
          var d = x0 - d0[ xField ] > d1[ xField ] - x0 ? d1 : d0;

            graph.focus.attr( 'transform', 'translate(' + graph.x( d[ xField ] ) + ',' + graph.y( d[ yField ] ) + ')' );
          }  
  } );

this.set( '_graph', graph );
this.drawGraph( this.get( 'dataSource' ) );


},


drawGraph: function ( data ) {
    var graph = this.get( '_graph' ),
      xField = this.get( 'xField' ),
      yField = this.get( 'yField' ),
      title = this.get( 'title' );

if ( !this.get( 'canDrawGraph' ) ) {
  graph.node
    .classed( 'empty', true )
    .select( '.line' )
    .remove();

  graph.overlay.style( 'display', 'none' );

  this.drawEmptyAxes();
}
else {
  graph.node.classed( 'empty', false );

  if (this.get( 'from' ) && this.get( 'to' )) {
    graph.x.domain([this.get( 'from' ), this.get( 'to' )]);
  }
  else {
    graph.x.domain( d3.extent( data, function ( d ) {
      return d[ xField ];
    } ) );
  }
  graph.y.domain( [ 0, d3.max( data, function ( d ) {
    return d[ yField ];
  } ) ] );

  graph.node.select( '.x.axis' )
    .call( graph.xAxis );

  graph.node.select( '.y.axis' )
    .call( graph.yAxis );

  var line = graph.node.select( '.line' );

  if ( line.empty() ) {
    line = graph.node.append( 'path' )
      .attr( 'class', 'line' )
      .attr( 'color', '#000' );
  }

  line.attr( 'd', graph.line( data ) );

  graph.overlay.style( 'display', null );
}

graph.data = data;



  this.set( '_graph', graph );
  },

  drawEmptyAxes: function() {
    var graph = this.get( '_graph' );

graph.x.domain( [ moment().toDate(), moment().subtract( 'days', 1 ).toDate() ] );
graph.y.domain( [0, 1] );

graph.node.select( '.x.axis' )
  .call( graph.xAxis );

graph.node.select( '.y.axis' )
  .call( graph.yAxis );

this.set( '_graph', graph );


},

  canDrawGraph: function () {
    return !Ember.isEmpty( this.get( 'dataSource' ) ) && !Ember.isEmpty( this.get( 'xField' ) ) && !Ember.isEmpty( this.get( 'yField' ) );
  }.property( 'xField', 'yField', 'dataSource' ),

  didDataSourceChanged: function () {
this.drawGraph( this.get( 'dataSource' ) );


}.observes( 'dataSource' ),

  didAxesChanged: function () {
    this.drawGraph( this.get( 'dataSource' ) );
  }.observes( 'xField', 'yField' ),

  didTitleChanged: function () {

    var graph = this.get( '_graph' );
    var title = this.get( 'title' );
    var yField = this.get( 'yField' );
    var xField = this.get( 'xField' );

    graph.title.text( title );
  }.observes( 'title' ),

  actions: {
    onChoice: function ( checked ) {
      this.toggleProperty( 'isHidden' );
    }
  }

} );




Aucun commentaire:

Enregistrer un commentaire