this.is_initial_draw_ = true;
this.annotations_ = [];
+ // Zoomed indicators - These indicate when the graph has been zoomed and on what axis.
+ this.zoomed = false;
+ this.zoomedX = false;
+ this.zoomedY = false;
+
// Clear the div. This ensure that, if multiple dygraphs are passed the same
// div, then only one will be drawn.
div.innerHTML = "";
* Returns a two-element array: [bottom, top].
*/
Dygraph.prototype.yAxisRange = function(idx) {
- if (typeof(idx) == "undefined") idx == 0;
+ if (typeof(idx) == "undefined") idx = 0;
if (idx < 0 || idx >= this.axes_.length) return null;
return [ this.axes_[idx].computedValueRange[0],
this.axes_[idx].computedValueRange[1] ];
var area = this.plotter_.area;
var div = this.attr_("labelsDiv");
- div.style.left = area.x + area.w - this.attr_("labelsDivWidth") + "px";
+ div.style.left = area.x + area.w - this.attr_("labelsDivWidth") - 1 + "px";
};
/**
* Create the text box to adjust the averaging period
- * @return {Object} The newly-created text box
* @private
*/
Dygraph.prototype.createRollInterface_ = function() {
- // Destroy any existing roller.
- if (this.roller_) this.graphDiv.removeChild(this.roller_);
+ // Create a roller if one doesn't exist already.
+ if (!this.roller_) {
+ this.roller_ = document.createElement("input");
+ this.roller_.type = "text";
+ this.roller_.style.display = "none";
+ this.graphDiv.appendChild(this.roller_);
+ }
+
+ var display = this.attr_('showRoller') ? 'block' : 'none';
- var display = this.attr_('showRoller') ? "block" : "none";
var textAttr = { "position": "absolute",
"zIndex": 10,
"top": (this.plotter_.area.h - 25) + "px",
"left": (this.plotter_.area.x + 1) + "px",
"display": display
};
- var roller = document.createElement("input");
- roller.type = "text";
- roller.size = "2";
- roller.value = this.rollPeriod_;
+ this.roller_.size = "2";
+ this.roller_.value = this.rollPeriod_;
for (var name in textAttr) {
if (textAttr.hasOwnProperty(name)) {
- roller.style[name] = textAttr[name];
+ this.roller_.style[name] = textAttr[name];
}
}
- var pa = this.graphDiv;
- pa.appendChild(roller);
var dygraph = this;
- roller.onchange = function() { dygraph.adjustRoll(roller.value); };
- return roller;
+ this.roller_.onchange = function() { dygraph.adjustRoll(dygraph.roller_.value); };
};
// These functions are taken from MochiKit.Signal
// Track the beginning of drag events
Dygraph.addEvent(this.mouseEventElement_, 'mousedown', function(event) {
+ // prevents mouse drags from selecting page text.
+ if (event.preventDefault) {
+ event.preventDefault(); // Firefox, Chrome, etc.
+ } else {
+ event.returnValue = false; // IE
+ event.cancelBubble = true;
+ }
+
px = Dygraph.findPosX(self.canvas_);
py = Dygraph.findPosY(self.canvas_);
dragStartX = getX(event);
draggingDate = null;
dateRange = null;
for (var i = 0; i < self.axes_.length; i++) {
- delete this.axes_[i].draggingValue;
- delete this.axes_[i].dragValueRange;
+ delete self.axes_[i].draggingValue;
+ delete self.axes_[i].dragValueRange;
}
}
});
*/
Dygraph.prototype.doZoomXDates_ = function(minDate, maxDate) {
this.dateWindow_ = [minDate, maxDate];
+ this.zoomed = true;
+ this.zoomedX = true;
this.drawGraph_();
if (this.attr_("zoomCallback")) {
var yRange = this.yAxisRange();
valueRanges.push([low[1], hi[1]]);
}
+ this.zoomed = true;
+ this.zoomedY = true;
this.drawGraph_();
if (this.attr_("zoomCallback")) {
var xRange = this.xAxisRange();
- this.attr_("zoomCallback")(xRange[0], xRange[1], this.yAxisRanges());
+ var yRange = this.yAxisRange();
+ this.attr_("zoomCallback")(xRange[0], xRange[1], yRange[0], yRange[1]);
}
};
if (dirty) {
// Putting the drawing operation before the callback because it resets
// yAxisRange.
+ this.zoomed = false;
+ this.zoomedX = false;
+ this.zoomedY = false;
this.drawGraph_();
if (this.attr_("zoomCallback")) {
var minDate = this.rawData_[0][0];
// The roller sits in the bottom left corner of the chart. We don't know where
// this will be until the options are available, so it's positioned here.
- this.roller_ = this.createRollInterface_();
+ this.createRollInterface_();
// Same thing applies for the labelsDiv. It's right edge should be flush with
// the right edge of the charting area (which may not be the same as the right
}
var seriesExtremes = this.extremeValues_(series);
- extremes[seriesName] = seriesExtremes;
- var thisMinY = seriesExtremes[0];
- var thisMaxY = seriesExtremes[1];
- if (minY === null || (thisMinY != null && thisMinY < minY)) minY = thisMinY;
- if (maxY === null || (thisMaxY != null && thisMaxY > maxY)) maxY = thisMaxY;
if (bars) {
for (var j=0; j<series.length; j++) {
// If one data set has a NaN, let all subsequent stacked
// sets inherit the NaN -- only start at 0 for the first set.
var x = series[j][0];
- if (cumulative_y[x] === undefined)
+ if (cumulative_y[x] === undefined) {
cumulative_y[x] = 0;
+ }
actual_y = series[j][1];
cumulative_y[x] += actual_y;
series[j] = [x, cumulative_y[x]]
- if (!maxY || cumulative_y[x] > maxY)
- maxY = cumulative_y[x];
+ if (cumulative_y[x] > seriesExtremes[1]) {
+ seriesExtremes[1] = cumulative_y[x];
+ }
+ if (cumulative_y[x] < seriesExtremes[0]) {
+ seriesExtremes[0] = cumulative_y[x];
+ }
}
}
+ extremes[seriesName] = seriesExtremes;
datasets[i] = series;
}
* indices are into the axes_ array.
*/
Dygraph.prototype.computeYAxes_ = function() {
+ var valueWindow;
+ if (this.axes_ != undefined) {
+ // Preserve valueWindow settings.
+ valueWindow = [];
+ for (var index = 0; index < this.axes_.length; index++) {
+ valueWindow.push(this.axes_[index].valueWindow);
+ }
+ }
+
this.axes_ = [{}]; // always have at least one y-axis.
this.seriesToAxisMap_ = {};
// Get a list of series names.
var labels = this.attr_("labels");
- var series = [];
+ var series = {};
for (var i = 1; i < labels.length; i++) series[labels[i]] = (i - 1);
// all options which could be applied per-axis:
this.seriesToAxisMap_[seriesName] = idx;
}
}
+
+ // Now we remove series from seriesToAxisMap_ which are not visible. We do
+ // this last so that hiding the first series doesn't destroy the axis
+ // properties of the primary axis.
+ var seriesToAxisFiltered = {};
+ var vis = this.visibility();
+ for (var i = 1; i < labels.length; i++) {
+ var s = labels[i];
+ if (vis[i - 1]) seriesToAxisFiltered[s] = this.seriesToAxisMap_[s];
+ }
+ this.seriesToAxisMap_ = seriesToAxisFiltered;
+
+ if (valueWindow != undefined) {
+ // Restore valueWindow settings.
+ for (var index = 0; index < valueWindow.length; index++) {
+ this.axes_[index].valueWindow = valueWindow[index];
+ }
+ }
};
/**
// This is a user-set value range for this axis.
axis.computedValueRange = [axis.valueRange[0], axis.valueRange[1]];
} else {
- // Calcuate the extremes of extremes.
+ // Calculate the extremes of extremes.
var series = seriesForAxis[i];
var minY = Infinity; // extremes[series[0]][0];
var maxY = -Infinity; // extremes[series[0]][1];
*/
Dygraph.prototype.setVisibility = function(num, value) {
var x = this.visibility();
- if (num < 0 && num >= x.length) {
+ if (num < 0 || num >= x.length) {
this.warn("invalid series number in setVisibility: " + num);
} else {
x[num] = value;
}
Dygraph.GVizChart.prototype.draw = function(data, options) {
+ // Clear out any existing dygraph.
+ // TODO(danvk): would it make more sense to simply redraw using the current
+ // date_graph object?
this.container.innerHTML = '';
+ if (typeof(this.date_graph) != 'undefined') {
+ this.date_graph.destroy();
+ }
+
this.date_graph = new Dygraph(this.container, data, options);
}