},
labelsSeparateLines: false,
labelsKMB: false,
+ labelsKMG2: false,
strokeWidth: 1.0,
// Create the containing DIV and other interactive elements
this.createInterface_();
- // Create the PlotKit grapher
- // TODO(danvk): why does the Layout need its own set of options?
- this.layoutOptions_ = { 'xOriginIsZero': false };
- Dygraph.update(this.layoutOptions_, this.attrs_);
- Dygraph.update(this.layoutOptions_, this.user_attrs_);
- Dygraph.update(this.layoutOptions_, {
- 'errorBars': (this.attr_("errorBars") || this.attr_("customBars")) });
-
- this.layout_ = new DygraphLayout(this, this.layoutOptions_);
-
- // TODO(danvk): why does the Renderer need its own set of options?
- this.renderOptions_ = { colorScheme: this.colors_,
- strokeColor: null,
- axisLineWidth: Dygraph.AXIS_LINE_WIDTH };
- Dygraph.update(this.renderOptions_, this.attrs_);
- Dygraph.update(this.renderOptions_, this.user_attrs_);
- this.plotter_ = new DygraphCanvasRenderer(this,
- this.hidden_, this.layout_,
- this.renderOptions_);
-
- this.createStatusMessage_();
- this.createRollInterface_();
- this.createDragInterface_();
-
this.start_();
};
/**
* Generates interface elements for the Dygraph: a containing div, a div to
* display the current point, and a textbox to adjust the rolling average
- * period.
+ * period. Also creates the Renderer/Layout elements.
* @private
*/
Dygraph.prototype.createInterface_ = function() {
Dygraph.addEvent(this.hidden_, 'mouseout', function(e) {
dygraph.mouseOut_(e);
});
+
+ // Create the grapher
+ // TODO(danvk): why does the Layout need its own set of options?
+ this.layoutOptions_ = { 'xOriginIsZero': false };
+ Dygraph.update(this.layoutOptions_, this.attrs_);
+ Dygraph.update(this.layoutOptions_, this.user_attrs_);
+ Dygraph.update(this.layoutOptions_, {
+ 'errorBars': (this.attr_("errorBars") || this.attr_("customBars")) });
+
+ this.layout_ = new DygraphLayout(this, this.layoutOptions_);
+
+ // TODO(danvk): why does the Renderer need its own set of options?
+ this.renderOptions_ = { colorScheme: this.colors_,
+ strokeColor: null,
+ axisLineWidth: Dygraph.AXIS_LINE_WIDTH };
+ Dygraph.update(this.renderOptions_, this.attrs_);
+ Dygraph.update(this.renderOptions_, this.user_attrs_);
+ this.plotter_ = new DygraphCanvasRenderer(this,
+ this.hidden_, this.layout_,
+ this.renderOptions_);
+
+ this.createStatusMessage_();
+ this.createRollInterface_();
+ this.createDragInterface_();
}
/**
Dygraph.update(messagestyle, this.attr_('labelsDivStyles'));
var div = document.createElement("div");
for (var name in messagestyle) {
- div.style[name] = messagestyle[name];
+ if (messagestyle.hasOwnProperty(name)) {
+ div.style[name] = messagestyle[name];
+ }
}
this.graphDiv.appendChild(div);
this.attrs_.labelsDiv = div;
roller.size = "2";
roller.value = this.rollPeriod_;
for (var name in textAttr) {
- roller.style[name] = textAttr[name];
+ if (textAttr.hasOwnProperty(name)) {
+ roller.style[name] = textAttr[name];
+ }
}
var pa = this.graphDiv;
Dygraph.SHORT_SPACINGS[Dygraph.TEN_MINUTELY] = 1000 * 60 * 10;
Dygraph.SHORT_SPACINGS[Dygraph.THIRTY_MINUTELY] = 1000 * 60 * 30;
Dygraph.SHORT_SPACINGS[Dygraph.HOURLY] = 1000 * 3600;
-Dygraph.SHORT_SPACINGS[Dygraph.HOURLY] = 1000 * 3600 * 6;
+Dygraph.SHORT_SPACINGS[Dygraph.SIX_HOURLY] = 1000 * 3600 * 6;
Dygraph.SHORT_SPACINGS[Dygraph.DAILY] = 1000 * 86400;
Dygraph.SHORT_SPACINGS[Dygraph.WEEKLY] = 1000 * 604800;
// Construct labels for the ticks
var ticks = [];
+ var k;
+ var k_labels = [];
+ if (self.attr_("labelsKMB")) {
+ k = 1000;
+ k_labels = [ "K", "M", "B", "T" ];
+ }
+ if (self.attr_("labelsKMG2")) {
+ if (k) self.warn("Setting both labelsKMB and labelsKMG2. Pick one!");
+ k = 1024;
+ k_labels = [ "k", "M", "G", "T" ];
+ }
+
for (var i = 0; i < nTicks; i++) {
var tickV = low_val + i * scale;
+ var absTickV = Math.abs(tickV);
var label = self.round_(tickV, 2);
- if (self.attr_("labelsKMB")) {
- var k = 1000;
- if (tickV >= k*k*k) {
- label = self.round_(tickV/(k*k*k), 1) + "B";
- } else if (tickV >= k*k) {
- label = self.round_(tickV/(k*k), 1) + "M";
- } else if (tickV >= k) {
- label = self.round_(tickV/k, 1) + "K";
+ if (k_labels.length) {
+ // Round up to an appropriate unit.
+ var n = k*k*k*k;
+ for (var j = 3; j >= 0; j--, n /= k) {
+ if (absTickV >= n) {
+ label = self.round_(tickV / n, 1) + k_labels[j];
+ break;
+ }
}
}
ticks.push( {label: label, v: tickV} );
var y = data[1];
rollingData[i] = [originalData[i][0], [y, y - data[0], data[2] - y]];
- if (y && !isNaN(y)) {
+ if (y != null && !isNaN(y)) {
low += data[0];
mid += y;
high += data[2];
}
if (i - rollPeriod >= 0) {
var prev = originalData[i - rollPeriod];
- if (prev[1][1] && !isNaN(prev[1][1])) {
+ if (prev[1][1] != null && !isNaN(prev[1][1])) {
low -= prev[1][0];
mid -= prev[1][1];
high -= prev[1][2];
var num_ok = 0;
for (var j = Math.max(0, i - rollPeriod + 1); j < i + 1; j++) {
var y = originalData[j][1];
- if (!y || isNaN(y)) continue;
+ if (y == null || isNaN(y)) continue;
num_ok++;
sum += originalData[j][1];
}
var num_ok = 0;
for (var j = Math.max(0, i - rollPeriod + 1); j < i + 1; j++) {
var y = originalData[j][1][0];
- if (!y || isNaN(y)) continue;
+ if (y == null || isNaN(y)) continue;
num_ok++;
sum += originalData[j][1][0];
variance += Math.pow(originalData[j][1][1], 2);
var labels = [];
for (var i = 0; i < cols; i++) {
labels.push(data.getColumnLabel(i));
+ if (i != 0 && this.attr_("errorBars")) i += 1;
}
this.attrs_.labels = labels;
+ cols = labels.length;
var indepType = data.getColumnType(0);
if (indepType == 'date') {
} else {
row.push(data.getValue(i, 0));
}
- for (var j = 1; j < cols; j++) {
- row.push(data.getValue(i, j));
+ if (!this.attr_("errorBars")) {
+ for (var j = 1; j < cols; j++) {
+ row.push(data.getValue(i, j));
+ }
+ } else {
+ for (var j = 0; j < cols - 1; j++) {
+ row.push([ data.getValue(i, 1 + 2 * j), data.getValue(i, 2 + 2 * j) ]);
+ }
}
ret.push(row);
}
Dygraph.update = function (self, o) {
if (typeof(o) != 'undefined' && o !== null) {
for (var k in o) {
- self[k] = o[k];
+ if (o.hasOwnProperty(k)) {
+ self[k] = o[k];
+ }
}
}
return self;
};
/**
+ * Resizes the dygraph. If no parameters are specified, resizes to fill the
+ * containing div (which has presumably changed size since the dygraph was
+ * instantiated. If the width/height are specified, the div will be resized.
+ *
+ * This is far more efficient than destroying and re-instantiating a
+ * Dygraph, since it doesn't have to reparse the underlying data.
+ *
+ * @param {Number} width Width (in pixels)
+ * @param {Number} height Height (in pixels)
+ */
+Dygraph.prototype.resize = function(width, height) {
+ if ((width === null) != (height === null)) {
+ this.warn("Dygraph.resize() should be called with zero parameters or " +
+ "two non-NULL parameters. Pretending it was zero.");
+ width = height = null;
+ }
+
+ this.maindiv_.innerHTML = "";
+ if (width) {
+ this.maindiv_.style.width = width + "px";
+ this.maindiv_.style.height = height + "px";
+ this.width_ = width;
+ this.height_ = height;
+ } else {
+ this.width_ = this.maindiv_.offsetWidth;
+ this.height_ = this.maindiv_.offsetHeight;
+ }
+
+ this.createInterface_();
+ this.drawGraph_(this.rawData_);
+};
+
+/**
* Adjusts the number of days in the rolling average. Updates the graph to
* reflect the new averaging period.
* @param {Number} length Number of days over which to average the data.