Merge commit '9ac5e4aea125e706201c61b0ccb13a2cafe5618f' into clipping
[dygraphs.git] / dygraph.js
index f8ca478..ba2f31e 100644 (file)
@@ -162,6 +162,7 @@ Dygraph.prototype.__init__ = function(div, file, attrs) {
   this.dateWindow_ = attrs.dateWindow || null;
   this.valueRange_ = attrs.valueRange || null;
   this.wilsonInterval_ = attrs.wilsonInterval || true;
+  this.is_initial_draw_ = true;
 
   // Clear the div. This ensure that, if multiple dygraphs are passed the same
   // div, then only one will be drawn.
@@ -291,6 +292,13 @@ Dygraph.addEvent = function(el, evt, fn) {
   }
 };
 
+Dygraph.clipCanvas_ = function(cnv, clip) {
+  var ctx = cnv.getContext("2d");
+  ctx.beginPath();
+  ctx.rect(clip.left, clip.top, clip.width, clip.height);
+  ctx.clip();
+};
+
 /**
  * Generates interface elements for the Dygraph: a containing div, a div to
  * display the current point, and a textbox to adjust the rolling average
@@ -306,8 +314,16 @@ Dygraph.prototype.createInterface_ = function() {
   this.graphDiv.style.height = this.height_ + "px";
   enclosing.appendChild(this.graphDiv);
 
+  var clip = {
+    top: 0,
+    left: this.attr_("yAxisLabelWidth") + 2 * this.attr_("axisTickSize")
+  };
+  clip.width = this.width_ - clip.left - this.attr_("rightGap");
+  clip.height = this.height_ - this.attr_("axisLabelFontSize")
+      - 2 * this.attr_("axisTickSize");
+  this.clippingArea_ = clip;
+
   // Create the canvas for interactive parts of the chart.
-  // this.canvas_ = document.createElement("canvas");
   this.canvas_ = Dygraph.createCanvas();
   this.canvas_.style.position = "absolute";
   this.canvas_.width = this.width_;
@@ -319,6 +335,10 @@ Dygraph.prototype.createInterface_ = function() {
   // ... and for static parts of the chart.
   this.hidden_ = this.createPlotKitCanvas_(this.canvas_);
 
+  // Make sure we don't overdraw.
+  Dygraph.clipCanvas_(this.hidden_, this.clippingArea_);
+  Dygraph.clipCanvas_(this.canvas_, this.clippingArea_);
+
   var dygraph = this;
   Dygraph.addEvent(this.hidden_, 'mousemove', function(e) {
     dygraph.mouseMove_(e);
@@ -350,7 +370,35 @@ Dygraph.prototype.createInterface_ = function() {
   this.createStatusMessage_();
   this.createRollInterface_();
   this.createDragInterface_();
-}
+};
+
+/**
+ * Detach DOM elements in the dygraph and null out all data references.
+ * Calling this when you're done with a dygraph can dramatically reduce memory
+ * usage. See, e.g., the tests/perf.html example.
+ */
+Dygraph.prototype.destroy = function() {
+  var removeRecursive = function(node) {
+    while (node.hasChildNodes()) {
+      removeRecursive(node.firstChild);
+      node.removeChild(node.firstChild);
+    }
+  };
+  removeRecursive(this.maindiv_);
+
+  var nullOut = function(obj) {
+    for (var n in obj) {
+      if (typeof(obj[n]) === 'object') {
+        obj[n] = null;
+      }
+    }
+  };
+
+  // These may not all be necessary, but it can't hurt...
+  nullOut(this.layout_);
+  nullOut(this.plotter_);
+  nullOut(this);
+};
 
 /**
  * Creates the canvas containing the PlotKit graph. Only plotkit ever draws on
@@ -1300,6 +1348,10 @@ Dygraph.prototype.extremeValues_ = function(series) {
  * @private
  */
 Dygraph.prototype.drawGraph_ = function(data) {
+  // This is used to set the second parameter to drawCallback, below.
+  var is_initial_draw = this.is_initial_draw_;
+  this.is_initial_draw_ = false;
+
   var minY = null, maxY = null;
   this.layout_.removeAllDatasets();
   this.setColors_();
@@ -1416,7 +1468,7 @@ Dygraph.prototype.drawGraph_ = function(data) {
                                          this.canvas_.height);
 
   if (this.attr_("drawCallback") !== null) {
-    this.attr_("drawCallback")(this);
+    this.attr_("drawCallback")(this, is_initial_draw);
   }
 };