this.boundaryIds_ = [];
- // Make a note of whether labels will be pulled from the CSV file.
- this.labelsFromCSV_ = (this.attr_("labels") == null);
-
// Create the containing DIV and other interactive elements
this.createInterface_();
*/
Dygraph.prototype.yAxisRange = function(idx) {
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] ];
+ if (idx < 0 || idx >= this.axes_.length) {
+ return null;
+ }
+ var axis = this.axes_[idx];
+ return [ axis.computedValueRange[0], axis.computedValueRange[1] ];
};
/**
}
}
- g.drawGraph_();
+ g.drawGraph_(false);
};
/**
* dragStartX/dragStartY/etc. properties). This function modifies the context.
*/
Dygraph.Interaction.endPan = function(event, g, context) {
+ context.dragEndX = g.dragGetX_(event, context);
+ context.dragEndY = g.dragGetY_(event, context);
+
+ var regionWidth = Math.abs(context.dragEndX - context.dragStartX);
+ var regionHeight = Math.abs(context.dragEndY - context.dragStartY);
+
+ if (regionWidth < 2 && regionHeight < 2 &&
+ g.lastx_ != undefined && g.lastx_ != -1) {
+ Dygraph.Interaction.treatMouseOpAsClick(g, context);
+ }
+
// TODO(konigsberg): Clear the context data from the axis.
+ // (replace with "context = {}" ?)
// TODO(konigsberg): mouseup should just delete the
// context object, and mousedown should create a new one.
context.isPanning = false;
context.valueRange = null;
context.boundedDates = null;
context.boundedValues = null;
+
+ var dragEndX = g.dragGetX_(event, context);
+ var dragEndY = g.dragGetY_(event, context);
+ var regionWidth = Math.abs(context.dragEndX - context.dragStartX);
+ var regionHeight = Math.abs(context.dragEndY - context.dragStartY);
+
+ if (regionWidth < 2 && regionHeight < 2 &&
+ g.lastx_ != undefined && g.lastx_ != -1) {
+ Dygraph.Interaction.treatMouseOpAsClick(g);
+ }
};
/**
context.prevDragDirection = context.dragDirection;
};
+Dygraph.Interaction.treatMouseOpAsClick = function(g, context) {
+ // TODO(danvk): pass along more info about the points, e.g. 'x'
+ if (g.attr_('clickCallback') != null) {
+ g.attr_('clickCallback')(event, g.lastx_, g.selPoints_, context);
+ }
+ if (g.attr_('pointClickCallback')) {
+ // check if the click was on a particular point.
+ var closestIdx = -1;
+ var closestDistance = 0;
+ for (var i = 0; i < g.selPoints_.length; i++) {
+ var p = g.selPoints_[i];
+ var distance = Math.pow(p.canvasx - context.dragEndX, 2) +
+ Math.pow(p.canvasy - context.dragEndY, 2);
+ if (closestIdx == -1 || distance < closestDistance) {
+ closestDistance = distance;
+ closestIdx = i;
+ }
+ }
+
+ // Allow any click within two pixels of the dot.
+ var radius = g.attr_('highlightCircleSize') + 2;
+ if (closestDistance <= 5 * 5) {
+ g.attr_('pointClickCallback')(event, g.selPoints_[closestIdx]);
+ }
+ }
+}
+
/**
* Called in response to an interaction model operation that
* responds to an event that performs a zoom based on previously defined
* dragStartX/dragStartY/etc. properties). This function modifies the context.
*/
Dygraph.Interaction.endZoom = function(event, g, context) {
- // TODO(konigsberg): Refactor or rename this fn -- it deals with clicks, too.
context.isZooming = false;
context.dragEndX = g.dragGetX_(event, context);
context.dragEndY = g.dragGetY_(event, context);
if (regionWidth < 2 && regionHeight < 2 &&
g.lastx_ != undefined && g.lastx_ != -1) {
- // TODO(danvk): pass along more info about the points, e.g. 'x'
- if (g.attr_('clickCallback') != null) {
- g.attr_('clickCallback')(event, g.lastx_, g.selPoints_);
- }
- if (g.attr_('pointClickCallback')) {
- // check if the click was on a particular point.
- var closestIdx = -1;
- var closestDistance = 0;
- for (var i = 0; i < g.selPoints_.length; i++) {
- var p = g.selPoints_[i];
- var distance = Math.pow(p.canvasx - context.dragEndX, 2) +
- Math.pow(p.canvasy - context.dragEndY, 2);
- if (closestIdx == -1 || distance < closestDistance) {
- closestDistance = distance;
- closestIdx = i;
- }
- }
-
- // Allow any click within two pixels of the dot.
- var radius = g.attr_('highlightCircleSize') + 2;
- if (closestDistance <= 5 * 5) {
- g.attr_('pointClickCallback')(event, g.selPoints_[closestIdx]);
- }
- }
+ Dygraph.Interaction.treatMouseOpAsClick(g);
}
if (regionWidth >= 10 && context.dragDirection == Dygraph.HORIZONTAL) {
* Update the graph with new data. This method is called when the viewing area
* has changed. If the underlying data or options have changed, predraw_ will
* be called before drawGraph_ is called.
+ *
+ * clearSelection, when undefined or true, causes this.clearSelection to be
+ * called at the end of the draw operation. This should rarely be defined,
+ * and never true (that is it should be undefined most of the time, and
+ * rarely false.)
+ *
* @private
*/
-Dygraph.prototype.drawGraph_ = function() {
+Dygraph.prototype.drawGraph_ = function(clearSelection) {
+ if (typeof(clearSelection) === 'undefined') {
+ clearSelection = true;
+ }
+
var data = this.rawData_;
// This is used to set the second parameter to drawCallback, below.
// Generate a static legend before any particular point is selected.
this.setLegendHTML_();
} else {
- if (typeof(this.selPoints_) !== 'undefined' && this.selPoints_.length) {
- // We should select the point nearest the page x/y here, but it's easier
- // to just clear the selection. This prevents erroneous hover dots from
- // being displayed.
- this.clearSelection();
- } else {
- this.clearSelection();
+ if (clearSelection) {
+ if (typeof(this.selPoints_) !== 'undefined' && this.selPoints_.length) {
+ // We should select the point nearest the page x/y here, but it's easier
+ // to just clear the selection. This prevents erroneous hover dots from
+ // being displayed.
+ this.clearSelection();
+ } else {
+ this.clearSelection();
+ }
}
}
* indices are into the axes_ array.
*/
Dygraph.prototype.computeYAxes_ = function() {
+ // Preserve valueWindow settings if they exist, and if the user hasn't
+ // specified a new valueRange.
+ var valueWindows;
+ if (this.axes_ != undefined && this.user_attrs_.hasOwnProperty("valueRange") == false) {
+ valueWindows = [];
+ for (var index = 0; index < this.axes_.length; index++) {
+ valueWindows.push(this.axes_[index].valueWindow);
+ }
+ }
+
+
this.axes_ = [{ yAxisId : 0, g : this }]; // always have at least one y-axis.
this.seriesToAxisMap_ = {};
if (vis[i - 1]) seriesToAxisFiltered[s] = this.seriesToAxisMap_[s];
}
this.seriesToAxisMap_ = seriesToAxisFiltered;
+
+ if (valueWindows != undefined) {
+ // Restore valueWindow settings.
+ for (var index = 0; index < valueWindows.length; index++) {
+ this.axes_[index].valueWindow = valueWindows[index];
+ }
+ }
};
/**
}
var start = 0;
- if (this.labelsFromCSV_) {
+ if (!('labels' in this.user_attrs_)) {
+ // User hasn't explicitly set labels, so they're (presumably) in the CSV.
start = 1;
- this.attrs_.labels = lines[0].split(delim);
+ this.attrs_.labels = lines[0].split(delim); // NOTE: _not_ user_attrs_.
}
var line_no = 0;
// These functions are all based on MochiKit.
/**
+ * Copies all the properties from o to self.
+ *
* @private
*/
Dygraph.update = function (self, o) {
* <li>errorBars: changes whether the data contains stddev</li>
* </ul>
*
+ * There's a huge variety of options that can be passed to this method. For a
+ * full list, see http://dygraphs.com/options.html.
+ *
* @param {Object} attrs The new properties and values
+ * @param {Boolean} [block_redraw] Usually the chart is redrawn after every
+ * call to updateOptions(). If you know better, you can pass true to explicitly
+ * block the redraw. This can be useful for chaining updateOptions() calls,
+ * avoiding the occasional infinite loop and preventing redraws when it's not
+ * necessary (e.g. when updating a callback).
*/
-Dygraph.prototype.updateOptions = function(attrs) {
- // TODO(danvk): this is a mess. Rethink this function.
+Dygraph.prototype.updateOptions = function(attrs, block_redraw) {
+ if (typeof(block_redraw) == 'undefined') block_redraw = false;
+
+ // TODO(danvk): this is a mess. Move these options into attr_.
if ('rollPeriod' in attrs) {
this.rollPeriod_ = attrs.rollPeriod;
}
Dygraph.update(this.user_attrs_, attrs);
- this.labelsFromCSV_ = (this.attr_("labels") == null);
-
if (attrs['file']) {
this.file_ = attrs['file'];
- this.start_();
+ if (!block_redraw) this.start_();
} else {
- this.predraw_();
+ if (!block_redraw) this.predraw_();
}
};