UNPKG

dygraphs

Version:

dygraphs is a fast, flexible open source JavaScript charting library.

1,372 lines (1,287 loc) 430 kB
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Dygraph = f()}})(function(){var define,module,exports;var r=(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){ /* * dygraphs is MIT-licenced: * * Copyright (c) 2006, 2009, 2011, 2012, 2013, 2017 * Dan Vanderkam <danvdk@gmail.com> * Copyright (c) 2011 Paul Felix <paul.eric.felix@gmail.com> * Copyright (c) 2011, 2013 Robert Konigsberg <konigsberg@google.com> * Copyright (c) 2013 David Eberlein <david.eberlein@ch.sauter-bc.com> * Copyright (c) 2013 Google, Inc. * Copyright (c) 2014 mirabilos <m@mirbsd.org> * Copyright (c) 2015 Petr Shevtsov <petr.shevtsov@gmail.com> * Copyright (c) 2022, 2023 mirabilos <t.glaser@tarent.de> * Deutsche Telekom LLCTO * and numerous contributors (see git log) * * Some tests additionally are: * * Copyright (c) 2011, 2012 Google, Inc. <danvk@google.com> * or contributed by: * - Benoit Boivin <benoitboivin.pro@gmail.com> * - Paul Felix <paul.eric.felix@gmail.com> * - Marek Janda <nyx@nyx.cz> * - Robert Konigsberg <konigsberg@google.com> * - George Madrid <gmadrid@gmail.com> * - Anthony Robledo <antrob@google.com> * - Fr. Sauter AG <julian.eichstaedt@ch.sauter-bc.com> * - Fr. Sauter AG <david.eberlein@ch.sauter-bc.com> * - Ümit Seren <uemit.seren@gmail.com> * - Sergey Slepian <sergeyslepian@gmail.com> * - Dan Vanderkam <dan@dygraphs.com> * * Parts of the documentation are or make use of code that is: * * Copyright (c) 2012 Google, Inc. * - Robert Konigsberg <konigsberg@google.com> * * The automatically added browser-pack shim is: * * Copyright (c) 2013, 2014 James Halliday <mail@substack.net> * Copyright (c) 2013 Roman Shtylman <shtylman@gmail.com> * Copyright (c) 2013 Esa-Matti Suuronen <esa-matti@suuronen.org> * Copyright (c) 2018 Philipp Simon Schmidt <github@philippsimon.de> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * The documentation and gallery uses Bootstrap and jQuery; see the * relevant licence files of those external libraries for details. * * The icons under common/ are CC0-licenced and adapted by mirabilos. * In Debian, /usr/share/common-licenses/CC0-1.0 has the full text. */ "use strict"; },{}],"dygraphs/src/datahandler/bars-custom.js":[function(require,module,exports){ /** * @license * Copyright 2013 David Eberlein (david.eberlein@ch.sauter-bc.com) * MIT-licenced: https://opensource.org/licenses/MIT */ /** * @fileoverview DataHandler implementation for the custom bars option. * @author David Eberlein (david.eberlein@ch.sauter-bc.com) */ /*global Dygraph:false */ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = void 0; var _bars = _interopRequireDefault(require("./bars")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } /** * @constructor * @extends Dygraph.DataHandlers.BarsHandler */ var CustomBarsHandler = function CustomBarsHandler() {}; CustomBarsHandler.prototype = new _bars["default"](); /** @inheritDoc */ CustomBarsHandler.prototype.extractSeries = function (rawData, i, options) { // TODO(danvk): pre-allocate series here. var series = []; var x, y, point; var seriesLabel = options.get("labels")[i]; var logScale = options.getForSeries("logscale", seriesLabel); 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]]); } } else { series.push([x, null, [null, null]]); } } return series; }; /** @inheritDoc */ CustomBarsHandler.prototype.rollingAverage = function (originalData, rollPeriod, options, i) { 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]; 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; }; var _default = CustomBarsHandler; exports["default"] = _default; module.exports = exports.default; },{"./bars":"dygraphs/src/datahandler/bars.js"}],"dygraphs/src/datahandler/bars-error.js":[function(require,module,exports){ /** * @license * Copyright 2013 David Eberlein (david.eberlein@ch.sauter-bc.com) * MIT-licenced: https://opensource.org/licenses/MIT */ /** * @fileoverview DataHandler implementation for the errorBars option. * @author David Eberlein (david.eberlein@ch.sauter-bc.com) */ /*global Dygraph:false */ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = void 0; var _bars = _interopRequireDefault(require("./bars")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } /** * @constructor * @extends BarsHandler */ var ErrorBarsHandler = function ErrorBarsHandler() {}; ErrorBarsHandler.prototype = new _bars["default"](); /** @inheritDoc */ ErrorBarsHandler.prototype.extractSeries = function (rawData, i, options) { // TODO(danvk): pre-allocate series here. var series = []; var x, y, variance, point; var seriesLabel = options.get("labels")[i]; var logScale = options.getForSeries("logscale", seriesLabel); var sigma = options.getForSeries("sigma", seriesLabel); 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]]); } } else { series.push([x, null, [null, null, null]]); } } return series; }; /** @inheritDoc */ ErrorBarsHandler.prototype.rollingAverage = function (originalData, rollPeriod, options, i) { rollPeriod = Math.min(rollPeriod, originalData.length); var rollingData = []; var seriesLabel = options.get("labels")[i]; var sigma = options.getForSeries("sigma", seriesLabel); 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]]; } } return rollingData; }; var _default = ErrorBarsHandler; exports["default"] = _default; module.exports = exports.default; },{"./bars":"dygraphs/src/datahandler/bars.js"}],"dygraphs/src/datahandler/bars-fractions.js":[function(require,module,exports){ /** * @license * Copyright 2013 David Eberlein (david.eberlein@ch.sauter-bc.com) * MIT-licenced: https://opensource.org/licenses/MIT */ /** * @fileoverview DataHandler implementation for the combination * of error bars and fractions options. * @author David Eberlein (david.eberlein@ch.sauter-bc.com) */ /*global Dygraph:false */ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = void 0; var _bars = _interopRequireDefault(require("./bars")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } /** * @constructor * @extends Dygraph.DataHandlers.BarsHandler */ var FractionsBarsHandler = function FractionsBarsHandler() {}; FractionsBarsHandler.prototype = new _bars["default"](); /** @inheritDoc */ 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 seriesLabel = options.get("labels")[i]; var logScale = options.getForSeries("logscale", seriesLabel); var sigma = options.getForSeries("sigma", seriesLabel); 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]]); } } else { series.push([x, null, [null, null, null, null]]); } } return series; }; /** @inheritDoc */ FractionsBarsHandler.prototype.rollingAverage = function (originalData, rollPeriod, options, i) { rollPeriod = Math.min(rollPeriod, originalData.length); var rollingData = []; var seriesLabel = options.get("labels")[i]; var sigma = options.getForSeries("sigma", seriesLabel); var wilsonInterval = options.getForSeries("wilsonInterval", seriesLabel); 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: // https://en.wikipedia.org/wiki/Binomial_proportion_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]]; } } 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; }; var _default = FractionsBarsHandler; exports["default"] = _default; module.exports = exports.default; },{"./bars":"dygraphs/src/datahandler/bars.js"}],"dygraphs/src/datahandler/bars.js":[function(require,module,exports){ /** * @license * Copyright 2013 David Eberlein (david.eberlein@ch.sauter-bc.com) * MIT-licenced: https://opensource.org/licenses/MIT */ /** * @fileoverview DataHandler base implementation for the "bar" * data formats. This implementation must be extended and the * extractSeries and rollingAverage must be implemented. * @author David Eberlein (david.eberlein@ch.sauter-bc.com) */ /*global Dygraph:false */ /*global DygraphLayout:false */ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = void 0; var _datahandler = _interopRequireDefault(require("./datahandler")); var _dygraphLayout = _interopRequireDefault(require("../dygraph-layout")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } /** * @constructor * @extends {Dygraph.DataHandler} */ var BarsHandler = function BarsHandler() { _datahandler["default"].call(this); }; BarsHandler.prototype = new _datahandler["default"](); // TODO(danvk): figure out why the jsdoc has to be copy/pasted from superclass. // (I get closure compiler errors if this isn't here.) /** * @override * @param {!Array.<Array>} rawData The raw data passed into dygraphs where * rawData[i] = [x,ySeries1,...,ySeriesN]. * @param {!number} seriesIndex Index of the series to extract. All other * series should be ignored. * @param {!DygraphOptions} options Dygraph options. * @return {Array.<[!number,?number,?]>} The series in the unified data format * where series[i] = [x,y,{extras}]. */ BarsHandler.prototype.extractSeries = function (rawData, seriesIndex, options) { // Not implemented here must be extended }; /** * @override * @param {!Array.<[!number,?number,?]>} series The series in the unified * data format where series[i] = [x,y,{extras}]. * @param {!number} rollPeriod The number of points over which to average the data * @param {!DygraphOptions} options The dygraph options. * @param {!number} seriesIndex Index of the series this was extracted from. * TODO(danvk): be more specific than "Array" here. * @return {!Array.<[!number,?number,?]>} the rolled series. */ BarsHandler.prototype.rollingAverage = function (series, rollPeriod, options, seriesIndex) { // Not implemented here, must be extended. }; /** @inheritDoc */ 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 = _datahandler["default"].parseFloat(item[2][0]); point.yval_plus = _datahandler["default"].parseFloat(item[2][1]); } }; /** @inheritDoc */ BarsHandler.prototype.getExtremeYValues = function (series, dateWindow, stepPlot) { 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]; }; /** @inheritDoc */ 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["default"].calcYNormal_(axis, point.yval_minus, logscale); point.y_bottom = _dygraphLayout["default"].calcYNormal_(axis, point.yval_plus, logscale); } }; var _default = BarsHandler; exports["default"] = _default; module.exports = exports.default; },{"../dygraph-layout":"dygraphs/src/dygraph-layout.js","./datahandler":"dygraphs/src/datahandler/datahandler.js"}],"dygraphs/src/datahandler/datahandler.js":[function(require,module,exports){ /** * @license * Copyright 2013 David Eberlein (david.eberlein@ch.sauter-bc.com) * MIT-licenced: https://opensource.org/licenses/MIT */ /** * @fileoverview This file contains the managment of data handlers * @author David Eberlein (david.eberlein@ch.sauter-bc.com) * * The idea is to define a common, generic data format that works for all data * structures supported by dygraphs. To make this possible, the DataHandler * interface is introduced. This makes it possible, that dygraph itself can work * with the same logic for every data type independent of the actual format and * the DataHandler takes care of the data format specific jobs. * DataHandlers are implemented for all data types supported by Dygraphs and * return Dygraphs compliant formats. * By default the correct DataHandler is chosen based on the options set. * Optionally the user may use his own DataHandler (similar to the plugin * system). * * * The unified data format returend by each handler is defined as so: * series[n][point] = [x,y,(extras)] * * This format contains the common basis that is needed to draw a simple line * series extended by optional extras for more complex graphing types. It * contains a primitive x value as first array entry, a primitive y value as * second array entry and an optional extras object for additional data needed. * * x must always be a number. * y must always be a number, NaN of type number or null. * extras is optional and must be interpreted by the DataHandler. It may be of * any type. * * In practice this might look something like this: * default: [x, yVal] * errorBar / customBar: [x, yVal, [yTopVariance, yBottomVariance] ] * */ /*global Dygraph:false */ /*global DygraphLayout:false */ "use strict"; /** * * 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 * @constructor */ Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = void 0; var DygraphDataHandler = function DygraphDataHandler() {}; var handler = DygraphDataHandler; /** * X-value array index constant for unified data samples. * @const * @type {number} */ handler.X = 0; /** * Y-value array index constant for unified data samples. * @const * @type {number} */ handler.Y = 1; /** * Extras-value array index constant for unified data samples. * @const * @type {number} */ handler.EXTRAS = 2; /** * Extracts one series from the raw data (a 2D array) into an array of the * unified data format. * This is where undesirable points (i.e. negative values on log scales and * missing values through which we wish to connect lines) are dropped. * TODO(danvk): the "missing values" bit above doesn't seem right. * * @param {!Array.<Array>} rawData The raw data passed into dygraphs where * rawData[i] = [x,ySeries1,...,ySeriesN]. * @param {!number} seriesIndex Index of the series to extract. All other * series should be ignored. * @param {!DygraphOptions} options Dygraph options. * @return {Array.<[!number,?number,?]>} The series in the unified data format * where series[i] = [x,y,{extras}]. */ handler.prototype.extractSeries = function (rawData, seriesIndex, options) {}; /** * Converts a series to a Point array. The resulting point array must be * returned in increasing order of idx property. * * @param {!Array.<[!number,?number,?]>} series The series in the unified * data format where series[i] = [x,y,{extras}]. * @param {!string} setName Name of the series. * @param {!number} boundaryIdStart Index offset of the first point, equal to the * number of skipped points left of the date window minimum (if any). * @return {!Array.<Dygraph.PointType>} List of points for this series. */ handler.prototype.seriesToPoints = function (series, setName, boundaryIdStart) { // TODO(bhs): these loops are a hot-spot for high-point-count charts. In // fact, // on chrome+linux, they are 6 times more expensive than iterating through // the // points and drawing the lines. The brunt of the cost comes from allocating // the |point| structures. var points = []; for (var i = 0; i < series.length; ++i) { var item = series[i]; var yraw = item[1]; var yval = yraw === null ? null : handler.parseFloat(yraw); var point = { x: NaN, y: NaN, xval: handler.parseFloat(item[0]), yval: yval, name: setName, // TODO(danvk): is this really necessary? idx: i + boundaryIdStart, canvasx: NaN, // add these so we do not alter the structure later, which slows Chrome canvasy: NaN }; points.push(point); } this.onPointsCreated_(series, points); return points; }; /** * Callback called for each series after the series points have been generated * which will later be used by the plotters to draw the graph. * Here data may be added to the seriesPoints which is needed by the plotters. * The indexes of series and points are in sync meaning the original data * sample for series[i] is points[i]. * * @param {!Array.<[!number,?number,?]>} series The series in the unified * data format where series[i] = [x,y,{extras}]. * @param {!Array.<Dygraph.PointType>} points The corresponding points passed * to the plotter. * @protected */ handler.prototype.onPointsCreated_ = function (series, points) {}; /** * Calculates the rolling average of a data set. * * @param {!Array.<[!number,?number,?]>} series The series in the unified * data format where series[i] = [x,y,{extras}]. * @param {!number} rollPeriod The number of points over which to average the data * @param {!DygraphOptions} options The dygraph options. * @param {!number} seriesIndex Index of the series this was extracted from. * @return {!Array.<[!number,?number,?]>} the rolled series. */ handler.prototype.rollingAverage = function (series, rollPeriod, options, seriesIndex) {}; /** * Computes the range of the data series (including confidence intervals). * * @param {!Array.<[!number,?number,?]>} series The series in the unified * data format where series[i] = [x, y, {extras}]. * @param {!Array.<number>} dateWindow The x-value range to display with * the format: [min, max]. * @param {boolean} stepPlot Whether the stepPlot option is set. * @return {Array.<number>} The low and high extremes of the series in the * given window with the format: [low, high]. */ handler.prototype.getExtremeYValues = function (series, dateWindow, stepPlot) {}; /** * Callback called for each series after the layouting data has been * calculated before the series is drawn. Here normalized positioning data * should be calculated for the extras of each point. * * @param {!Array.<Dygraph.PointType>} points The points passed to * the plotter. * @param {!Object} axis The axis on which the series will be plotted. * @param {!boolean} logscale Whether or not to use a logscale. */ handler.prototype.onLineEvaluated = function (points, axis, logscale) {}; /** * Optimized replacement for parseFloat, which was way too slow when almost * all values were type number, with few edge cases, none of which were strings. * @param {?number} val * @return {number} * @protected */ handler.parseFloat = function (val) { // parseFloat(null) is NaN if (val === null) { return NaN; } // Assume it's a number or NaN. If it's something else, I'll be shocked. return val; }; var _default = DygraphDataHandler; exports["default"] = _default; module.exports = exports.default; },{}],"dygraphs/src/datahandler/default-fractions.js":[function(require,module,exports){ /** * @license * Copyright 2013 David Eberlein (david.eberlein@ch.sauter-bc.com) * MIT-licenced: https://opensource.org/licenses/MIT */ /** * @fileoverview DataHandler implementation for the fractions option. * @author David Eberlein (david.eberlein@ch.sauter-bc.com) */ /*global Dygraph:false */ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = void 0; var _datahandler = _interopRequireDefault(require("./datahandler")); var _default2 = _interopRequireDefault(require("./default")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } /** * @extends DefaultHandler * @constructor */ var DefaultFractionHandler = function DefaultFractionHandler() {}; DefaultFractionHandler.prototype = new _default2["default"](); 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 seriesLabel = options.get("labels")[i]; var logScale = options.getForSeries("logscale", seriesLabel); 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]]); } } else { series.push([x, null, [null, null]]); } } return series; }; DefaultFractionHandler.prototype.rollingAverage = function (originalData, rollPeriod, options, i) { rollPeriod = Math.min(rollPeriod, originalData.length); var rollingData = []; 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]; } var date = originalData[i][0]; var value = den ? num / den : 0.0; rollingData[i] = [date, mult * value]; } return rollingData; }; var _default = DefaultFractionHandler; exports["default"] = _default; module.exports = exports.default; },{"./datahandler":"dygraphs/src/datahandler/datahandler.js","./default":"dygraphs/src/datahandler/default.js"}],"dygraphs/src/datahandler/default.js":[function(require,module,exports){ /** * @license * Copyright 2013 David Eberlein (david.eberlein@ch.sauter-bc.com) * MIT-licenced: https://opensource.org/licenses/MIT */ /** * @fileoverview DataHandler default implementation used for simple line charts. * @author David Eberlein (david.eberlein@ch.sauter-bc.com) */ /*global Dygraph:false */ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = void 0; var _datahandler = _interopRequireDefault(require("./datahandler")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } /** * @constructor * @extends Dygraph.DataHandler */ var DefaultHandler = function DefaultHandler() {}; DefaultHandler.prototype = new _datahandler["default"](); /** @inheritDoc */ DefaultHandler.prototype.extractSeries = function (rawData, i, options) { // TODO(danvk): pre-allocate series here. var series = []; var seriesLabel = options.get("labels")[i]; var logScale = options.getForSeries("logscale", seriesLabel); 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; }; /** @inheritDoc */ DefaultHandler.prototype.rollingAverage = function (originalData, rollPeriod, options, i) { 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; } 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]; } } return rollingData; }; /** @inheritDoc */ DefaultHandler.prototype.getExtremeYValues = function getExtremeYValues(series, dateWindow, stepPlot) { 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; } } return [minY, maxY]; }; var _default = DefaultHandler; exports["default"] = _default; module.exports = exports.default; },{"./datahandler":"dygraphs/src/datahandler/datahandler.js"}],"dygraphs/src/dygraph-canvas.js":[function(require,module,exports){ /** * @license * Copyright 2006 Dan Vanderkam (danvdk@gmail.com) * MIT-licenced: https://opensource.org/licenses/MIT */ /** * @fileoverview Based on PlotKit.CanvasRenderer, but modified to meet the * needs of dygraphs. * * In particular, support for: * - grid overlays * - high/low bands * - dygraphs attribute system */ /** * The DygraphCanvasRenderer class does the actual rendering of the chart onto * a canvas. It's based on PlotKit.CanvasRenderer. * @param {Object} element The canvas to attach to * @param {Object} elementContext The 2d context of the canvas (injected so it * can be mocked for testing.) * @param {Layout} layout The DygraphLayout object for this graph. * @constructor */ /*global Dygraph:false */ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = void 0; var utils = _interopRequireWildcard(require("./dygraph-utils")); var _dygraph = _interopRequireDefault(require("./dygraph")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; } /** * @constructor * * This gets called when there are "new points" to chart. This is generally the * case when the underlying data being charted has changed. It is _not_ called * in the common case that the user has zoomed or is panning the view. * * The chart canvas has already been created by the Dygraph object. The * renderer simply gets a drawing context. * * @param {Dygraph} dygraph The chart to which this renderer belongs. * @param {HTMLCanvasElement} element The &lt;canvas&gt; DOM element on which to draw. * @param {CanvasRenderingContext2D} elementContext The drawing context. * @param {DygraphLayout} layout The chart's DygraphLayout object. * * TODO(danvk): remove the elementContext property. */ var DygraphCanvasRenderer = function DygraphCanvasRenderer(dygraph, element, elementContext, layout) { this.dygraph_ = dygraph; this.layout = layout; this.element = element; this.elementContext = elementContext; this.height = dygraph.height_; this.width = dygraph.width_; // --- check whether everything is ok before we return if (!utils.isCanvasSupported(this.element)) { throw "Canvas is not supported."; } // internal state this.area = layout.getPlotArea(); // Set up a clipping area for the canvas (and the interaction canvas). // This ensures that we don't overdraw. var ctx = this.dygraph_.canvas_ctx_; ctx.beginPath(); ctx.rect(this.area.x, this.area.y, this.area.w, this.area.h); ctx.clip(); ctx = this.dygraph_.hidden_ctx_; ctx.beginPath(); ctx.rect(this.area.x, this.area.y, this.area.w, this.area.h); ctx.clip(); }; /** * Clears out all chart content and DOM elements. * This is called immediately before render() on every frame, including * during zooms and pans. * @private */ DygraphCanvasRenderer.prototype.clear = function () { this.elementContext.clearRect(0, 0, this.width, this.height); }; /** * This method is responsible for drawing everything on the chart, including * lines, high/low bands, fills and axes. * It is called immediately after clear() on every frame, including during pans * and zooms. * @private */ DygraphCanvasRenderer.prototype.render = function () { // attaches point.canvas{x,y} this._updatePoints(); // actually draws the chart. this._renderLineChart(); }; /** * Returns a predicate to be used with an iterator, which will * iterate over points appropriately, depending on whether * connectSeparatedPoints is true. When it's false, the predicate will * skip over points with missing yVals. */ DygraphCanvasRenderer._getIteratorPredicate = function (connectSeparatedPoints) { return connectSeparatedPoints ? DygraphCanvasRenderer._predicateThatSkipsEmptyPoints : null; }; DygraphCanvasRenderer._predicateThatSkipsEmptyPoints = function (array, idx) { return array[idx].yval !== null; }; /** * Draws a line with the styles passed in and calls all the drawPointCallbacks. * @param {Object} e The dictionary passed to the plotter function. * @private */ DygraphCanvasRenderer._drawStyledLine = function (e, color, strokeWidth, strokePattern, drawPoints, drawPointCallback, pointSize) { var g = e.dygraph; // TODO(konigsberg): Compute attributes outside this method call. var stepPlot = g.getBooleanOption("stepPlot", e.setName); if (!utils.isArrayLike(strokePattern)) { strokePattern = null; } var drawGapPoints = g.getBooleanOption('drawGapEdgePoints', e.setName); var points = e.points; var setName = e.setName; var iter = utils.createIterator(points, 0, points.length, DygraphCanvasRenderer._getIteratorPredicate(g.getBooleanOption("connectSeparatedPoints", setName))); var stroking = strokePattern && strokePattern.length >= 2; var ctx = e.drawingContext; ctx.save(); if (stroking) { if (ctx.setLineDash) ctx.setLineDash(strokePattern); } var pointsOnLine = DygraphCanvasRenderer._drawSeries(e, iter, strokeWidth, pointSize, drawPoints, drawGapPoints, stepPlot, color); DygraphCanvasRenderer._drawPointsOnLine(e, pointsOnLine, drawPointCallback, color, pointSize); if (stroking) { if (ctx.setLineDash) ctx.setLineDash([]); } ctx.restore(); }; /** * This does the actual drawing of lines on the canvas, for just one series. * Returns a list of [canvasx, canvasy] pairs for points for which a * drawPointCallback should be fired. These include isolated points, or all * points if drawPoints=true. * @param {Object} e The dictionary passed to the plotter function. * @private */ DygraphCanvasRenderer._drawSeries = function (e, iter, strokeWidth, pointSize, drawPoints, drawGapPoints, stepPlot, color) { var prevCanvasX = null; var prevCanvasY = null; var nextCanvasY = null; var isIsolated; // true if this point is isolated (no line segments) var point; // the point being processed in the while loop var pointsOnLine = []; // Array of [canvasx, canvasy] pairs. var first = true; // the first cycle through the while loop var ctx = e.drawingContext; ctx.beginPath(); ctx.strokeStyle = color; ctx.lineWidth = strokeWidth; // NOTE: we break the iterator's encapsulation here for about a 25% speedup. var arr = iter.array_; var limit = iter.end_; var predicate = iter.predicate_; for (var i = iter.start_; i < limit; i++) { point = arr[i]; if (predicate) { while (i < limit && !predicate(arr, i)) { i++; } if (i == limit) break; point = arr[i]; } // FIXME: The 'canvasy != canvasy' test here catches NaN values but the test // doesn't catch Infinity values. Could change this to // !isFinite(point.canvasy), but I assume it avoids isNaN for performance? if (point.canvasy === null || point.canvasy != point.canvasy) { if (stepPlot && prevCanvasX !== null) { // Draw a horizontal line to the start of the missing data ctx.moveTo(prevCanvasX, prevCanvasY); ctx.lineTo(point.canvasx, prevCanvasY); } prevCanvasX = prevCanvasY = null; } else { isIsolated = false; if (drawGapPoints || prevCanvasX === null) { iter.nextIdx_ = i; iter.next(); nextCanvasY = iter.hasNext ? iter.peek.canvasy : null; var isNextCanvasYNullOrNaN = nextCanvasY === null || nextCanvasY != nextCanvasY; isIsolated = prevCanvasX === null && isNextCanvasYNullOrNaN; if (drawGapPoints) { // Also consider a point to be "isolated" if it's adjacent to a // null point, excluding the graph edges. if (!first && prevCanvasX === null || iter.hasNext && isNextCanvasYNullOrNaN) { isIsolated = true; } } } if (prevCanvasX !== null) { if (strokeWidth) { if (stepPlot) { ctx.moveTo(prevCanvasX, prevCanvasY); ctx.lineTo(point.canvasx, prevCanvasY); } ctx.lineTo(point.canvasx, point.canvasy); } } else { ctx.moveTo(point.canvasx, point.canvasy); } if (drawPoints || isIsolated) { pointsOnLine.push([point.canvasx, point.canvasy, point.idx]); } prevCanvasX = point.canvasx; prevCanvasY = point.canvasy; } first = false; } ctx.stroke(); return pointsOnLine; }; /** * This fires the drawPointCallback functions, which draw dots on the points by * default. This gets used when the "drawPoints" option is set, or when there * are isolated points. * @param {Object} e The dictionary passed to the plotter function. * @private */ DygraphCanvasRenderer._drawPointsOnLine = function (e, pointsOnLine, drawPointCallback, color, pointSize) { var ctx = e.drawingContext; for (var idx = 0; idx < pointsOnLine.length; idx++) { var cb = pointsOnLine[idx]; ctx.save(); drawPointCallback.call(e.dygraph, e.dygraph, e.setName, ctx, cb[0], cb[1], color, pointSize, cb[2]); ctx.restore(); } }; /** * Attaches canvas coordinates to the points array. * @private */ DygraphCanvasRenderer.prototype._updatePoints = function () { // Update Points // TODO(danvk): here // // TODO(bhs): this loop is a hot-spot for high-point-count charts. These // transformations can be pushed into the canvas via linear transformation // matrices. // NOTE(danvk): this is trickier than it sounds at first. The transformation // needs to be done before the .moveTo() and .lineTo() calls, but must be // undone before the .stroke() call to ensure that the stroke width is // unaffected. An alternative is to reduce the stroke width in the // transformed coordinate space, but you can't specify different values for // each dimension (as you can with .scale()). The speedup here is ~12%. var sets = this.layout.points; for (var i = sets.length; i--;) { var points = sets[i]; for (var j = points.length; j--;) { var point = points[j]; point.canvasx = this.area.w * point.x + this.area.x; point.canvasy = this.area.h * point.y + this.area.y; } } }; /** * Add canvas Actually draw the lines chart, including high/low bands. * * This function can only be called if DygraphLayout's points array has been * updated with canvas{x,y} attributes, i.e. by * DygraphCanvasRenderer._updatePoints. * * @param {string=} opt_seriesName when specified, only that series will * be drawn. (This is used for expedited redrawing with highlightSeriesOpts) * @param {CanvasRenderingContext2D} opt_ctx when specified, the drawing * context. However, lines are typically drawn on the object's * elementContext. * @private */ DygraphCanvasRenderer.prototype._renderLineChart = function (opt_seriesName, opt_ctx) { var ctx = opt_ctx || this.elementContext; var i; var sets = this.layout.points; var setNames = this.layout.setNames; var setName; this.colors = this.dygraph_.colorsMap_; // Determine which series have specialized plotters. var plotter_attr = this.dygraph_.getOption("plotter"); var plotters = plotter_attr; if (!utils.isArrayLike(plotters)) { plotters = [plotters]; } var setPlotters = {}; // series name -> plotter fn. for (i = 0; i < setNames.length; i++) { setName = setNames[i]; var setPlotter = this.dygraph_.getOption("plotter", setName); if (setPlotter == plotter_attr) continue; // not specialized. setPlotters[setName] = setPlotter; } for (i = 0; i < plotters.length; i++) { var plotter = plotters[i]; var is_last = i == plotters.length - 1; for (var j = 0; j < sets.length; j++) { setName = setNames[j]; if (opt_seriesName && setName != opt_seriesName) continue; var points = sets[j]; // Only throw in the specialized plotters on the last iteration. var p = plotter; if (setName in setPlotters) { if (is_last) { p = setPlotters[setName]; } else { // Don't use the standard plotters in this case. continue; } } var color = this.colors[setName]; var strokeWidth = this.dygraph_.getOption("strokeWidth", setName); ctx.save(); ctx.strokeStyle = color; ctx.lineWidth = strokeWidth; p({ points: points, setName: setName, drawingContext: ctx, color: color, strokeWidth: strokeWidth, dygraph: this.dygraph_, axis: this.dygraph_.axisPropertiesForSeries(setName), plotArea: this.area, seriesIndex: j, seriesCount: sets.length, singleSeriesName: opt_seriesName, allSeriesPoints: sets }); ctx.restore(); } } }; /** * Standard plotters. These may be used by clients via Dygraph.Plotters. * See comments there for more details. */ DygraphCanvasRenderer._Plotters = { linePlotter: function linePlotter(e) { DygraphCanvasRenderer._linePlotter(e); }, fillPlotter: function fillPlotter(e) { DygraphCanvasRenderer._fillPlotter(e); }, errorPlotter: function errorPlotter(e) { DygraphCanvasRenderer._errorPlotter(e); } }; /** * Plotter which draws the central lines for a series. * @private */ DygraphCanvasRenderer._linePlotter = function (e) { var g = e.dygraph; var setName = e.setName; var strokeWidth = e.strokeWidth; // TODO(danvk): Check if there's any performance impact of just calling // getOption() inside of _drawStyledLine. Passing in so many parameters makes // this code a bit nasty. var borderWidth = g.getNumericOption("strokeBorderWidth", setName); var drawPointCallback = g.getOption("drawPointCallback", setName) || utils.Circles.DEFAULT; var strokePattern = g.getOption("strokePattern", setName); var drawPoints = g.getBooleanOption("drawPoints", setName); var pointSize = g.getNumericOption("pointSize", setName); if (borderWidth && strokeWidth) { DygraphCanvasRenderer._drawStyledLine(e, g.getOption("strokeBorderColor", setName), strokeWidth + 2 * borderWidth, strokePattern, drawPoints, drawPointCallback, pointSize); } DygraphCanvasRenderer._drawStyledLine(e, e.color, strokeWidth, strokePattern, drawPoints, drawPointCallback, pointSize); }; /** * Draws the shaded high/low bands (confidence intervals) for each series. * This happens before the center lines are drawn, since the center lines * need to be drawn on top of the high/low bands for all series. * @private */ DygraphCanvasRenderer._errorPlotter = function (e) { var g = e.dygraph; var setName = e.setName; var errorBars = g.getBooleanOption("errorBars") || g.getBooleanOption("customBars"); if (!errorBars) return; var fillGraph = g.getBooleanOption("fillGraph", setName); if (fillGraph) { console.warn("Can't use fillGraph option with customBars or errorBars option"); } var ctx = e.drawingContext; var color = e.color; var fillAlpha = g.getNumericOption('fillAlpha', setName); var stepPlot = g.getBooleanOption("stepPlot", setName); var points = e.points; var iter = utils.createIterator(points, 0, points.length, DygraphCanvasRenderer._getIteratorPredicate(g.getBooleanOption("connectSeparatedPoints", setName))); var newYs; // setup graphics context var prevX = NaN; var prevY = NaN; var prevYs = [-1, -1]; // should be same color as the lines but only 15% opaque. var rgb = utils.toRGB_(color); var err_color = 'rgba(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ',' + fillAlpha + ')'; ctx.fillStyle = err_color; ctx.beginPath(); var isNullUndefinedOrNaN = function isNullUndefinedOrNaN(x) { return x === null || x === undefined || isNaN(x); }; while (iter.hasNext) { var point = iter.next(); if (!stepPlot && isNullUndefinedOrNaN(point.y) || stepPlot && !isNaN(prevY) && isNullUndefinedOrNaN(prevY)) { prevX = NaN; continue; } newYs = [point.y_bottom, point.y_top]; if (stepPlot) { prevY = point.y; } // The documentation specifically disallows nulls inside the point arrays, // but in case it happens we should do something sensible. if (isNaN(newYs[0])) newYs[0] = point.y; if (isNaN(newYs[1])) newYs[1] = point.y; newYs[0] = e.plotArea.h * newYs[0] + e.plotArea.y; newYs[1] = e.plotArea.h * newYs[1] + e.plotArea.y; if (!isNaN(prevX)) { if (stepPlot) { ctx.moveTo(prevX, prevYs[0]); ctx.lineTo(point.canvasx, prevYs[0]); ctx.lineTo(point.canvasx, prevYs[1]); } else { ctx.moveTo(prevX, prevYs[0]); ctx.lineTo(point.canvasx, newYs[0]); ctx.lineTo(point.canvasx, newYs[1]); } ctx.lineTo(prevX, prevYs[1]); ctx.closePath(); } prevYs = newYs; prevX = point.canvasx; } ctx.fill(); }; /** * Proxy for CanvasRenderingContext2D which drops moveTo/lineTo calls which ar