From 3ea41d86e76be3e19b633bfdde5e05cb3d1da643 Mon Sep 17 00:00:00 2001 From: Dan Vanderkam Date: Wed, 28 Aug 2013 00:00:57 -0400 Subject: [PATCH] Cleanup from DataHandler change. Highlights: - Move from the string-based DataHandler registration system to plain old JS symbols. This gets us some extra sanity checking from the JS interpretor and linter. - Standardize module pattern and indentation across datahandler/*.js. - Document dataHandler option. --- datahandler/bars-custom.js | 141 ++++++++++++++++++----------------- datahandler/bars-error.js | 141 ++++++++++++++++++----------------- datahandler/bars-fractions.js | 157 ++++++++++++++++++++------------------- datahandler/bars.js | 121 +++++++++++++++--------------- datahandler/datahandler.js | 54 ++------------ datahandler/default-fractions.js | 114 ++++++++++++++-------------- datahandler/default.js | 128 +++++++++++++++---------------- dygraph-options-reference.js | 8 +- dygraph.js | 36 +++++---- 9 files changed, 439 insertions(+), 461 deletions(-) diff --git a/datahandler/bars-custom.js b/datahandler/bars-custom.js index e77d746..37255e5 100644 --- a/datahandler/bars-custom.js +++ b/datahandler/bars-custom.js @@ -10,84 +10,87 @@ */ (function() { - /*global Dygraph:false */ - "use strict"; - var CustomBarsHandler = Dygraph.DataHandler(); - CustomBarsHandler.prototype = Dygraph.DataHandlers.createHandler("bars"); - Dygraph.DataHandlers.registerHandler("bars-custom", CustomBarsHandler); - // customBars - CustomBarsHandler.prototype.extractSeries = function(rawData, i, options) { - // TODO(danvk): pre-allocate series here. - var series = []; - var x, y, point; - var logScale = options.get('logscale'); - for ( var j = 0; j < rawData.length; j++) { - x = rawData[j][0]; - point = rawData[j][i]; - if (logScale && point !== null) { - // On the log scale, points less than zero do not exist. - // This will create a gap in the chart. - if (point[0] <= 0 || point[1] <= 0 || point[2] <= 0) { - point = null; - } +/*global Dygraph:false */ +"use strict"; + +Dygraph.DataHandlers.CustomBarsHandler = Dygraph.DataHandler(); +var CustomBarsHandler = Dygraph.DataHandlers.CustomBarsHandler; +CustomBarsHandler.prototype = new Dygraph.DataHandlers.BarsHandler(); + +// customBars +CustomBarsHandler.prototype.extractSeries = function(rawData, i, options) { + // TODO(danvk): pre-allocate series here. + var series = []; + var x, y, point; + var logScale = options.get('logscale'); + for ( var j = 0; j < rawData.length; j++) { + x = rawData[j][0]; + point = rawData[j][i]; + if (logScale && point !== null) { + // On the log scale, points less than zero do not exist. + // This will create a gap in the chart. + if (point[0] <= 0 || point[1] <= 0 || point[2] <= 0) { + point = null; } - // Extract to the unified data format. - if (point !== null) { - y = point[1]; - if (y !== null && !isNaN(y)) { - series.push([ x, y, [ point[0], point[2] ] ]); - } else { - series.push([ x, y, [ y, y ] ]); - } + } + // Extract to the unified data format. + if (point !== null) { + y = point[1]; + if (y !== null && !isNaN(y)) { + series.push([ x, y, [ point[0], point[2] ] ]); } else { - series.push([ x, null, [ null, null ] ]); + series.push([ x, y, [ y, y ] ]); } + } else { + series.push([ x, null, [ null, null ] ]); } - return series; - }; + } + return series; +}; - CustomBarsHandler.prototype.rollingAverage = function(originalData, rollPeriod, - options) { - rollPeriod = Math.min(rollPeriod, originalData.length); - var rollingData = []; - var y, low, high, mid,count, i, extremes; +CustomBarsHandler.prototype.rollingAverage = function(originalData, rollPeriod, + options) { + rollPeriod = Math.min(rollPeriod, originalData.length); + var rollingData = []; + var y, low, high, mid,count, i, extremes; - low = 0; - mid = 0; - high = 0; - count = 0; - for (i = 0; i < originalData.length; i++) { - y = originalData[i][1]; - extremes = originalData[i][2]; - rollingData[i] = originalData[i]; + low = 0; + mid = 0; + high = 0; + count = 0; + for (i = 0; i < originalData.length; i++) { + y = originalData[i][1]; + extremes = originalData[i][2]; + rollingData[i] = originalData[i]; - if (y !== null && !isNaN(y)) { - low += extremes[0]; - mid += y; - high += extremes[1]; - count += 1; - } - if (i - rollPeriod >= 0) { - var prev = originalData[i - rollPeriod]; - if (prev[1] !== null && !isNaN(prev[1])) { - low -= prev[2][0]; - mid -= prev[1]; - high -= prev[2][1]; - count -= 1; - } - } - if (count) { - rollingData[i] = [ - originalData[i][0], - 1.0 * mid / count, - [ 1.0 * low / count, - 1.0 * high / count ] ]; - } else { - rollingData[i] = [ originalData[i][0], null, [ null, null ] ]; + if (y !== null && !isNaN(y)) { + low += extremes[0]; + mid += y; + high += extremes[1]; + count += 1; + } + if (i - rollPeriod >= 0) { + var prev = originalData[i - rollPeriod]; + if (prev[1] !== null && !isNaN(prev[1])) { + low -= prev[2][0]; + mid -= prev[1]; + high -= prev[2][1]; + count -= 1; } } + if (count) { + rollingData[i] = [ + originalData[i][0], + 1.0 * mid / count, + [ 1.0 * low / count, + 1.0 * high / count ] ]; + } else { + rollingData[i] = [ originalData[i][0], null, [ null, null ] ]; + } + } + + return rollingData; +}; - return rollingData; - }; })(); diff --git a/datahandler/bars-error.js b/datahandler/bars-error.js index ff4ba92..6da2fc5 100644 --- a/datahandler/bars-error.js +++ b/datahandler/bars-error.js @@ -10,83 +10,86 @@ */ (function() { - /*global Dygraph:false */ - "use strict"; - var ErrorBarsHandler = Dygraph.DataHandler(); - ErrorBarsHandler.prototype = Dygraph.DataHandlers.createHandler("bars"); - Dygraph.DataHandlers.registerHandler("bars-error", ErrorBarsHandler); - // errorBars - ErrorBarsHandler.prototype.extractSeries = function(rawData, i, options) { - // TODO(danvk): pre-allocate series here. - var series = []; - var x, y, variance, point; - var sigma = options.get("sigma"); - var logScale = options.get('logscale'); - for ( var j = 0; j < rawData.length; j++) { - x = rawData[j][0]; - point = rawData[j][i]; - if (logScale && point !== null) { - // On the log scale, points less than zero do not exist. - // This will create a gap in the chart. - if (point[0] <= 0 || point[0] - sigma * point[1] <= 0) { - point = null; - } +/*global Dygraph:false */ +"use strict"; + +Dygraph.DataHandlers.ErrorBarsHandler = Dygraph.DataHandler(); +var ErrorBarsHandler = Dygraph.DataHandlers.ErrorBarsHandler; +ErrorBarsHandler.prototype = new Dygraph.DataHandlers.BarsHandler(); + +// errorBars +ErrorBarsHandler.prototype.extractSeries = function(rawData, i, options) { + // TODO(danvk): pre-allocate series here. + var series = []; + var x, y, variance, point; + var sigma = options.get("sigma"); + var logScale = options.get('logscale'); + for ( var j = 0; j < rawData.length; j++) { + x = rawData[j][0]; + point = rawData[j][i]; + if (logScale && point !== null) { + // On the log scale, points less than zero do not exist. + // This will create a gap in the chart. + if (point[0] <= 0 || point[0] - sigma * point[1] <= 0) { + point = null; } - // Extract to the unified data format. - if (point !== null) { - y = point[0]; - if (y !== null && !isNaN(y)) { - variance = sigma * point[1]; - // preserve original error value in extras for further - // filtering - series.push([ x, y, [ y - variance, y + variance, point[1] ] ]); - } else { - series.push([ x, y, [ y, y, y ] ]); - } + } + // Extract to the unified data format. + if (point !== null) { + y = point[0]; + if (y !== null && !isNaN(y)) { + variance = sigma * point[1]; + // preserve original error value in extras for further + // filtering + series.push([ x, y, [ y - variance, y + variance, point[1] ] ]); } else { - series.push([ x, null, [ null, null, null ] ]); + series.push([ x, y, [ y, y, y ] ]); } + } else { + series.push([ x, null, [ null, null, null ] ]); } - return series; - }; + } + return series; +}; - ErrorBarsHandler.prototype.rollingAverage = function(originalData, rollPeriod, - options) { - rollPeriod = Math.min(rollPeriod, originalData.length); - var rollingData = []; - var sigma = options.get("sigma"); +ErrorBarsHandler.prototype.rollingAverage = function(originalData, rollPeriod, + options) { + rollPeriod = Math.min(rollPeriod, originalData.length); + var rollingData = []; + var sigma = options.get("sigma"); - var i, j, y, v, sum, num_ok, stddev, variance, value; + var i, j, y, v, sum, num_ok, stddev, variance, value; - // Calculate the rolling average for the first rollPeriod - 1 points - // where there is not enough data to roll over the full number of points - for (i = 0; i < originalData.length; i++) { - sum = 0; - variance = 0; - num_ok = 0; - for (j = Math.max(0, i - rollPeriod + 1); j < i + 1; j++) { - y = originalData[j][1]; - if (y === null || isNaN(y)) - continue; - num_ok++; - sum += y; - variance += Math.pow(originalData[j][2][2], 2); - } - if (num_ok) { - stddev = Math.sqrt(variance) / num_ok; - value = sum / num_ok; - rollingData[i] = [ originalData[i][0], value, - [value - sigma * stddev, value + sigma * stddev] ]; - } else { - // This explicitly preserves NaNs to aid with "independent - // series". - // See testRollingAveragePreservesNaNs. - v = (rollPeriod == 1) ? originalData[i][1] : null; - rollingData[i] = [ originalData[i][0], v, [ v, v ] ]; - } + // Calculate the rolling average for the first rollPeriod - 1 points + // where there is not enough data to roll over the full number of points + for (i = 0; i < originalData.length; i++) { + sum = 0; + variance = 0; + num_ok = 0; + for (j = Math.max(0, i - rollPeriod + 1); j < i + 1; j++) { + y = originalData[j][1]; + if (y === null || isNaN(y)) + continue; + num_ok++; + sum += y; + variance += Math.pow(originalData[j][2][2], 2); } + if (num_ok) { + stddev = Math.sqrt(variance) / num_ok; + value = sum / num_ok; + rollingData[i] = [ originalData[i][0], value, + [value - sigma * stddev, value + sigma * stddev] ]; + } else { + // This explicitly preserves NaNs to aid with "independent + // series". + // See testRollingAveragePreservesNaNs. + v = (rollPeriod == 1) ? originalData[i][1] : null; + rollingData[i] = [ originalData[i][0], v, [ v, v ] ]; + } + } + + return rollingData; +}; - return rollingData; - }; })(); diff --git a/datahandler/bars-fractions.js b/datahandler/bars-fractions.js index 88c5ca6..28c0491 100644 --- a/datahandler/bars-fractions.js +++ b/datahandler/bars-fractions.js @@ -11,93 +11,96 @@ */ (function() { - /*global Dygraph:false */ - "use strict"; - var FractionsBarsHandler = Dygraph.DataHandler(); - FractionsBarsHandler.prototype = Dygraph.DataHandlers.createHandler("bars"); - Dygraph.DataHandlers.registerHandler("bars-fractions", FractionsBarsHandler); - // errorBars - FractionsBarsHandler.prototype.extractSeries = function(rawData, i, options) { - // TODO(danvk): pre-allocate series here. - var series = []; - var x, y, point, num, den, value, stddev, variance; - var mult = 100.0; - var sigma = options.get("sigma"); - var logScale = options.get('logscale'); - for ( var j = 0; j < rawData.length; j++) { - x = rawData[j][0]; - point = rawData[j][i]; - if (logScale && point !== null) { - // On the log scale, points less than zero do not exist. - // This will create a gap in the chart. - if (point[0] <= 0 || point[1] <= 0) { - point = null; - } +/*global Dygraph:false */ +"use strict"; + +Dygraph.DataHandlers.FractionsBarsHandler = Dygraph.DataHandler(); +var FractionsBarsHandler = Dygraph.DataHandlers.FractionsBarsHandler; +FractionsBarsHandler.prototype = new Dygraph.DataHandlers.BarsHandler(); + +// errorBars +FractionsBarsHandler.prototype.extractSeries = function(rawData, i, options) { + // TODO(danvk): pre-allocate series here. + var series = []; + var x, y, point, num, den, value, stddev, variance; + var mult = 100.0; + var sigma = options.get("sigma"); + var logScale = options.get('logscale'); + for ( var j = 0; j < rawData.length; j++) { + x = rawData[j][0]; + point = rawData[j][i]; + if (logScale && point !== null) { + // On the log scale, points less than zero do not exist. + // This will create a gap in the chart. + if (point[0] <= 0 || point[1] <= 0) { + point = null; } - // Extract to the unified data format. - if (point !== null) { - num = point[0]; - den = point[1]; - if (num !== null && !isNaN(num)) { - value = den ? num / den : 0.0; - stddev = den ? sigma * Math.sqrt(value * (1 - value) / den) : 1.0; - variance = mult * stddev; - y = mult * value; - // preserve original values in extras for further filtering - series.push([ x, y, [ y - variance, y + variance, num, den ] ]); - } else { - series.push([ x, num, [ num, num, num, den ] ]); - } + } + // Extract to the unified data format. + if (point !== null) { + num = point[0]; + den = point[1]; + if (num !== null && !isNaN(num)) { + value = den ? num / den : 0.0; + stddev = den ? sigma * Math.sqrt(value * (1 - value) / den) : 1.0; + variance = mult * stddev; + y = mult * value; + // preserve original values in extras for further filtering + series.push([ x, y, [ y - variance, y + variance, num, den ] ]); } else { - series.push([ x, null, [ null, null, null, null ] ]); + series.push([ x, num, [ num, num, num, den ] ]); } + } else { + series.push([ x, null, [ null, null, null, null ] ]); } - return series; - }; + } + return series; +}; - FractionsBarsHandler.prototype.rollingAverage = function(originalData, rollPeriod, - options) { - rollPeriod = Math.min(rollPeriod, originalData.length); - var rollingData = []; - var sigma = options.get("sigma"); - var wilsonInterval = options.get("wilsonInterval"); +FractionsBarsHandler.prototype.rollingAverage = function(originalData, rollPeriod, + options) { + rollPeriod = Math.min(rollPeriod, originalData.length); + var rollingData = []; + var sigma = options.get("sigma"); + var wilsonInterval = options.get("wilsonInterval"); - var low, high, i, stddev; - var num = 0; - var den = 0; // numerator/denominator - var mult = 100.0; - for (i = 0; i < originalData.length; i++) { - num += originalData[i][2][2]; - den += originalData[i][2][3]; - if (i - rollPeriod >= 0) { - num -= originalData[i - rollPeriod][2][2]; - den -= originalData[i - rollPeriod][2][3]; - } + var low, high, i, stddev; + var num = 0; + var den = 0; // numerator/denominator + var mult = 100.0; + for (i = 0; i < originalData.length; i++) { + num += originalData[i][2][2]; + den += originalData[i][2][3]; + if (i - rollPeriod >= 0) { + num -= originalData[i - rollPeriod][2][2]; + den -= originalData[i - rollPeriod][2][3]; + } - var date = originalData[i][0]; - var value = den ? num / den : 0.0; - if (wilsonInterval) { - // For more details on this confidence interval, see: - // http://en.wikipedia.org/wiki/Binomial_confidence_interval - if (den) { - var p = value < 0 ? 0 : value, n = den; - var pm = sigma * Math.sqrt(p * (1 - p) / n + sigma * sigma / (4 * n * n)); - var denom = 1 + sigma * sigma / den; - low = (p + sigma * sigma / (2 * den) - pm) / denom; - high = (p + sigma * sigma / (2 * den) + pm) / denom; - rollingData[i] = [ date, p * mult, - [ low * mult, high * mult ] ]; - } else { - rollingData[i] = [ date, 0, [ 0, 0 ] ]; - } + var date = originalData[i][0]; + var value = den ? num / den : 0.0; + if (wilsonInterval) { + // For more details on this confidence interval, see: + // http://en.wikipedia.org/wiki/Binomial_confidence_interval + if (den) { + var p = value < 0 ? 0 : value, n = den; + var pm = sigma * Math.sqrt(p * (1 - p) / n + sigma * sigma / (4 * n * n)); + var denom = 1 + sigma * sigma / den; + low = (p + sigma * sigma / (2 * den) - pm) / denom; + high = (p + sigma * sigma / (2 * den) + pm) / denom; + rollingData[i] = [ date, p * mult, + [ low * mult, high * mult ] ]; } else { - stddev = den ? sigma * Math.sqrt(value * (1 - value) / den) : 1.0; - rollingData[i] = [ date, mult * value, - [ mult * (value - stddev), mult * (value + stddev) ] ]; + rollingData[i] = [ date, 0, [ 0, 0 ] ]; } + } else { + stddev = den ? sigma * Math.sqrt(value * (1 - value) / den) : 1.0; + rollingData[i] = [ date, mult * value, + [ mult * (value - stddev), mult * (value + stddev) ] ]; } + } + + return rollingData; +}; - return rollingData; - }; })(); diff --git a/datahandler/bars.js b/datahandler/bars.js index 5b84b69..914ee27 100644 --- a/datahandler/bars.js +++ b/datahandler/bars.js @@ -12,63 +12,66 @@ */ (function() { - /*global Dygraph:false */ - /*global DygraphLayout:false */ - "use strict"; - - var BarsHandler = Dygraph.DataHandler(); - Dygraph.DataHandlers.registerHandler("bars", BarsHandler); - // errorBars - BarsHandler.prototype.extractSeries = function(rawData, i, options) { - // Not implemented here must be extended - }; - - BarsHandler.prototype.rollingAverage = function(originalData, rollPeriod, - options) { - // Not implemented here, must be extended. - }; - - BarsHandler.prototype.onPointsCreated_ = function(series, points) { - for (var i = 0; i < series.length; ++i) { - var item = series[i]; - var point = points[i]; - point.y_top = NaN; - point.y_bottom = NaN; - point.yval_minus = DygraphLayout.parseFloat_(item[2][0]); - point.yval_plus = DygraphLayout.parseFloat_(item[2][1]); - } - }; - - BarsHandler.prototype.getExtremeYValues = function(series, dateWindow, options) { - var minY = null, maxY = null, y; - - var firstIdx = 0; - var lastIdx = series.length - 1; - - for ( var j = firstIdx; j <= lastIdx; j++) { - y = series[j][1]; - if (y === null || isNaN(y)) continue; - - var low = series[j][2][0]; - var high = series[j][2][1]; - - if (low > y) low = y; // this can happen with custom bars, - if (high < y) high = y; // e.g. in tests/custom-bars.html - - if (maxY === null || high > maxY) maxY = high; - if (minY === null || low < minY) minY = low; - } - - return [ minY, maxY ]; - }; - - BarsHandler.prototype.onLineEvaluated = function(points, axis, logscale) { - var point; - for (var j = 0; j < points.length; j++) { - // Copy over the error terms - point = points[j]; - point.y_top = DygraphLayout._calcYNormal(axis, point.yval_minus, logscale); - point.y_bottom = DygraphLayout._calcYNormal(axis, point.yval_plus, logscale); - } - }; + +/*global Dygraph:false */ +/*global DygraphLayout:false */ +"use strict"; + +Dygraph.DataHandlers.BarsHandler = Dygraph.DataHandler(); +var BarsHandler = Dygraph.DataHandlers.BarsHandler; + +// errorBars +BarsHandler.prototype.extractSeries = function(rawData, i, options) { + // Not implemented here must be extended +}; + +BarsHandler.prototype.rollingAverage = + function(originalData, rollPeriod, options) { + // Not implemented here, must be extended. +}; + +BarsHandler.prototype.onPointsCreated_ = function(series, points) { + for (var i = 0; i < series.length; ++i) { + var item = series[i]; + var point = points[i]; + point.y_top = NaN; + point.y_bottom = NaN; + point.yval_minus = DygraphLayout.parseFloat_(item[2][0]); + point.yval_plus = DygraphLayout.parseFloat_(item[2][1]); + } +}; + +BarsHandler.prototype.getExtremeYValues = function(series, dateWindow, options) { + var minY = null, maxY = null, y; + + var firstIdx = 0; + var lastIdx = series.length - 1; + + for ( var j = firstIdx; j <= lastIdx; j++) { + y = series[j][1]; + if (y === null || isNaN(y)) continue; + + var low = series[j][2][0]; + var high = series[j][2][1]; + + if (low > y) low = y; // this can happen with custom bars, + if (high < y) high = y; // e.g. in tests/custom-bars.html + + if (maxY === null || high > maxY) maxY = high; + if (minY === null || low < minY) minY = low; + } + + return [ minY, maxY ]; +}; + +BarsHandler.prototype.onLineEvaluated = function(points, axis, logscale) { + var point; + for (var j = 0; j < points.length; j++) { + // Copy over the error terms + point = points[j]; + point.y_top = DygraphLayout._calcYNormal(axis, point.yval_minus, logscale); + point.y_bottom = DygraphLayout._calcYNormal(axis, point.yval_plus, logscale); + } +}; + })(); diff --git a/datahandler/datahandler.js b/datahandler/datahandler.js index d08f7a7..5ed0112 100644 --- a/datahandler/datahandler.js +++ b/datahandler/datahandler.js @@ -38,68 +38,24 @@ * errorBar / customBar: [x, yVal, [yTopVariance, yBottomVariance] ] * */ -/*jshint globalstrict: true */ /*global Dygraph:false */ /*global DygraphLayout:false */ + +(function() { + "use strict"; /** * A collection of functions to create and retrieve data handlers. + * @type {Object.} */ Dygraph.DataHandlers = {}; /** - * All registered data handlers are stored here. - * - * @private - */ -Dygraph.DataHandlers.handlers_ = {}; - -/** - * @param name {!string} The name the data handler should be registered to. - * Registers a data handler by the given name and makes it publicly - * accessible. - * @param handler {!Dygraph.DataHandler} DataHandler implementation which must be an - * instance of Dygraph.DataHandler. - * @public - */ -Dygraph.DataHandlers.registerHandler = function(name, handler) { - if (!handler instanceof Dygraph.DataHandler) { - throw ("the handler must be a prototype of Dygraph.DataHandler"); - } - Dygraph.DataHandlers.handlers_[name] = handler; -}; - -/** - * Returns the data handler registered to the given name. - * Note this is the data handler constructor method. - * - * @param name {!string} The name, the handler was registered to. - * @returns {Dygraph.DataHandler} The data handler constructor. - * @public - */ -Dygraph.DataHandlers.getHandler = function(name) { - return Dygraph.DataHandlers.handlers_[name]; -}; - -/** - * Returns the cunstructed data handler registered to the given name. - * - * @param name {!string} The name, the handler was registered to. - * @returns {Dygraph.DataHandler} A constructed instance of the data handler. - * @public - */ -Dygraph.DataHandlers.createHandler = function(name) { - return new Dygraph.DataHandlers.handlers_[name](); -}; - -/** * * The data handler is responsible for all data specific operations. All of the * series data it receives and returns is always in the unified data format. * Initially the unified data is created by the extractSeries method - * - * @class */ Dygraph.DataHandler = function () { /** @@ -303,3 +259,5 @@ Dygraph.DataHandler = function () { return handler; }; + +})(); diff --git a/datahandler/default-fractions.js b/datahandler/default-fractions.js index 7e234b0..8da8e42 100644 --- a/datahandler/default-fractions.js +++ b/datahandler/default-fractions.js @@ -10,70 +10,72 @@ */ (function() { - /*global Dygraph:false */ - "use strict"; - var DefaultFractionHandler = Dygraph.DataHandler(); - DefaultFractionHandler.prototype = Dygraph.DataHandlers.createHandler("default"); - Dygraph.DataHandlers.registerHandler("default-fractions", DefaultFractionHandler); +/*global Dygraph:false */ +"use strict"; - DefaultFractionHandler.prototype.extractSeries = function(rawData, i, options) { - // TODO(danvk): pre-allocate series here. - var series = []; - var x, y, point, num, den, value; - var mult = 100.0; - var logScale = options.get('logscale'); - for ( var j = 0; j < rawData.length; j++) { - x = rawData[j][0]; - point = rawData[j][i]; - if (logScale && point !== null) { - // On the log scale, points less than zero do not exist. - // This will create a gap in the chart. - if (point[0] <= 0 || point[1] <= 0) { - point = null; - } +Dygraph.DataHandlers.DefaultFractionHandler = Dygraph.DataHandler(); +var DefaultFractionHandler = Dygraph.DataHandlers.DefaultFractionHandler; +DefaultFractionHandler.prototype = new Dygraph.DataHandlers.DefaultHandler(); + +DefaultFractionHandler.prototype.extractSeries = function(rawData, i, options) { + // TODO(danvk): pre-allocate series here. + var series = []; + var x, y, point, num, den, value; + var mult = 100.0; + var logScale = options.get('logscale'); + for ( var j = 0; j < rawData.length; j++) { + x = rawData[j][0]; + point = rawData[j][i]; + if (logScale && point !== null) { + // On the log scale, points less than zero do not exist. + // This will create a gap in the chart. + if (point[0] <= 0 || point[1] <= 0) { + point = null; } - // Extract to the unified data format. - if (point !== null) { - num = point[0]; - den = point[1]; - if (num !== null && !isNaN(num)) { - value = den ? num / den : 0.0; - y = mult * value; - // preserve original values in extras for further filtering - series.push([ x, y, [ num, den ] ]); - } else { - series.push([ x, num, [ num, den ] ]); - } + } + // Extract to the unified data format. + if (point !== null) { + num = point[0]; + den = point[1]; + if (num !== null && !isNaN(num)) { + value = den ? num / den : 0.0; + y = mult * value; + // preserve original values in extras for further filtering + series.push([ x, y, [ num, den ] ]); } else { - series.push([ x, null, [ null, null ] ]); + series.push([ x, num, [ num, den ] ]); } + } else { + series.push([ x, null, [ null, null ] ]); } - return series; - }; - - DefaultFractionHandler.prototype.rollingAverage = function(originalData, rollPeriod, - options) { - rollPeriod = Math.min(rollPeriod, originalData.length); - var rollingData = []; + } + return series; +}; - var i; - var num = 0; - var den = 0; // numerator/denominator - var mult = 100.0; - for (i = 0; i < originalData.length; i++) { - num += originalData[i][2][0]; - den += originalData[i][2][1]; - if (i - rollPeriod >= 0) { - num -= originalData[i - rollPeriod][2][0]; - den -= originalData[i - rollPeriod][2][1]; - } +DefaultFractionHandler.prototype.rollingAverage = function(originalData, rollPeriod, + options) { + rollPeriod = Math.min(rollPeriod, originalData.length); + var rollingData = []; - var date = originalData[i][0]; - var value = den ? num / den : 0.0; - rollingData[i] = [ date, mult * value ]; + var i; + var num = 0; + var den = 0; // numerator/denominator + var mult = 100.0; + for (i = 0; i < originalData.length; i++) { + num += originalData[i][2][0]; + den += originalData[i][2][1]; + if (i - rollPeriod >= 0) { + num -= originalData[i - rollPeriod][2][0]; + den -= originalData[i - rollPeriod][2][1]; } - return rollingData; - }; + var date = originalData[i][0]; + var value = den ? num / den : 0.0; + rollingData[i] = [ date, mult * value ]; + } + + return rollingData; +}; + })(); diff --git a/datahandler/default.js b/datahandler/default.js index 79adcb5..6e6697f 100644 --- a/datahandler/default.js +++ b/datahandler/default.js @@ -10,79 +10,81 @@ */ (function() { - /*global Dygraph:false */ - "use strict"; - var DefaultHandler = Dygraph.DataHandler(); - Dygraph.DataHandlers.registerHandler("default", DefaultHandler); +/*global Dygraph:false */ +"use strict"; - DefaultHandler.prototype.extractSeries = function(rawData, i, options) { - // TODO(danvk): pre-allocate series here. - var series = []; - var logScale = options.get('logscale'); - for ( var j = 0; j < rawData.length; j++) { - var x = rawData[j][0]; - var point = rawData[j][i]; - if (logScale) { - // On the log scale, points less than zero do not exist. - // This will create a gap in the chart. - if (point <= 0) { - point = null; - } +Dygraph.DataHandlers.DefaultHandler = Dygraph.DataHandler(); +var DefaultHandler = Dygraph.DataHandlers.DefaultHandler; + +DefaultHandler.prototype.extractSeries = function(rawData, i, options) { + // TODO(danvk): pre-allocate series here. + var series = []; + var logScale = options.get('logscale'); + for ( var j = 0; j < rawData.length; j++) { + var x = rawData[j][0]; + var point = rawData[j][i]; + if (logScale) { + // On the log scale, points less than zero do not exist. + // This will create a gap in the chart. + if (point <= 0) { + point = null; } - series.push([ x, point ]); } - return series; - }; + series.push([ x, point ]); + } + return series; +}; - DefaultHandler.prototype.rollingAverage = function(originalData, rollPeriod, - options) { - rollPeriod = Math.min(rollPeriod, originalData.length); - var rollingData = []; +DefaultHandler.prototype.rollingAverage = function(originalData, rollPeriod, + options) { + rollPeriod = Math.min(rollPeriod, originalData.length); + var rollingData = []; - var i, j, y, sum, num_ok; - // Calculate the rolling average for the first rollPeriod - 1 points - // where - // there is not enough data to roll over the full number of points - if (rollPeriod == 1) { - return originalData; + var i, j, y, sum, num_ok; + // Calculate the rolling average for the first rollPeriod - 1 points + // where + // there is not enough data to roll over the full number of points + if (rollPeriod == 1) { + return originalData; + } + for (i = 0; i < originalData.length; i++) { + sum = 0; + num_ok = 0; + for (j = Math.max(0, i - rollPeriod + 1); j < i + 1; j++) { + y = originalData[j][1]; + if (y === null || isNaN(y)) + continue; + num_ok++; + sum += originalData[j][1]; } - for (i = 0; i < originalData.length; i++) { - sum = 0; - num_ok = 0; - for (j = Math.max(0, i - rollPeriod + 1); j < i + 1; j++) { - y = originalData[j][1]; - if (y === null || isNaN(y)) - continue; - num_ok++; - sum += originalData[j][1]; - } - if (num_ok) { - rollingData[i] = [ originalData[i][0], sum / num_ok ]; - } else { - rollingData[i] = [ originalData[i][0], null ]; - } + if (num_ok) { + rollingData[i] = [ originalData[i][0], sum / num_ok ]; + } else { + rollingData[i] = [ originalData[i][0], null ]; } + } - return rollingData; - }; + return rollingData; +}; - DefaultHandler.prototype.getExtremeYValues = function(series, dateWindow, - options) { - var minY = null, maxY = null, y; - var firstIdx = 0, lastIdx = series.length - 1; +DefaultHandler.prototype.getExtremeYValues = function(series, dateWindow, + options) { + var minY = null, maxY = null, y; + var firstIdx = 0, lastIdx = series.length - 1; - for ( var j = firstIdx; j <= lastIdx; j++) { - y = series[j][1]; - if (y === null || isNaN(y)) - continue; - if (maxY === null || y > maxY) { - maxY = y; - } - if (minY === null || y < minY) { - minY = y; - } + for ( var j = firstIdx; j <= lastIdx; j++) { + y = series[j][1]; + if (y === null || isNaN(y)) + continue; + if (maxY === null || y > maxY) { + maxY = y; } - return [ minY, maxY ]; - }; + if (minY === null || y < minY) { + minY = y; + } + } + return [ minY, maxY ]; +}; + })(); diff --git a/dygraph-options-reference.js b/dygraph-options-reference.js index c952072..6220750 100644 --- a/dygraph-options-reference.js +++ b/dygraph-options-reference.js @@ -802,7 +802,13 @@ Dygraph.OPTIONS_REFERENCE = // "default": "[]", "labels": ["Configuration"], "type": "Array", - "description": "Defines per-graph plug-ins. Useful for per-graph customization" + "description": "Defines per-graph plugins. Useful for per-graph customization" + }, + "dataHandler": { + "default": "(depends on data)", + "labels": ["Data"], + "type": "Dygraph.DataHandler", + "description": "Custom DataHandler. This is an advanced customization. See http://bit.ly/151E7Aq." } } ; // diff --git a/dygraph.js b/dygraph.js index 48475ef..cd9f147 100644 --- a/dygraph.js +++ b/dygraph.js @@ -2153,29 +2153,27 @@ Dygraph.prototype.addXTicks_ = function() { }; /** + * Returns the correct handler class for the currently set options. * @private - * Returns the correct handler ID for the currently set options. - * The actual handler may then be retrieved using the - * Dygraph.DataHandlers.getHandler() method. - */ -Dygraph.prototype.getHandlerId_ = function() { - var handlerId; - if (this.attr_("dataHandlerId")) { - handlerId = this.attr_("dataHandlerId"); - } else if (this.fractions_){ - if (this.attr_("errorBars")) { - handlerId = "bars-fractions"; + */ +Dygraph.prototype.getHandlerClass_ = function() { + var handlerClass; + if (this.attr_('dataHandler')) { + handlerClass = this.attr_('dataHandler'); + } else if (this.fractions_) { + if (this.attr_('errorBars')) { + handlerClass = Dygraph.DataHandlers.FractionsBarsHandler; } else { - handlerId = "default-fractions"; + handlerClass = Dygraph.DataHandlers.DefaultFractionHandler; } - } else if (this.attr_("customBars")) { - handlerId = "bars-custom"; - } else if (this.attr_("errorBars")) { - handlerId = "bars-error"; + } else if (this.attr_('customBars')) { + handlerClass = Dygraph.DataHandlers.CustomBarsHandler; + } else if (this.attr_('errorBars')) { + handlerClass = Dygraph.DataHandlers.ErrorBarsHandler; } else { - handlerId = "default"; + handlerClass = Dygraph.DataHandlers.DefaultHandler; } - return handlerId; + return handlerClass; }; /** @@ -2190,7 +2188,7 @@ Dygraph.prototype.predraw_ = function() { var start = new Date(); // Create the correct dataHandler - this.dataHandler_ = new (Dygraph.DataHandlers.getHandler(this.getHandlerId_()))(); + this.dataHandler_ = new (this.getHandlerClass_())(); this.layout_.computePlotArea(); -- 2.7.4