Merge branch 'master' of http://github.com/danvk/dygraphs
authorNeal Nelson <neal@makalumedia.com>
Mon, 31 Jan 2011 13:08:52 +0000 (14:08 +0100)
committerNeal Nelson <neal@makalumedia.com>
Mon, 31 Jan 2011 13:08:52 +0000 (14:08 +0100)
Conflicts:
dygraph.js

1  2 
dygraph.js

diff --combined dygraph.js
@@@ -195,10 -195,6 +195,10 @@@ Dygraph.prototype.__init__ = function(d
    this.is_initial_draw_ = true;
    this.annotations_ = [];
  
 +  // Zoomed indicators - These indicate when the graph has been zoomed and on what axis.
 +  this.zoomed_x_ = false;
 +  this.zoomed_y_ = false;
 +
    // Clear the div. This ensure that, if multiple dygraphs are passed the same
    // div, then only one will be drawn.
    div.innerHTML = "";
    this.start_();
  };
  
 +// axis is an optional parameter. Can be set to 'x' or 'y'.
 +Dygraph.prototype.isZoomed = function(axis) {
 +  if (axis == null) return this.zoomed_x_ || this.zoomed_y_;
 +  if (axis == 'x') return this.zoomed_x_;
 +  if (axis == 'y') return this.zoomed_y_;
 +  throw "axis parameter to Dygraph.isZoomed must be missing, 'x' or 'y'.";
 +};
 +
  Dygraph.prototype.attr_ = function(name, seriesName) {
    if (seriesName &&
        typeof(this.user_attrs_[seriesName]) != 'undefined' &&
@@@ -813,6 -801,8 +813,8 @@@ Dygraph.startPan = function(event, g, c
    context.isPanning = true;
    var xRange = g.xAxisRange();
    context.dateRange = xRange[1] - xRange[0];
+   context.initialLeftmostDate = xRange[0];
+   context.xUnitsPerPixel = context.dateRange / (g.plotter_.area.w - 1);
  
    // Record the range of each y-axis at the start of the drag.
    // If any axis has a valueRange or valueWindow, then we want a 2D pan.
    for (var i = 0; i < g.axes_.length; i++) {
      var axis = g.axes_[i];
      var yRange = g.yAxisRange(i);
+     // TODO(konigsberg): These values should be in |context|.
      axis.dragValueRange = yRange[1] - yRange[0];
-     var r = g.toDataCoords(null, context.dragStartY, i);
-     axis.draggingValue = r[1];
+     axis.initialTopValue = yRange[1];
+     axis.unitsPerPixel = axis.dragValueRange / (g.plotter_.area.h - 1);
      if (axis.valueWindow || axis.valueRange) context.is2DPan = true;
    }
-   // TODO(konigsberg): Switch from all this math to toDataCoords?
-   // Seems to work for the dragging value.
-   context.draggingDate = (context.dragStartX / g.width_) * context.dateRange + xRange[0];
  };
  
  // Called in response to an interaction model operation that
@@@ -842,24 -829,18 +841,18 @@@ Dygraph.movePan = function(event, g, co
    context.dragEndX = g.dragGetX_(event, context);
    context.dragEndY = g.dragGetY_(event, context);
  
-   // TODO(danvk): update this comment
-   // Want to have it so that:
-   // 1. draggingDate appears at dragEndX, draggingValue appears at dragEndY.
-   // 2. daterange = (dateWindow_[1] - dateWindow_[0]) is unaltered.
-   // 3. draggingValue appears at dragEndY.
-   // 4. valueRange is unaltered.
-   var minDate = context.draggingDate - (context.dragEndX / g.width_) * context.dateRange;
+   var minDate = context.initialLeftmostDate -
+     (context.dragEndX - context.dragStartX) * context.xUnitsPerPixel;
    var maxDate = minDate + context.dateRange;
    g.dateWindow_ = [minDate, maxDate];
  
    // y-axis scaling is automatic unless this is a full 2D pan.
    if (context.is2DPan) {
      // Adjust each axis appropriately.
-     var y_frac = context.dragEndY / g.height_;
      for (var i = 0; i < g.axes_.length; i++) {
        var axis = g.axes_[i];
-       var maxValue = axis.draggingValue + y_frac * axis.dragValueRange;
+       var maxValue = axis.initialTopValue +
+         (context.dragEndY - context.dragStartY) * axis.unitsPerPixel;
        var minValue = maxValue - axis.dragValueRange;
        axis.valueWindow = [ minValue, maxValue ];
      }
  // panning behavior.
  //
  Dygraph.endPan = function(event, g, context) {
+   // TODO(konigsberg): Clear the context data from the axis.
+   // TODO(konigsberg): mouseup should just delete the
+   // context object, and mousedown should create a new one.
    context.isPanning = false;
    context.is2DPan = false;
-   context.draggingDate = null;
+   context.initialLeftmostDate = null;
    context.dateRange = null;
    context.valueRange = null;
  }
@@@ -1054,12 -1038,12 +1050,12 @@@ Dygraph.prototype.createDragInterface_ 
      prevEndY: null,
      prevDragDirection: null,
  
-     // TODO(danvk): update this comment
-     // draggingDate and draggingValue represent the [date,value] point on the
-     // graph at which the mouse was pressed. As the mouse moves while panning,
-     // the viewport must pan so that the mouse position points to
-     // [draggingDate, draggingValue]
-     draggingDate: null,
+     // The value on the left side of the graph when a pan operation starts.
+     initialLeftmostDate: null,
+     // The number of units each pixel spans. (This won't be valid for log
+     // scales)
+     xUnitsPerPixel: null,
  
      // TODO(danvk): update this comment
      // The range in second/value units that the viewport encompasses during a
@@@ -1208,7 -1192,6 +1204,7 @@@ Dygraph.prototype.doZoomX_ = function(l
   */
  Dygraph.prototype.doZoomXDates_ = function(minDate, maxDate) {
    this.dateWindow_ = [minDate, maxDate];
 +  this.zoomed_x_ = true;
    this.drawGraph_();
    if (this.attr_("zoomCallback")) {
      this.attr_("zoomCallback")(minDate, maxDate, this.yAxisRanges());
@@@ -1236,11 -1219,9 +1232,11 @@@ Dygraph.prototype.doZoomY_ = function(l
      valueRanges.push([low[1], hi[1]]);
    }
  
 +  this.zoomed_y_ = true;
    this.drawGraph_();
    if (this.attr_("zoomCallback")) {
      var xRange = this.xAxisRange();
 +    var yRange = this.yAxisRange();
      this.attr_("zoomCallback")(xRange[0], xRange[1], this.yAxisRanges());
    }
  };
@@@ -1268,8 -1249,6 +1264,8 @@@ Dygraph.prototype.doUnzoom_ = function(
    if (dirty) {
      // Putting the drawing operation before the callback because it resets
      // yAxisRange.
 +    this.zoomed_x_ = false;
 +    this.zoomed_y_ = false;
      this.drawGraph_();
      if (this.attr_("zoomCallback")) {
        var minDate = this.rawData_[0][0];
@@@ -2104,22 -2083,18 +2100,22 @@@ Dygraph.prototype.drawGraph_ = function
      this.layout_.addDataset(this.attr_("labels")[i], datasets[i]);
    }
  
 -  // TODO(danvk): this method doesn't need to return anything.
 -  var out = this.computeYAxisRanges_(extremes);
 -  var axes = out[0];
 -  var seriesToAxisMap = out[1];
 -  this.layout_.updateOptions( { yAxes: axes,
 -                                seriesToAxisMap: seriesToAxisMap
 -                              } );
 -
 +  if (datasets.length > 0) {
 +    // TODO(danvk): this method doesn't need to return anything.
 +    var out = this.computeYAxisRanges_(extremes);
 +    var axes = out[0];
 +    var seriesToAxisMap = out[1];
 +    this.layout_.updateOptions( { yAxes: axes,
 +                                  seriesToAxisMap: seriesToAxisMap
 +                                } );
 +  }
    this.addXTicks_();
  
 +  // Save the X axis zoomed status as the updateOptions call will tend to set it errorneously
 +  var tmp_zoomed_x = this.zoomed_x_;
    // Tell PlotKit to use this new data and render itself
    this.layout_.updateOptions({dateWindow: this.dateWindow_});
 +  this.zoomed_x_ = tmp_zoomed_x;
    this.layout_.evaluateWithError();
    this.plotter_.clear();
    this.plotter_.render();
   *   indices are into the axes_ array.
   */
  Dygraph.prototype.computeYAxes_ = function() {
-   this.axes_ = [{}];  // always have at least one y-axis.
 +  var valueWindows;
 +  if (this.axes_ != undefined) {
 +    // Preserve valueWindow settings.
 +    valueWindows = [];
 +    for (var index = 0; index < this.axes_.length; index++) {
 +      valueWindows.push(this.axes_[index].valueWindow);
 +    }
 +  }
 +
+   this.axes_ = [{ yAxisId: 0 }];  // always have at least one y-axis.
    this.seriesToAxisMap_ = {};
  
    // Get a list of series names.
        var opts = {};
        Dygraph.update(opts, this.axes_[0]);
        Dygraph.update(opts, { valueRange: null });  // shouldn't inherit this.
+       var yAxisId = this.axes_.length;
+       opts.yAxisId = yAxisId;
        Dygraph.update(opts, axis);
        this.axes_.push(opts);
-       this.seriesToAxisMap_[seriesName] = this.axes_.length - 1;
+       this.seriesToAxisMap_[seriesName] = yAxisId;
      }
    }
  
      if (vis[i - 1]) seriesToAxisFiltered[s] = this.seriesToAxisMap_[s];
    }
    this.seriesToAxisMap_ = seriesToAxisFiltered;
 +
 +  if (valueWindows != undefined) {
 +    // Restore valueWindow settings.
 +    for (var index = 0; index < valueWindows.length; index++) {
 +      this.axes_[index].valueWindow = valueWindows[index];
 +    }
 +  }
  };
  
  /**
@@@ -2925,12 -2886,6 +2923,12 @@@ Dygraph.prototype.updateOptions = funct
    }
    if ('dateWindow' in attrs) {
      this.dateWindow_ = attrs.dateWindow;
 +    if (!('noZoomFlagChange' in attrs)) {
 +      this.zoomed_x_ = attrs.dateWindow != null;
 +    }
 +  }
 +  if ('valueRange' in attrs && !('noZoomFlagChange' in attrs)) {
 +    this.zoomed_y_ = attrs.valueRange != null;
    }
  
    // TODO(danvk): validate per-series options.