X-Git-Url: https://adrianiainlam.tk/git/?a=blobdiff_plain;ds=sidebyside;f=dygraph.js;h=0589c787834ee1ba7a76b989687319d58cc0c1ed;hb=d160cc3bcd039336057fd05ee7e19abe8675709c;hp=d187aa985380d9347602816a95d99b73c3c7b42b;hpb=987840a2160d5f7afc8e87213e6fbb39a378e557;p=dygraphs.git diff --git a/dygraph.js b/dygraph.js index d187aa9..0589c78 100644 --- a/dygraph.js +++ b/dygraph.js @@ -92,6 +92,9 @@ Dygraph.DEFAULT_ATTRS = { labelsSeparateLines: false, labelsKMB: false, labelsKMG2: false, + showLabelsOnHighlight: true, + + yValueFormatter: null, strokeWidth: 1.0, @@ -114,7 +117,11 @@ Dygraph.DEFAULT_ATTRS = { fractions: false, wilsonInterval: true, // only relevant if fractions is true customBars: false, - fillGraph: false + fillGraph: false, + fillAlpha: 0.15, + + stackedGraph: false, + hideOverlayOnMouseOut: true }; // Various logging levels. @@ -139,8 +146,8 @@ Dygraph.prototype.__old_init__ = function(div, file, labels, attrs) { * Initializes the Dygraph. This creates a new DIV and constructs the PlotKit * and interaction <canvas> inside of it. See the constructor for details * on the parameters. + * @param {Element} div the Element to render the graph into. * @param {String | Function} file Source data - * @param {Array.} labels Names of the data series * @param {Object} attrs Miscellaneous other options * @private */ @@ -183,6 +190,11 @@ Dygraph.prototype.__init__ = function(div, file, attrs) { this.height_ = (this.height_ * self.innerHeight / 100) - 10; } + if (attrs['stackedGraph']) { + attrs['fillGraph'] = true; + // TODO(nikhilk): Add any other stackedGraph checks here. + } + // Dygraphs has many options, some of which interact with one another. // To keep track of everything, we maintain two sets of options: // @@ -397,11 +409,15 @@ Dygraph.prototype.setColors_ = function() { var sat = this.attr_('colorSaturation') || 1.0; var val = this.attr_('colorValue') || 0.5; for (var i = 1; i <= num; i++) { - var hue = (1.0*i/(1+num)); - this.colors_.push( Dygraph.hsvToRGB(hue, sat, val) ); + if (!this.visibility()[i-1]) continue; + // alternate colors for high contrast. + var idx = i - parseInt(i % 2 ? i / 2 : (i - num)/2, 10); + var hue = (1.0 * idx/ (1 + num)); + this.colors_.push(Dygraph.hsvToRGB(hue, sat, val)); } } else { for (var i = 0; i < num; i++) { + if (!this.visibility()[i]) continue; var colorStr = colors[i % colors.length]; this.colors_.push(colorStr); } @@ -414,6 +430,15 @@ Dygraph.prototype.setColors_ = function() { Dygraph.update(this.layoutOptions_, this.attrs_); } +/** + * Return the list of colors. This is either the list of colors passed in the + * attributes, or the autogenerated list of rgb(r,g,b) strings. + * @return {Array} The list of colors. + */ +Dygraph.prototype.getColors = function() { + return this.colors_; +}; + // The following functions are from quirksmode.org // http://www.quirksmode.org/js/findpos.html Dygraph.findPosX = function(obj) { @@ -760,7 +785,21 @@ Dygraph.prototype.mouseMove_ = function(event) { this.selPoints_ = []; for (var i = 0; i < points.length; i++) { if (points[i].xval == lastx) { - this.selPoints_.push(points[i]); + // Clone the point. + var p = {}; + for (var k in points[i]) { + p[k] = points[i][k]; + } + this.selPoints_.push(p); + } + } + + if (this.attr_("stackedGraph")) { + // "unstack" the points. + var cumulative_sum = 0; + for (var j = this.selPoints_.length - 1; j >= 0; j--) { + this.selPoints_[j].yval -= cumulative_sum; + cumulative_sum += this.selPoints_[j].yval; } } @@ -780,28 +819,32 @@ Dygraph.prototype.mouseMove_ = function(event) { if (this.selPoints_.length > 0) { var canvasx = this.selPoints_[0].canvasx; - - // Set the status message to indicate the selected point(s) - var replace = this.attr_('xValueFormatter')(lastx, this) + ":"; var clen = this.colors_.length; - for (var i = 0; i < this.selPoints_.length; i++) { - if (!isOK(this.selPoints_[i].canvasy)) continue; - if (this.attr_("labelsSeparateLines")) { - replace += "
"; + + if (this.attr_('showLabelsOnHighlight')) { + // Set the status message to indicate the selected point(s) + var replace = this.attr_('xValueFormatter')(lastx, this) + ":"; + var fmtFunc = this.attr_('yValueFormatter'); + for (var i = 0; i < this.selPoints_.length; i++) { + if (!isOK(this.selPoints_[i].canvasy)) continue; + if (this.attr_("labelsSeparateLines")) { + replace += "
"; + } + var point = this.selPoints_[i]; + var c = new RGBColor(this.colors_[i%clen]); + var yval = fmtFunc ? fmtFunc(point.yval) : this.round_(point.yval, 2); + replace += " " + + point.name + ":" + + yval; } - var point = this.selPoints_[i]; - var c = new RGBColor(this.colors_[i%clen]); - replace += " " - + point.name + ":" - + this.round_(point.yval, 2); + this.attr_("labelsDiv").innerHTML = replace; } - this.attr_("labelsDiv").innerHTML = replace; // Save last x position for callbacks. this.lastx_ = lastx; // Draw colored circles over the center of each selected point - ctx.save() + ctx.save(); for (var i = 0; i < this.selPoints_.length; i++) { if (!isOK(this.selPoints_[i%clen].canvasy)) continue; ctx.beginPath(); @@ -822,10 +865,12 @@ Dygraph.prototype.mouseMove_ = function(event) { * @private */ Dygraph.prototype.mouseOut_ = function(event) { - // Get rid of the overlay data - var ctx = this.canvas_.getContext("2d"); - ctx.clearRect(0, 0, this.width_, this.height_); - this.attr_("labelsDiv").innerHTML = ""; + if (this.attr_("hideOverlayOnMouseOut")) { + // Get rid of the overlay data + var ctx = this.canvas_.getContext("2d"); + ctx.clearRect(0, 0, this.width_, this.height_); + this.attr_("labelsDiv").innerHTML = ""; + } }; Dygraph.zeropad = function(x) { @@ -1241,7 +1286,12 @@ Dygraph.prototype.drawGraph_ = function(data) { this.setColors_(); this.attrs_['pointSize'] = 0.5 * this.attr_('highlightCircleSize'); + // For stacked series. + var cumulative_y = []; + var datasets = []; + // Loop over all fields in the dataset + for (var i = 1; i < data[0].length; i++) { if (!this.visibility()[i - 1]) continue; @@ -1278,18 +1328,49 @@ Dygraph.prototype.drawGraph_ = function(data) { vals[j] = [series[j][0], series[j][1][0], series[j][1][1], series[j][1][2]]; this.layout_.addDataset(this.attr_("labels")[i], vals); + } else if (this.attr_("stackedGraph")) { + var vals = []; + var l = series.length; + var actual_y; + for (var j = 0; j < l; j++) { + if (cumulative_y[series[j][0]] === undefined) + cumulative_y[series[j][0]] = 0; + + actual_y = series[j][1]; + cumulative_y[series[j][0]] += actual_y; + + vals[j] = [series[j][0], cumulative_y[series[j][0]]] + + if (!maxY || cumulative_y[series[j][0]] > maxY) + maxY = cumulative_y[series[j][0]]; + } + datasets.push([this.attr_("labels")[i], vals]); + //this.layout_.addDataset(this.attr_("labels")[i], vals); } else { this.layout_.addDataset(this.attr_("labels")[i], series); } } + if (datasets.length > 0) { + for (var i = (datasets.length - 1); i >= 0; i--) { + this.layout_.addDataset(datasets[i][0], datasets[i][1]); + } + } + // Use some heuristics to come up with a good maxY value, unless it's been // set explicitly by the user. if (this.valueRange_ != null) { this.addYTicks_(this.valueRange_[0], this.valueRange_[1]); } else { + // This affects the calculation of span, below. + if (this.attr_("includeZero") && minY > 0) { + minY = 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. + if (span == 0) { span = maxY; } var maxAxisY = maxY + 0.1 * span; var minAxisY = minY - 0.1 * span; @@ -1689,7 +1770,7 @@ Dygraph.prototype.parseDataTable_ = function(data) { cols = labels.length; var indepType = data.getColumnType(0); - if (indepType == 'date' || 'datetime') { + if (indepType == 'date' || indepType == 'datetime') { this.attrs_.xValueFormatter = Dygraph.dateString_; this.attrs_.xValueParser = Dygraph.dateParser; this.attrs_.xTicker = Dygraph.dateTicker;