Merge branch 'master' of http://github.com/adam-p/dygraphs
authorDan Vanderkam <danvdk@gmail.com>
Mon, 4 Oct 2010 14:16:31 +0000 (10:16 -0400)
committerDan Vanderkam <danvdk@gmail.com>
Mon, 4 Oct 2010 14:16:31 +0000 (10:16 -0400)
1  2 
dygraph-canvas.js
dygraph.js

diff --combined dygraph-canvas.js
@@@ -202,6 -202,35 +202,35 @@@ DygraphLayout.prototype.updateOptions 
    Dygraph.update(this.options, new_options ? new_options : {});
  };
  
+ /**
+  * Return a copy of the point at the indicated index, with its yval unstacked.
+  * @param int index of point in layout_.points
+  */
+ DygraphLayout.prototype.unstackPointAtIndex = function(idx) {
+   var point = this.points[idx];
+   
+   // Clone the point since we modify it
+   var unstackedPoint = {};  
+   for (var i in point) {
+     unstackedPoint[i] = point[i];
+   }
+   
+   if (!this.attr_("stackedGraph")) {
+     return unstackedPoint;
+   }
+   
+   // The unstacked yval is equal to the current yval minus the yval of the 
+   // next point at the same xval.
+   for (var i = idx+1; i < this.points.length; i++) {
+     if (this.points[i].xval == point.xval) {
+       unstackedPoint.yval -= this.points[i].yval; 
+       break;
+     }
+   }
+   
+   return unstackedPoint;
+ }  
  // Subclass PlotKit.CanvasRenderer to add:
  // 1. X/Y grid overlay
  // 2. Ability to draw error bars (if required)
