X-Git-Url: https://adrianiainlam.tk/git/?a=blobdiff_plain;f=dygraph.js;h=ef06082f49f8164d86d02f995f3f72bbd956cbf0;hb=5011e7a1a4764f7ae0b8703e319d635ab6e4abc8;hp=ea1f90460d9c869e623c6077d2e94f35fdeb4393;hpb=2e013c3232ba736b79e01f6c77d56adf603481e6;p=dygraphs.git diff --git a/dygraph.js b/dygraph.js index ea1f904..ef06082 100644 --- a/dygraph.js +++ b/dygraph.js @@ -155,6 +155,10 @@ Dygraph.prototype.__init__ = function(div, file, attrs) { this.wilsonInterval_ = attrs.wilsonInterval || true; this.customBars_ = attrs.customBars || false; + // Clear the div. This ensure that, if multiple dygraphs are passed the same + // div, then only one will be drawn. + div.innerHTML = ""; + // If the div isn't already sized then give it a default size. if (div.style.width == '') { div.style.width = Dygraph.DEFAULT_WIDTH + "px"; @@ -607,6 +611,8 @@ Dygraph.prototype.mouseMove_ = function(event) { ctx.clearRect(px - circleSize - 1, 0, 2 * circleSize + 2, this.height_); } + var isOK = function(x) { return x && !isNaN(x); }; + if (selPoints.length > 0) { var canvasx = selPoints[0].canvasx; @@ -614,6 +620,7 @@ Dygraph.prototype.mouseMove_ = function(event) { var replace = this.attr_('xValueFormatter')(lastx, this) + ":"; var clen = this.colors_.length; for (var i = 0; i < selPoints.length; i++) { + if (!isOK(selPoints[i].canvasy)) continue; if (this.attr_("labelsSeparateLines")) { replace += "
"; } @@ -630,6 +637,7 @@ Dygraph.prototype.mouseMove_ = function(event) { // Draw colored circles over the center of each selected point ctx.save() for (var i = 0; i < selPoints.length; i++) { + if (!isOK(selPoints[i%clen].canvasy)) continue; ctx.beginPath(); ctx.fillStyle = this.colors_[i%clen].toRGBString(); ctx.arc(canvasx, selPoints[i%clen].canvasy, circleSize, 0, 360, false); @@ -954,6 +962,46 @@ Dygraph.prototype.addYTicks_ = function(minY, maxY) { yTicks: ticks } ); }; +// Computes the range of the data series (including confidence intervals). +// series is either [ [x1, y1], [x2, y2], ... ] or +// [ [x1, [y1, dev_low, dev_high]], [x2, [y2, dev_low, dev_high]], ... +// Returns [low, high] +Dygraph.prototype.extremeValues_ = function(series) { + var minY = null, maxY = null; + + var bars = this.attr_("errorBars") || this.customBars_; + if (bars) { + // With custom bars, maxY is the max of the high values. + for (var j = 0; j < series.length; j++) { + var y = series[j][1][0]; + if (!y) continue; + var low = y - series[j][1][1]; + var high = y + series[j][1][2]; + 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; + } + } + } else { + for (var j = 0; j < series.length; j++) { + var y = series[j][1]; + if (!y) continue; + if (maxY == null || y > maxY) { + maxY = y; + } + if (minY == null || y < minY) { + minY = y; + } + } + } + + return [minY, maxY]; +}; + /** * Update the graph with new data. Data is in the format * [ [date1, val1, val2, ...], [date2, val1, val2, ...] if errorBars=false @@ -963,7 +1011,7 @@ Dygraph.prototype.addYTicks_ = function(minY, maxY) { * @private */ Dygraph.prototype.drawGraph_ = function(data) { - var maxY = null; + var minY = null, maxY = null; this.layout_.removeAllDatasets(); this.setColors_(); @@ -985,32 +1033,15 @@ Dygraph.prototype.drawGraph_ = function(data) { for (var k = 0; k < series.length; k++) { if (series[k][0] >= low && series[k][0] <= high) { pruned.push(series[k]); - var y = bars ? series[k][1][0] : series[k][1]; - if (maxY == null || y > maxY) maxY = y; } } series = pruned; - } else { - if (!this.customBars_) { - for (var j = 0; j < series.length; j++) { - var y = bars ? series[j][1][0] : series[j][1]; - if (maxY == null || y > maxY) { - maxY = bars ? y + series[j][1][1] : y; - } - } - } else { - // With custom bars, maxY is the max of the high values. - for (var j = 0; j < series.length; j++) { - var y = series[j][1][0]; - var high = series[j][1][2]; - if (high > y) y = high; - if (maxY == null || y > maxY) { - maxY = y; - } - } - } } + [thisMinY, thisMaxY] = this.extremeValues_(series); + if (!minY || thisMinY < minY) minY = thisMinY; + if (!maxY || thisMaxY > maxY) maxY = thisMaxY; + if (bars) { var vals = []; for (var j=0; j= 0) minAxisY = 0; + if (maxAxisY > 0 && maxY <= 0) maxAxisY = 0; + + if (this.attr_("includeZero")) { + if (maxY < 0) maxAxisY = 0; + if (minY > 0) minAxisY = 0; + } + + this.addYTicks_(minAxisY, maxAxisY); } this.addXTicks_(); @@ -1128,6 +1170,10 @@ Dygraph.prototype.rollingAverage = function(originalData, rollPeriod) { // there is not enough data to roll over the full number of days var num_init_points = Math.min(rollPeriod - 1, originalData.length - 2); if (!this.attr_("errorBars")){ + if (rollPeriod == 1) { + return originalData; + } + for (var i = 0; i < num_init_points; i++) { var sum = 0; for (var j = 0; j < i + 1; j++) @@ -1147,13 +1193,21 @@ Dygraph.prototype.rollingAverage = function(originalData, rollPeriod) { for (var i = 0; i < num_init_points; i++) { var sum = 0; var variance = 0; + var num_ok = 0; for (var j = 0; j < i + 1; j++) { - sum += originalData[j][1][0]; + var y = originalData[j][1][0]; + if (!y || isNaN(y)) continue; + num_ok++; + sum += y; variance += Math.pow(originalData[j][1][1], 2); } - var stddev = Math.sqrt(variance)/(i+1); - rollingData[i] = [originalData[i][0], - [sum/(i+1), sigma * stddev, sigma * stddev]]; + if (num_ok) { + var stddev = Math.sqrt(variance)/num_ok; + rollingData[i] = [originalData[i][0], + [sum/num_ok, sigma * stddev, sigma * stddev]]; + } else { + rollingData[i] = [originalData[i][0], [null, null, null]]; + } } // Calculate the rolling average for the remaining points for (var i = Math.min(rollPeriod - 1, originalData.length - 2); @@ -1161,13 +1215,21 @@ Dygraph.prototype.rollingAverage = function(originalData, rollPeriod) { i++) { var sum = 0; var variance = 0; + var num_ok = 0; for (var j = i - rollPeriod + 1; j < i + 1; j++) { + var y = originalData[j][1][0]; + if (!y || isNaN(y)) continue; + num_ok++; sum += originalData[j][1][0]; variance += Math.pow(originalData[j][1][1], 2); } - var stddev = Math.sqrt(variance) / rollPeriod; - rollingData[i] = [originalData[i][0], - [sum / rollPeriod, sigma * stddev, sigma * stddev]]; + if (num_ok) { + var stddev = Math.sqrt(variance) / num_ok; + rollingData[i] = [originalData[i][0], + [sum / num_ok, sigma * stddev, sigma * stddev]]; + } else { + rollingData[i] = [originalData[i][0], [null, null, null]]; + } } } }