X-Git-Url: https://adrianiainlam.tk/git/?a=blobdiff_plain;ds=sidebyside;f=dygraph.js;h=df41fdc2525c230cb5329d4c6179f7ec046cc8e6;hb=3df0ccf0a09d28577e3a695302f1deb926ae8a83;hp=0d77166c8591db847008fd20b706d4dfd7a11915;hpb=9a7309104212501d777d2b47b2f20f98833b9241;p=dygraphs.git diff --git a/dygraph.js b/dygraph.js index 0d77166..df41fdc 100644 --- a/dygraph.js +++ b/dygraph.js @@ -153,7 +153,6 @@ Dygraph.prototype.__init__ = function(div, file, attrs) { this.dateWindow_ = attrs.dateWindow || null; this.valueRange_ = attrs.valueRange || null; 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. @@ -193,12 +192,12 @@ Dygraph.prototype.__init__ = function(div, file, attrs) { // Create the PlotKit grapher // TODO(danvk): why does the Layout need its own set of options? this.layoutOptions_ = { 'errorBars': (this.attr_("errorBars") || - this.customBars_), + this.attr_("customBars")), 'xOriginIsZero': false }; MochiKit.Base.update(this.layoutOptions_, this.attrs_); MochiKit.Base.update(this.layoutOptions_, this.user_attrs_); - this.layout_ = new DygraphLayout(this.layoutOptions_); + this.layout_ = new DygraphLayout(this, this.layoutOptions_); // TODO(danvk): why does the Renderer need its own set of options? this.renderOptions_ = { colorScheme: this.colors_, @@ -206,7 +205,8 @@ Dygraph.prototype.__init__ = function(div, file, attrs) { axisLineWidth: Dygraph.AXIS_LINE_WIDTH }; MochiKit.Base.update(this.renderOptions_, this.attrs_); MochiKit.Base.update(this.renderOptions_, this.user_attrs_); - this.plotter_ = new DygraphCanvasRenderer(this.hidden_, this.layout_, + this.plotter_ = new DygraphCanvasRenderer(this, + this.hidden_, this.layout_, this.renderOptions_); this.createStatusMessage_(); @@ -353,6 +353,34 @@ Dygraph.prototype.setColors_ = function() { MochiKit.Base.update(this.layoutOptions_, this.attrs_); } +// The following functions are from quirksmode.org +// http://www.quirksmode.org/js/findpos.html +Dygraph.findPosX = function(obj) { + var curleft = 0; + if (obj.offsetParent) { + while (obj.offsetParent) { + curleft += obj.offsetLeft; + obj = obj.offsetParent; + } + } + else if (obj.x) + curleft += obj.x; + return curleft; +}; + +Dygraph.findPosY = function(obj) { + var curtop = 0; + if (obj.offsetParent) { + while (obj.offsetParent) { + curtop += obj.offsetTop; + obj = obj.offsetParent; + } + } + else if (obj.y) + curtop += obj.y; + return curtop; +}; + /** * Create the div that contains information on the selected point(s) * This goes in the top right of the canvas, unless an external div has already @@ -439,8 +467,8 @@ Dygraph.prototype.createDragInterface_ = function() { // Track the beginning of drag events connect(this.hidden_, 'onmousedown', function(event) { mouseDown = true; - px = PlotKit.Base.findPosX(self.canvas_); - py = PlotKit.Base.findPosY(self.canvas_); + px = Dygraph.findPosX(self.canvas_); + py = Dygraph.findPosY(self.canvas_); dragStartX = getX(event); dragStartY = getY(event); }); @@ -574,7 +602,7 @@ Dygraph.prototype.doZoom_ = function(lowX, highX) { * @private */ Dygraph.prototype.mouseMove_ = function(event) { - var canvasx = event.mouse().page.x - PlotKit.Base.findPosX(this.hidden_); + var canvasx = event.mouse().page.x - Dygraph.findPosX(this.hidden_); var points = this.layout_.points; var lastx = -1; @@ -611,6 +639,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; @@ -618,7 +648,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 (isNaN(selPoints[i].canvasy)) continue; + if (!isOK(selPoints[i].canvasy)) continue; if (this.attr_("labelsSeparateLines")) { replace += "
"; } @@ -635,7 +665,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 (isNaN(selPoints[i%clen].canvasy)) continue; + 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); @@ -960,6 +990,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.attr_("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 @@ -972,6 +1042,7 @@ Dygraph.prototype.drawGraph_ = function(data) { var minY = null, maxY = null; this.layout_.removeAllDatasets(); this.setColors_(); + this.attrs_['pointSize'] = 0.5 * this.attr_('highlightCircleSize'); // Loop over all fields in the dataset for (var i = 1; i < data[0].length; i++) { @@ -983,7 +1054,7 @@ Dygraph.prototype.drawGraph_ = function(data) { series = this.rollingAverage(series, this.rollPeriod_); // Prune down to the desired range, if necessary (for zooming) - var bars = this.attr_("errorBars") || this.customBars_; + var bars = this.attr_("errorBars") || this.attr_("customBars"); if (this.dateWindow_) { var low = this.dateWindow_[0]; var high= this.dateWindow_[1]; @@ -991,39 +1062,17 @@ 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; - if (minY == null || y < minY) minY = 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; - } - if (minY == null || y < minY) { - minY = 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; - } - if (minY == null || y < minY) { - minY = y; - } - } - } } + var extremes = this.extremeValues_(series); + var thisMinY = extremes[0]; + var thisMaxY = extremes[1]; + if (!minY || thisMinY < minY) minY = thisMinY; + if (!maxY || thisMaxY > maxY) maxY = thisMaxY; + if (bars) { var vals = []; for (var j=0; j