From: Dan Vanderkam Date: Mon, 19 Oct 2015 16:45:16 +0000 (-0400) Subject: Migrate most of core dygraphs to ES6 modules. X-Git-Tag: v2.0.0~38^2~16 X-Git-Url: https://adrianiainlam.tk/git/?a=commitdiff_plain;h=6ecc073934b76e5076f917112a24ff7094857730;p=dygraphs.git Migrate most of core dygraphs to ES6 modules. --- diff --git a/dygraph-dev.js b/dygraph-dev.js index 506312e..b09f28b 100644 --- a/dygraph-dev.js +++ b/dygraph-dev.js @@ -16,32 +16,32 @@ // 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++) { diff --git a/package.json b/package.json index cbe5638..b26f91d 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/src/datahandler/datahandler.js b/src/datahandler/datahandler.js index b3eae91..1b0efcb 100644 --- a/src/datahandler/datahandler.js +++ b/src/datahandler/datahandler.js @@ -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 @@ -48,20 +50,10 @@ * 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.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; diff --git a/src/datahandler/default.js b/src/datahandler/default.js index e42b92b..5ddf67c 100644 --- a/src/datahandler/default.js +++ b/src/datahandler/default.js @@ -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; diff --git a/src/dygraph-canvas.js b/src/dygraph-canvas.js index aed387b..256edc1 100644 --- a/src/dygraph-canvas.js +++ b/src/dygraph-canvas.js @@ -24,10 +24,11 @@ * @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 index 0000000..b7dd6e4 --- /dev/null +++ b/src/dygraph-default-attrs.js @@ -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; diff --git a/src/dygraph-interaction-model.js b/src/dygraph-interaction-model.js index 53e2f44..3813fc5 100644 --- a/src/dygraph-interaction-model.js +++ b/src/dygraph-interaction-model.js @@ -10,10 +10,11 @@ * @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; diff --git a/src/dygraph-layout.js b/src/dygraph-layout.js index ef1df91..3bc9135 100644 --- a/src/dygraph-layout.js +++ b/src/dygraph-layout.js @@ -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; diff --git a/src/dygraph-options.js b/src/dygraph-options.js index d21ccc1..8affcdf 100644 --- a/src/dygraph-options.js +++ b/src/dygraph-options.js @@ -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 index 7f758a9..0000000 --- a/src/dygraph-plugin-base.js +++ /dev/null @@ -1,4 +0,0 @@ -/*global Dygraph:false */ - -// Namespace for plugins. Load this before plugins/*.js files. -Dygraph.Plugins = {}; diff --git a/src/dygraph-tickers.js b/src/dygraph-tickers.js index 0f6b1ab..7eb17dd 100644 --- a/src/dygraph-tickers.js +++ b/src/dygraph-tickers.js @@ -60,11 +60,12 @@ /*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.= - * ): 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.} */ -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 -> 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; +// } diff --git a/src/dygraph-utils.js b/src/dygraph-utils.js index a960ba7..d16da53 100644 --- a/src/dygraph-utils.js +++ b/src/dygraph-utils.js @@ -11,46 +11,46 @@ * 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.} */ 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.} + * @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] + ' ' + 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) + ' ' + 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')); +}; diff --git a/src/dygraph.js b/src/dygraph.js index a28e231..396b858 100644 --- a/src/dygraph.js +++ b/src/dygraph.js @@ -44,9 +44,26 @@ */ // 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.} - * @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] + ' ' + 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) + ' ' + 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; diff --git a/src/plugins/annotations.js b/src/plugins/annotations.js index 8576104..46d0891 100644 --- a/src/plugins/annotations.js +++ b/src/plugins/annotations.js @@ -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; diff --git a/src/plugins/axes.js b/src/plugins/axes.js index aa142ce..e913534 100644 --- a/src/plugins/axes.js +++ b/src/plugins/axes.js @@ -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; diff --git a/src/plugins/chart-labels.js b/src/plugins/chart-labels.js index 504ed3a..5fbbdc5 100644 --- a/src/plugins/chart-labels.js +++ b/src/plugins/chart-labels.js @@ -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; diff --git a/src/plugins/grid.js b/src/plugins/grid.js index db1b42d..bf6e3fe 100644 --- a/src/plugins/grid.js +++ b/src/plugins/grid.js @@ -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; diff --git a/src/plugins/legend.js b/src/plugins/legend.js index 3db4d07..95a161c 100644 --- a/src/plugins/legend.js +++ b/src/plugins/legend.js @@ -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 += "
"; var series = g.getPropertiesForSeries(pt.name); @@ -361,6 +362,4 @@ generateLegendDashHTML = function(strokePattern, color, oneEmWidth) { return dash; }; - -return legend; -})(); +export default legend; diff --git a/src/plugins/range-selector.js b/src/plugins/range-selector.js index d062382..2090fae 100644 --- a/src/plugins/range-selector.js +++ b/src/plugins/range-selector.js @@ -10,11 +10,12 @@ * 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; diff --git a/tests/demo.html b/tests/demo.html index c4a1623..a057bad 100644 --- a/tests/demo.html +++ b/tests/demo.html @@ -2,7 +2,10 @@ demo + +

Demo

@@ -43,7 +46,8 @@ title: 'Interesting Shapes', xlabel: 'Date', ylabel: 'Count', - axisLineColor: 'white' + axisLineColor: 'white', + showRangeSelector: true // drawXGrid: false } );