this.canvas_.height = this.height_;
this.canvas_.style.width = this.width_ + "px"; // for IE
this.canvas_.style.height = this.height_ + "px"; // for IE
- this.graphDiv.appendChild(this.canvas_);
// ... and for static parts of the chart.
this.hidden_ = this.createPlotKitCanvas_(this.canvas_);
+ // The interactive parts of the graph are drawn on top of the chart.
+ this.graphDiv.appendChild(this.hidden_);
+ this.graphDiv.appendChild(this.canvas_);
+ this.mouseEventElement_ = this.canvas_;
+
// Make sure we don't overdraw.
Dygraph.clipCanvas_(this.hidden_, this.clippingArea_);
Dygraph.clipCanvas_(this.canvas_, this.clippingArea_);
var dygraph = this;
- Dygraph.addEvent(this.hidden_, 'mousemove', function(e) {
+ Dygraph.addEvent(this.mouseEventElement_, 'mousemove', function(e) {
dygraph.mouseMove_(e);
});
- Dygraph.addEvent(this.hidden_, 'mouseout', function(e) {
+ Dygraph.addEvent(this.mouseEventElement_, 'mouseout', function(e) {
dygraph.mouseOut_(e);
});
h.height = this.height_;
h.style.width = this.width_ + "px"; // for IE
h.style.height = this.height_ + "px"; // for IE
- this.graphDiv.appendChild(h);
return h;
};
var getY = function(e) { return Dygraph.pageX(e) - py };
// Draw zoom rectangles when the mouse is down and the user moves around
- Dygraph.addEvent(this.hidden_, 'mousemove', function(event) {
+ Dygraph.addEvent(this.mouseEventElement_, 'mousemove', function(event) {
if (isZooming) {
dragEndX = getX(event);
dragEndY = getY(event);
});
// Track the beginning of drag events
- Dygraph.addEvent(this.hidden_, 'mousedown', function(event) {
+ Dygraph.addEvent(this.mouseEventElement_, 'mousedown', function(event) {
px = Dygraph.findPosX(self.canvas_);
py = Dygraph.findPosY(self.canvas_);
dragStartX = getX(event);
});
// Temporarily cancel the dragging event when the mouse leaves the graph
- Dygraph.addEvent(this.hidden_, 'mouseout', function(event) {
+ Dygraph.addEvent(this.mouseEventElement_, 'mouseout', function(event) {
if (isZooming) {
dragEndX = null;
dragEndY = null;
// If the mouse is released on the canvas during a drag event, then it's a
// zoom. Only do the zoom if it's over a large enough area (>= 10 pixels)
- Dygraph.addEvent(this.hidden_, 'mouseup', function(event) {
+ Dygraph.addEvent(this.mouseEventElement_, 'mouseup', function(event) {
if (isZooming) {
isZooming = false;
dragEndX = getX(event);
});
// Double-clicking zooms back out
- Dygraph.addEvent(this.hidden_, 'dblclick', function(event) {
+ Dygraph.addEvent(this.mouseEventElement_, 'dblclick', function(event) {
if (self.dateWindow_ == null) return;
self.dateWindow_ = null;
self.drawGraph_(self.rawData_);
* @private
*/
Dygraph.prototype.mouseMove_ = function(event) {
- var canvasx = Dygraph.pageX(event) - Dygraph.findPosX(this.hidden_);
+ var canvasx = Dygraph.pageX(event) - Dygraph.findPosX(this.mouseEventElement_);
var points = this.layout_.points;
var lastx = -1;
// Extract the points we've selected
this.selPoints_ = [];
- var cumulative_sum = 0; // used only if we have a stackedGraph.
var l = points.length;
- var isStacked = this.attr_("stackedGraph");
if (!this.attr_("stackedGraph")) {
for (var i = 0; i < l; i++) {
if (points[i].xval == lastx) {
}
}
} else {
- // Stacked points need to be examined in reverse order.
+ // Need to 'unstack' points starting from the bottom
+ var cumulative_sum = 0;
for (var i = l - 1; i >= 0; i--) {
if (points[i].xval == lastx) {
- // Clone the point, since we need to 'unstack' it below.
- var p = {};
+ var p = {}; // Clone the point since we modify it
for (var k in points[i]) {
p[k] = points[i][k];
}
this.selPoints_.push(p);
}
}
+ this.selPoints_.reverse();
}
if (this.attr_("highlightCallback")) {
var connectSeparatedPoints = this.attr_('connectSeparatedPoints');
- // For stacked series.
- var cumulative_y = [];
- var stacked_datasets = [];
+ // Loop over the fields (series). Go from the last to the first,
+ // because if they're stacked that's how we accumulate the values.
- // Loop over all fields in the dataset
- for (var i = 1; i < data[0].length; i++) {
+ var cumulative_y = []; // For stacked series.
+ var datasets = [];
+
+ // Loop over all fields and create datasets
+ for (var i = data[0].length - 1; i >= 1; i--) {
if (!this.visibility()[i - 1]) continue;
var series = [];
if (maxY === null || thisMaxY > maxY) maxY = thisMaxY;
if (bars) {
- var vals = [];
- for (var j=0; j<series.length; j++)
- 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);
+ for (var j=0; j<series.length; j++) {
+ val = [series[j][0], series[j][1][0], series[j][1][1], series[j][1][2]];
+ series[j] = val;
+ }
} 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;
+ // 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)
+ cumulative_y[x] = 0;
actual_y = series[j][1];
- cumulative_y[series[j][0]] += actual_y;
+ cumulative_y[x] += actual_y;
- vals[j] = [series[j][0], cumulative_y[series[j][0]]]
+ series[j] = [x, cumulative_y[x]]
- if (!maxY || cumulative_y[series[j][0]] > maxY)
- maxY = cumulative_y[series[j][0]];
+ if (!maxY || cumulative_y[x] > maxY)
+ maxY = cumulative_y[x];
}
- stacked_datasets.push([this.attr_("labels")[i], vals]);
- //this.layout_.addDataset(this.attr_("labels")[i], vals);
- } else {
- this.layout_.addDataset(this.attr_("labels")[i], series);
}
+
+ datasets[i] = series;
}
- if (stacked_datasets.length > 0) {
- for (var i = (stacked_datasets.length - 1); i >= 0; i--) {
- this.layout_.addDataset(stacked_datasets[i][0], stacked_datasets[i][1]);
- }
+ for (var i = 1; i < datasets.length; i++) {
+ this.layout_.addDataset(this.attr_("labels")[i], datasets[i]);
}
// Use some heuristics to come up with a good maxY value, unless it's been