this.graphDiv = document.createElement("div");
this.graphDiv.style.width = this.width_ + "px";
this.graphDiv.style.height = this.height_ + "px";
+ // TODO(danvk): any other styles that are useful to set here?
+ this.graphDiv.style.textAlign = 'left'; // This is a CSS "reset"
enclosing.appendChild(this.graphDiv);
// Create the canvas for interactive parts of the chart.
};
this.mouseOutHandler_ = function(e) {
- dygraph.mouseOut_(e);
+ // The mouse has left the chart if:
+ // 1. e.target is inside the chart
+ // 2. e.relatedTarget is outside the chart
+ var target = e.target || e.fromElement;
+ var relatedTarget = e.relatedTarget || e.toElement;
+ if (Dygraph.isElementContainedBy(target, dygraph.graphDiv) &&
+ !Dygraph.isElementContainedBy(relatedTarget, dygraph.graphDiv)) {
+ dygraph.mouseOut_(e);
+ }
};
+ this.addEvent(window, 'mouseout', this.mouseOutHandler_);
this.addEvent(this.mouseEventElement_, 'mousemove', this.mouseMoveHandler_);
- this.addEvent(this.mouseEventElement_, 'mouseout', this.mouseOutHandler_);
// Don't recreate and register the resize handler on subsequent calls.
// This happens when the graph is resized.
}
};
- for (var idx = 0; idx < this.registeredEvents_.length; idx++) {
- var reg = this.registeredEvents_[idx];
- Dygraph.removeEvent(reg.elem, reg.type, reg.fn);
+ if (this.registeredEvents_) {
+ for (var idx = 0; idx < this.registeredEvents_.length; idx++) {
+ var reg = this.registeredEvents_[idx];
+ Dygraph.removeEvent(reg.elem, reg.type, reg.fn);
+ }
}
+
this.registeredEvents_ = [];
// remove mouse event handlers (This may not be necessary anymore)
- Dygraph.removeEvent(this.mouseEventElement_, 'mouseout', this.mouseOutHandler_);
+ Dygraph.removeEvent(window, 'mouseout', this.mouseOutHandler_);
Dygraph.removeEvent(this.mouseEventElement_, 'mousemove', this.mouseMoveHandler_);
- Dygraph.removeEvent(this.mouseEventElement_, 'mousemove', this.mouseUpHandler_);
+ Dygraph.removeEvent(this.mouseEventElement_, 'mouseup', this.mouseUpHandler_);
// remove window handlers
Dygraph.removeEvent(window,'resize',this.resizeHandler_);
* Returns a two-element array: [X, Y].
*/
Dygraph.prototype.eventToDomCoords = function(event) {
- var canvasx = Dygraph.pageX(event) - Dygraph.findPosX(this.mouseEventElement_);
- var canvasy = Dygraph.pageY(event) - Dygraph.findPosY(this.mouseEventElement_);
- return [canvasx, canvasy];
+ if (event.offsetX && event.offsetY) {
+ return [ event.offsetX, event.offsetY ];
+ } else {
+ var canvasx = Dygraph.pageX(event) - Dygraph.findPosX(this.mouseEventElement_);
+ var canvasy = Dygraph.pageY(event) - Dygraph.findPosY(this.mouseEventElement_);
+ return [canvasx, canvasy];
+ }
};
/**
* This fills in the valueRange and ticks fields in each entry of this.axes_.
*/
Dygraph.prototype.computeYAxisRanges_ = function(extremes) {
+
+ var isNullUndefinedOrNaN = function(num) {
+ return isNaN(parseFloat(num));
+ };
var series;
var numAxes = this.attributes_.numAxes();
axis.computedValueRange = [axis.valueWindow[0], axis.valueWindow[1]];
} else if (axis.valueRange) {
// This is a user-set value range for this axis.
- axis.computedValueRange = [axis.valueRange[0], axis.valueRange[1]];
+ axis.computedValueRange = [
+ isNullUndefinedOrNaN(axis.valueRange[0]) ? axis.extremeRange[0] : axis.valueRange[0],
+ isNullUndefinedOrNaN(axis.valueRange[1]) ? axis.extremeRange[1] : axis.valueRange[1]
+ ];
} else {
axis.computedValueRange = axis.extremeRange;
}
* data
*/
Dygraph.prototype.rollingAverage = function(originalData, rollPeriod) {
- if (originalData.length < 2)
- return originalData;
rollPeriod = Math.min(rollPeriod, originalData.length);
var rollingData = [];
var sigma = this.attr_("sigma");
/**
* Get the list of label names for this graph. The first column is the
* x-axis, so the data series names start at index 1.
+ *
+ * Returns null when labels have not yet been defined.
*/
Dygraph.prototype.getLabels = function() {
- return this.attr_("labels").slice();
+ var labels = this.attr_("labels");
+ return labels ? labels.slice() : null;
};
/**