Migrate most of core dygraphs to ES6 modules.
authorDan Vanderkam <danvdk@gmail.com>
Mon, 19 Oct 2015 16:45:16 +0000 (12:45 -0400)
committerDan Vanderkam <danvdk@gmail.com>
Sun, 25 Oct 2015 02:43:29 +0000 (22:43 -0400)
20 files changed:
dygraph-dev.js
package.json
src/datahandler/datahandler.js
src/datahandler/default.js
src/dygraph-canvas.js
src/dygraph-default-attrs.js [new file with mode: 0644]
src/dygraph-interaction-model.js
src/dygraph-layout.js
src/dygraph-options.js
src/dygraph-plugin-base.js [deleted file]
src/dygraph-tickers.js
src/dygraph-utils.js
src/dygraph.js
src/plugins/annotations.js
src/plugins/axes.js
src/plugins/chart-labels.js
src/plugins/grid.js
src/plugins/legend.js
src/plugins/range-selector.js
tests/demo.html

index 506312e..b09f28b 100644 (file)
   // This list needs to be kept in sync w/ the one in generate-combined.sh
   // and the one in jsTestDriver.conf.
   var source_files = [
-    "src/polyfills/console.js",
-    "src/polyfills/dashed-canvas.js",
+    // "src/polyfills/console.js",
+    // "src/polyfills/dashed-canvas.js",
     "src/dygraph-options.js",
     "src/dygraph-layout.js",
     "src/dygraph-canvas.js",
     "src/dygraph.js",
     "src/dygraph-utils.js",
-    "src/dygraph-gviz.js",
+    // "src/dygraph-gviz.js",
     "src/dygraph-interaction-model.js",
     "src/dygraph-tickers.js",
-    "src/dygraph-plugin-base.js",
-    "src/plugins/annotations.js",
-    "src/plugins/axes.js",
-    "src/plugins/chart-labels.js",
-    "src/plugins/grid.js",
-    "src/plugins/legend.js",
-    "src/plugins/range-selector.js",
-    "src/dygraph-plugin-install.js",
-    "src/dygraph-options-reference.js",  // Shouldn't be included in generate-combined.sh
+    // "src/dygraph-plugin-base.js",
+    // "src/plugins/annotations.js",
+    // "src/plugins/axes.js",
+    // "src/plugins/chart-labels.js",
+    // "src/plugins/grid.js",
+    // "src/plugins/legend.js",
+    // "src/plugins/range-selector.js",
+    // "src/dygraph-plugin-install.js",
+    // "src/dygraph-options-reference.js",  // Shouldn't be included in generate-combined.sh
     "src/datahandler/datahandler.js",
     "src/datahandler/default.js",
-    "src/datahandler/default-fractions.js",
-    "src/datahandler/bars.js",
-    "src/datahandler/bars-error.js",
-    "src/datahandler/bars-custom.js",
-    "src/datahandler/bars-fractions.js"
+    // "src/datahandler/default-fractions.js",
+    // "src/datahandler/bars.js",
+    // "src/datahandler/bars-error.js",
+    // "src/datahandler/bars-custom.js",
+    // "src/datahandler/bars-fractions.js"
   ];
 
   for (var i = 0; i < source_files.length; i++) {
index cbe5638..b26f91d 100644 (file)
@@ -26,6 +26,8 @@
   },
   "homepage": "https://github.com/danvk/dygraphs",
   "devDependencies": {
+    "babelify": "^6.3.0",
+    "browserify": "^11.2.0",
     "closure-compiler": "^0.2.6",
     "coveralls": "^2.11.2",
     "gulp": "^3.8.10",
@@ -55,7 +57,8 @@
     "phantomjs": "^1.9.7-8",
     "pre-commit": "^1.0.6",
     "source-map": "^0.4.2",
-    "uglify-js": "^2"
+    "uglify-js": "^2",
+    "watchify": "^3.4.0"
   },
   "scripts": {
     "test": "make test",
index b3eae91..1b0efcb 100644 (file)
@@ -41,6 +41,8 @@
 /*global Dygraph:false */
 /*global DygraphLayout:false */
 
+"use strict";
+
 /**
  * 
  * The data handler is responsible for all data specific operations. All of the
  * Initially the unified data is created by the extractSeries method
  * @constructor
  */
-Dygraph.DataHandler = function () {
+var DygraphDataHandler = function () {
 };
 
-/**
- * A collection of functions to create and retrieve data handlers.
- * @type {Object.<!Dygraph.DataHandler>}
- */
-Dygraph.DataHandlers = {};
-
-(function() {
-
-"use strict";
-
-var handler = Dygraph.DataHandler;
+var handler = DygraphDataHandler;
 
 /**
  * X-value array index constant for unified data samples.
@@ -267,4 +259,4 @@ handler.parseFloat = function(val) {
   return val;
 };
 
-})();
+export default DygraphDataHandler;
index e42b92b..5ddf67c 100644 (file)
@@ -9,20 +9,19 @@
  * @author David Eberlein (david.eberlein@ch.sauter-bc.com)
  */
 
-(function() {
-
 /*global Dygraph:false */
 "use strict";
 
+import DygraphDataHandler from './datahandler';
+
 /**
  * @constructor
  * @extends Dygraph.DataHandler
  */
-Dygraph.DataHandlers.DefaultHandler = function() {
+var DefaultHandler = function() {
 };
 
-var DefaultHandler = Dygraph.DataHandlers.DefaultHandler;
-DefaultHandler.prototype = new Dygraph.DataHandler();
+DefaultHandler.prototype = new DygraphDataHandler();
 
 /** @inheritDoc */
 DefaultHandler.prototype.extractSeries = function(rawData, i, options) {
@@ -97,4 +96,4 @@ DefaultHandler.prototype.getExtremeYValues = function(series, dateWindow,
   return [ minY, maxY ];
 };
 
-})();
+export default DefaultHandler;
index aed387b..256edc1 100644 (file)
  * @constructor
  */
 
-var DygraphCanvasRenderer = (function() {
 /*global Dygraph:false */
 "use strict";
 
+import * as utils from './dygraph-utils';
+
 
 /**
  * @constructor
@@ -57,7 +58,7 @@ var DygraphCanvasRenderer = function(dygraph, element, elementContext, layout) {
   this.width = dygraph.width_;
 
   // --- check whether everything is ok before we return
-  if (!Dygraph.isCanvasSupported(this.element)) {
+  if (!utils.isCanvasSupported(this.element)) {
     throw "Canvas is not supported.";
   }
 
@@ -68,7 +69,7 @@ var DygraphCanvasRenderer = function(dygraph, element, elementContext, layout) {
   // This ensures that we don't overdraw.
   // on Android 3 and 4, setting a clipping area on a canvas prevents it from
   // displaying anything.
-  if (!Dygraph.isAndroid()) {
+  if (!utils.isAndroid()) {
     var ctx = this.dygraph_.canvas_ctx_;
     ctx.beginPath();
     ctx.rect(this.area.x, this.area.y, this.area.w, this.area.h);
@@ -135,7 +136,7 @@ DygraphCanvasRenderer._drawStyledLine = function(e,
   // TODO(konigsberg): Compute attributes outside this method call.
   var stepPlot = g.getBooleanOption("stepPlot", e.setName);
 
-  if (!Dygraph.isArrayLike(strokePattern)) {
+  if (!utils.isArrayLike(strokePattern)) {
     strokePattern = null;
   }
 
@@ -143,7 +144,7 @@ DygraphCanvasRenderer._drawStyledLine = function(e,
 
   var points = e.points;
   var setName = e.setName;
-  var iter = Dygraph.createIterator(points, 0, points.length,
+  var iter = utils.createIterator(points, 0, points.length,
       DygraphCanvasRenderer._getIteratorPredicate(
           g.getBooleanOption("connectSeparatedPoints", setName)));
 
@@ -334,7 +335,7 @@ DygraphCanvasRenderer.prototype._renderLineChart = function(opt_seriesName, opt_
   // Determine which series have specialized plotters.
   var plotter_attr = this.dygraph_.getOption("plotter");
   var plotters = plotter_attr;
-  if (!Dygraph.isArrayLike(plotters)) {
+  if (!utils.isArrayLike(plotters)) {
     plotters = [plotters];
   }
 
@@ -425,7 +426,7 @@ DygraphCanvasRenderer._linePlotter = function(e) {
   // this code a bit nasty.
   var borderWidth = g.getNumericOption("strokeBorderWidth", setName);
   var drawPointCallback = g.getOption("drawPointCallback", setName) ||
-      Dygraph.Circles.DEFAULT;
+      utils.Circles.DEFAULT;
   var strokePattern = g.getOption("strokePattern", setName);
   var drawPoints = g.getBooleanOption("drawPoints", setName);
   var pointSize = g.getNumericOption("pointSize", setName);
@@ -475,7 +476,7 @@ DygraphCanvasRenderer._errorPlotter = function(e) {
   var stepPlot = g.getBooleanOption("stepPlot", setName);
   var points = e.points;
 
-  var iter = Dygraph.createIterator(points, 0, points.length,
+  var iter = utils.createIterator(points, 0, points.length,
       DygraphCanvasRenderer._getIteratorPredicate(
           g.getBooleanOption("connectSeparatedPoints", setName)));
 
@@ -486,7 +487,7 @@ DygraphCanvasRenderer._errorPlotter = function(e) {
   var prevY = NaN;
   var prevYs = [-1, -1];
   // should be same color as the lines but only 15% opaque.
-  var rgb = Dygraph.toRGB_(color);
+  var rgb = utils.toRGB_(color);
   var err_color =
       'rgba(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ',' + fillAlpha + ')';
   ctx.fillStyle = err_color;
@@ -748,7 +749,7 @@ DygraphCanvasRenderer._fillPlotter = function(e) {
     axisY = area.h * axisY + area.y;
 
     var points = sets[setIdx];
-    var iter = Dygraph.createIterator(points, 0, points.length,
+    var iter = utils.createIterator(points, 0, points.length,
         DygraphCanvasRenderer._getIteratorPredicate(
             g.getBooleanOption("connectSeparatedPoints", setName)));
 
@@ -757,7 +758,7 @@ DygraphCanvasRenderer._fillPlotter = function(e) {
     var prevYs = [-1, -1];
     var newYs;
     // should be same color as the lines but only 15% opaque.
-    var rgb = Dygraph.toRGB_(color);
+    var rgb = utils.toRGB_(color);
     var err_color =
         'rgba(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ',' + fillAlpha + ')';
     ctx.fillStyle = err_color;
@@ -782,7 +783,7 @@ DygraphCanvasRenderer._fillPlotter = function(e) {
     var point;
     while (iter.hasNext) {
       point = iter.next();
-      if (!Dygraph.isOK(point.y) && !stepPlot) {
+      if (!utils.isOK(point.y) && !stepPlot) {
         traceBackPath(ctx, prevX, prevYs[1], pathBack);
         pathBack = [];
         prevX = NaN;
@@ -866,6 +867,4 @@ DygraphCanvasRenderer._fillPlotter = function(e) {
   }
 };
 
-return DygraphCanvasRenderer;
-
-})();
+export default DygraphCanvasRenderer;
diff --git a/src/dygraph-default-attrs.js b/src/dygraph-default-attrs.js
new file mode 100644 (file)
index 0000000..b7dd6e4
--- /dev/null
@@ -0,0 +1,135 @@
+'use strict'
+
+import * as DygraphTickers from './dygraph-tickers';
+import DygraphInteraction from './dygraph-interaction-model';
+import DygraphCanvasRenderer from './dygraph-canvas';
+import * as utils from './dygraph-utils';
+
+// Default attribute values.
+var DEFAULT_ATTRS = {
+  highlightCircleSize: 3,
+  highlightSeriesOpts: null,
+  highlightSeriesBackgroundAlpha: 0.5,
+
+  labelsDivWidth: 250,
+  labelsDivStyles: {
+    // TODO(danvk): move defaults from createStatusMessage_ here.
+  },
+  labelsSeparateLines: false,
+  labelsShowZeroValues: true,
+  labelsKMB: false,
+  labelsKMG2: false,
+  showLabelsOnHighlight: true,
+
+  digitsAfterDecimal: 2,
+  maxNumberWidth: 6,
+  sigFigs: null,
+
+  strokeWidth: 1.0,
+  strokeBorderWidth: 0,
+  strokeBorderColor: "white",
+
+  axisTickSize: 3,
+  axisLabelFontSize: 14,
+  rightGap: 5,
+
+  showRoller: false,
+  xValueParser: utils.dateParser,
+
+  delimiter: ',',
+
+  sigma: 2.0,
+  errorBars: false,
+  fractions: false,
+  wilsonInterval: true,  // only relevant if fractions is true
+  customBars: false,
+  fillGraph: false,
+  fillAlpha: 0.15,
+  connectSeparatedPoints: false,
+
+  stackedGraph: false,
+  stackedGraphNaNFill: 'all',
+  hideOverlayOnMouseOut: true,
+
+  legend: 'onmouseover',
+  stepPlot: false,
+  avoidMinZero: false,
+  xRangePad: 0,
+  yRangePad: null,
+  drawAxesAtZero: false,
+
+  // Sizes of the various chart labels.
+  titleHeight: 28,
+  xLabelHeight: 18,
+  yLabelWidth: 18,
+
+  axisLineColor: "black",
+  axisLineWidth: 0.3,
+  gridLineWidth: 0.3,
+  axisLabelColor: "black",
+  axisLabelWidth: 50,
+  gridLineColor: "rgb(128,128,128)",
+
+  interactionModel: DygraphInteraction.defaultModel,
+  animatedZooms: false,  // (for now)
+
+  // Range selector options
+  showRangeSelector: false,
+  rangeSelectorHeight: 40,
+  rangeSelectorPlotStrokeColor: "#808FAB",
+  rangeSelectorPlotFillGradientColor: "white",
+  rangeSelectorPlotFillColor: "#A7B1C4",
+  rangeSelectorBackgroundStrokeColor: "gray",
+  rangeSelectorBackgroundLineWidth: 1,
+  rangeSelectorPlotLineWidth:1.5,
+  rangeSelectorForegroundStrokeColor: "black",
+  rangeSelectorForegroundLineWidth: 1,
+  rangeSelectorAlpha: 0.6,
+  showInRangeSelector: null,
+
+  // The ordering here ensures that central lines always appear above any
+  // fill bars/error bars.
+  plotter: [
+    DygraphCanvasRenderer._fillPlotter,
+    DygraphCanvasRenderer._errorPlotter,
+    DygraphCanvasRenderer._linePlotter
+  ],
+
+  plugins: [ ],
+
+  // per-axis options
+  axes: {
+    x: {
+      pixelsPerLabel: 70,
+      axisLabelWidth: 60,
+      axisLabelFormatter: utils.dateAxisLabelFormatter,
+      valueFormatter: utils.dateValueFormatter,
+      drawGrid: true,
+      drawAxis: true,
+      independentTicks: true,
+      ticker: DygraphTickers.dateTicker
+    },
+    y: {
+      axisLabelWidth: 50,
+      pixelsPerLabel: 30,
+      valueFormatter: utils.numberValueFormatter,
+      axisLabelFormatter: utils.numberAxisLabelFormatter,
+      drawGrid: true,
+      drawAxis: true,
+      independentTicks: true,
+      ticker: DygraphTickers.numericTicks
+    },
+    y2: {
+      axisLabelWidth: 50,
+      pixelsPerLabel: 30,
+      valueFormatter: utils.numberValueFormatter,
+      axisLabelFormatter: utils.numberAxisLabelFormatter,
+      drawAxis: true,  // only applies when there are two axes of data.
+      drawGrid: false,
+      independentTicks: false,
+      ticker: DygraphTickers.numericTicks
+    }
+  }
+};
+
+export default DEFAULT_ATTRS;
index 53e2f44..3813fc5 100644 (file)
  * @author Robert Konigsberg (konigsberg@google.com)
  */
 
-(function() {
 /*global Dygraph:false */
 "use strict";
 
+import * as utils from './dygraph-utils';
+
 /**
  * You can drag this many pixels past the edge of the chart and still have it
  * be considered a zoom. This makes it easier to zoom to the exact edge of the
@@ -25,7 +26,7 @@ var DRAG_EDGE_MARGIN = 100;
  * A collection of functions to facilitate build custom interaction models.
  * @class
  */
-Dygraph.Interaction = {};
+var DygraphInteraction = {};
 
 /**
  * Checks whether the beginning & ending of an event were close enough that it
@@ -36,15 +37,15 @@ Dygraph.Interaction = {};
  * @param {Dygraph} g
  * @param {Object} context
  */
-Dygraph.Interaction.maybeTreatMouseOpAsClick = function(event, g, context) {
-  context.dragEndX = Dygraph.dragGetX_(event, context);
-  context.dragEndY = Dygraph.dragGetY_(event, context);
+DygraphInteraction.maybeTreatMouseOpAsClick = function(event, g, context) {
+  context.dragEndX = utils.dragGetX_(event, context);
+  context.dragEndY = utils.dragGetY_(event, context);
   var regionWidth = Math.abs(context.dragEndX - context.dragStartX);
   var regionHeight = Math.abs(context.dragEndY - context.dragStartY);
 
   if (regionWidth < 2 && regionHeight < 2 &&
       g.lastx_ !== undefined && g.lastx_ != -1) {
-    Dygraph.Interaction.treatMouseOpAsClick(g, event, context);
+    DygraphInteraction.treatMouseOpAsClick(g, event, context);
   }
 
   context.regionWidth = regionWidth;
@@ -65,14 +66,14 @@ Dygraph.Interaction.maybeTreatMouseOpAsClick = function(event, g, context) {
  *     dragStartX/dragStartY/etc. properties). This function modifies the
  *     context.
  */
-Dygraph.Interaction.startPan = function(event, g, context) {
+DygraphInteraction.startPan = function(event, g, context) {
   var i, axis;
   context.isPanning = true;
   var xRange = g.xAxisRange();
 
   if (g.getOptionForAxis("logscale", "x")) {
-    context.initialLeftmostDate = Dygraph.log10(xRange[0]);
-    context.dateRange = Dygraph.log10(xRange[1]) - Dygraph.log10(xRange[0]);
+    context.initialLeftmostDate = utils.log10(xRange[0]);
+    context.dateRange = utils.log10(xRange[1]) - utils.log10(xRange[0]);
   } else {
     context.initialLeftmostDate = xRange[0];    
     context.dateRange = xRange[1] - xRange[0];
@@ -123,8 +124,8 @@ Dygraph.Interaction.startPan = function(event, g, context) {
     // In log scale, initialTopValue, dragValueRange and unitsPerPixel are log scale.
     var logscale = g.attributes_.getForAxis("logscale", i);
     if (logscale) {
-      axis_data.initialTopValue = Dygraph.log10(yRange[1]);
-      axis_data.dragValueRange = Dygraph.log10(yRange[1]) - Dygraph.log10(yRange[0]);
+      axis_data.initialTopValue = utils.log10(yRange[1]);
+      axis_data.dragValueRange = utils.log10(yRange[1]) - utils.log10(yRange[0]);
     } else {
       axis_data.initialTopValue = yRange[1];
       axis_data.dragValueRange = yRange[1] - yRange[0];
@@ -151,9 +152,9 @@ Dygraph.Interaction.startPan = function(event, g, context) {
  *     dragStartX/dragStartY/etc. properties). This function modifies the
  *     context.
  */
-Dygraph.Interaction.movePan = function(event, g, context) {
-  context.dragEndX = Dygraph.dragGetX_(event, context);
-  context.dragEndY = Dygraph.dragGetY_(event, context);
+DygraphInteraction.movePan = function(event, g, context) {
+  context.dragEndX = utils.dragGetX_(event, context);
+  context.dragEndY = utils.dragGetY_(event, context);
 
   var minDate = context.initialLeftmostDate -
     (context.dragEndX - context.dragStartX) * context.xUnitsPerPixel;
@@ -170,8 +171,8 @@ Dygraph.Interaction.movePan = function(event, g, context) {
   }
 
   if (g.getOptionForAxis("logscale", "x")) {
-    g.dateWindow_ = [ Math.pow(Dygraph.LOG_SCALE, minDate),
-                      Math.pow(Dygraph.LOG_SCALE, maxDate) ];
+    g.dateWindow_ = [ Math.pow(utils.LOG_SCALE, minDate),
+                      Math.pow(utils.LOG_SCALE, maxDate) ];
   } else {
     g.dateWindow_ = [minDate, maxDate];    
   }
@@ -203,8 +204,8 @@ Dygraph.Interaction.movePan = function(event, g, context) {
         }
       }
       if (g.attributes_.getForAxis("logscale", i)) {
-        axis.valueWindow = [ Math.pow(Dygraph.LOG_SCALE, minValue),
-                             Math.pow(Dygraph.LOG_SCALE, maxValue) ];
+        axis.valueWindow = [ Math.pow(utils.LOG_SCALE, minValue),
+                             Math.pow(utils.LOG_SCALE, maxValue) ];
       } else {
         axis.valueWindow = [ minValue, maxValue ];
       }
@@ -228,7 +229,7 @@ Dygraph.Interaction.movePan = function(event, g, context) {
  *     dragStartX/dragStartY/etc. properties). This function modifies the
  *     context.
  */
-Dygraph.Interaction.endPan = Dygraph.Interaction.maybeTreatMouseOpAsClick;
+DygraphInteraction.endPan = DygraphInteraction.maybeTreatMouseOpAsClick;
 
 /**
  * Called in response to an interaction model operation that
@@ -244,7 +245,7 @@ Dygraph.Interaction.endPan = Dygraph.Interaction.maybeTreatMouseOpAsClick;
  *     dragStartX/dragStartY/etc. properties). This function modifies the
  *     context.
  */
-Dygraph.Interaction.startZoom = function(event, g, context) {
+DygraphInteraction.startZoom = function(event, g, context) {
   context.isZooming = true;
   context.zoomMoved = false;
 };
@@ -263,16 +264,16 @@ Dygraph.Interaction.startZoom = function(event, g, context) {
  *     dragStartX/dragStartY/etc. properties). This function modifies the
  *     context.
  */
-Dygraph.Interaction.moveZoom = function(event, g, context) {
+DygraphInteraction.moveZoom = function(event, g, context) {
   context.zoomMoved = true;
-  context.dragEndX = Dygraph.dragGetX_(event, context);
-  context.dragEndY = Dygraph.dragGetY_(event, context);
+  context.dragEndX = utils.dragGetX_(event, context);
+  context.dragEndY = utils.dragGetY_(event, context);
 
   var xDelta = Math.abs(context.dragStartX - context.dragEndX);
   var yDelta = Math.abs(context.dragStartY - context.dragEndY);
 
   // drag direction threshold for y axis is twice as large as x axis
-  context.dragDirection = (xDelta < yDelta / 2) ? Dygraph.VERTICAL : Dygraph.HORIZONTAL;
+  context.dragDirection = (xDelta < yDelta / 2) ? utils.VERTICAL : utils.HORIZONTAL;
 
   g.drawZoomRect_(
       context.dragDirection,
@@ -295,7 +296,7 @@ Dygraph.Interaction.moveZoom = function(event, g, context) {
  * @param {Event} event
  * @param {Object} context
  */
-Dygraph.Interaction.treatMouseOpAsClick = function(g, event, context) {
+DygraphInteraction.treatMouseOpAsClick = function(g, event, context) {
   var clickCallback = g.getFunctionOption('clickCallback');
   var pointClickCallback = g.getFunctionOption('pointClickCallback');
 
@@ -370,17 +371,17 @@ Dygraph.Interaction.treatMouseOpAsClick = function(g, event, context) {
  *     dragStartX/dragStartY/etc. properties). This function modifies the
  *     context.
  */
-Dygraph.Interaction.endZoom = function(event, g, context) {
+DygraphInteraction.endZoom = function(event, g, context) {
   g.clearZoomRect_();
   context.isZooming = false;
-  Dygraph.Interaction.maybeTreatMouseOpAsClick(event, g, context);
+  DygraphInteraction.maybeTreatMouseOpAsClick(event, g, context);
 
   // The zoom rectangle is visibly clipped to the plot area, so its behavior
   // should be as well.
   // See http://code.google.com/p/dygraphs/issues/detail?id=280
   var plotArea = g.getArea();
   if (context.regionWidth >= 10 &&
-      context.dragDirection == Dygraph.HORIZONTAL) {
+      context.dragDirection == utils.HORIZONTAL) {
     var left = Math.min(context.dragStartX, context.dragEndX),
         right = Math.max(context.dragStartX, context.dragEndX);
     left = Math.max(left, plotArea.x);
@@ -390,7 +391,7 @@ Dygraph.Interaction.endZoom = function(event, g, context) {
     }
     context.cancelNextDblclick = true;
   } else if (context.regionHeight >= 10 &&
-             context.dragDirection == Dygraph.VERTICAL) {
+             context.dragDirection == utils.VERTICAL) {
     var top = Math.min(context.dragStartY, context.dragEndY),
         bottom = Math.max(context.dragStartY, context.dragEndY);
     top = Math.max(top, plotArea.y);
@@ -407,7 +408,7 @@ Dygraph.Interaction.endZoom = function(event, g, context) {
 /**
  * @private
  */
-Dygraph.Interaction.startTouch = function(event, g, context) {
+DygraphInteraction.startTouch = function(event, g, context) {
   event.preventDefault();  // touch browsers are all nice.
   if (event.touches.length > 1) {
     // If the user ever puts two fingers down, it's not a double tap.
@@ -471,7 +472,7 @@ Dygraph.Interaction.startTouch = function(event, g, context) {
 /**
  * @private
  */
-Dygraph.Interaction.moveTouch = function(event, g, context) {
+DygraphInteraction.moveTouch = function(event, g, context) {
   // If the tap moves, then it's definitely not part of a double-tap.
   context.startTimeForDoubleTapMs = null;
 
@@ -564,10 +565,10 @@ Dygraph.Interaction.moveTouch = function(event, g, context) {
 /**
  * @private
  */
-Dygraph.Interaction.endTouch = function(event, g, context) {
+DygraphInteraction.endTouch = function(event, g, context) {
   if (event.touches.length !== 0) {
     // this is effectively a "reset"
-    Dygraph.Interaction.startTouch(event, g, context);
+    DygraphInteraction.startTouch(event, g, context);
   } else if (event.changedTouches.length == 1) {
     // Could be part of a "double tap"
     // The heuristic here is that it's a double-tap if the two touchend events
@@ -603,7 +604,7 @@ var distanceFromInterval = function(x, left, right) {
  * edge of the chart. For events in the interior of the chart, this returns zero.
  */
 var distanceFromChart = function(event, g) {
-  var chartPos = Dygraph.findPos(g.canvas_);
+  var chartPos = utils.findPos(g.canvas_);
   var box = {
     left: chartPos.x,
     right: chartPos.x + g.canvas_.offsetWidth,
@@ -612,8 +613,8 @@ var distanceFromChart = function(event, g) {
   };
 
   var pt = {
-    x: Dygraph.pageX(event),
-    y: Dygraph.pageY(event)
+    x: utils.pageX(event),
+    y: utils.pageY(event)
   };
 
   var dx = distanceFromInterval(pt.x, box.left, box.right),
@@ -626,11 +627,11 @@ var distanceFromChart = function(event, g) {
  * this when constructing your own interaction model, e.g.:
  * g.updateOptions( {
  *   interactionModel: {
- *     mousedown: Dygraph.defaultInteractionModel.mousedown
+ *     mousedown: DygraphInteraction.defaultInteractionModel.mousedown
  *   }
  * } );
  */
-Dygraph.Interaction.defaultModel = {
+DygraphInteraction.defaultModel = {
   // Track the beginning of drag events
   mousedown: function(event, g, context) {
     // Right-click should not initiate a zoom.
@@ -639,9 +640,9 @@ Dygraph.Interaction.defaultModel = {
     context.initializeMouseDown(event, g, context);
 
     if (event.altKey || event.shiftKey) {
-      Dygraph.startPan(event, g, context);
+      DygraphInteraction.startPan(event, g, context);
     } else {
-      Dygraph.startZoom(event, g, context);
+      DygraphInteraction.startZoom(event, g, context);
     }
 
     // Note: we register mousemove/mouseup on document to allow some leeway for
@@ -652,7 +653,7 @@ Dygraph.Interaction.defaultModel = {
         // When the mouse moves >200px from the chart edge, cancel the zoom.
         var d = distanceFromChart(event, g);
         if (d < DRAG_EDGE_MARGIN) {
-          Dygraph.moveZoom(event, g, context);
+          DygraphInteraction.moveZoom(event, g, context);
         } else {
           if (context.dragEndX !== null) {
             context.dragEndX = null;
@@ -661,22 +662,22 @@ Dygraph.Interaction.defaultModel = {
           }
         }
       } else if (context.isPanning) {
-        Dygraph.movePan(event, g, context);
+        DygraphInteraction.movePan(event, g, context);
       }
     };
     var mouseup = function(event) {
       if (context.isZooming) {
         if (context.dragEndX !== null) {
-          Dygraph.endZoom(event, g, context);
+          DygraphInteraction.endZoom(event, g, context);
         } else {
-          Dygraph.Interaction.maybeTreatMouseOpAsClick(event, g, context);
+          DygraphInteraction.maybeTreatMouseOpAsClick(event, g, context);
         }
       } else if (context.isPanning) {
-        Dygraph.endPan(event, g, context);
+        DygraphInteraction.endPan(event, g, context);
       }
 
-      Dygraph.removeEvent(document, 'mousemove', mousemove);
-      Dygraph.removeEvent(document, 'mouseup', mouseup);
+      utils.removeEvent(document, 'mousemove', mousemove);
+      utils.removeEvent(document, 'mouseup', mouseup);
       context.destroy();
     };
 
@@ -686,13 +687,13 @@ Dygraph.Interaction.defaultModel = {
   willDestroyContextMyself: true,
 
   touchstart: function(event, g, context) {
-    Dygraph.Interaction.startTouch(event, g, context);
+    DygraphInteraction.startTouch(event, g, context);
   },
   touchmove: function(event, g, context) {
-    Dygraph.Interaction.moveTouch(event, g, context);
+    DygraphInteraction.moveTouch(event, g, context);
   },
   touchend: function(event, g, context) {
-    Dygraph.Interaction.endTouch(event, g, context);
+    DygraphInteraction.endTouch(event, g, context);
   },
 
   // Disable zooming out if panning.
@@ -718,40 +719,42 @@ Dygraph.Interaction.defaultModel = {
   }
 };
 
-Dygraph.DEFAULT_ATTRS.interactionModel = Dygraph.Interaction.defaultModel;
+/*
+Dygraph.DEFAULT_ATTRS.interactionModel = DygraphInteraction.defaultModel;
 
 // old ways of accessing these methods/properties
-Dygraph.defaultInteractionModel = Dygraph.Interaction.defaultModel;
-Dygraph.endZoom = Dygraph.Interaction.endZoom;
-Dygraph.moveZoom = Dygraph.Interaction.moveZoom;
-Dygraph.startZoom = Dygraph.Interaction.startZoom;
-Dygraph.endPan = Dygraph.Interaction.endPan;
-Dygraph.movePan = Dygraph.Interaction.movePan;
-Dygraph.startPan = Dygraph.Interaction.startPan;
-
-Dygraph.Interaction.nonInteractiveModel_ = {
+Dygraph.defaultInteractionModel = DygraphInteraction.defaultModel;
+Dygraph.endZoom = DygraphInteraction.endZoom;
+Dygraph.moveZoom = DygraphInteraction.moveZoom;
+Dygraph.startZoom = DygraphInteraction.startZoom;
+Dygraph.endPan = DygraphInteraction.endPan;
+Dygraph.movePan = DygraphInteraction.movePan;
+Dygraph.startPan = DygraphInteraction.startPan;
+*/
+
+DygraphInteraction.nonInteractiveModel_ = {
   mousedown: function(event, g, context) {
     context.initializeMouseDown(event, g, context);
   },
-  mouseup: Dygraph.Interaction.maybeTreatMouseOpAsClick
+  mouseup: DygraphInteraction.maybeTreatMouseOpAsClick
 };
 
 // Default interaction model when using the range selector.
-Dygraph.Interaction.dragIsPanInteractionModel = {
+DygraphInteraction.dragIsPanInteractionModel = {
   mousedown: function(event, g, context) {
     context.initializeMouseDown(event, g, context);
-    Dygraph.startPan(event, g, context);
+    DygraphInteraction.startPan(event, g, context);
   },
   mousemove: function(event, g, context) {
     if (context.isPanning) {
-      Dygraph.movePan(event, g, context);
+      DygraphInteraction.movePan(event, g, context);
     }
   },
   mouseup: function(event, g, context) {
     if (context.isPanning) {
-      Dygraph.endPan(event, g, context);
+      DygraphInteraction.endPan(event, g, context);
     }
   }
 };
 
-})();
+export default DygraphInteraction;
index ef1df91..3bc9135 100644 (file)
@@ -9,11 +9,11 @@
  * dygraphs.
  */
 
-var DygraphLayout = (function() {
-
 /*global Dygraph:false */
 "use strict";
 
+import * as utils from './dygraph-utils';
+
 /**
  * Creates a new DygraphLayout object.
  *
@@ -160,7 +160,7 @@ DygraphLayout.prototype.setAnnotations = function(ann) {
                     "annotation.icon property");
       return;
     }
-    Dygraph.update(a, ann[i]);
+    utils.update(a, ann[i]);
     if (!a.xval) a.xval = parse(a.x);
     this.annotations.push(a);
   }
@@ -191,7 +191,7 @@ DygraphLayout.prototype._evaluateLimits = function() {
   this._xAxis.scale = (xrange !== 0 ? 1 / xrange : 1.0);
 
   if (this.dygraph_.getOptionForAxis("logscale", 'x')) {
-    this._xAxis.xlogrange = Dygraph.log10(this._xAxis.maxval) - Dygraph.log10(this._xAxis.minval);
+    this._xAxis.xlogrange = utils.log10(this._xAxis.maxval) - utils.log10(this._xAxis.minval);
     this._xAxis.xlogscale = (this._xAxis.xlogrange !== 0 ? 1.0 / this._xAxis.xlogrange : 1.0);
   }
   for (var i = 0; i < this.yAxes_.length; i++) {
@@ -202,7 +202,7 @@ DygraphLayout.prototype._evaluateLimits = function() {
     axis.yscale = (axis.yrange !== 0 ? 1.0 / axis.yrange : 1.0);
 
     if (this.dygraph_.getOption("logscale")) {
-      axis.ylogrange = Dygraph.log10(axis.maxyval) - Dygraph.log10(axis.minyval);
+      axis.ylogrange = utils.log10(axis.maxyval) - utils.log10(axis.minyval);
       axis.ylogscale = (axis.ylogrange !== 0 ? 1.0 / axis.ylogrange : 1.0);
       if (!isFinite(axis.ylogrange) || isNaN(axis.ylogrange)) {
         console.error('axis ' + i + ' of graph at ' + axis.g +
@@ -215,7 +215,7 @@ DygraphLayout.prototype._evaluateLimits = function() {
 
 DygraphLayout.calcXNormal_ = function(value, xAxis, logscale) {
   if (logscale) {
-    return ((Dygraph.log10(value) - Dygraph.log10(xAxis.minval)) * xAxis.xlogscale);
+    return ((utils.log10(value) - utils.log10(xAxis.minval)) * xAxis.xlogscale);
   } else {
     return (value - xAxis.minval) * xAxis.scale;
   }
@@ -229,7 +229,7 @@ DygraphLayout.calcXNormal_ = function(value, xAxis, logscale) {
  */
 DygraphLayout.calcYNormal_ = function(axis, value, logscale) {
   if (logscale) {
-    var x = 1.0 - ((Dygraph.log10(value) - Dygraph.log10(axis.minyval)) * axis.ylogscale);
+    var x = 1.0 - ((utils.log10(value) - utils.log10(axis.minyval)) * axis.ylogscale);
     return isFinite(x) ? x : NaN;  // shim for v8 issue; see pull request 276
   } else {
     return 1.0 - ((value - axis.minyval) * axis.yscale);
@@ -346,6 +346,4 @@ DygraphLayout.prototype.removeAllDatasets = function() {
   this.setPointsOffsets = [];
 };
 
-return DygraphLayout;
-
-})();
+export default DygraphLayout;
index d21ccc1..8affcdf 100644 (file)
@@ -5,25 +5,18 @@
  */
 
 /**
- * @fileoverview DygraphOptions is responsible for parsing and returning information about options.
- *
- * Still tightly coupled to Dygraphs, we could remove some of that, you know.
+ * @fileoverview DygraphOptions is responsible for parsing and returning
+ * information about options.
  */
 
-var DygraphOptions = (function() {
-/*jshint strict:false */
-
-// For "production" code, this gets set to false by uglifyjs.
-// Need to define it outside of "use strict", hence the nested IIFEs.
-if (typeof(DEBUG) === 'undefined') DEBUG=true;
-
-return (function() {
-
 // TODO: remove this jshint directive & fix the warnings.
 /*jshint sub:true */
 /*global Dygraph:false */
 "use strict";
 
+import * as utils from './dygraph-utils';
+import DEFAULT_ATTRS from './dygraph-default-attrs';
+
 /*
  * Interesting member variables: (REMOVING THIS LIST AS I CLOSURIZE)
  * global_ - global attributes (common among all graphs, AIUI)
@@ -167,13 +160,13 @@ DygraphOptions.prototype.reparseSeries = function() {
   }
 
   var axis_opts = this.user_["axes"] || {};
-  Dygraph.update(this.yAxes_[0].options, axis_opts["y"] || {});
+  utils.update(this.yAxes_[0].options, axis_opts["y"] || {});
   if (this.yAxes_.length > 1) {
-    Dygraph.update(this.yAxes_[1].options, axis_opts["y2"] || {});
+    utils.update(this.yAxes_[1].options, axis_opts["y2"] || {});
   }
-  Dygraph.update(this.xAxis_.options, axis_opts["x"] || {});
+  utils.update(this.xAxis_.options, axis_opts["x"] || {});
 
-  if (DEBUG) this.validateOptions_();
+  // if (DEBUG) this.validateOptions_();
 };
 
 /**
@@ -200,8 +193,8 @@ DygraphOptions.prototype.getGlobalDefault_ = function(name) {
   if (this.global_.hasOwnProperty(name)) {
     return this.global_[name];
   }
-  if (Dygraph.DEFAULT_ATTRS.hasOwnProperty(name)) {
-    return Dygraph.DEFAULT_ATTRS[name];
+  if (DEFAULT_ATTRS.hasOwnProperty(name)) {
+    return DEFAULT_ATTRS[name];
   }
   return null;
 };
@@ -255,7 +248,7 @@ DygraphOptions.prototype.getForAxis = function(name, axis) {
     }
   }
   // Default axis options third.
-  var defaultAxisOptions = Dygraph.DEFAULT_ATTRS.axes[axisString];
+  var defaultAxisOptions = DEFAULT_ATTRS.axes[axisString];
   if (defaultAxisOptions.hasOwnProperty(name)) {
     return defaultAxisOptions[name];
   }
@@ -329,7 +322,9 @@ DygraphOptions.prototype.seriesNames = function() {
   return this.labels_;
 };
 
-if (DEBUG) {
+// TODO: fix this
+// if (DEBUG) {
+if (false) {
 
 /**
  * Validate all options.
@@ -399,7 +394,4 @@ DygraphOptions.resetWarnings_ = function() {
 
 }
 
-return DygraphOptions;
-
-})();
-})();
+export default DygraphOptions;
diff --git a/src/dygraph-plugin-base.js b/src/dygraph-plugin-base.js
deleted file mode 100644 (file)
index 7f758a9..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-/*global Dygraph:false */
-
-// Namespace for plugins. Load this before plugins/*.js files.
-Dygraph.Plugins = {};
index 0f6b1ab..7eb17dd 100644 (file)
 
 /*jshint sub:true */
 /*global Dygraph:false */
-(function() {
 "use strict";
 
+import * as utils from './dygraph-utils';
+
 /** @typedef {Array.<{v:number, label:string, label_v:(string|undefined)}>} */
-Dygraph.TickList = undefined;  // the ' = undefined' keeps jshint happy.
+var TickList = undefined;  // the ' = undefined' keeps jshint happy.
 
 /** @typedef {function(
  *    number,
@@ -73,21 +74,21 @@ Dygraph.TickList = undefined;  // the ' = undefined' keeps jshint happy.
  *    function(string):*,
  *    Dygraph=,
  *    Array.<number>=
- *  ): Dygraph.TickList}
+ *  ): TickList}
  */
-Dygraph.Ticker = undefined;  // the ' = undefined' keeps jshint happy.
+var Ticker = undefined;  // the ' = undefined' keeps jshint happy.
 
-/** @type {Dygraph.Ticker} */
-Dygraph.numericLinearTicks = function(a, b, pixels, opts, dygraph, vals) {
+/** @type {Ticker} */
+export var numericLinearTicks = function(a, b, pixels, opts, dygraph, vals) {
   var nonLogscaleOpts = function(opt) {
     if (opt === 'logscale') return false;
     return opts(opt);
   };
-  return Dygraph.numericTicks(a, b, pixels, nonLogscaleOpts, dygraph, vals);
+  return numericTicks(a, b, pixels, nonLogscaleOpts, dygraph, vals);
 };
 
-/** @type {Dygraph.Ticker} */
-Dygraph.numericTicks = function(a, b, pixels, opts, dygraph, vals) {
+/** @type {Ticker} */
+export var numericTicks = function(a, b, pixels, opts, dygraph, vals) {
   var pixels_per_tick = /** @type{number} */(opts('pixelsPerLabel'));
   var ticks = [];
   var i, j, tickV, nTicks;
@@ -99,20 +100,20 @@ Dygraph.numericTicks = function(a, b, pixels, opts, dygraph, vals) {
     // TODO(danvk): factor this log-scale block out into a separate function.
     if (opts("logscale")) {
       nTicks  = Math.floor(pixels / pixels_per_tick);
-      var minIdx = Dygraph.binarySearch(a, Dygraph.PREFERRED_LOG_TICK_VALUES, 1);
-      var maxIdx = Dygraph.binarySearch(b, Dygraph.PREFERRED_LOG_TICK_VALUES, -1);
+      var minIdx = utils.binarySearch(a, PREFERRED_LOG_TICK_VALUES, 1);
+      var maxIdx = utils.binarySearch(b, PREFERRED_LOG_TICK_VALUES, -1);
       if (minIdx == -1) {
         minIdx = 0;
       }
       if (maxIdx == -1) {
-        maxIdx = Dygraph.PREFERRED_LOG_TICK_VALUES.length - 1;
+        maxIdx = PREFERRED_LOG_TICK_VALUES.length - 1;
       }
       // Count the number of tick values would appear, if we can get at least
       // nTicks / 4 accept them.
       var lastDisplayed = null;
       if (maxIdx - minIdx >= nTicks / 4) {
         for (var idx = maxIdx; idx >= minIdx; idx--) {
-          var tickValue = Dygraph.PREFERRED_LOG_TICK_VALUES[idx];
+          var tickValue = PREFERRED_LOG_TICK_VALUES[idx];
           var pixel_coord = Math.log(tickValue / a) / Math.log(b / a) * pixels;
           var tick = { v: tickValue };
           if (lastDisplayed === null) {
@@ -205,12 +206,12 @@ Dygraph.numericTicks = function(a, b, pixels, opts, dygraph, vals) {
 };
 
 
-/** @type {Dygraph.Ticker} */
-Dygraph.dateTicker = function(a, b, pixels, opts, dygraph, vals) {
-  var chosen = Dygraph.pickDateTickGranularity(a, b, pixels, opts);
+/** @type {Ticker} */
+export var dateTicker = function(a, b, pixels, opts, dygraph, vals) {
+  var chosen = pickDateTickGranularity(a, b, pixels, opts);
 
   if (chosen >= 0) {
-    return Dygraph.getDateAxis(a, b, chosen, opts, dygraph);
+    return getDateAxis(a, b, chosen, opts, dygraph);
   } else {
     // this can happen if self.width_ is zero.
     return [];
@@ -218,41 +219,44 @@ Dygraph.dateTicker = function(a, b, pixels, opts, dygraph, vals) {
 };
 
 // Time granularity enumeration
-// TODO(danvk): make this an @enum
-Dygraph.SECONDLY = 0;
-Dygraph.TWO_SECONDLY = 1;
-Dygraph.FIVE_SECONDLY = 2;
-Dygraph.TEN_SECONDLY = 3;
-Dygraph.THIRTY_SECONDLY  = 4;
-Dygraph.MINUTELY = 5;
-Dygraph.TWO_MINUTELY = 6;
-Dygraph.FIVE_MINUTELY = 7;
-Dygraph.TEN_MINUTELY = 8;
-Dygraph.THIRTY_MINUTELY = 9;
-Dygraph.HOURLY = 10;
-Dygraph.TWO_HOURLY = 11;
-Dygraph.SIX_HOURLY = 12;
-Dygraph.DAILY = 13;
-Dygraph.TWO_DAILY = 14;
-Dygraph.WEEKLY = 15;
-Dygraph.MONTHLY = 16;
-Dygraph.QUARTERLY = 17;
-Dygraph.BIANNUAL = 18;
-Dygraph.ANNUAL = 19;
-Dygraph.DECADAL = 20;
-Dygraph.CENTENNIAL = 21;
-Dygraph.NUM_GRANULARITIES = 22;
+export var Granularity = {
+  SECONDLY: 0,
+  TWO_SECONDLY: 1,
+  FIVE_SECONDLY: 2,
+  TEN_SECONDLY: 3,
+  THIRTY_SECONDLY : 4,
+  MINUTELY: 5,
+  TWO_MINUTELY: 6,
+  FIVE_MINUTELY: 7,
+  TEN_MINUTELY: 8,
+  THIRTY_MINUTELY: 9,
+  HOURLY: 10,
+  TWO_HOURLY: 11,
+  SIX_HOURLY: 12,
+  DAILY: 13,
+  TWO_DAILY: 14,
+  WEEKLY: 15,
+  MONTHLY: 16,
+  QUARTERLY: 17,
+  BIANNUAL: 18,
+  ANNUAL: 19,
+  DECADAL: 20,
+  CENTENNIAL: 21,
+  NUM_GRANULARITIES: 22
+}
 
 // Date components enumeration (in the order of the arguments in Date)
 // TODO: make this an @enum
-Dygraph.DATEFIELD_Y = 0;
-Dygraph.DATEFIELD_M = 1;
-Dygraph.DATEFIELD_D = 2;
-Dygraph.DATEFIELD_HH = 3;
-Dygraph.DATEFIELD_MM = 4;
-Dygraph.DATEFIELD_SS = 5;
-Dygraph.DATEFIELD_MS = 6;
-Dygraph.NUM_DATEFIELDS = 7;
+var DateField = {
+  DATEFIELD_Y: 0,
+  DATEFIELD_M: 1,
+  DATEFIELD_D: 2,
+  DATEFIELD_HH: 3,
+  DATEFIELD_MM: 4,
+  DATEFIELD_SS: 5,
+  DATEFIELD_MS: 6,
+  NUM_DATEFIELDS: 7
+};
 
 
 /**
@@ -268,29 +272,29 @@ Dygraph.NUM_DATEFIELDS = 7;
  *
  * @type {Array.<{datefield:number, step:number, spacing:number}>}
  */
-Dygraph.TICK_PLACEMENT = [];
-Dygraph.TICK_PLACEMENT[Dygraph.SECONDLY]        = {datefield: Dygraph.DATEFIELD_SS, step:   1, spacing: 1000 * 1};
-Dygraph.TICK_PLACEMENT[Dygraph.TWO_SECONDLY]    = {datefield: Dygraph.DATEFIELD_SS, step:   2, spacing: 1000 * 2};
-Dygraph.TICK_PLACEMENT[Dygraph.FIVE_SECONDLY]   = {datefield: Dygraph.DATEFIELD_SS, step:   5, spacing: 1000 * 5};
-Dygraph.TICK_PLACEMENT[Dygraph.TEN_SECONDLY]    = {datefield: Dygraph.DATEFIELD_SS, step:  10, spacing: 1000 * 10};
-Dygraph.TICK_PLACEMENT[Dygraph.THIRTY_SECONDLY] = {datefield: Dygraph.DATEFIELD_SS, step:  30, spacing: 1000 * 30};
-Dygraph.TICK_PLACEMENT[Dygraph.MINUTELY]        = {datefield: Dygraph.DATEFIELD_MM, step:   1, spacing: 1000 * 60};
-Dygraph.TICK_PLACEMENT[Dygraph.TWO_MINUTELY]    = {datefield: Dygraph.DATEFIELD_MM, step:   2, spacing: 1000 * 60 * 2};
-Dygraph.TICK_PLACEMENT[Dygraph.FIVE_MINUTELY]   = {datefield: Dygraph.DATEFIELD_MM, step:   5, spacing: 1000 * 60 * 5};
-Dygraph.TICK_PLACEMENT[Dygraph.TEN_MINUTELY]    = {datefield: Dygraph.DATEFIELD_MM, step:  10, spacing: 1000 * 60 * 10};
-Dygraph.TICK_PLACEMENT[Dygraph.THIRTY_MINUTELY] = {datefield: Dygraph.DATEFIELD_MM, step:  30, spacing: 1000 * 60 * 30};
-Dygraph.TICK_PLACEMENT[Dygraph.HOURLY]          = {datefield: Dygraph.DATEFIELD_HH, step:   1, spacing: 1000 * 3600};
-Dygraph.TICK_PLACEMENT[Dygraph.TWO_HOURLY]      = {datefield: Dygraph.DATEFIELD_HH, step:   2, spacing: 1000 * 3600 * 2};
-Dygraph.TICK_PLACEMENT[Dygraph.SIX_HOURLY]      = {datefield: Dygraph.DATEFIELD_HH, step:   6, spacing: 1000 * 3600 * 6};
-Dygraph.TICK_PLACEMENT[Dygraph.DAILY]           = {datefield: Dygraph.DATEFIELD_D,  step:   1, spacing: 1000 * 86400};
-Dygraph.TICK_PLACEMENT[Dygraph.TWO_DAILY]       = {datefield: Dygraph.DATEFIELD_D,  step:   2, spacing: 1000 * 86400 * 2};
-Dygraph.TICK_PLACEMENT[Dygraph.WEEKLY]          = {datefield: Dygraph.DATEFIELD_D,  step:   7, spacing: 1000 * 604800};
-Dygraph.TICK_PLACEMENT[Dygraph.MONTHLY]         = {datefield: Dygraph.DATEFIELD_M,  step:   1, spacing: 1000 * 7200  * 365.2524}; // 1e3 * 60 * 60 * 24 * 365.2524 / 12
-Dygraph.TICK_PLACEMENT[Dygraph.QUARTERLY]       = {datefield: Dygraph.DATEFIELD_M,  step:   3, spacing: 1000 * 21600 * 365.2524}; // 1e3 * 60 * 60 * 24 * 365.2524 / 4
-Dygraph.TICK_PLACEMENT[Dygraph.BIANNUAL]        = {datefield: Dygraph.DATEFIELD_M,  step:   6, spacing: 1000 * 43200 * 365.2524}; // 1e3 * 60 * 60 * 24 * 365.2524 / 2
-Dygraph.TICK_PLACEMENT[Dygraph.ANNUAL]          = {datefield: Dygraph.DATEFIELD_Y,  step:   1, spacing: 1000 * 86400   * 365.2524}; // 1e3 * 60 * 60 * 24 * 365.2524 * 1
-Dygraph.TICK_PLACEMENT[Dygraph.DECADAL]         = {datefield: Dygraph.DATEFIELD_Y,  step:  10, spacing: 1000 * 864000  * 365.2524}; // 1e3 * 60 * 60 * 24 * 365.2524 * 10
-Dygraph.TICK_PLACEMENT[Dygraph.CENTENNIAL]      = {datefield: Dygraph.DATEFIELD_Y,  step: 100, spacing: 1000 * 8640000 * 365.2524}; // 1e3 * 60 * 60 * 24 * 365.2524 * 100
+var TICK_PLACEMENT = [];
+TICK_PLACEMENT[Granularity.SECONDLY]        = {datefield: DateField.DATEFIELD_SS, step:   1, spacing: 1000 * 1};
+TICK_PLACEMENT[Granularity.TWO_SECONDLY]    = {datefield: DateField.DATEFIELD_SS, step:   2, spacing: 1000 * 2};
+TICK_PLACEMENT[Granularity.FIVE_SECONDLY]   = {datefield: DateField.DATEFIELD_SS, step:   5, spacing: 1000 * 5};
+TICK_PLACEMENT[Granularity.TEN_SECONDLY]    = {datefield: DateField.DATEFIELD_SS, step:  10, spacing: 1000 * 10};
+TICK_PLACEMENT[Granularity.THIRTY_SECONDLY] = {datefield: DateField.DATEFIELD_SS, step:  30, spacing: 1000 * 30};
+TICK_PLACEMENT[Granularity.MINUTELY]        = {datefield: DateField.DATEFIELD_MM, step:   1, spacing: 1000 * 60};
+TICK_PLACEMENT[Granularity.TWO_MINUTELY]    = {datefield: DateField.DATEFIELD_MM, step:   2, spacing: 1000 * 60 * 2};
+TICK_PLACEMENT[Granularity.FIVE_MINUTELY]   = {datefield: DateField.DATEFIELD_MM, step:   5, spacing: 1000 * 60 * 5};
+TICK_PLACEMENT[Granularity.TEN_MINUTELY]    = {datefield: DateField.DATEFIELD_MM, step:  10, spacing: 1000 * 60 * 10};
+TICK_PLACEMENT[Granularity.THIRTY_MINUTELY] = {datefield: DateField.DATEFIELD_MM, step:  30, spacing: 1000 * 60 * 30};
+TICK_PLACEMENT[Granularity.HOURLY]          = {datefield: DateField.DATEFIELD_HH, step:   1, spacing: 1000 * 3600};
+TICK_PLACEMENT[Granularity.TWO_HOURLY]      = {datefield: DateField.DATEFIELD_HH, step:   2, spacing: 1000 * 3600 * 2};
+TICK_PLACEMENT[Granularity.SIX_HOURLY]      = {datefield: DateField.DATEFIELD_HH, step:   6, spacing: 1000 * 3600 * 6};
+TICK_PLACEMENT[Granularity.DAILY]           = {datefield: DateField.DATEFIELD_D,  step:   1, spacing: 1000 * 86400};
+TICK_PLACEMENT[Granularity.TWO_DAILY]       = {datefield: DateField.DATEFIELD_D,  step:   2, spacing: 1000 * 86400 * 2};
+TICK_PLACEMENT[Granularity.WEEKLY]          = {datefield: DateField.DATEFIELD_D,  step:   7, spacing: 1000 * 604800};
+TICK_PLACEMENT[Granularity.MONTHLY]         = {datefield: DateField.DATEFIELD_M,  step:   1, spacing: 1000 * 7200  * 365.2524}; // 1e3 * 60 * 60 * 24 * 365.2524 / 12
+TICK_PLACEMENT[Granularity.QUARTERLY]       = {datefield: DateField.DATEFIELD_M,  step:   3, spacing: 1000 * 21600 * 365.2524}; // 1e3 * 60 * 60 * 24 * 365.2524 / 4
+TICK_PLACEMENT[Granularity.BIANNUAL]        = {datefield: DateField.DATEFIELD_M,  step:   6, spacing: 1000 * 43200 * 365.2524}; // 1e3 * 60 * 60 * 24 * 365.2524 / 2
+TICK_PLACEMENT[Granularity.ANNUAL]          = {datefield: DateField.DATEFIELD_Y,  step:   1, spacing: 1000 * 86400   * 365.2524}; // 1e3 * 60 * 60 * 24 * 365.2524 * 1
+TICK_PLACEMENT[Granularity.DECADAL]         = {datefield: DateField.DATEFIELD_Y,  step:  10, spacing: 1000 * 864000  * 365.2524}; // 1e3 * 60 * 60 * 24 * 365.2524 * 10
+TICK_PLACEMENT[Granularity.CENTENNIAL]      = {datefield: DateField.DATEFIELD_Y,  step: 100, spacing: 1000 * 8640000 * 365.2524}; // 1e3 * 60 * 60 * 24 * 365.2524 * 100
 
 
 /**
@@ -300,7 +304,7 @@ Dygraph.TICK_PLACEMENT[Dygraph.CENTENNIAL]      = {datefield: Dygraph.DATEFIELD_
  * NOTE: this assumes that Dygraph.LOG_SCALE = 10.
  * @type {Array.<number>}
  */
-Dygraph.PREFERRED_LOG_TICK_VALUES = (function() {
+var PREFERRED_LOG_TICK_VALUES = (function() {
   var vals = [];
   for (var power = -39; power <= 39; power++) {
     var range = Math.pow(10, power);
@@ -322,10 +326,10 @@ Dygraph.PREFERRED_LOG_TICK_VALUES = (function() {
  * @return {number} The appropriate axis granularity for this chart. See the
  *     enumeration of possible values in dygraph-tickers.js.
  */
-Dygraph.pickDateTickGranularity = function(a, b, pixels, opts) {
+var pickDateTickGranularity = function(a, b, pixels, opts) {
   var pixels_per_tick = /** @type{number} */(opts('pixelsPerLabel'));
-  for (var i = 0; i < Dygraph.NUM_GRANULARITIES; i++) {
-    var num_ticks = Dygraph.numDateTicks(a, b, i);
+  for (var i = 0; i < Granularity.NUM_GRANULARITIES; i++) {
+    var num_ticks = numDateTicks(a, b, i);
     if (pixels / num_ticks >= pixels_per_tick) {
       return i;
     }
@@ -340,8 +344,8 @@ Dygraph.pickDateTickGranularity = function(a, b, pixels, opts) {
  * @param {number} granularity (one of the granularities enumerated above)
  * @return {number} (Approximate) number of ticks that would result.
  */
-Dygraph.numDateTicks = function(start_time, end_time, granularity) {
-  var spacing = Dygraph.TICK_PLACEMENT[granularity].spacing;
+var numDateTicks = function(start_time, end_time, granularity) {
+  var spacing = TICK_PLACEMENT[granularity].spacing;
   return Math.round(1.0 * (end_time - start_time) / spacing);
 };
 
@@ -352,17 +356,17 @@ Dygraph.numDateTicks = function(start_time, end_time, granularity) {
  * @param {number} granularity (one of the granularities enumerated above)
  * @param {function(string):*} opts Function mapping from option name -&gt; value.
  * @param {Dygraph=} dg
- * @return {!Dygraph.TickList}
+ * @return {!TickList}
  */
-Dygraph.getDateAxis = function(start_time, end_time, granularity, opts, dg) {
+export var getDateAxis = function(start_time, end_time, granularity, opts, dg) {
   var formatter = /** @type{AxisLabelFormatter} */(
       opts("axisLabelFormatter"));
   var utc = opts("labelsUTC");
-  var accessors = utc ? Dygraph.DateAccessorsUTC : Dygraph.DateAccessorsLocal;
+  var accessors = utc ? utils.DateAccessorsUTC : utils.DateAccessorsLocal;
 
-  var datefield = Dygraph.TICK_PLACEMENT[granularity].datefield;
-  var step = Dygraph.TICK_PLACEMENT[granularity].step;
-  var spacing = Dygraph.TICK_PLACEMENT[granularity].spacing;
+  var datefield = TICK_PLACEMENT[granularity].datefield;
+  var step = TICK_PLACEMENT[granularity].step;
+  var spacing = TICK_PLACEMENT[granularity].spacing;
 
   // Choose a nice tick position before the initial instant.
   // Currently, this code deals properly with the existent daily granularities:
@@ -371,24 +375,24 @@ Dygraph.getDateAxis = function(start_time, end_time, granularity, opts, dg) {
   // by setting the start_date_offset to 0.
   var start_date = new Date(start_time);
   var date_array = [];
-  date_array[Dygraph.DATEFIELD_Y]  = accessors.getFullYear(start_date);
-  date_array[Dygraph.DATEFIELD_M]  = accessors.getMonth(start_date);
-  date_array[Dygraph.DATEFIELD_D]  = accessors.getDate(start_date);
-  date_array[Dygraph.DATEFIELD_HH] = accessors.getHours(start_date);
-  date_array[Dygraph.DATEFIELD_MM] = accessors.getMinutes(start_date);
-  date_array[Dygraph.DATEFIELD_SS] = accessors.getSeconds(start_date);
-  date_array[Dygraph.DATEFIELD_MS] = accessors.getMilliseconds(start_date);
+  date_array[DateField.DATEFIELD_Y]  = accessors.getFullYear(start_date);
+  date_array[DateField.DATEFIELD_M]  = accessors.getMonth(start_date);
+  date_array[DateField.DATEFIELD_D]  = accessors.getDate(start_date);
+  date_array[DateField.DATEFIELD_HH] = accessors.getHours(start_date);
+  date_array[DateField.DATEFIELD_MM] = accessors.getMinutes(start_date);
+  date_array[DateField.DATEFIELD_SS] = accessors.getSeconds(start_date);
+  date_array[DateField.DATEFIELD_MS] = accessors.getMilliseconds(start_date);
 
   var start_date_offset = date_array[datefield] % step;
-  if (granularity == Dygraph.WEEKLY) {
+  if (granularity == Granularity.WEEKLY) {
     // This will put the ticks on Sundays.
     start_date_offset = accessors.getDay(start_date);
   }
   
   date_array[datefield] -= start_date_offset;
-  for (var df = datefield + 1; df < Dygraph.NUM_DATEFIELDS; df++) {
+  for (var df = datefield + 1; df < DateField.NUM_DATEFIELDS; df++) {
     // The minimum value is 1 for the day of month, and 0 for all other fields.
-    date_array[df] = (df === Dygraph.DATEFIELD_D) ? 1 : 0;
+    date_array[df] = (df === DateField.DATEFIELD_D) ? 1 : 0;
   }
 
   // Generate the ticks.
@@ -407,7 +411,7 @@ Dygraph.getDateAxis = function(start_time, end_time, granularity, opts, dg) {
   var ticks = [];
   var tick_date = accessors.makeDate.apply(null, date_array);
   var tick_time = tick_date.getTime();
-  if (granularity <= Dygraph.HOURLY) {
+  if (granularity <= Granularity.HOURLY) {
     if (tick_time < start_time) {
       tick_time += spacing;
       tick_date = new Date(tick_time);
@@ -426,7 +430,7 @@ Dygraph.getDateAxis = function(start_time, end_time, granularity, opts, dg) {
       tick_time = tick_date.getTime();
     }
     while (tick_time <= end_time) {
-      if (granularity >= Dygraph.DAILY ||
+      if (granularity >= Granularity.DAILY ||
           accessors.getHours(tick_date) % step === 0) {
         ticks.push({ v: tick_time,
                      label: formatter.call(dg, tick_date, granularity, opts, dg)
@@ -442,15 +446,13 @@ Dygraph.getDateAxis = function(start_time, end_time, granularity, opts, dg) {
 
 // These are set here so that this file can be included after dygraph.js
 // or independently.
-if (Dygraph &&
-    Dygraph.DEFAULT_ATTRS &&
-    Dygraph.DEFAULT_ATTRS['axes'] &&
-    Dygraph.DEFAULT_ATTRS['axes']['x'] &&
-    Dygraph.DEFAULT_ATTRS['axes']['y'] &&
-    Dygraph.DEFAULT_ATTRS['axes']['y2']) {
-  Dygraph.DEFAULT_ATTRS['axes']['x']['ticker'] = Dygraph.dateTicker;
-  Dygraph.DEFAULT_ATTRS['axes']['y']['ticker'] = Dygraph.numericTicks;
-  Dygraph.DEFAULT_ATTRS['axes']['y2']['ticker'] = Dygraph.numericTicks;
-}
-
-})();
+// if (Dygraph &&
+//     Dygraph.DEFAULT_ATTRS &&
+//     Dygraph.DEFAULT_ATTRS['axes'] &&
+//     Dygraph.DEFAULT_ATTRS['axes']['x'] &&
+//     Dygraph.DEFAULT_ATTRS['axes']['y'] &&
+//     Dygraph.DEFAULT_ATTRS['axes']['y2']) {
+//   Dygraph.DEFAULT_ATTRS['axes']['x']['ticker'] = Dygraph.dateTicker;
+//   Dygraph.DEFAULT_ATTRS['axes']['y']['ticker'] = Dygraph.numericTicks;
+//   Dygraph.DEFAULT_ATTRS['axes']['y2']['ticker'] = Dygraph.numericTicks;
+// }
index a960ba7..d16da53 100644 (file)
  * search) and generic DOM-manipulation functions.
  */
 
-(function() {
-
 /*global Dygraph:false, Node:false */
 "use strict";
 
-Dygraph.LOG_SCALE = 10;
-Dygraph.LN_TEN = Math.log(Dygraph.LOG_SCALE);
+import * as DygraphTickers from './dygraph-tickers';
+
+export var LOG_SCALE = 10;
+export var LN_TEN = Math.log(LOG_SCALE);
 
 /**
  * @private
  * @param {number} x
  * @return {number}
  */
-Dygraph.log10 = function(x) {
-  return Math.log(x) / Dygraph.LN_TEN;
+export var log10 = function(x) {
+  return Math.log(x) / LN_TEN;
 };
 
 /** A dotted line stroke pattern. */
-Dygraph.DOTTED_LINE = [2, 2];
+export var DOTTED_LINE = [2, 2];
 /** A dashed line stroke pattern. */
-Dygraph.DASHED_LINE = [7, 3];
+export var DASHED_LINE = [7, 3];
 /** A dot dash stroke pattern. */
-Dygraph.DOT_DASH_LINE = [7, 2, 2, 2];
+export var DOT_DASH_LINE = [7, 2, 2, 2];
+
+// Directions for panning and zooming. Use bit operations when combined
+// values are possible.
+export var HORIZONTAL = 1;
+export var VERTICAL = 2;
 
 /**
  * Return the 2d context for a dygraph canvas.
  *
  * This method is only exposed for the sake of replacing the function in
- * automated tests, e.g.
+ * automated tests.
  *
- * var oldFunc = Dygraph.getContext();
- * Dygraph.getContext = function(canvas) {
- *   var realContext = oldFunc(canvas);
- *   return new Proxy(realContext);
- * };
  * @param {!HTMLCanvasElement} canvas
  * @return {!CanvasRenderingContext2D}
  * @private
  */
-Dygraph.getContext = function(canvas) {
+export var getContext = function(canvas) {
   return /** @type{!CanvasRenderingContext2D}*/(canvas.getContext("2d"));
 };
 
@@ -62,48 +62,21 @@ Dygraph.getContext = function(canvas) {
  *     on the event. The function takes one parameter: the event object.
  * @private
  */
-Dygraph.addEvent = function addEvent(elem, type, fn) {
+export var addEvent = function addEvent(elem, type, fn) {
   elem.addEventListener(type, fn, false);
 };
 
 /**
- * Add an event handler. This event handler is kept until the graph is
- * destroyed with a call to graph.destroy().
- *
- * @param {!Node} elem The element to add the event to.
- * @param {string} type The type of the event, e.g. 'click' or 'mousemove'.
- * @param {function(Event):(boolean|undefined)} fn The function to call
- *     on the event. The function takes one parameter: the event object.
- * @private
- */
-Dygraph.prototype.addAndTrackEvent = function(elem, type, fn) {
-  Dygraph.addEvent(elem, type, fn);
-  this.registeredEvents_.push({ elem : elem, type : type, fn : fn });
-};
-
-/**
  * Remove an event handler.
  * @param {!Node} elem The element to remove the event from.
  * @param {string} type The type of the event, e.g. 'click' or 'mousemove'.
  * @param {function(Event):(boolean|undefined)} fn The function to call
  *     on the event. The function takes one parameter: the event object.
- * @private
  */
-Dygraph.removeEvent = function(elem, type, fn) {
+export function removeEvent(elem, type, fn) {
   elem.removeEventListener(type, fn, false);
 };
 
-Dygraph.prototype.removeTrackedEvents_ = function() {
-  if (this.registeredEvents_) {
-    for (var idx = 0; idx < this.registeredEvents_.length; idx++) {
-      var reg = this.registeredEvents_[idx];
-      Dygraph.removeEvent(reg.elem, reg.type, reg.fn);
-    }
-  }
-
-  this.registeredEvents_ = [];
-};
-
 /**
  * Cancels further processing of an event. This is useful to prevent default
  * browser actions, e.g. highlighting text on a double-click.
@@ -112,7 +85,7 @@ Dygraph.prototype.removeTrackedEvents_ = function() {
  * @param {!Event} e The event whose normal behavior should be canceled.
  * @private
  */
-Dygraph.cancelEvent = function(e) {
+export function cancelEvent(e) {
   e = e ? e : window.event;
   if (e.stopPropagation) {
     e.stopPropagation();
@@ -136,7 +109,7 @@ Dygraph.cancelEvent = function(e) {
  * @return { string } "rgb(r,g,b)" where r, g and b range from 0-255.
  * @private
  */
-Dygraph.hsvToRGB = function (hue, saturation, value) {
+export function hsvToRGB(hue, saturation, value) {
   var red;
   var green;
   var blue;
@@ -173,7 +146,7 @@ Dygraph.hsvToRGB = function (hue, saturation, value) {
  * @return {{x:number,y:number}}
  * @private
  */
-Dygraph.findPos = function(obj) {
+export function findPos(obj) {
   var p = obj.getBoundingClientRect(),
       w = window,
       d = document.documentElement;
@@ -192,7 +165,7 @@ Dygraph.findPos = function(obj) {
  * @return {number}
  * @private
  */
-Dygraph.pageX = function(e) {
+export function pageX(e) {
   return (!e.pageX || e.pageX < 0) ? 0 : e.pageX;
 };
 
@@ -204,7 +177,7 @@ Dygraph.pageX = function(e) {
  * @return {number}
  * @private
  */
-Dygraph.pageY = function(e) {
+export function pageY(e) {
   return (!e.pageY || e.pageY < 0) ? 0 : e.pageY;
 };
 
@@ -215,8 +188,8 @@ Dygraph.pageY = function(e) {
  * @param {!DygraphInteractionContext} context Interaction context object.
  * @return {number} The amount by which the drag has moved to the right.
  */
-Dygraph.dragGetX_ = function(e, context) {
-  return Dygraph.pageX(e) - context.px;
+export function dragGetX_(e, context) {
+  return pageX(e) - context.px;
 };
 
 /**
@@ -226,8 +199,8 @@ Dygraph.dragGetX_ = function(e, context) {
  * @param {!DygraphInteractionContext} context Interaction context object.
  * @return {number} The amount by which the drag has moved down.
  */
-Dygraph.dragGetY_ = function(e, context) {
-  return Dygraph.pageY(e) - context.py;
+export function dragGetY_(e, context) {
+  return pageY(e) - context.py;
 };
 
 /**
@@ -238,7 +211,7 @@ Dygraph.dragGetY_ = function(e, context) {
  * @return {boolean} Whether the number is zero or NaN.
  * @private
  */
-Dygraph.isOK = function(x) {
+export function isOK(x) {
   return !!x && !isNaN(x);
 };
 
@@ -249,7 +222,7 @@ Dygraph.isOK = function(x) {
  * @return {boolean} Whether the point has numeric x and y.
  * @private
  */
-Dygraph.isValidPoint = function(p, opt_allowNaNY) {
+export function isValidPoint(p, opt_allowNaNY) {
   if (!p) return false;  // null or undefined object
   if (p.yval === null) return false;  // missing point
   if (p.x === null || p.x === undefined) return false;
@@ -276,7 +249,7 @@ Dygraph.isValidPoint = function(p, opt_allowNaNY) {
  * @return {string} A string formatted like %g in printf.  The max generated
  *                  string length should be precision + 6 (e.g 1.123e+300).
  */
-Dygraph.floatFormat = function(x, opt_precision) {
+export function floatFormat(x, opt_precision) {
   // Avoid invalid precision values; [1, 21] is the valid range.
   var p = Math.min(Math.max(1, opt_precision || 2), 21);
 
@@ -306,7 +279,7 @@ Dygraph.floatFormat = function(x, opt_precision) {
  * @return {string}
  * @private
  */
-Dygraph.zeropad = function(x) {
+export function zeropad(x) {
   if (x < 10) return "0" + x; else return "" + x;
 };
 
@@ -315,15 +288,15 @@ Dygraph.zeropad = function(x) {
  * day, hour, minute, second and millisecond) according to local time,
  * and factory method to call the Date constructor with an array of arguments.
  */
-Dygraph.DateAccessorsLocal = {
-  getFullYear:     function(d) {return d.getFullYear();},
-  getMonth:        function(d) {return d.getMonth();},
-  getDate:         function(d) {return d.getDate();},
-  getHours:        function(d) {return d.getHours();},
-  getMinutes:      function(d) {return d.getMinutes();},
-  getSeconds:      function(d) {return d.getSeconds();},
-  getMilliseconds: function(d) {return d.getMilliseconds();},
-  getDay:          function(d) {return d.getDay();},
+export var DateAccessorsLocal = {
+  getFullYear:     d => d.getFullYear(),
+  getMonth:        d => d.getMonth(),
+  getDate:         d => d.getDate(),
+  getHours:        d => d.getHours(),
+  getMinutes:      d => d.getMinutes(),
+  getSeconds:      d => d.getSeconds(),
+  getMilliseconds: d => d.getMilliseconds(),
+  getDay:          d => d.getDay(),
   makeDate:        function(y, m, d, hh, mm, ss, ms) {
     return new Date(y, m, d, hh, mm, ss, ms);
   }
@@ -334,15 +307,15 @@ Dygraph.DateAccessorsLocal = {
  * day of month, hour, minute, second and millisecond) according to UTC time,
  * and factory method to call the Date constructor with an array of arguments.
  */
-Dygraph.DateAccessorsUTC = {
-  getFullYear:     function(d) {return d.getUTCFullYear();},
-  getMonth:        function(d) {return d.getUTCMonth();},
-  getDate:         function(d) {return d.getUTCDate();},
-  getHours:        function(d) {return d.getUTCHours();},
-  getMinutes:      function(d) {return d.getUTCMinutes();},
-  getSeconds:      function(d) {return d.getUTCSeconds();},
-  getMilliseconds: function(d) {return d.getUTCMilliseconds();},
-  getDay:          function(d) {return d.getUTCDay();},
+export var DateAccessorsUTC = {
+  getFullYear:     d => d.getUTCFullYear(),
+  getMonth:        d => d.getUTCMonth(),
+  getDate:         d => d.getUTCDate(),
+  getHours:        d => d.getUTCHours(),
+  getMinutes:      d => d.getUTCMinutes(),
+  getSeconds:      d => d.getUTCSeconds(),
+  getMilliseconds: d => d.getUTCMilliseconds(),
+  getDay:          d => d.getUTCDay(),
   makeDate:        function(y, m, d, hh, mm, ss, ms) {
     return new Date(Date.UTC(y, m, d, hh, mm, ss, ms));
   }
@@ -356,7 +329,7 @@ Dygraph.DateAccessorsUTC = {
  * @return {string} A time of the form "HH:MM" or "HH:MM:SS"
  * @private
  */
-Dygraph.hmsString_ = function(hh, mm, ss) {
+export function hmsString_(hh, mm, ss) {
   var zeropad = Dygraph.zeropad;
   var ret = zeropad(hh) + ":" + zeropad(mm);
   if (ss) {
@@ -373,9 +346,8 @@ Dygraph.hmsString_ = function(hh, mm, ss) {
  *     "YYYY/MM/DD", "YYYY/MM/DD HH:MM" or "YYYY/MM/DD HH:MM:SS"
  * @private
  */
-Dygraph.dateString_ = function(time, utc) {
-  var zeropad = Dygraph.zeropad;
-  var accessors = utc ? Dygraph.DateAccessorsUTC : Dygraph.DateAccessorsLocal;
+export function dateString_(time, utc) {
+  var accessors = utc ? DateAccessorsUTC : DateAccessorsLocal;
   var date = new Date(time);
   var y = accessors.getFullYear(date);
   var m = accessors.getMonth(date);
@@ -392,7 +364,7 @@ Dygraph.dateString_ = function(time, utc) {
   var frac = hh * 3600 + mm * 60 + ss;
   var ret = year + "/" + month + "/" + day;
   if (frac) {
-    ret += " " + Dygraph.hmsString_(hh, mm, ss);
+    ret += " " + hmsString_(hh, mm, ss);
   }
   return ret;
 };
@@ -404,7 +376,7 @@ Dygraph.dateString_ = function(time, utc) {
  * @return {number} The rounded number
  * @private
  */
-Dygraph.round_ = function(num, places) {
+export function round_(num, places) {
   var shift = Math.pow(10, places);
   return Math.round(num * shift)/shift;
 };
@@ -422,7 +394,7 @@ Dygraph.round_ = function(num, places) {
  * @return {number} Index of the element, or -1 if it isn't found.
  * @private
  */
-Dygraph.binarySearch = function(val, arry, abs, low, high) {
+export function binarySearch(val, arry, abs, low, high) {
   if (low === null || low === undefined ||
       high === null || high === undefined) {
     low = 0;
@@ -450,7 +422,7 @@ Dygraph.binarySearch = function(val, arry, abs, low, high) {
         return mid;
       }
     }
-    return Dygraph.binarySearch(val, arry, abs, low, mid - 1);
+    return binarySearch(val, arry, abs, low, mid - 1);
   } else if (element < val) {
     if (abs < 0) {
       // Accept if element < val, but also if prior element > val.
@@ -459,7 +431,7 @@ Dygraph.binarySearch = function(val, arry, abs, low, high) {
         return mid;
       }
     }
-    return Dygraph.binarySearch(val, arry, abs, mid + 1, high);
+    return binarySearch(val, arry, abs, mid + 1, high);
   }
   return -1;  // can't actually happen, but makes closure compiler happy
 };
@@ -473,7 +445,7 @@ Dygraph.binarySearch = function(val, arry, abs, low, high) {
  * @return {number} Milliseconds since epoch.
  * @private
  */
-Dygraph.dateParser = function(dateStr) {
+export function dateParser(dateStr) {
   var dateStrSlashed;
   var d;
 
@@ -485,7 +457,7 @@ Dygraph.dateParser = function(dateStr) {
   // Issue: http://code.google.com/p/dygraphs/issues/detail?id=255
   if (dateStr.search("-") == -1 ||
       dateStr.search("T") != -1 || dateStr.search("Z") != -1) {
-    d = Dygraph.dateStrToMillis(dateStr);
+    d = dateStrToMillis(dateStr);
     if (d && !isNaN(d)) return d;
   }
 
@@ -494,16 +466,16 @@ Dygraph.dateParser = function(dateStr) {
     while (dateStrSlashed.search("-") != -1) {
       dateStrSlashed = dateStrSlashed.replace("-", "/");
     }
-    d = Dygraph.dateStrToMillis(dateStrSlashed);
+    d = dateStrToMillis(dateStrSlashed);
   } else if (dateStr.length == 8) {  // e.g. '20090712'
     // TODO(danvk): remove support for this format. It's confusing.
     dateStrSlashed = dateStr.substr(0,4) + "/" + dateStr.substr(4,2) + "/" +
         dateStr.substr(6,2);
-    d = Dygraph.dateStrToMillis(dateStrSlashed);
+    d = dateStrToMillis(dateStrSlashed);
   } else {
     // Any format that Date.parse will accept, e.g. "2009/07/12" or
     // "2009/07/12 12:34:56"
-    d = Dygraph.dateStrToMillis(dateStr);
+    d = dateStrToMillis(dateStr);
   }
 
   if (!d || isNaN(d)) {
@@ -520,7 +492,7 @@ Dygraph.dateParser = function(dateStr) {
  * @return {number} millis since epoch
  * @private
  */
-Dygraph.dateStrToMillis = function(str) {
+export function dateStrToMillis(str) {
   return new Date(str).getTime();
 };
 
@@ -532,7 +504,7 @@ Dygraph.dateStrToMillis = function(str) {
  * @param {!Object} o
  * @return {!Object}
  */
-Dygraph.update = function(self, o) {
+export function update(self, o) {
   if (typeof(o) != 'undefined' && o !== null) {
     for (var k in o) {
       if (o.hasOwnProperty(k)) {
@@ -551,7 +523,7 @@ Dygraph.update = function(self, o) {
  * @return {!Object}
  * @private
  */
-Dygraph.updateDeep = function (self, o) {
+export function updateDeep(self, o) {
   // Taken from http://stackoverflow.com/questions/384286/javascript-isdom-how-do-you-check-if-a-javascript-object-is-a-dom-object
   function isNode(o) {
     return (
@@ -565,7 +537,7 @@ Dygraph.updateDeep = function (self, o) {
       if (o.hasOwnProperty(k)) {
         if (o[k] === null) {
           self[k] = null;
-        } else if (Dygraph.isArrayLike(o[k])) {
+        } else if (isArrayLike(o[k])) {
           self[k] = o[k].slice();
         } else if (isNode(o[k])) {
           // DOM objects are shallowly-copied.
@@ -574,7 +546,7 @@ Dygraph.updateDeep = function (self, o) {
           if (typeof(self[k]) != 'object' || self[k] === null) {
             self[k] = {};
           }
-          Dygraph.updateDeep(self[k], o[k]);
+          updateDeep(self[k], o[k]);
         } else {
           self[k] = o[k];
         }
@@ -589,7 +561,7 @@ Dygraph.updateDeep = function (self, o) {
  * @return {boolean}
  * @private
  */
-Dygraph.isArrayLike = function(o) {
+export function isArrayLike(o) {
   var typ = typeof(o);
   if (
       (typ != 'object' && !(typ == 'function' &&
@@ -608,7 +580,7 @@ Dygraph.isArrayLike = function(o) {
  * @return {boolean}
  * @private
  */
-Dygraph.isDateLike = function (o) {
+export function isDateLike(o) {
   if (typeof(o) != "object" || o === null ||
       typeof(o.getTime) != 'function') {
     return false;
@@ -622,11 +594,11 @@ Dygraph.isDateLike = function (o) {
  * @return {!Array}
  * @private
  */
-Dygraph.clone = function(o) {
+export function clone(o) {
   // TODO(danvk): figure out how MochiKit's version works
   var r = [];
   for (var i = 0; i < o.length; i++) {
-    if (Dygraph.isArrayLike(o[i])) {
+    if (isArrayLike(o[i])) {
       r.push(Dygraph.clone(o[i]));
     } else {
       r.push(o[i]);
@@ -641,7 +613,7 @@ Dygraph.clone = function(o) {
  * @return {!HTMLCanvasElement}
  * @private
  */
-Dygraph.createCanvas = function() {
+export function createCanvas() {
   return document.createElement('canvas');
 };
 
@@ -655,7 +627,7 @@ Dygraph.createCanvas = function() {
  * @return {number} The ratio of the device pixel ratio and the backing store
  * ratio for the specified context.
  */
-Dygraph.getContextPixelRatio = function(context) {
+export function getContextPixelRatio(context) {
   try {
     var devicePixelRatio = window.devicePixelRatio;
     var backingStoreRatio = context.webkitBackingStorePixelRatio ||
@@ -682,7 +654,7 @@ Dygraph.getContextPixelRatio = function(context) {
  * @return {boolean}
  * @private
  */
-Dygraph.isAndroid = function() {
+export function isAndroid() {
   return (/Android/).test(navigator.userAgent);
 };
 
@@ -695,7 +667,7 @@ Dygraph.isAndroid = function() {
  * @param {function(!Array,?):boolean=} predicate
  * @constructor
  */
-Dygraph.Iterator = function(array, start, length, predicate) {
+export function Iterator(array, start, length, predicate) {
   start = start || 0;
   length = length || array.length;
   this.hasNext = true; // Use to identify if there's another element.
@@ -711,7 +683,7 @@ Dygraph.Iterator = function(array, start, length, predicate) {
 /**
  * @return {Object}
  */
-Dygraph.Iterator.prototype.next = function() {
+Iterator.prototype.next = function() {
   if (!this.hasNext) {
     return null;
   }
@@ -750,15 +722,15 @@ Dygraph.Iterator.prototype.next = function() {
  *     returned.  If omitted, all elements are accepted.
  * @private
  */
-Dygraph.createIterator = function(array, start, length, opt_predicate) {
-  return new Dygraph.Iterator(array, start, length, opt_predicate);
+export function createIterator(array, start, length, opt_predicate) {
+  return new Iterator(array, start, length, opt_predicate);
 };
 
 // Shim layer with setTimeout fallback.
 // From: http://paulirish.com/2011/requestanimationframe-for-smart-animating/
 // Should be called with the window context:
 //   Dygraph.requestAnimFrame.call(window, function() {})
-Dygraph.requestAnimFrame = (function() {
+export var requestAnimFrame = (function() {
   return window.requestAnimationFrame       ||
           window.webkitRequestAnimationFrame ||
           window.mozRequestAnimationFrame    ||
@@ -782,7 +754,7 @@ Dygraph.requestAnimFrame = (function() {
  * @param {function()} cleanupFn A function to call after all repeatFn calls.
  * @private
  */
-Dygraph.repeatAndCleanup = function(repeatFn, maxFrames, framePeriodInMillis,
+export function repeatAndCleanup(repeatFn, maxFrames, framePeriodInMillis,
     cleanupFn) {
   var frameNumber = 0;
   var previousFrameNumber;
@@ -883,7 +855,7 @@ var pixelSafeOptions = {
  * @return {boolean} true if the graph needs new points else false.
  * @private
  */
-Dygraph.isPixelChangingOptionList = function(labels, attrs) {
+export function isPixelChangingOptionList(labels, attrs) {
   // Assume that we do not require new points.
   // This will change to true if we actually do need new points.
 
@@ -936,7 +908,7 @@ Dygraph.isPixelChangingOptionList = function(labels, attrs) {
   return false;
 };
 
-Dygraph.Circles = {
+export var Circles = {
   DEFAULT : function(g, name, ctx, canvasx, canvasy, color, radius) {
     ctx.beginPath();
     ctx.fillStyle = color;
@@ -959,7 +931,7 @@ Dygraph.Circles = {
  *
  * Usage:
  * element.addEventListener('mousedown', function() {
- *   var tarper = new Dygraph.IFrameTarp();
+ *   var tarper = new utils.IFrameTarp();
  *   tarper.cover();
  *   var mouseUpHandler = function() {
  *     ...
@@ -971,7 +943,7 @@ Dygraph.Circles = {
  *
  * @constructor
  */
-Dygraph.IFrameTarp = function() {
+export function IFrameTarp() {
   /** @type {Array.<!HTMLDivElement>} */
   this.tarps = [];
 };
@@ -980,7 +952,7 @@ Dygraph.IFrameTarp = function() {
  * Find all the iframes in the document and cover them with high z-index
  * transparent divs.
  */
-Dygraph.IFrameTarp.prototype.cover = function() {
+IFrameTarp.prototype.cover = function() {
   var iframes = document.getElementsByTagName("iframe");
   for (var i = 0; i < iframes.length; i++) {
     var iframe = iframes[i];
@@ -1005,7 +977,7 @@ Dygraph.IFrameTarp.prototype.cover = function() {
 /**
  * Remove all the iframe covers. You should call this in a mouseup handler.
  */
-Dygraph.IFrameTarp.prototype.uncover = function() {
+IFrameTarp.prototype.uncover = function() {
   for (var i = 0; i < this.tarps.length; i++) {
     this.tarps[i].parentNode.removeChild(this.tarps[i]);
   }
@@ -1017,7 +989,7 @@ Dygraph.IFrameTarp.prototype.uncover = function() {
  * @param {string} data
  * @return {?string} the delimiter that was detected (or null on failure).
  */
-Dygraph.detectLineDelimiter = function(data) {
+export function detectLineDelimiter(data) {
   for (var i = 0; i < data.length; i++) {
     var code = data.charAt(i);
     if (code === '\r') {
@@ -1046,7 +1018,7 @@ Dygraph.detectLineDelimiter = function(data) {
  * @return {boolean} Whether containee is inside (or equal to) container.
  * @private
  */
-Dygraph.isNodeContainedBy = function(containee, container) {
+export function isNodeContainedBy(containee, container) {
   if (container === null || containee === null) {
     return false;
   }
@@ -1061,7 +1033,7 @@ Dygraph.isNodeContainedBy = function(containee, container) {
 // This masks some numeric issues in older versions of Firefox,
 // where 1.0/Math.pow(10,2) != Math.pow(10,-2).
 /** @type {function(number,number):number} */
-Dygraph.pow = function(base, exp) {
+export function pow(base, exp) {
   if (exp < 0) {
     return 1.0 / Math.pow(base, -exp);
   }
@@ -1096,7 +1068,7 @@ function parseRGBA(rgbStr) {
  * @return {{r:number,g:number,b:number,a:number?}} Parsed RGB tuple.
  * @private
  */
-Dygraph.toRGB_ = function(colorStr) {
+export function toRGB_(colorStr) {
   // Strategy: First try to parse colorStr directly. This is fast & avoids DOM
   // manipulation.  If that fails (e.g. for named colors like 'red'), then
   // create a hidden DOM element and parse its computed color.
@@ -1118,7 +1090,7 @@ Dygraph.toRGB_ = function(colorStr) {
  *     optimization if you have one.
  * @return {boolean} Whether the browser supports canvas.
  */
-Dygraph.isCanvasSupported = function(opt_canvasElement) {
+export function isCanvasSupported(opt_canvasElement) {
   try {
     var canvas = opt_canvasElement || document.createElement("canvas");
     canvas.getContext("2d");
@@ -1138,7 +1110,7 @@ Dygraph.isCanvasSupported = function(opt_canvasElement) {
  * @param {number=} opt_line_no The line number from which the string comes.
  * @param {string=} opt_line The text of the line from which the string comes.
  */
-Dygraph.parseFloat_ = function(x, opt_line_no, opt_line) {
+export function parseFloat_(x, opt_line_no, opt_line) {
   var val = parseFloat(x);
   if (!isNaN(val)) return val;
 
@@ -1159,4 +1131,149 @@ Dygraph.parseFloat_ = function(x, opt_line_no, opt_line) {
   return null;
 };
 
-})();
+
+// Label constants for the labelsKMB and labelsKMG2 options.
+// (i.e. '100000' -> '100K')
+var KMB_LABELS = [ 'K', 'M', 'B', 'T', 'Q' ];
+var KMG2_BIG_LABELS = [ 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y' ];
+var KMG2_SMALL_LABELS = [ 'm', 'u', 'n', 'p', 'f', 'a', 'z', 'y' ];
+
+/**
+ * @private
+ * Return a string version of a number. This respects the digitsAfterDecimal
+ * and maxNumberWidth options.
+ * @param {number} x The number to be formatted
+ * @param {Dygraph} opts An options view
+ */
+export function numberValueFormatter(x, opts) {
+  var sigFigs = opts('sigFigs');
+
+  if (sigFigs !== null) {
+    // User has opted for a fixed number of significant figures.
+    return floatFormat(x, sigFigs);
+  }
+
+  var digits = opts('digitsAfterDecimal');
+  var maxNumberWidth = opts('maxNumberWidth');
+
+  var kmb = opts('labelsKMB');
+  var kmg2 = opts('labelsKMG2');
+
+  var label;
+
+  // switch to scientific notation if we underflow or overflow fixed display.
+  if (x !== 0.0 &&
+      (Math.abs(x) >= Math.pow(10, maxNumberWidth) ||
+       Math.abs(x) < Math.pow(10, -digits))) {
+    label = x.toExponential(digits);
+  } else {
+    label = '' + round_(x, digits);
+  }
+
+  if (kmb || kmg2) {
+    var k;
+    var k_labels = [];
+    var m_labels = [];
+    if (kmb) {
+      k = 1000;
+      k_labels = KMB_LABELS;
+    }
+    if (kmg2) {
+      if (kmb) console.warn("Setting both labelsKMB and labelsKMG2. Pick one!");
+      k = 1024;
+      k_labels = KMG2_BIG_LABELS;
+      m_labels = KMG2_SMALL_LABELS;
+    }
+
+    var absx = Math.abs(x);
+    var n = pow(k, k_labels.length);
+    for (var j = k_labels.length - 1; j >= 0; j--, n /= k) {
+      if (absx >= n) {
+        label = round_(x / n, digits) + k_labels[j];
+        break;
+      }
+    }
+    if (kmg2) {
+      // TODO(danvk): clean up this logic. Why so different than kmb?
+      var x_parts = String(x.toExponential()).split('e-');
+      if (x_parts.length === 2 && x_parts[1] >= 3 && x_parts[1] <= 24) {
+        if (x_parts[1] % 3 > 0) {
+          label = round_(x_parts[0] /
+              pow(10, (x_parts[1] % 3)),
+              digits);
+        } else {
+          label = Number(x_parts[0]).toFixed(2);
+        }
+        label += m_labels[Math.floor(x_parts[1] / 3) - 1];
+      }
+    }
+  }
+
+  return label;
+};
+
+/**
+ * variant for use as an axisLabelFormatter.
+ * @private
+ */
+export function numberAxisLabelFormatter(x, granularity, opts) {
+  return numberValueFormatter.call(this, x, opts);
+};
+
+/**
+ * @type {!Array.<string>}
+ * @private
+ * @constant
+ */
+var SHORT_MONTH_NAMES_ = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
+
+
+/**
+ * Convert a JS date to a string appropriate to display on an axis that
+ * is displaying values at the stated granularity. This respects the
+ * labelsUTC option.
+ * @param {Date} date The date to format
+ * @param {number} granularity One of the Dygraph granularity constants
+ * @param {Dygraph} opts An options view
+ * @return {string} The date formatted as local time
+ * @private
+ */
+export function dateAxisLabelFormatter(date, granularity, opts) {
+  var utc = opts('labelsUTC');
+  var accessors = utc ? DateAccessorsUTC : DateAccessorsLocal;
+
+  var year = accessors.getFullYear(date),
+      month = accessors.getMonth(date),
+      day = accessors.getDate(date),
+      hours = accessors.getHours(date),
+      mins = accessors.getMinutes(date),
+      secs = accessors.getSeconds(date),
+      millis = accessors.getSeconds(date);
+
+  if (granularity >= DygraphTickers.Granularity.DECADAL) {
+    return '' + year;
+  } else if (granularity >= DygraphTickers.Granularity.MONTHLY) {
+    return SHORT_MONTH_NAMES_[month] + '&#160;' + year;
+  } else {
+    var frac = hours * 3600 + mins * 60 + secs + 1e-3 * millis;
+    if (frac === 0 || granularity >= DygraphTickers.Granularity.DAILY) {
+      // e.g. '21 Jan' (%d%b)
+      return zeropad(day) + '&#160;' + SHORT_MONTH_NAMES_[month];
+    } else {
+      return hmsString_(hours, mins, secs);
+    }
+  }
+};
+// alias in case anyone is referencing the old method.
+// Dygraph.dateAxisFormatter = Dygraph.dateAxisLabelFormatter;
+
+/**
+ * Return a string version of a JS date for a value label. This respects the
+ * labelsUTC option.
+ * @param {Date} date The date to be formatted
+ * @param {Dygraph} opts An options view
+ * @private
+ */
+export function dateValueFormatter(d, opts) {
+  return dateString_(d, opts('labelsUTC'));
+};
index a28e231..396b858 100644 (file)
  */
 
 // For "production" code, this gets set to false by uglifyjs.
-if (typeof(DEBUG) === 'undefined') DEBUG=true;
+// if (typeof(DEBUG) === 'undefined') DEBUG=true;
+var DEBUG = true;
+
+import DygraphLayout from './dygraph-layout';
+import DygraphCanvasRenderer from './dygraph-canvas';
+import DygraphOptions from './dygraph-options';
+import DygraphInteraction from './dygraph-interaction-model';
+import * as DygraphTickers from './dygraph-tickers';
+import * as utils from './dygraph-utils';
+import DEFAULT_ATTRS from './dygraph-default-attrs';
+import DygraphDataHandler from './datahandler/datahandler';
+import DefaultHandler from './datahandler/default';
+
+import AnnotationsPlugin from './plugins/annotations';
+import AxesPlugin from './plugins/axes';
+import ChartLabelsPlugin from './plugins/chart-labels';
+import GridPlugin from './plugins/grid';
+import LegendPlugin from './plugins/legend';
+import RangeSelectorPlugin from './plugins/range-selector';
 
-var Dygraph = (function() {
 /*global DygraphLayout:false, DygraphCanvasRenderer:false, DygraphOptions:false, G_vmlCanvasManager:false,ActiveXObject:false */
 "use strict";
 
@@ -80,153 +97,6 @@ Dygraph.DEFAULT_HEIGHT = 320;
 Dygraph.ANIMATION_STEPS = 12;
 Dygraph.ANIMATION_DURATION = 200;
 
-// Label constants for the labelsKMB and labelsKMG2 options.
-// (i.e. '100000' -> '100K')
-Dygraph.KMB_LABELS = [ 'K', 'M', 'B', 'T', 'Q' ];
-Dygraph.KMG2_BIG_LABELS = [ 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y' ];
-Dygraph.KMG2_SMALL_LABELS = [ 'm', 'u', 'n', 'p', 'f', 'a', 'z', 'y' ];
-
-// These are defined before DEFAULT_ATTRS so that it can refer to them.
-/**
- * @private
- * Return a string version of a number. This respects the digitsAfterDecimal
- * and maxNumberWidth options.
- * @param {number} x The number to be formatted
- * @param {Dygraph} opts An options view
- */
-Dygraph.numberValueFormatter = function(x, opts) {
-  var sigFigs = opts('sigFigs');
-
-  if (sigFigs !== null) {
-    // User has opted for a fixed number of significant figures.
-    return Dygraph.floatFormat(x, sigFigs);
-  }
-
-  var digits = opts('digitsAfterDecimal');
-  var maxNumberWidth = opts('maxNumberWidth');
-
-  var kmb = opts('labelsKMB');
-  var kmg2 = opts('labelsKMG2');
-
-  var label;
-
-  // switch to scientific notation if we underflow or overflow fixed display.
-  if (x !== 0.0 &&
-      (Math.abs(x) >= Math.pow(10, maxNumberWidth) ||
-       Math.abs(x) < Math.pow(10, -digits))) {
-    label = x.toExponential(digits);
-  } else {
-    label = '' + Dygraph.round_(x, digits);
-  }
-
-  if (kmb || kmg2) {
-    var k;
-    var k_labels = [];
-    var m_labels = [];
-    if (kmb) {
-      k = 1000;
-      k_labels = Dygraph.KMB_LABELS;
-    }
-    if (kmg2) {
-      if (kmb) console.warn("Setting both labelsKMB and labelsKMG2. Pick one!");
-      k = 1024;
-      k_labels = Dygraph.KMG2_BIG_LABELS;
-      m_labels = Dygraph.KMG2_SMALL_LABELS;
-    }
-
-    var absx = Math.abs(x);
-    var n = Dygraph.pow(k, k_labels.length);
-    for (var j = k_labels.length - 1; j >= 0; j--, n /= k) {
-      if (absx >= n) {
-        label = Dygraph.round_(x / n, digits) + k_labels[j];
-        break;
-      }
-    }
-    if (kmg2) {
-      // TODO(danvk): clean up this logic. Why so different than kmb?
-      var x_parts = String(x.toExponential()).split('e-');
-      if (x_parts.length === 2 && x_parts[1] >= 3 && x_parts[1] <= 24) {
-        if (x_parts[1] % 3 > 0) {
-          label = Dygraph.round_(x_parts[0] /
-              Dygraph.pow(10, (x_parts[1] % 3)),
-              digits);
-        } else {
-          label = Number(x_parts[0]).toFixed(2);
-        }
-        label += m_labels[Math.floor(x_parts[1] / 3) - 1];
-      }
-    }
-  }
-
-  return label;
-};
-
-/**
- * variant for use as an axisLabelFormatter.
- * @private
- */
-Dygraph.numberAxisLabelFormatter = function(x, granularity, opts) {
-  return Dygraph.numberValueFormatter.call(this, x, opts);
-};
-
-/**
- * @type {!Array.<string>}
- * @private
- * @constant
- */
-Dygraph.SHORT_MONTH_NAMES_ = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
-
-
-/**
- * Convert a JS date to a string appropriate to display on an axis that
- * is displaying values at the stated granularity. This respects the
- * labelsUTC option.
- * @param {Date} date The date to format
- * @param {number} granularity One of the Dygraph granularity constants
- * @param {Dygraph} opts An options view
- * @return {string} The date formatted as local time
- * @private
- */
-Dygraph.dateAxisLabelFormatter = function(date, granularity, opts) {
-  var utc = opts('labelsUTC');
-  var accessors = utc ? Dygraph.DateAccessorsUTC : Dygraph.DateAccessorsLocal;
-
-  var year = accessors.getFullYear(date),
-      month = accessors.getMonth(date),
-      day = accessors.getDate(date),
-      hours = accessors.getHours(date),
-      mins = accessors.getMinutes(date),
-      secs = accessors.getSeconds(date),
-      millis = accessors.getSeconds(date);
-
-  if (granularity >= Dygraph.DECADAL) {
-    return '' + year;
-  } else if (granularity >= Dygraph.MONTHLY) {
-    return Dygraph.SHORT_MONTH_NAMES_[month] + '&#160;' + year;
-  } else {
-    var frac = hours * 3600 + mins * 60 + secs + 1e-3 * millis;
-    if (frac === 0 || granularity >= Dygraph.DAILY) {
-      // e.g. '21 Jan' (%d%b)
-      return Dygraph.zeropad(day) + '&#160;' + Dygraph.SHORT_MONTH_NAMES_[month];
-    } else {
-      return Dygraph.hmsString_(hours, mins, secs);
-    }
-  }
-};
-// alias in case anyone is referencing the old method.
-Dygraph.dateAxisFormatter = Dygraph.dateAxisLabelFormatter;
-
-/**
- * Return a string version of a JS date for a value label. This respects the
- * labelsUTC option.
- * @param {Date} date The date to be formatted
- * @param {Dygraph} opts An options view
- * @private
- */
-Dygraph.dateValueFormatter = function(d, opts) {
-  return Dygraph.dateString_(d, opts('labelsUTC'));
-};
-
 /**
  * Standard plotters. These may be used by clients.
  * Available plotters are:
@@ -240,143 +110,6 @@ Dygraph.dateValueFormatter = function(d, opts) {
 Dygraph.Plotters = DygraphCanvasRenderer._Plotters;
 
 
-// Default attribute values.
-Dygraph.DEFAULT_ATTRS = {
-  highlightCircleSize: 3,
-  highlightSeriesOpts: null,
-  highlightSeriesBackgroundAlpha: 0.5,
-
-  labelsDivWidth: 250,
-  labelsDivStyles: {
-    // TODO(danvk): move defaults from createStatusMessage_ here.
-  },
-  labelsSeparateLines: false,
-  labelsShowZeroValues: true,
-  labelsKMB: false,
-  labelsKMG2: false,
-  showLabelsOnHighlight: true,
-
-  digitsAfterDecimal: 2,
-  maxNumberWidth: 6,
-  sigFigs: null,
-
-  strokeWidth: 1.0,
-  strokeBorderWidth: 0,
-  strokeBorderColor: "white",
-
-  axisTickSize: 3,
-  axisLabelFontSize: 14,
-  rightGap: 5,
-
-  showRoller: false,
-  xValueParser: Dygraph.dateParser,
-
-  delimiter: ',',
-
-  sigma: 2.0,
-  errorBars: false,
-  fractions: false,
-  wilsonInterval: true,  // only relevant if fractions is true
-  customBars: false,
-  fillGraph: false,
-  fillAlpha: 0.15,
-  connectSeparatedPoints: false,
-
-  stackedGraph: false,
-  stackedGraphNaNFill: 'all',
-  hideOverlayOnMouseOut: true,
-
-  legend: 'onmouseover',
-  stepPlot: false,
-  avoidMinZero: false,
-  xRangePad: 0,
-  yRangePad: null,
-  drawAxesAtZero: false,
-
-  // Sizes of the various chart labels.
-  titleHeight: 28,
-  xLabelHeight: 18,
-  yLabelWidth: 18,
-
-  axisLineColor: "black",
-  axisLineWidth: 0.3,
-  gridLineWidth: 0.3,
-  axisLabelColor: "black",
-  axisLabelWidth: 50,
-  gridLineColor: "rgb(128,128,128)",
-
-  interactionModel: null,  // will be set to Dygraph.Interaction.defaultModel
-  animatedZooms: false,  // (for now)
-
-  // Range selector options
-  showRangeSelector: false,
-  rangeSelectorHeight: 40,
-  rangeSelectorPlotStrokeColor: "#808FAB",
-  rangeSelectorPlotFillGradientColor: "white",
-  rangeSelectorPlotFillColor: "#A7B1C4",
-  rangeSelectorBackgroundStrokeColor: "gray",
-  rangeSelectorBackgroundLineWidth: 1,
-  rangeSelectorPlotLineWidth:1.5,
-  rangeSelectorForegroundStrokeColor: "black",
-  rangeSelectorForegroundLineWidth: 1,
-  rangeSelectorAlpha: 0.6,
-  showInRangeSelector: null,
-
-  // The ordering here ensures that central lines always appear above any
-  // fill bars/error bars.
-  plotter: [
-    Dygraph.Plotters.fillPlotter,
-    Dygraph.Plotters.errorPlotter,
-    Dygraph.Plotters.linePlotter
-  ],
-
-  plugins: [ ],
-
-  // per-axis options
-  axes: {
-    x: {
-      pixelsPerLabel: 70,
-      axisLabelWidth: 60,
-      axisLabelFormatter: Dygraph.dateAxisLabelFormatter,
-      valueFormatter: Dygraph.dateValueFormatter,
-      drawGrid: true,
-      drawAxis: true,
-      independentTicks: true,
-      ticker: null  // will be set in dygraph-tickers.js
-    },
-    y: {
-      axisLabelWidth: 50,
-      pixelsPerLabel: 30,
-      valueFormatter: Dygraph.numberValueFormatter,
-      axisLabelFormatter: Dygraph.numberAxisLabelFormatter,
-      drawGrid: true,
-      drawAxis: true,
-      independentTicks: true,
-      ticker: null  // will be set in dygraph-tickers.js
-    },
-    y2: {
-      axisLabelWidth: 50,
-      pixelsPerLabel: 30,
-      valueFormatter: Dygraph.numberValueFormatter,
-      axisLabelFormatter: Dygraph.numberAxisLabelFormatter,
-      drawAxis: true,  // only applies when there are two axes of data.
-      drawGrid: false,
-      independentTicks: false,
-      ticker: null  // will be set in dygraph-tickers.js
-    }
-  }
-};
-
-// Directions for panning and zooming. Use bit operations when combined
-// values are possible.
-Dygraph.HORIZONTAL = 1;
-Dygraph.VERTICAL = 2;
-
-// Installed plugins, in order of precedence (most-general to most-specific).
-// Plugins are installed after they are defined, in plugins/install.js.
-Dygraph.PLUGINS = [
-];
-
 // Used for initializing annotation CSS rules only once.
 Dygraph.addedAnnotationCSS = false;
 
@@ -466,11 +199,11 @@ Dygraph.prototype.__init__ = function(div, file, attrs) {
   // user_attrs_ and then computed attrs_. This way Dygraphs can set intelligent
   // defaults without overriding behavior that the user specifically asks for.
   this.user_attrs_ = {};
-  Dygraph.update(this.user_attrs_, attrs);
+  utils.update(this.user_attrs_, attrs);
 
   // This sequence ensures that Dygraph.DEFAULT_ATTRS is never modified.
   this.attrs_ = {};
-  Dygraph.updateDeep(this.attrs_, Dygraph.DEFAULT_ATTRS);
+  utils.updateDeep(this.attrs_, DEFAULT_ATTRS);
 
   this.boundaryIds_ = [];
   this.setIndexByName_ = {};
@@ -560,7 +293,7 @@ Dygraph.prototype.cascadeEvents_ = function(name, extra_props) {
       e.propagationStopped = true;
     }
   };
-  Dygraph.update(e, extra_props);
+  utils.update(e, extra_props);
 
   var callback_plugin_pairs = this.eventListeners_[name];
   if (callback_plugin_pairs) {
@@ -629,16 +362,16 @@ Dygraph.prototype.toString = function() {
  * @return { ... } The value of the option.
  */
 Dygraph.prototype.attr_ = function(name, seriesName) {
-  if (DEBUG) {
-    if (typeof(Dygraph.OPTIONS_REFERENCE) === 'undefined') {
-      console.error('Must include options reference JS for testing');
-    } else if (!Dygraph.OPTIONS_REFERENCE.hasOwnProperty(name)) {
-      console.error('Dygraphs is using property ' + name + ', which has no ' +
-                    'entry in the Dygraphs.OPTIONS_REFERENCE listing.');
-      // Only log this error once.
-      Dygraph.OPTIONS_REFERENCE[name] = true;
-    }
-  }
+  // if (DEBUG) {
+  //   if (typeof(Dygraph.OPTIONS_REFERENCE) === 'undefined') {
+  //     console.error('Must include options reference JS for testing');
+  //   } else if (!Dygraph.OPTIONS_REFERENCE.hasOwnProperty(name)) {
+  //     console.error('Dygraphs is using property ' + name + ', which has no ' +
+  //                   'entry in the Dygraphs.OPTIONS_REFERENCE listing.');
+  //     // Only log this error once.
+  //     Dygraph.OPTIONS_REFERENCE[name] = true;
+  //   }
+  // }
   return seriesName ? this.attributes_.getForSeries(name, seriesName) : this.attributes_.get(name);
 };
 
@@ -1098,14 +831,14 @@ Dygraph.prototype.createInterface_ = function() {
   enclosing.appendChild(this.graphDiv);
 
   // Create the canvas for interactive parts of the chart.
-  this.canvas_ = Dygraph.createCanvas();
+  this.canvas_ = utils.createCanvas();
   this.canvas_.style.position = "absolute";
 
   // ... and for static parts of the chart.
   this.hidden_ = this.createPlotKitCanvas_(this.canvas_);
 
-  this.canvas_ctx_ = Dygraph.getContext(this.canvas_);
-  this.hidden_ctx_ = Dygraph.getContext(this.hidden_);
+  this.canvas_ctx_ = utils.getContext(this.canvas_);
+  this.hidden_ctx_ = utils.getContext(this.hidden_);
 
   this.resizeElements_();
 
@@ -1129,8 +862,8 @@ Dygraph.prototype.createInterface_ = function() {
     // 2. e.relatedTarget is outside the chart
     var target = e.target || e.fromElement;
     var relatedTarget = e.relatedTarget || e.toElement;
-    if (Dygraph.isNodeContainedBy(target, dygraph.graphDiv) &&
-        !Dygraph.isNodeContainedBy(relatedTarget, dygraph.graphDiv)) {
+    if (utils.isNodeContainedBy(target, dygraph.graphDiv) &&
+        !utils.isNodeContainedBy(relatedTarget, dygraph.graphDiv)) {
       dygraph.mouseOut_(e);
     }
   };
@@ -1155,7 +888,7 @@ Dygraph.prototype.resizeElements_ = function() {
   this.graphDiv.style.width = this.width_ + "px";
   this.graphDiv.style.height = this.height_ + "px";
 
-  var canvasScale = Dygraph.getContextPixelRatio(this.canvas_ctx_);
+  var canvasScale = utils.getContextPixelRatio(this.canvas_ctx_);
   this.canvas_.width = this.width_ * canvasScale;
   this.canvas_.height = this.height_ * canvasScale;
   this.canvas_.style.width = this.width_ + "px";    // for IE
@@ -1164,7 +897,7 @@ Dygraph.prototype.resizeElements_ = function() {
     this.canvas_ctx_.scale(canvasScale, canvasScale);
   }
 
-  var hiddenScale = Dygraph.getContextPixelRatio(this.hidden_ctx_);
+  var hiddenScale = utils.getContextPixelRatio(this.hidden_ctx_);
   this.hidden_.width = this.width_ * hiddenScale;
   this.hidden_.height = this.height_ * hiddenScale;
   this.hidden_.style.width = this.width_ + "px";    // for IE
@@ -1230,7 +963,7 @@ Dygraph.prototype.destroy = function() {
  * @private
  */
 Dygraph.prototype.createPlotKitCanvas_ = function(canvas) {
-  var h = Dygraph.createCanvas();
+  var h = utils.createCanvas();
   h.style.position = "absolute";
   // TODO(danvk): h should be offset from canvas. canvas needs to include
   // some extra area to make it easier to zoom in on the far left and far
@@ -1412,7 +1145,7 @@ Dygraph.prototype.createDragInterface_ = function() {
 
     // We cover iframes during mouse interactions. See comments in
     // dygraph-utils.js for more info on why this is a good idea.
-    tarp: new Dygraph.IFrameTarp(),
+    tarp: new utils.IFrameTarp(),
 
     // contextB is the same thing as this context object but renamed.
     initializeMouseDown: function(event, g, contextB) {
@@ -1424,11 +1157,11 @@ Dygraph.prototype.createDragInterface_ = function() {
         event.cancelBubble = true;
       }
 
-      var canvasPos = Dygraph.findPos(g.canvas_);
+      var canvasPos = utils.findPos(g.canvas_);
       contextB.px = canvasPos.x;
       contextB.py = canvasPos.y;
-      contextB.dragStartX = Dygraph.dragGetX_(event, contextB);
-      contextB.dragStartY = Dygraph.dragGetY_(event, contextB);
+      contextB.dragStartX = utils.dragGetX_(event, contextB);
+      contextB.dragStartY = utils.dragGetY_(event, contextB);
       contextB.cancelNextDblclick = false;
       contextB.tarp.cover();
     },
@@ -1490,7 +1223,7 @@ Dygraph.prototype.createDragInterface_ = function() {
  * dots.
  *
  * @param {number} direction the direction of the zoom rectangle. Acceptable
- *     values are Dygraph.HORIZONTAL and Dygraph.VERTICAL.
+ *     values are utils.HORIZONTAL and utils.VERTICAL.
  * @param {number} startX The X position where the drag started, in canvas
  *     coordinates.
  * @param {number} endX The current X position of the drag, in canvas coords.
@@ -1511,22 +1244,22 @@ Dygraph.prototype.drawZoomRect_ = function(direction, startX, endX, startY,
   var ctx = this.canvas_ctx_;
 
   // Clean up from the previous rect if necessary
-  if (prevDirection == Dygraph.HORIZONTAL) {
+  if (prevDirection == utils.HORIZONTAL) {
     ctx.clearRect(Math.min(startX, prevEndX), this.layout_.getPlotArea().y,
                   Math.abs(startX - prevEndX), this.layout_.getPlotArea().h);
-  } else if (prevDirection == Dygraph.VERTICAL) {
+  } else if (prevDirection == utils.VERTICAL) {
     ctx.clearRect(this.layout_.getPlotArea().x, Math.min(startY, prevEndY),
                   this.layout_.getPlotArea().w, Math.abs(startY - prevEndY));
   }
 
   // Draw a light-grey rectangle to show the new viewing area
-  if (direction == Dygraph.HORIZONTAL) {
+  if (direction == utils.HORIZONTAL) {
     if (endX && startX) {
       ctx.fillStyle = "rgba(128,128,128,0.33)";
       ctx.fillRect(Math.min(startX, endX), this.layout_.getPlotArea().y,
                    Math.abs(endX - startX), this.layout_.getPlotArea().h);
     }
-  } else if (direction == Dygraph.VERTICAL) {
+  } else if (direction == utils.VERTICAL) {
     if (endY && startY) {
       ctx.fillStyle = "rgba(128,128,128,0.33)";
       ctx.fillRect(this.layout_.getPlotArea().x, Math.min(startY, endY),
@@ -1755,7 +1488,7 @@ Dygraph.prototype.doAnimatedZoom = function(oldXRange, newXRange, oldYRanges, ne
   }
 
   var that = this;
-  Dygraph.repeatAndCleanup(function(step) {
+  utils.repeatAndCleanup(function(step) {
     if (valueRanges.length) {
       for (var i = 0; i < that.axes_.length; i++) {
         var w = valueRanges[step][i];
@@ -1787,9 +1520,9 @@ Dygraph.prototype.eventToDomCoords = function(event) {
   if (event.offsetX && event.offsetY) {
     return [ event.offsetX, event.offsetY ];
   } else {
-    var eventElementPos = Dygraph.findPos(this.mouseEventElement_);
-    var canvasx = Dygraph.pageX(event) - eventElementPos.x;
-    var canvasy = Dygraph.pageY(event) - eventElementPos.y;
+    var eventElementPos = utils.findPos(this.mouseEventElement_);
+    var canvasx = utils.pageX(event) - eventElementPos.x;
+    var canvasy = utils.pageY(event) - eventElementPos.y;
     return [canvasx, canvasy];
   }
 };
@@ -1809,7 +1542,7 @@ Dygraph.prototype.findClosestRow = function(domX) {
     var len = points.length;
     for (var j = 0; j < len; j++) {
       var point = points[j];
-      if (!Dygraph.isValidPoint(point, true)) continue;
+      if (!utils.isValidPoint(point, true)) continue;
       var dist = Math.abs(point.canvasx - domX);
       if (dist < minDistX) {
         minDistX = dist;
@@ -2001,7 +1734,7 @@ Dygraph.prototype.animateSelection_ = function(direction) {
       that.clearSelection();
     }
   };
-  Dygraph.repeatAndCleanup(
+  utils.repeatAndCleanup(
     function(n) {
       // ignore simultaneous animations
       if (that.animateId != thisId) return;
@@ -2075,13 +1808,13 @@ Dygraph.prototype.updateSelection_ = function(opt_animFraction) {
     ctx.save();
     for (i = 0; i < this.selPoints_.length; i++) {
       var pt = this.selPoints_[i];
-      if (!Dygraph.isOK(pt.canvasy)) continue;
+      if (!utils.isOK(pt.canvasy)) continue;
 
       var circleSize = this.getNumericOption('highlightCircleSize', pt.name);
       var callback = this.getFunctionOption("drawHighlightPointCallback", pt.name);
       var color = this.plotter_.colors[pt.name];
       if (!callback) {
-        callback = Dygraph.Circles.DEFAULT;
+        callback = utils.Circles.DEFAULT;
       }
       ctx.lineWidth = this.getNumericOption('strokeWidth', pt.name);
       ctx.strokeStyle = color;
@@ -2281,16 +2014,16 @@ Dygraph.prototype.getHandlerClass_ = function() {
     handlerClass =  this.attr_('dataHandler');
   } else if (this.fractions_) {
     if (this.getBooleanOption('errorBars')) {
-      handlerClass = Dygraph.DataHandlers.FractionsBarsHandler;
+      handlerClass = DygraphDataHandlers.FractionsBarsHandler;
     } else {
-      handlerClass = Dygraph.DataHandlers.DefaultFractionHandler;
+      handlerClass = DygraphDataHandlers.DefaultFractionHandler;
     }
   } else if (this.getBooleanOption('customBars')) {
-    handlerClass = Dygraph.DataHandlers.CustomBarsHandler;
+    handlerClass = DygraphDataHandlers.CustomBarsHandler;
   } else if (this.getBooleanOption('errorBars')) {
-    handlerClass = Dygraph.DataHandlers.ErrorBarsHandler;
+    handlerClass = DygraphDataHandlers.ErrorBarsHandler;
   } else {
-    handlerClass = Dygraph.DataHandlers.DefaultHandler;
+    handlerClass = DefaultHandler;
   }
   return handlerClass;
 };
@@ -2712,7 +2445,7 @@ Dygraph.prototype.computeYAxes_ = function() {
   for (axis = 0; axis < this.attributes_.numAxes(); axis++) {
     // Add a new axis, making a copy of its per-axis options.
     opts = { g : this };
-    Dygraph.update(opts, this.attributes_.axisOptions(axis));
+    utils.update(opts, this.attributes_.axisOptions(axis));
     this.axes_[axis] = opts;
   }
 
@@ -2979,17 +2712,17 @@ Dygraph.prototype.detectTypeFromString_ = function(str) {
 
 Dygraph.prototype.setXAxisOptions_ = function(isDate) {
   if (isDate) {
-    this.attrs_.xValueParser = Dygraph.dateParser;
-    this.attrs_.axes.x.valueFormatter = Dygraph.dateValueFormatter;
-    this.attrs_.axes.x.ticker = Dygraph.dateTicker;
-    this.attrs_.axes.x.axisLabelFormatter = Dygraph.dateAxisLabelFormatter;
+    this.attrs_.xValueParser = utils.dateParser;
+    this.attrs_.axes.x.valueFormatter = utils.dateValueFormatter;
+    this.attrs_.axes.x.ticker = DygraphTickers.dateTicker;
+    this.attrs_.axes.x.axisLabelFormatter = utils.dateAxisLabelFormatter;
   } else {
     /** @private (shut up, jsdoc!) */
     this.attrs_.xValueParser = function(x) { return parseFloat(x); };
     // TODO(danvk): use Dygraph.numberValueFormatter here?
     /** @private (shut up, jsdoc!) */
     this.attrs_.axes.x.valueFormatter = function(x) { return x; };
-    this.attrs_.axes.x.ticker = Dygraph.numericTicks;
+    this.attrs_.axes.x.ticker = DygraphTickers.numericTicks;
     this.attrs_.axes.x.axisLabelFormatter = this.attrs_.axes.x.valueFormatter;
   }
 };
@@ -3013,7 +2746,7 @@ Dygraph.prototype.setXAxisOptions_ = function(isDate) {
  */
 Dygraph.prototype.parseCSV_ = function(data) {
   var ret = [];
-  var line_delimiter = Dygraph.detectLineDelimiter(data);
+  var line_delimiter = utils.detectLineDelimiter(data);
   var lines = data.split(line_delimiter || "\n");
   var vals, j;
 
@@ -3063,8 +2796,8 @@ Dygraph.prototype.parseCSV_ = function(data) {
                         (1 + i) + " ('" + line + "') which is not of this form.");
           fields[j] = [0, 0];
         } else {
-          fields[j] = [Dygraph.parseFloat_(vals[0], i, line),
-                       Dygraph.parseFloat_(vals[1], i, line)];
+          fields[j] = [utils.parseFloat_(vals[0], i, line),
+                       utils.parseFloat_(vals[1], i, line)];
         }
       }
     } else if (this.getBooleanOption("errorBars")) {
@@ -3075,8 +2808,8 @@ Dygraph.prototype.parseCSV_ = function(data) {
                       (inFields.length - 1) + "): '" + line + "'");
       }
       for (j = 1; j < inFields.length; j += 2) {
-        fields[(j + 1) / 2] = [Dygraph.parseFloat_(inFields[j], i, line),
-                               Dygraph.parseFloat_(inFields[j + 1], i, line)];
+        fields[(j + 1) / 2] = [utils.parseFloat_(inFields[j], i, line),
+                               utils.parseFloat_(inFields[j + 1], i, line)];
       }
     } else if (this.getBooleanOption("customBars")) {
       // Bars are a low;center;high tuple
@@ -3087,9 +2820,9 @@ Dygraph.prototype.parseCSV_ = function(data) {
         } else {
           vals = val.split(";");
           if (vals.length == 3) {
-            fields[j] = [ Dygraph.parseFloat_(vals[0], i, line),
-                          Dygraph.parseFloat_(vals[1], i, line),
-                          Dygraph.parseFloat_(vals[2], i, line) ];
+            fields[j] = [ utils.parseFloat_(vals[0], i, line),
+                          utils.parseFloat_(vals[1], i, line),
+                          utils.parseFloat_(vals[2], i, line) ];
           } else {
             console.warn('When using customBars, values must be either blank ' +
                          'or "low;center;high" tuples (got "' + val +
@@ -3100,7 +2833,7 @@ Dygraph.prototype.parseCSV_ = function(data) {
     } else {
       // Values are just numbers
       for (j = 1; j < inFields.length; j++) {
-        fields[j] = Dygraph.parseFloat_(inFields[j], i, line);
+        fields[j] = utils.parseFloat_(inFields[j], i, line);
       }
     }
     if (ret.length > 0 && fields[0] < ret[ret.length - 1][0]) {
@@ -3178,14 +2911,14 @@ Dygraph.prototype.parseArray_ = function(data) {
     }
   }
 
-  if (Dygraph.isDateLike(data[0][0])) {
+  if (utils.isDateLike(data[0][0])) {
     // Some intelligent defaults for a date x-axis.
-    this.attrs_.axes.x.valueFormatter = Dygraph.dateValueFormatter;
-    this.attrs_.axes.x.ticker = Dygraph.dateTicker;
-    this.attrs_.axes.x.axisLabelFormatter = Dygraph.dateAxisLabelFormatter;
+    this.attrs_.axes.x.valueFormatter = utils.dateValueFormatter;
+    this.attrs_.axes.x.ticker = DygraphTickers.dateTicker;
+    this.attrs_.axes.x.axisLabelFormatter = utils.dateAxisLabelFormatter;
 
     // Assume they're all dates.
-    var parsedData = Dygraph.clone(data);
+    var parsedData = utils.clone(data);
     for (i = 0; i < data.length; i++) {
       if (parsedData[i].length === 0) {
         console.error("Row " + (1 + i) + " of data is empty");
@@ -3204,8 +2937,8 @@ Dygraph.prototype.parseArray_ = function(data) {
     // Some intelligent defaults for a numeric x-axis.
     /** @private (shut up, jsdoc!) */
     this.attrs_.axes.x.valueFormatter = function(x) { return x; };
-    this.attrs_.axes.x.ticker = Dygraph.numericTicks;
-    this.attrs_.axes.x.axisLabelFormatter = Dygraph.numberAxisLabelFormatter;
+    this.attrs_.axes.x.ticker = DygraphTickers.numericTicks;
+    this.attrs_.axes.x.axisLabelFormatter = utils.numberAxisLabelFormatter;
     return data;
   }
 };
@@ -3238,14 +2971,14 @@ Dygraph.prototype.parseDataTable_ = function(data) {
 
   var indepType = data.getColumnType(0);
   if (indepType == 'date' || indepType == 'datetime') {
-    this.attrs_.xValueParser = Dygraph.dateParser;
-    this.attrs_.axes.x.valueFormatter = Dygraph.dateValueFormatter;
-    this.attrs_.axes.x.ticker = Dygraph.dateTicker;
-    this.attrs_.axes.x.axisLabelFormatter = Dygraph.dateAxisLabelFormatter;
+    this.attrs_.xValueParser = utils.dateParser;
+    this.attrs_.axes.x.valueFormatter = utils.dateValueFormatter;
+    this.attrs_.axes.x.ticker = DygraphTickers.dateTicker;
+    this.attrs_.axes.x.axisLabelFormatter = utils.dateAxisLabelFormatter;
   } else if (indepType == 'number') {
     this.attrs_.xValueParser = function(x) { return parseFloat(x); };
     this.attrs_.axes.x.valueFormatter = function(x) { return x; };
-    this.attrs_.axes.x.ticker = Dygraph.numericTicks;
+    this.attrs_.axes.x.ticker = DygraphTickers.numericTicks;
     this.attrs_.axes.x.axisLabelFormatter = this.attrs_.axes.x.valueFormatter;
   } else {
     throw new Error(
@@ -3376,7 +3109,7 @@ Dygraph.prototype.start_ = function() {
     data = data();
   }
 
-  if (Dygraph.isArrayLike(data)) {
+  if (utils.isArrayLike(data)) {
     this.rawData_ = this.parseArray_(data);
     this.cascadeDataDidUpdateEvent_();
     this.predraw_();
@@ -3388,7 +3121,7 @@ Dygraph.prototype.start_ = function() {
     this.predraw_();
   } else if (typeof data == 'string') {
     // Heuristic: a newline means it's CSV data. Otherwise it's an URL.
-    var line_delimiter = Dygraph.detectLineDelimiter(data);
+    var line_delimiter = utils.detectLineDelimiter(data);
     if (line_delimiter) {
       this.loadedEvent_(data);
     } else {
@@ -3467,9 +3200,9 @@ Dygraph.prototype.updateOptions = function(input_attrs, block_redraw) {
   // highlightCircleSize
 
   // Check if this set options will require new points.
-  var requiresNewPoints = Dygraph.isPixelChangingOptionList(this.attr_("labels"), attrs);
+  var requiresNewPoints = utils.isPixelChangingOptionList(this.attr_("labels"), attrs);
 
-  Dygraph.updateDeep(this.user_attrs_, attrs);
+  utils.updateDeep(this.user_attrs_, attrs);
 
   this.attributes_.reparseSeries();
 
@@ -3778,10 +3511,41 @@ Dygraph.addAnnotationRule = function() {
   console.warn("Unable to add default annotation CSS rule; display may be off.");
 };
 
-if (typeof exports === "object" && typeof module !== "undefined") {
-  module.exports = Dygraph;
-}
+/**
+ * Add an event handler. This event handler is kept until the graph is
+ * destroyed with a call to graph.destroy().
+ *
+ * @param {!Node} elem The element to add the event to.
+ * @param {string} type The type of the event, e.g. 'click' or 'mousemove'.
+ * @param {function(Event):(boolean|undefined)} fn The function to call
+ *     on the event. The function takes one parameter: the event object.
+ * @private
+ */
+Dygraph.prototype.addAndTrackEvent = function(elem, type, fn) {
+  utils.addEvent(elem, type, fn);
+  this.registeredEvents_.push({elem, type, fn});
+};
 
-return Dygraph;
+Dygraph.prototype.removeTrackedEvents_ = function() {
+  if (this.registeredEvents_) {
+    for (var idx = 0; idx < this.registeredEvents_.length; idx++) {
+      var reg = this.registeredEvents_[idx];
+      utils.removeEvent(reg.elem, reg.type, reg.fn);
+    }
+  }
+
+  this.registeredEvents_ = [];
+};
+
+
+// Installed plugins, in order of precedence (most-general to most-specific).
+Dygraph.PLUGINS = [
+  LegendPlugin,
+  AxesPlugin,
+  RangeSelectorPlugin, // Has to be before ChartLabels so that its callbacks are called after ChartLabels' callbacks.
+  ChartLabelsPlugin,
+  AnnotationsPlugin,
+  GridPlugin
+];
 
-})();
+export default Dygraph;
index 8576104..46d0891 100644 (file)
@@ -6,8 +6,6 @@
 
 /*global Dygraph:false */
 
-Dygraph.Plugins.Annotations = (function() {
-
 "use strict";
 
 /**
@@ -20,7 +18,6 @@ the core dygraphs classes, but annotations involve quite a bit of parsing and
 layout.
 
 TODO(danvk): cache DOM elements.
-
 */
 
 var annotations = function() {
@@ -177,6 +174,4 @@ annotations.prototype.destroy = function() {
   this.detachLabels();
 };
 
-return annotations;
-
-})();
+export default annotations;
index aa142ce..e913534 100644 (file)
@@ -6,8 +6,6 @@
 
 /*global Dygraph:false */
 
-Dygraph.Plugins.Axes = (function() {
-
 'use strict';
 
 /*
@@ -319,5 +317,4 @@ axes.prototype.willDrawChart = function(e) {
   context.restore();
 };
 
-return axes;
-})();
+export default axes;
index 504ed3a..5fbbdc5 100644 (file)
@@ -5,8 +5,6 @@
  */
 /*global Dygraph:false */
 
-Dygraph.Plugins.ChartLabels = (function() {
-
 "use strict";
 
 // TODO(danvk): move chart label options out of dygraphs and into the plugin.
@@ -185,6 +183,4 @@ chart_labels.prototype.destroy = function() {
   this.detachLabels_();
 };
 
-
-return chart_labels;
-})();
+export default chart_labels;
index db1b42d..bf6e3fe 100644 (file)
@@ -5,8 +5,6 @@
  */
 /*global Dygraph:false */
 
-Dygraph.Plugins.Grid = (function() {
-
 /*
 
 Current bits of jankiness:
@@ -119,6 +117,4 @@ grid.prototype.willDrawChart = function(e) {
 grid.prototype.destroy = function() {
 };
 
-return grid;
-
-})();
+export default grid;
index 3db4d07..95a161c 100644 (file)
@@ -5,7 +5,6 @@
  */
 /*global Dygraph:false */
 
-Dygraph.Plugins.Legend = (function() {
 /*
 Current bits of jankiness:
 - Uses two private APIs:
@@ -18,6 +17,8 @@ Current bits of jankiness:
 /*global Dygraph:false */
 "use strict";
 
+import * as utils from '../dygraph-utils';
+
 
 /**
  * Creates the legend, which appears when the user hovers over the chart.
@@ -271,7 +272,7 @@ legend.generateLegendHTML = function(g, x, sel_points, oneEmWidth, row) {
   for (i = 0; i < sel_points.length; i++) {
     var pt = sel_points[i];
     if (pt.yval === 0 && !showZeros) continue;
-    if (!Dygraph.isOK(pt.canvasy)) continue;
+    if (!utils.isOK(pt.canvasy)) continue;
     if (sepLines) html += "<br/>";
 
     var series = g.getPropertiesForSeries(pt.name);
@@ -361,6 +362,4 @@ generateLegendDashHTML = function(strokePattern, color, oneEmWidth) {
   return dash;
 };
 
-
-return legend;
-})();
+export default legend;
index d062382..2090fae 100644 (file)
  * a timeline range selector widget for dygraphs.
  */
 
-Dygraph.Plugins.RangeSelector = (function() {
-
 /*global Dygraph:false */
 "use strict";
 
+import * as utils from '../dygraph-utils';
+import DygraphInteraction from '../dygraph-interaction-model';
+
 var rangeSelector = function() {
   this.hasTouchInterface_ = typeof(TouchEvent) != 'undefined';
   this.isMobileDevice_ = /mobile|android/gi.test(navigator.appVersion);
@@ -160,7 +161,7 @@ rangeSelector.prototype.updateVisibility_ = function() {
  */
 rangeSelector.prototype.resize_ = function() {
   function setElementRect(canvas, context, rect) {
-    var canvasScale = Dygraph.getContextPixelRatio(context);
+    var canvasScale = utils.getContextPixelRatio(context);
 
     canvas.style.top = rect.y + 'px';
     canvas.style.left = rect.x + 'px';
@@ -196,18 +197,18 @@ rangeSelector.prototype.resize_ = function() {
  * Creates the background and foreground canvases.
  */
 rangeSelector.prototype.createCanvases_ = function() {
-  this.bgcanvas_ = Dygraph.createCanvas();
+  this.bgcanvas_ = utils.createCanvas();
   this.bgcanvas_.className = 'dygraph-rangesel-bgcanvas';
   this.bgcanvas_.style.position = 'absolute';
   this.bgcanvas_.style.zIndex = 9;
-  this.bgcanvas_ctx_ = Dygraph.getContext(this.bgcanvas_);
+  this.bgcanvas_ctx_ = utils.getContext(this.bgcanvas_);
 
-  this.fgcanvas_ = Dygraph.createCanvas();
+  this.fgcanvas_ = utils.createCanvas();
   this.fgcanvas_.className = 'dygraph-rangesel-fgcanvas';
   this.fgcanvas_.style.position = 'absolute';
   this.fgcanvas_.style.zIndex = 9;
   this.fgcanvas_.style.cursor = 'default';
-  this.fgcanvas_ctx_ = Dygraph.getContext(this.fgcanvas_);
+  this.fgcanvas_ctx_ = utils.getContext(this.fgcanvas_);
 };
 
 /**
@@ -255,7 +256,7 @@ rangeSelector.prototype.initInteraction_ = function() {
 
   // We cover iframes during mouse interactions. See comments in
   // dygraph-utils.js for more info on why this is a good idea.
-  var tarp = new Dygraph.IFrameTarp();
+  var tarp = new utils.IFrameTarp();
 
   // functions, defined below.  Defining them this way (rather than with
   // "function foo() {...}" makes JSHint happy.
@@ -274,14 +275,14 @@ rangeSelector.prototype.initInteraction_ = function() {
   };
 
   onZoomStart = function(e) {
-    Dygraph.cancelEvent(e);
+    utils.cancelEvent(e);
     isZooming = true;
     clientXLast = e.clientX;
     handle = e.target ? e.target : e.srcElement;
     if (e.type === 'mousedown' || e.type === 'dragstart') {
       // These events are removed manually.
-      Dygraph.addEvent(topElem, 'mousemove', onZoom);
-      Dygraph.addEvent(topElem, 'mouseup', onZoomEnd);
+      utils.addEvent(topElem, 'mousemove', onZoom);
+      utils.addEvent(topElem, 'mouseup', onZoomEnd);
     }
     self.fgcanvas_.style.cursor = 'col-resize';
     tarp.cover();
@@ -292,7 +293,7 @@ rangeSelector.prototype.initInteraction_ = function() {
     if (!isZooming) {
       return false;
     }
-    Dygraph.cancelEvent(e);
+    utils.cancelEvent(e);
 
     var delX = e.clientX - clientXLast;
     if (Math.abs(delX) < 4) {
@@ -329,8 +330,8 @@ rangeSelector.prototype.initInteraction_ = function() {
     }
     isZooming = false;
     tarp.uncover();
-    Dygraph.removeEvent(topElem, 'mousemove', onZoom);
-    Dygraph.removeEvent(topElem, 'mouseup', onZoomEnd);
+    utils.removeEvent(topElem, 'mousemove', onZoom);
+    utils.removeEvent(topElem, 'mouseup', onZoomEnd);
     self.fgcanvas_.style.cursor = 'default';
 
     // If on a slower device, zoom now.
@@ -365,13 +366,13 @@ rangeSelector.prototype.initInteraction_ = function() {
 
   onPanStart = function(e) {
     if (!isPanning && isMouseInPanZone(e) && self.getZoomHandleStatus_().isZoomed) {
-      Dygraph.cancelEvent(e);
+      utils.cancelEvent(e);
       isPanning = true;
       clientXLast = e.clientX;
       if (e.type === 'mousedown') {
         // These events are removed manually.
-        Dygraph.addEvent(topElem, 'mousemove', onPan);
-        Dygraph.addEvent(topElem, 'mouseup', onPanEnd);
+        utils.addEvent(topElem, 'mousemove', onPan);
+        utils.addEvent(topElem, 'mouseup', onPanEnd);
       }
       return true;
     }
@@ -382,7 +383,7 @@ rangeSelector.prototype.initInteraction_ = function() {
     if (!isPanning) {
       return false;
     }
-    Dygraph.cancelEvent(e);
+    utils.cancelEvent(e);
 
     var delX = e.clientX - clientXLast;
     if (Math.abs(delX) < 4) {
@@ -422,8 +423,8 @@ rangeSelector.prototype.initInteraction_ = function() {
       return false;
     }
     isPanning = false;
-    Dygraph.removeEvent(topElem, 'mousemove', onPan);
-    Dygraph.removeEvent(topElem, 'mouseup', onPanEnd);
+    utils.removeEvent(topElem, 'mousemove', onPan);
+    utils.removeEvent(topElem, 'mouseup', onPanEnd);
     // If on a slower device, do pan now.
     if (!dynamic) {
       doPan();
@@ -454,11 +455,11 @@ rangeSelector.prototype.initInteraction_ = function() {
   onZoomHandleTouchEvent = function(e) {
     if (e.type == 'touchstart' && e.targetTouches.length == 1) {
       if (onZoomStart(e.targetTouches[0])) {
-        Dygraph.cancelEvent(e);
+        utils.cancelEvent(e);
       }
     } else if (e.type == 'touchmove' && e.targetTouches.length == 1) {
       if (onZoom(e.targetTouches[0])) {
-        Dygraph.cancelEvent(e);
+        utils.cancelEvent(e);
       }
     } else {
       onZoomEnd(e);
@@ -468,11 +469,11 @@ rangeSelector.prototype.initInteraction_ = function() {
   onCanvasTouchEvent = function(e) {
     if (e.type == 'touchstart' && e.targetTouches.length == 1) {
       if (onPanStart(e.targetTouches[0])) {
-        Dygraph.cancelEvent(e);
+        utils.cancelEvent(e);
       }
     } else if (e.type == 'touchmove' && e.targetTouches.length == 1) {
       if (onPan(e.targetTouches[0])) {
-        Dygraph.cancelEvent(e);
+        utils.cancelEvent(e);
       }
     } else {
       onPanEnd(e);
@@ -486,7 +487,7 @@ rangeSelector.prototype.initInteraction_ = function() {
     }
   };
 
-  this.setDefaultOption_('interactionModel', Dygraph.Interaction.dragIsPanInteractionModel);
+  this.setDefaultOption_('interactionModel', DygraphInteraction.dragIsPanInteractionModel);
   this.setDefaultOption_('panEdgeFraction', 0.0001);
 
   var dragStartEvent = window.opera ? 'mousedown' : 'dragstart';
@@ -685,11 +686,11 @@ rangeSelector.prototype.computeCombinedSeriesAndLimits_ = function() {
   // Also, expand the Y range to compress the mini plot a little.
   var extraPercent = 0.25;
   if (logscale) {
-    yMax = Dygraph.log10(yMax);
+    yMax = utils.log10(yMax);
     yMax += yMax*extraPercent;
-    yMin = Dygraph.log10(yMin);
+    yMin = utils.log10(yMin);
     for (i = 0; i < combinedSeries.length; i++) {
-      combinedSeries[i][1] = Dygraph.log10(combinedSeries[i][1]);
+      combinedSeries[i][1] = utils.log10(combinedSeries[i][1]);
     }
   } else {
     var yExtra;
@@ -785,6 +786,4 @@ rangeSelector.prototype.getZoomHandleStatus_ = function() {
   };
 };
 
-return rangeSelector;
-
-})();
+export default rangeSelector;
index c4a1623..a057bad 100644 (file)
@@ -2,7 +2,10 @@
 <html>
   <head>
     <title>demo</title>
+    <!--
     <script type="text/javascript" src="../dygraph-dev.js"></script>
+    -->
+    <script type="text/javascript" src="../bundle.js"></script>
   </head>
   <body>
     <h2>Demo</h2>
@@ -43,7 +46,8 @@
                 title: 'Interesting Shapes',
                 xlabel: 'Date',
                 ylabel: 'Count',
-                axisLineColor: 'white'
+                axisLineColor: 'white',
+                showRangeSelector: true
                 // drawXGrid: false
               }
           );