X-Git-Url: https://adrianiainlam.tk/git/?a=blobdiff_plain;f=src%2Fdygraph.js;h=ce9f11072a789f6c83b146903fc3b7a55f9af2d4;hb=cf61aeb77cda5e2638b1f00588dcd90394afd24c;hp=396b85869857d2d4fa1ff98a36bc2bb24b323dbe;hpb=6ecc073934b76e5076f917112a24ff7094857730;p=dygraphs.git diff --git a/src/dygraph.js b/src/dygraph.js index 396b858..ce9f110 100644 --- a/src/dygraph.js +++ b/src/dygraph.js @@ -43,10 +43,6 @@ */ -// For "production" code, this gets set to false by uglifyjs. -// if (typeof(DEBUG) === 'undefined') DEBUG=true; -var DEBUG = true; - import DygraphLayout from './dygraph-layout'; import DygraphCanvasRenderer from './dygraph-canvas'; import DygraphOptions from './dygraph-options'; @@ -54,8 +50,15 @@ 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 OPTIONS_REFERENCE from './dygraph-options-reference'; +import IFrameTarp from './iframe-tarp'; + import DefaultHandler from './datahandler/default'; +import ErrorBarsHandler from './datahandler/bars-error'; +import CustomBarsHandler from './datahandler/bars-custom'; +import DefaultFractionHandler from './datahandler/default-fractions'; +import FractionsBarsHandler from './datahandler/bars-fractions'; +import BarsHandler from './datahandler/bars'; import AnnotationsPlugin from './plugins/annotations'; import AxesPlugin from './plugins/axes'; @@ -64,7 +67,8 @@ import GridPlugin from './plugins/grid'; import LegendPlugin from './plugins/legend'; import RangeSelectorPlugin from './plugins/range-selector'; -/*global DygraphLayout:false, DygraphCanvasRenderer:false, DygraphOptions:false, G_vmlCanvasManager:false,ActiveXObject:false */ +import GVizChart from './dygraph-gviz'; + "use strict"; /** @@ -362,16 +366,17 @@ 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; - // } - // } + // For "production" code, this gets removed by uglifyjs. + if (process.env.NODE_ENV != 'production') { + if (typeof(OPTIONS_REFERENCE) === 'undefined') { + console.error('Must include options reference JS for testing'); + } else if (!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. + OPTIONS_REFERENCE[name] = true; + } + } return seriesName ? this.attributes_.getForSeries(name, seriesName) : this.attributes_.get(name); }; @@ -627,32 +632,8 @@ Dygraph.prototype.toDataXCoord = function(x) { if (!this.attributes_.getForAxis("logscale", 'x')) { return xRange[0] + (x - area.x) / area.w * (xRange[1] - xRange[0]); } else { - // TODO: remove duplicate code? - // Computing the inverse of toDomCoord. var pct = (x - area.x) / area.w; - - // Computing the inverse of toPercentXCoord. The function was arrived at with - // the following steps: - // - // Original calcuation: - // pct = (log(x) - log(xRange[0])) / (log(xRange[1]) - log(xRange[0]))); - // - // Multiply both sides by the right-side demoninator. - // pct * (log(xRange[1] - log(xRange[0]))) = log(x) - log(xRange[0]) - // - // add log(xRange[0]) to both sides - // log(xRange[0]) + (pct * (log(xRange[1]) - log(xRange[0])) = log(x); - // - // Swap both sides of the equation, - // log(x) = log(xRange[0]) + (pct * (log(xRange[1]) - log(xRange[0])) - // - // Use both sides as the exponent in 10^exp and we're done. - // x = 10 ^ (log(xRange[0]) + (pct * (log(xRange[1]) - log(xRange[0]))) - var logr0 = Dygraph.log10(xRange[0]); - var logr1 = Dygraph.log10(xRange[1]); - var exponent = logr0 + (pct * (logr1 - logr0)); - var value = Math.pow(Dygraph.LOG_SCALE, exponent); - return value; + return utils.logRangeFraction(xRange[0], xRange[1], pct); } }; @@ -676,32 +657,8 @@ Dygraph.prototype.toDataYCoord = function(y, axis) { } else { // Computing the inverse of toDomCoord. var pct = (y - area.y) / area.h; - - // Computing the inverse of toPercentYCoord. The function was arrived at with - // the following steps: - // - // Original calcuation: - // pct = (log(yRange[1]) - log(y)) / (log(yRange[1]) - log(yRange[0])); - // - // Multiply both sides by the right-side demoninator. - // pct * (log(yRange[1]) - log(yRange[0])) = log(yRange[1]) - log(y); - // - // subtract log(yRange[1]) from both sides. - // (pct * (log(yRange[1]) - log(yRange[0]))) - log(yRange[1]) = -log(y); - // - // and multiply both sides by -1. - // log(yRange[1]) - (pct * (logr1 - log(yRange[0])) = log(y); - // - // Swap both sides of the equation, - // log(y) = log(yRange[1]) - (pct * (log(yRange[1]) - log(yRange[0]))); - // - // Use both sides as the exponent in 10^exp and we're done. - // y = 10 ^ (log(yRange[1]) - (pct * (log(yRange[1]) - log(yRange[0])))); - var logr0 = Dygraph.log10(yRange[0]); - var logr1 = Dygraph.log10(yRange[1]); - var exponent = logr1 - (pct * (logr1 - logr0)); - var value = Math.pow(Dygraph.LOG_SCALE, exponent); - return value; + // Note reversed yRange, y1 is on top with pct==0. + return utils.logRangeFraction(yRange[1], yRange[0], pct); } }; @@ -732,9 +689,9 @@ Dygraph.prototype.toPercentYCoord = function(y, axis) { var pct; var logscale = this.attributes_.getForAxis("logscale", axis); if (logscale) { - var logr0 = Dygraph.log10(yRange[0]); - var logr1 = Dygraph.log10(yRange[1]); - pct = (logr1 - Dygraph.log10(y)) / (logr1 - logr0); + var logr0 = utils.log10(yRange[0]); + var logr1 = utils.log10(yRange[1]); + pct = (logr1 - utils.log10(y)) / (logr1 - logr0); } else { // yRange[1] - y is unit distance from the bottom. // yRange[1] - yRange[0] is the scale of the range. @@ -766,9 +723,9 @@ Dygraph.prototype.toPercentXCoord = function(x) { var pct; var logscale = this.attributes_.getForAxis("logscale", 'x') ; if (logscale === true) { // logscale can be null so we test for true explicitly. - var logr0 = Dygraph.log10(xRange[0]); - var logr1 = Dygraph.log10(xRange[1]); - pct = (Dygraph.log10(x) - logr0) / (logr1 - logr0); + var logr0 = utils.log10(xRange[0]); + var logr1 = utils.log10(xRange[1]); + pct = (utils.log10(x) - logr0) / (logr1 - logr0); } else { // x - xRange[0] is unit distance from the left. // xRange[1] - xRange[0] is the scale of the range. @@ -932,11 +889,11 @@ Dygraph.prototype.destroy = function() { this.removeTrackedEvents_(); // remove mouse event handlers (This may not be necessary anymore) - Dygraph.removeEvent(window, 'mouseout', this.mouseOutHandler_); - Dygraph.removeEvent(this.mouseEventElement_, 'mousemove', this.mouseMoveHandler_); + utils.removeEvent(window, 'mouseout', this.mouseOutHandler_); + utils.removeEvent(this.mouseEventElement_, 'mousemove', this.mouseMoveHandler_); // remove window handlers - Dygraph.removeEvent(window,'resize', this.resizeHandler_); + utils.removeEvent(window,'resize', this.resizeHandler_); this.resizeHandler_ = null; removeRecursive(this.maindiv_); @@ -1019,7 +976,7 @@ Dygraph.prototype.setColors_ = function() { // alternate colors for high contrast. var idx = i % 2 ? (half + (i + 1)/ 2) : Math.ceil((i + 1) / 2); var hue = (1.0 * idx / (1 + num)); - colorStr = Dygraph.hsvToRGB(hue, sat, val); + colorStr = utils.hsvToRGB(hue, sat, val); } } this.colors_.push(colorStr); @@ -1072,32 +1029,28 @@ Dygraph.prototype.getPropertiesForSeries = function(series_name) { */ Dygraph.prototype.createRollInterface_ = function() { // Create a roller if one doesn't exist already. - if (!this.roller_) { - this.roller_ = document.createElement("input"); - this.roller_.type = "text"; - this.roller_.style.display = "none"; - this.graphDiv.appendChild(this.roller_); + var roller = this.roller_; + if (!roller) { + this.roller_ = roller = document.createElement("input"); + roller.type = "text"; + roller.style.display = "none"; + roller.className = 'dygraph-roller'; + this.graphDiv.appendChild(roller); } var display = this.getBooleanOption('showRoller') ? 'block' : 'none'; - var area = this.plotter_.area; - var textAttr = { "position": "absolute", - "zIndex": 10, + var area = this.getArea(); + var textAttr = { "top": (area.y + area.h - 25) + "px", "left": (area.x + 1) + "px", "display": display - }; - this.roller_.size = "2"; - this.roller_.value = this.rollPeriod_; - for (var name in textAttr) { - if (textAttr.hasOwnProperty(name)) { - this.roller_.style[name] = textAttr[name]; - } - } + }; + roller.size = "2"; + roller.value = this.rollPeriod_; + utils.update(roller.style, textAttr); - var dygraph = this; - this.roller_.onchange = function() { dygraph.adjustRoll(dygraph.roller_.value); }; + roller.onchange = () => this.adjustRoll(roller.value); }; /** @@ -1145,7 +1098,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 utils.IFrameTarp(), + tarp: new IFrameTarp(), // contextB is the same thing as this context object but renamed. initializeMouseDown: function(event, g, contextB) { @@ -1573,7 +1526,7 @@ Dygraph.prototype.findClosestPoint = function(domX, domY) { var points = this.layout_.points[setIdx]; for (var i = 0; i < points.length; ++i) { point = points[i]; - if (!Dygraph.isValidPoint(point)) continue; + if (!utils.isValidPoint(point)) continue; dx = point.canvasx - domX; dy = point.canvasy - domY; dist = dx * dx + dy * dy; @@ -1614,12 +1567,12 @@ Dygraph.prototype.findStackedPoint = function(domX, domY) { var points = this.layout_.points[setIdx]; if (rowIdx >= points.length) continue; var p1 = points[rowIdx]; - if (!Dygraph.isValidPoint(p1)) continue; + if (!utils.isValidPoint(p1)) continue; var py = p1.canvasy; if (domX > p1.canvasx && rowIdx + 1 < points.length) { // interpolate series Y value using next point var p2 = points[rowIdx + 1]; - if (Dygraph.isValidPoint(p2)) { + if (utils.isValidPoint(p2)) { var dx = p2.canvasx - p1.canvasx; if (dx > 0) { var r = (domX - p1.canvasx) / dx; @@ -1629,7 +1582,7 @@ Dygraph.prototype.findStackedPoint = function(domX, domY) { } else if (domX < p1.canvasx && rowIdx > 0) { // interpolate series Y value using previous point var p0 = points[rowIdx - 1]; - if (Dygraph.isValidPoint(p0)) { + if (utils.isValidPoint(p0)) { var dx = p1.canvasx - p0.canvasx; if (dx > 0) { var r = (p1.canvasx - domX) / dx; @@ -1769,6 +1722,8 @@ Dygraph.prototype.updateSelection_ = function(opt_animFraction) { if (this.getOption('highlightSeriesOpts')) { ctx.clearRect(0, 0, this.width_, this.height_); var alpha = 1.0 - this.getNumericOption('highlightSeriesBackgroundAlpha'); + var backgroundColor = utils.toRGB_(this.getOption('highlightSeriesBackgroundColor')); + if (alpha) { // Activating background fade includes an animation effect for a gradual // fade. TODO(klausw): make this independently configurable if it causes @@ -1782,7 +1737,7 @@ Dygraph.prototype.updateSelection_ = function(opt_animFraction) { } alpha *= opt_animFraction; } - ctx.fillStyle = 'rgba(255,255,255,' + alpha + ')'; + ctx.fillStyle = 'rgba(' + backgroundColor.r + ',' + backgroundColor.g + ',' + backgroundColor.b + ',' + alpha + ')'; ctx.fillRect(0, 0, this.width_, this.height_); } @@ -1808,7 +1763,7 @@ Dygraph.prototype.updateSelection_ = function(opt_animFraction) { ctx.save(); for (i = 0; i < this.selPoints_.length; i++) { var pt = this.selPoints_[i]; - if (!utils.isOK(pt.canvasy)) continue; + if (isNaN(pt.canvasy)) continue; var circleSize = this.getNumericOption('highlightCircleSize', pt.name); var callback = this.getFunctionOption("drawHighlightPointCallback", pt.name); @@ -1854,7 +1809,7 @@ Dygraph.prototype.setSelection = function(row, opt_seriesName, opt_locked) { // for. If it is, just use it, otherwise search the array for a point // in the proper place. var setRow = row - this.getLeftBoundary_(setIdx); - if (setRow < points.length && points[setRow].idx == row) { + if (setRow >= 0 && setRow < points.length && points[setRow].idx == row) { var point = points[setRow]; if (point.yval !== null) this.selPoints_.push(point); } else { @@ -2014,14 +1969,14 @@ Dygraph.prototype.getHandlerClass_ = function() { handlerClass = this.attr_('dataHandler'); } else if (this.fractions_) { if (this.getBooleanOption('errorBars')) { - handlerClass = DygraphDataHandlers.FractionsBarsHandler; + handlerClass = FractionsBarsHandler; } else { - handlerClass = DygraphDataHandlers.DefaultFractionHandler; + handlerClass = DefaultFractionHandler; } } else if (this.getBooleanOption('customBars')) { - handlerClass = DygraphDataHandlers.CustomBarsHandler; + handlerClass = CustomBarsHandler; } else if (this.getBooleanOption('errorBars')) { - handlerClass = DygraphDataHandlers.ErrorBarsHandler; + handlerClass = ErrorBarsHandler; } else { handlerClass = DefaultHandler; } @@ -2345,16 +2300,15 @@ Dygraph.prototype.drawGraph_ = function() { this.setIndexByName_ = {}; var labels = this.attr_("labels"); - if (labels.length > 0) { - this.setIndexByName_[labels[0]] = 0; - } var dataIdx = 0; for (var i = 1; i < points.length; i++) { - this.setIndexByName_[labels[i]] = i; if (!this.visibility()[i - 1]) continue; this.layout_.addDataset(labels[i], points[i]); this.datasetIndex_[i] = dataIdx++; } + for (var i = 0; i < labels.length; i++) { + this.setIndexByName_[labels[i]] = i; + } this.computeYAxisRanges_(extremes); this.layout_.setYAxes(this.axes_); @@ -2595,25 +2549,21 @@ Dygraph.prototype.computeYAxisRanges_ = function(extremes) { } } - var maxAxisY, minAxisY; - if (logscale) { - if (ypadCompat) { + var maxAxisY = maxY, minAxisY = minY; + if (ypadCompat) { + if (logscale) { maxAxisY = maxY + ypad * span; minAxisY = minY; } else { - var logpad = Math.exp(Math.log(span) * ypad); - maxAxisY = maxY * logpad; - minAxisY = minY / logpad; - } - } else { - maxAxisY = maxY + ypad * span; - minAxisY = minY - ypad * span; - - // Backwards-compatible behavior: Move the span to start or end at zero if it's - // close to zero, but not if avoidMinZero is set. - if (ypadCompat && !this.getBooleanOption("avoidMinZero")) { - if (minAxisY < 0 && minY >= 0) minAxisY = 0; - if (maxAxisY > 0 && maxY <= 0) maxAxisY = 0; + maxAxisY = maxY + ypad * span; + minAxisY = minY - ypad * span; + + // Backwards-compatible behavior: Move the span to start or end at zero if it's + // close to zero, but not if avoidMinZero is set. + if (!this.getBooleanOption("avoidMinZero")) { + if (minAxisY < 0 && minY >= 0) minAxisY = 0; + if (maxAxisY > 0 && maxY <= 0) maxAxisY = 0; + } } } axis.extremeRange = [minAxisY, maxAxisY]; @@ -2627,21 +2577,28 @@ Dygraph.prototype.computeYAxisRanges_ = function(extremes) { // This is a user-set value range for this axis. var y0 = isNullUndefinedOrNaN(axis.valueRange[0]) ? axis.extremeRange[0] : axis.valueRange[0]; var y1 = isNullUndefinedOrNaN(axis.valueRange[1]) ? axis.extremeRange[1] : axis.valueRange[1]; - if (!ypadCompat) { - if (axis.logscale) { - var logpad = Math.exp(Math.log(span) * ypad); - y0 *= logpad; - y1 /= logpad; - } else { - span = y1 - y0; - y0 -= span * ypad; - y1 += span * ypad; - } - } axis.computedValueRange = [y0, y1]; } else { axis.computedValueRange = axis.extremeRange; } + if (!axis.valueWindow && !ypadCompat) { + // When using yRangePad, adjust the upper/lower bounds to add + // padding unless the user has zoomed/panned the Y axis range. + if (logscale) { + y0 = axis.computedValueRange[0]; + y1 = axis.computedValueRange[1]; + var y0pct = ypad / (2 * ypad - 1); + var y1pct = (ypad - 1) / (2 * ypad - 1); + axis.computedValueRange[0] = utils.logRangeFraction(y0, y1, y0pct); + axis.computedValueRange[1] = utils.logRangeFraction(y0, y1, y1pct); + } else { + y0 = axis.computedValueRange[0]; + y1 = axis.computedValueRange[1]; + span = y1 - y0; + axis.computedValueRange[0] = y0 - span * ypad; + axis.computedValueRange[1] = y1 + span * ypad; + } + } if (independentTicks) { @@ -3379,7 +3336,6 @@ Dygraph.prototype.size = function() { */ Dygraph.prototype.setAnnotations = function(ann, suppressDraw) { // Only add the annotation CSS rule once we know it will be used. - Dygraph.addAnnotationRule(); this.annotations_ = ann; if (!this.layout_) { console.warn("Tried to setAnnotations before dygraph was ready. " + @@ -3470,48 +3426,6 @@ Dygraph.prototype.ready = function(callback) { }; /** - * @private - * Adds a default style for the annotation CSS classes to the document. This is - * only executed when annotations are actually used. It is designed to only be - * called once -- all calls after the first will return immediately. - */ -Dygraph.addAnnotationRule = function() { - // TODO(danvk): move this function into plugins/annotations.js? - if (Dygraph.addedAnnotationCSS) return; - - var rule = "border: 1px solid black; " + - "background-color: white; " + - "text-align: center;"; - - var styleSheetElement = document.createElement("style"); - styleSheetElement.type = "text/css"; - document.getElementsByTagName("head")[0].appendChild(styleSheetElement); - - // Find the first style sheet that we can access. - // We may not add a rule to a style sheet from another domain for security - // reasons. This sometimes comes up when using gviz, since the Google gviz JS - // adds its own style sheets from google.com. - for (var i = 0; i < document.styleSheets.length; i++) { - if (document.styleSheets[i].disabled) continue; - var mysheet = document.styleSheets[i]; - try { - if (mysheet.insertRule) { // Firefox - var idx = mysheet.cssRules ? mysheet.cssRules.length : 0; - mysheet.insertRule(".dygraphDefaultAnnotation { " + rule + " }", idx); - } else if (mysheet.addRule) { // IE - mysheet.addRule(".dygraphDefaultAnnotation", rule); - } - Dygraph.addedAnnotationCSS = true; - return; - } catch(err) { - // Was likely a security exception. - } - } - - console.warn("Unable to add default annotation CSS rule; display may be off."); -}; - -/** * Add an event handler. This event handler is kept until the graph is * destroyed with a call to graph.destroy(). * @@ -3548,4 +3462,51 @@ Dygraph.PLUGINS = [ GridPlugin ]; +// There are many symbols which have historically been available through the +// Dygraph class. These are exported here for backwards compatibility. +Dygraph.GVizChart = GVizChart; +Dygraph.DASHED_LINE = utils.DASHED_LINE; +Dygraph.DOT_DASH_LINE = utils.DOT_DASH_LINE; +Dygraph.dateAxisLabelFormatter = utils.dateAxisLabelFormatter; +Dygraph.toRGB_ = utils.toRGB_; +Dygraph.findPos = utils.findPos; +Dygraph.pageX = utils.pageX; +Dygraph.pageY = utils.pageY; +Dygraph.dateString_ = utils.dateString_; +Dygraph.defaultInteractionModel = DygraphInteraction.defaultModel; +Dygraph.nonInteractiveModel = Dygraph.nonInteractiveModel_ = DygraphInteraction.nonInteractiveModel_; +Dygraph.Circles = utils.Circles; + +Dygraph.Plugins = { + Legend: LegendPlugin, + Axes: AxesPlugin, + Annotations: AnnotationsPlugin, + ChartLabels: ChartLabelsPlugin, + Grid: GridPlugin, + RangeSelector: RangeSelectorPlugin +}; + +Dygraph.DataHandlers = { + DefaultHandler, + BarsHandler, + CustomBarsHandler, + DefaultFractionHandler, + ErrorBarsHandler, + FractionsBarsHandler +}; + +Dygraph.startPan = DygraphInteraction.startPan; +Dygraph.startZoom = DygraphInteraction.startZoom; +Dygraph.movePan = DygraphInteraction.movePan; +Dygraph.moveZoom = DygraphInteraction.moveZoom; +Dygraph.endPan = DygraphInteraction.endPan; +Dygraph.endZoom = DygraphInteraction.endZoom; + +Dygraph.numericLinearTicks = DygraphTickers.numericLinearTicks; +Dygraph.numericTicks = DygraphTickers.numericTicks; +Dygraph.dateTicker = DygraphTickers.dateTicker; +Dygraph.Granularity = DygraphTickers.Granularity; +Dygraph.getDateAxis = DygraphTickers.getDateAxis; +Dygraph.floatFormat = utils.floatFormat; + export default Dygraph;