@@@ -755,14 -784,13 +784,14 @@@ DygraphCanvasRenderer.prototype._render
    for (var i = 0; i < setCount; i++) {
      var setName = setNames[i];
      var color = this.colors[setName];
 +    var strokeWidth = this.dygraph_.attr_("strokeWidth", setName);
  
      // setup graphics context
      context.save();
      var point = this.layout.points[0];
 -    var pointSize = this.dygraph_.attr_("pointSize");
 +    var pointSize = this.dygraph_.attr_("pointSize", setName);
      var prevX = null, prevY = null;
 -    var drawPoints = this.dygraph_.attr_("drawPoints");
 +    var drawPoints = this.dygraph_.attr_("drawPoints", setName);
      var points = this.layout.points;
      for (var j = 0; j < points.length; j++) {
        var point = points[j];
              prevX = point.canvasx;
              prevY = point.canvasy;
            } else {
 -            ctx.beginPath();
 -            ctx.strokeStyle = color;
 -            ctx.lineWidth = this.options.strokeWidth;
 -            ctx.moveTo(prevX, prevY);
 -            if (stepPlot) {
 -              ctx.lineTo(point.canvasx, prevY);
 +            // TODO(danvk): figure out why this conditional is necessary.
 +            if (strokeWidth) {
 +              ctx.beginPath();
 +              ctx.strokeStyle = color;
 +              ctx.lineWidth = strokeWidth;
 +              ctx.moveTo(prevX, prevY);
 +              if (stepPlot) {
 +                ctx.lineTo(point.canvasx, prevY);
 +              }
 +              prevX = point.canvasx;
 +              prevY = point.canvasy;
 +              ctx.lineTo(prevX, prevY);
 +              ctx.stroke();
              }
 -            prevX = point.canvasx;
 -            prevY = point.canvasy;
 -            ctx.lineTo(prevX, prevY);
 -            ctx.stroke();
            }
  
            if (drawPoints || isIsolated) {
diff --combined dygraph.js
@@@ -240,13 -240,8 +240,13 @@@ Dygraph.prototype.__init__ = function(d
    this.start_();
  };
  
 -Dygraph.prototype.attr_ = function(name) {
 -  if (typeof(this.user_attrs_[name]) != 'undefined') {
 +Dygraph.prototype.attr_ = function(name, seriesName) {
 +  if (seriesName &&
 +      typeof(this.user_attrs_[seriesName]) != 'undefined' &&
 +      this.user_attrs_[seriesName] != null &&
 +      typeof(this.user_attrs_[seriesName][name]) != 'undefined') {
 +    return this.user_attrs_[seriesName][name];
 +  } else if (typeof(this.user_attrs_[name]) != 'undefined') {
      return this.user_attrs_[name];
    } else if (typeof(this.attrs_[name]) != 'undefined') {
      return this.attrs_[name];
@@@ -1022,18 -1017,11 +1022,18 @@@ Dygraph.prototype.mouseMove_ = function
   */
  Dygraph.prototype.updateSelection_ = function() {
    // Clear the previously drawn vertical, if there is one
 -  var circleSize = this.attr_('highlightCircleSize');
    var ctx = this.canvas_.getContext("2d");
    if (this.previousVerticalX_ >= 0) {
 +    // Determine the maximum highlight circle size.
 +    var maxCircleSize = 0;
 +    var labels = this.attr_('labels');
 +    for (var i = 1; i < labels.length; i++) {
 +      var r = this.attr_('highlightCircleSize', labels[i]);
 +      if (r > maxCircleSize) maxCircleSize = r;
 +    }
      var px = this.previousVerticalX_;
 -    ctx.clearRect(px - circleSize - 1, 0, 2 * circleSize + 2, this.height_);
 +    ctx.clearRect(px - maxCircleSize - 1, 0,
 +                  2 * maxCircleSize + 2, this.height_);
    }
  
    var isOK = function(x) { return x && !isNaN(x); };
      ctx.save();
      for (var i = 0; i < this.selPoints_.length; i++) {
        if (!isOK(this.selPoints_[i].canvasy)) continue;
 +      var circleSize =
 +        this.attr_('highlightCircleSize', this.selPoints_[i].name);
        ctx.beginPath();
        ctx.fillStyle = this.plotter_.colors[this.selPoints_[i].name];
        ctx.arc(canvasx, this.selPoints_[i].canvasy, circleSize,
@@@ -1101,7 -1087,13 +1101,13 @@@ Dygraph.prototype.setSelection = functi
    if (row !== false && row >= 0) {
      for (var i in this.layout_.datasets) {
        if (row < this.layout_.datasets[i].length) {
-         this.selPoints_.push(this.layout_.points[pos+row]);
+         var point = this.layout_.points[pos+row];
+         
+         if (this.attr_("stackedGraph")) {
+           point = this.layout_.unstackPointAtIndex(pos+row);
+         }
+         
+         this.selPoints_.push(point);
        }
        pos += this.layout_.datasets[i].length;
      }
@@@ -1595,6 -1587,8 +1601,6 @@@ Dygraph.prototype.drawGraph_ = function
    this.setColors_();
    this.attrs_['pointSize'] = 0.5 * this.attr_('highlightCircleSize');
  
 -  var connectSeparatedPoints = this.attr_('connectSeparatedPoints');
 -
    // Loop over the fields (series).  Go from the last to the first,
    // because if they're stacked that's how we accumulate the values.
  
    for (var i = data[0].length - 1; i >= 1; i--) {
      if (!this.visibility()[i - 1]) continue;
  
 +    var connectSeparatedPoints = this.attr_('connectSeparatedPoints', i);
 +
      var series = [];
      for (var j = 0; j < data.length; j++) {
        if (data[j][i] != null || !connectSeparatedPoints) {
@@@ -2320,14 -2312,6 +2326,14 @@@ Dygraph.prototype.updateOptions = funct
    if (attrs.valueRange) {
      this.valueRange_ = attrs.valueRange;
    }
 +
 +  // TODO(danvk): validate per-series options.
 +  // Supported:
 +  // strokeWidth
 +  // pointSize
 +  // drawPoints
 +  // highlightCircleSize
 +
    Dygraph.update(this.user_attrs_, attrs);
    Dygraph.update(this.renderOptions_, attrs);
  
@@@ -2442,18 -2426,6 +2448,18 @@@ Dygraph.prototype.annotations = functio
    return this.annotations_;
  };
  
 +/**
 + * Get the index of a series (column) given its name. The first column is the
 + * x-axis, so the data series start with index 1.
 + */
 +Dygraph.prototype.indexFromSetName = function(name) {
 +  var labels = this.attr_("labels");
 +  for (var i = 0; i < labels.length; i++) {
 +    if (labels[i] == name) return i;
 +  }
 +  return null;
 +};
 +
  Dygraph.addAnnotationRule = function() {
    if (Dygraph.addedAnnotationCSS) return;