X-Git-Url: https://adrianiainlam.tk/git/?a=blobdiff_plain;ds=sidebyside;f=dygraph.js;h=4bd775a3f606a326b3c66a9f4fc454387294c2b0;hb=ba049b8986972a9feb9c770e6094ea9035e9fb3b;hp=661ebfbc74df5efaf8591dd9102d757536f3cf4d;hpb=c1bc242a0326dc48ee2de27321195090a3eb486a;p=dygraphs.git diff --git a/dygraph.js b/dygraph.js index 661ebfb..4bd775a 100644 --- a/dygraph.js +++ b/dygraph.js @@ -198,6 +198,10 @@ Dygraph.prototype.__init__ = function(div, file, attrs) { this.is_initial_draw_ = true; this.annotations_ = []; + // Zoomed indicators - These indicate when the graph has been zoomed and on what axis. + this.zoomed_x_ = false; + this.zoomed_y_ = false; + // Clear the div. This ensure that, if multiple dygraphs are passed the same // div, then only one will be drawn. div.innerHTML = ""; @@ -260,6 +264,28 @@ Dygraph.prototype.__init__ = function(div, file, attrs) { this.start_(); }; +/** + * Returns the zoomed status of the chart for one or both axes. + * + * Axis is an optional parameter. Can be set to 'x' or 'y'. + * + * The zoomed status for an axis is set whenever a user zooms using the mouse + * or when the dateWindow or valueRange are updated (unless the noZoomFlagChange + * option is also specified). + */ +Dygraph.prototype.isZoomed = function(axis) { + if (axis == null) return this.zoomed_x_ || this.zoomed_y_; + if (axis == 'x') return this.zoomed_x_; + if (axis == 'y') return this.zoomed_y_; + throw "axis parameter to Dygraph.isZoomed must be missing, 'x' or 'y'."; +}; + +Dygraph.prototype.toString = function() { + var maindiv = this.maindiv_; + var id = (maindiv && maindiv.id) ? maindiv.id : maindiv + return "[Dygraph " + id + "]"; +} + Dygraph.prototype.attr_ = function(name, seriesName) { if (seriesName && typeof(this.user_attrs_[seriesName]) != 'undefined' && @@ -966,7 +992,8 @@ Dygraph.movePan = function(event, g, context) { var maxValue = axis.initialTopValue + unitsDragged; var minValue = maxValue - axis.dragValueRange; if (axis.logscale) { - axis.valueWindow = [ Math.pow(10, minValue), Math.pow(10, maxValue) ]; + axis.valueWindow = [ Math.pow(Dygraph.LOG_SCALE, minValue), + Math.pow(Dygraph.LOG_SCALE, maxValue) ]; } else { axis.valueWindow = [ minValue, maxValue ]; } @@ -1317,6 +1344,7 @@ Dygraph.prototype.doZoomX_ = function(lowX, highX) { */ Dygraph.prototype.doZoomXDates_ = function(minDate, maxDate) { this.dateWindow_ = [minDate, maxDate]; + this.zoomed_x_ = true; this.drawGraph_(); if (this.attr_("zoomCallback")) { this.attr_("zoomCallback")(minDate, maxDate, this.yAxisRanges()); @@ -1344,9 +1372,11 @@ Dygraph.prototype.doZoomY_ = function(lowY, highY) { valueRanges.push([low, hi]); } + this.zoomed_y_ = true; this.drawGraph_(); if (this.attr_("zoomCallback")) { var xRange = this.xAxisRange(); + var yRange = this.yAxisRange(); this.attr_("zoomCallback")(xRange[0], xRange[1], this.yAxisRanges()); } }; @@ -1374,6 +1404,8 @@ Dygraph.prototype.doUnzoom_ = function() { if (dirty) { // Putting the drawing operation before the callback because it resets // yAxisRange. + this.zoomed_x_ = false; + this.zoomed_y_ = false; this.drawGraph_(); if (this.attr_("zoomCallback")) { var minDate = this.rawData_[0][0]; @@ -1410,10 +1442,6 @@ Dygraph.prototype.mouseMove_ = function(event) { idx = i; } if (idx >= 0) lastx = points[idx].xval; - // Check that you can really highlight the last day's data - var last = points[points.length-1]; - if (last != null && canvasx > last.canvasx) - lastx = points[points.length-1].xval; // Extract the points we've selected this.selPoints_ = []; @@ -1924,6 +1952,7 @@ Dygraph.dateTicker = function(startDate, endDate, self) { // This is a list of human-friendly values at which to show tick marks on a log // scale. It is k * 10^n, where k=1..9 and n=-39..+39, so: // ..., 1, 2, 3, 4, 5, ..., 9, 10, 20, 30, ..., 90, 100, 200, 300, ... +// NOTE: this assumes that Dygraph.LOG_SCALE = 10. Dygraph.PREFERRED_LOG_TICK_VALUES = function() { var vals = []; for (var power = -39; power <= 39; power++) { @@ -1981,7 +2010,7 @@ Dygraph.binarySearch = function(val, arry, abs, low, high) { } return Dygraph.binarySearch(val, arry, abs, mid + 1, high); } -} +}; /** * Add ticks when the x axis has numbers on it (instead of dates) @@ -2181,7 +2210,7 @@ Dygraph.prototype.extremeValues_ = function(series) { * number of axes, rolling averages, etc. */ Dygraph.prototype.predraw_ = function() { - // TODO(danvk): movabilitye more computations out of drawGraph_ and into here. + // TODO(danvk): move more computations out of drawGraph_ and into here. this.computeYAxes_(); // Create a new plotter. @@ -2245,7 +2274,7 @@ Dygraph.prototype.drawGraph_ = function() { // On the log scale, points less than zero do not exist. // This will create a gap in the chart. Note that this ignores // connectSeparatedPoints. - if (point < 0) { + if (point <= 0) { point = null; } series.push([date, point]); @@ -2332,18 +2361,22 @@ Dygraph.prototype.drawGraph_ = function() { this.layout_.addDataset(this.attr_("labels")[i], datasets[i]); } - // TODO(danvk): this method doesn't need to return anything. - var out = this.computeYAxisRanges_(extremes); - var axes = out[0]; - var seriesToAxisMap = out[1]; - this.layout_.updateOptions( { yAxes: axes, - seriesToAxisMap: seriesToAxisMap - } ); - + if (datasets.length > 0) { + // TODO(danvk): this method doesn't need to return anything. + var out = this.computeYAxisRanges_(extremes); + var axes = out[0]; + var seriesToAxisMap = out[1]; + this.layout_.updateOptions( { yAxes: axes, + seriesToAxisMap: seriesToAxisMap + } ); + } this.addXTicks_(); + // Save the X axis zoomed status as the updateOptions call will tend to set it errorneously + var tmp_zoomed_x = this.zoomed_x_; // Tell PlotKit to use this new data and render itself this.layout_.updateOptions({dateWindow: this.dateWindow_}); + this.zoomed_x_ = tmp_zoomed_x; this.layout_.evaluateWithError(); this.plotter_.clear(); this.plotter_.render(); @@ -2366,6 +2399,15 @@ Dygraph.prototype.drawGraph_ = function() { * indices are into the axes_ array. */ Dygraph.prototype.computeYAxes_ = function() { + var valueWindows; + if (this.axes_ != undefined) { + // Preserve valueWindow settings. + valueWindows = []; + for (var index = 0; index < this.axes_.length; index++) { + valueWindows.push(this.axes_[index].valueWindow); + } + } + this.axes_ = [{ yAxisId : 0, g : this }]; // always have at least one y-axis. this.seriesToAxisMap_ = {}; @@ -2442,6 +2484,13 @@ Dygraph.prototype.computeYAxes_ = function() { if (vis[i - 1]) seriesToAxisFiltered[s] = this.seriesToAxisMap_[s]; } this.seriesToAxisMap_ = seriesToAxisFiltered; + + if (valueWindows != undefined) { + // Restore valueWindow settings. + for (var index = 0; index < valueWindows.length; index++) { + this.axes_[index].valueWindow = valueWindows[index]; + } + } }; /** @@ -2489,12 +2538,29 @@ Dygraph.prototype.computeYAxisRanges_ = function(extremes) { var series = seriesForAxis[i]; var minY = Infinity; // extremes[series[0]][0]; var maxY = -Infinity; // extremes[series[0]][1]; + var extremeMinY, extremeMaxY; for (var j = 0; j < series.length; j++) { - minY = Math.min(extremes[series[j]][0], minY); - maxY = Math.max(extremes[series[j]][1], maxY); + // Only use valid extremes to stop null data series' from corrupting the scale. + extremeMinY = extremes[series[j]][0]; + if (extremeMinY != null) { + minY = Math.min(extremeMinY, minY); + } + extremeMaxY = extremes[series[j]][1]; + if (extremeMaxY != null) { + maxY = Math.max(extremeMaxY, maxY); + } } if (axis.includeZero && minY > 0) minY = 0; + // Ensure we have a valid scale, otherwise defualt to zero for safety. + if (minY == Infinity) { + minY = 0; + } + + if (maxY == -Infinity) { + maxY = 0; + } + // Add some padding and round up to an integer to be human-friendly. var span = maxY - minY; // special case: if we have no sense of scale, use +/-10% of the sole value. @@ -2732,7 +2798,7 @@ Dygraph.dateParser = function(dateStr, self) { */ Dygraph.prototype.detectTypeFromString_ = function(str) { var isDate = false; - if (str.indexOf('-') >= 0 || + if (str.indexOf('-') > 0 || str.indexOf('/') >= 0 || isNaN(parseFloat(str))) { isDate = true; @@ -3136,6 +3202,12 @@ Dygraph.prototype.start_ = function() { *
  • file: changes the source data for the graph
  • *
  • errorBars: changes whether the data contains stddev
  • * + * + * If the dateWindow or valueRange options are specified, the relevant zoomed_x_ + * or zoomed_y_ flags are set, unless the noZoomFlagChange option is also + * secified. This allows for the chart to be programmatically zoomed without + * altering the zoomed flags. + * * @param {Object} attrs The new properties and values */ Dygraph.prototype.updateOptions = function(attrs) { @@ -3145,6 +3217,12 @@ Dygraph.prototype.updateOptions = function(attrs) { } if ('dateWindow' in attrs) { this.dateWindow_ = attrs.dateWindow; + if (!('noZoomFlagChange' in attrs)) { + this.zoomed_x_ = attrs.dateWindow != null; + } + } + if ('valueRange' in attrs && !('noZoomFlagChange' in attrs)) { + this.zoomed_y_ = attrs.valueRange != null; } // TODO(danvk): validate per-series options.