+ } else {
+ for (i = 0; i < num; i++) {
+ if (!this.visibility()[i]) continue;
+ var colorStr = colors[i % colors.length];
+ this.colors_.push(colorStr);
+ }
+ }
+
+ this.plotter_.setColors(this.colors_);
+};
+
+/**
+ * Return the list of colors. This is either the list of colors passed in the
+ * attributes or the autogenerated list of rgb(r,g,b) strings.
+ * This does not return colors for invisible series.
+ * @return {Array<string>} The list of colors.
+ */
+Dygraph.prototype.getColors = function() {
+ return this.colors_;
+};
+
+/**
+ * Returns a few attributes of a series, i.e. its color, its visibility, which
+ * axis it's assigned to, and its column in the original data.
+ * Returns null if the series does not exist.
+ * Otherwise, returns an object with column, visibility, color and axis properties.
+ * The "axis" property will be set to 1 for y1 and 2 for y2.
+ * The "column" property can be fed back into getValue(row, column) to get
+ * values for this series.
+ */
+Dygraph.prototype.getPropertiesForSeries = function(series_name) {
+ var idx = -1;
+ var labels = this.getLabels();
+ for (var i = 1; i < labels.length; i++) {
+ if (labels[i] == series_name) {
+ idx = i;
+ break;
+ }
+ }
+ if (idx == -1) return null;
+
+ return {
+ name: series_name,
+ column: idx,
+ visible: this.visibility()[idx - 1],
+ color: this.plotter_.colors[series_name],
+ axis: 1 + this.seriesToAxisMap_[series_name]
+ };
+};
+
+/**
+ * Create the text box to adjust the averaging period
+ * @private
+ */
+Dygraph.prototype.createRollInterface_ = function() {
+ // 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 area = this.plotter_.area;
+ var textAttr = { "position": "absolute",
+ "zIndex": 10,
+ "top": (area.y + area.h - 25) + "px",
+ "left": (area.x + 1) + "px",
+ "display": display
+ };
+ this.roller_.size = "2";
+ this.roller_.value = this.rollPeriod_;
+ for (var name in textAttr) {
+ if (textAttr.hasOwnProperty(name)) {
+ this.roller_.style[name] = textAttr[name];
+ }
+ }
+
+ var dygraph = this;
+ this.roller_.onchange = function() { dygraph.adjustRoll(dygraph.roller_.value); };
+};
+
+/**
+ * @private
+ * Converts page the x-coordinate of the event to pixel x-coordinates on the
+ * canvas (i.e. DOM Coords).
+ */
+Dygraph.prototype.dragGetX_ = function(e, context) {
+ return Dygraph.pageX(e) - context.px;
+};
+
+/**
+ * @private
+ * Converts page the y-coordinate of the event to pixel y-coordinates on the
+ * canvas (i.e. DOM Coords).
+ */
+Dygraph.prototype.dragGetY_ = function(e, context) {
+ return Dygraph.pageY(e) - context.py;
+};
+
+/**
+ * Set up all the mouse handlers needed to capture dragging behavior for zoom
+ * events.
+ * @private
+ */
+Dygraph.prototype.createDragInterface_ = function() {
+ var context = {
+ // Tracks whether the mouse is down right now
+ isZooming: false,
+ isPanning: false, // is this drag part of a pan?
+ is2DPan: false, // if so, is that pan 1- or 2-dimensional?
+ dragStartX: null, // pixel coordinates
+ dragStartY: null, // pixel coordinates
+ dragEndX: null, // pixel coordinates
+ dragEndY: null, // pixel coordinates
+ dragDirection: null,
+ prevEndX: null, // pixel coordinates
+ prevEndY: null, // pixel coordinates
+ prevDragDirection: null,
+ cancelNextDblclick: false, // see comment in dygraph-interaction-model.js
+
+ // The value on the left side of the graph when a pan operation starts.
+ initialLeftmostDate: null,
+
+ // The number of units each pixel spans. (This won't be valid for log
+ // scales)
+ xUnitsPerPixel: null,
+
+ // TODO(danvk): update this comment
+ // The range in second/value units that the viewport encompasses during a
+ // panning operation.
+ dateRange: null,
+
+ // Top-left corner of the canvas, in DOM coords
+ // TODO(konigsberg): Rename topLeftCanvasX, topLeftCanvasY.
+ px: 0,
+ py: 0,
+
+ // Values for use with panEdgeFraction, which limit how far outside the
+ // graph's data boundaries it can be panned.
+ boundedDates: null, // [minDate, maxDate]
+ boundedValues: null, // [[minValue, maxValue] ...]
+
+ // contextB is the same thing as this context object but renamed.
+ initializeMouseDown: function(event, g, contextB) {
+ // prevents mouse drags from selecting page text.
+ if (event.preventDefault) {
+ event.preventDefault(); // Firefox, Chrome, etc.
+ } else {
+ event.returnValue = false; // IE
+ event.cancelBubble = true;
+ }
+
+ contextB.px = Dygraph.findPosX(g.canvas_);
+ contextB.py = Dygraph.findPosY(g.canvas_);
+ contextB.dragStartX = g.dragGetX_(event, contextB);
+ contextB.dragStartY = g.dragGetY_(event, contextB);
+ contextB.cancelNextDblclick = false;
+ }
+ };
+
+ var interactionModel = this.attr_("interactionModel");
+
+ // Self is the graph.
+ var self = this;
+
+ // Function that binds the graph and context to the handler.
+ var bindHandler = function(handler) {
+ return function(event) {
+ handler(event, self, context);
+ };
+ };
+
+ for (var eventName in interactionModel) {
+ if (!interactionModel.hasOwnProperty(eventName)) continue;
+ this.addEvent(this.mouseEventElement_, eventName,
+ bindHandler(interactionModel[eventName]));
+ }