X-Git-Url: https://adrianiainlam.tk/git/?a=blobdiff_plain;f=dygraph.js;h=0fc48cef97e2e07b5d2bc553bb362c2afda3af8b;hb=25b70e09fe463ced2ee49f7af2f47cf74c131b01;hp=41ad05ccc5f1e6f12bf6fdacfd6e048bd8c9ba52;hpb=f978433f1679216e312114af7d2a9ea3e3b5b36b;p=dygraphs.git diff --git a/dygraph.js b/dygraph.js index 41ad05c..0fc48ce 100644 --- a/dygraph.js +++ b/dygraph.js @@ -180,6 +180,18 @@ Dygraph.dateAxisFormatter = function(date, granularity) { } }; +/** + * Standard plotters. These may be used by clients. + * Available plotters are: + * - Dygraph.Plotters.linePlotter: draws central lines (most common) + * - Dygraph.Plotters.errorPlotter: draws error bars + * - Dygraph.Plotters.fillPlotter: draws fills under lines (used with fillGraph) + * + * By default, the plotter is [fillPlotter, errorPlotter, linePlotter]. + * This causes all the lines to be drawn over all the fills/error bars. + */ +Dygraph.Plotters = DygraphCanvasRenderer._Plotters; + // Default attribute values. Dygraph.DEFAULT_ATTRS = { @@ -261,6 +273,14 @@ Dygraph.DEFAULT_ATTRS = { rangeSelectorPlotStrokeColor: "#808FAB", rangeSelectorPlotFillColor: "#A7B1C4", + // The ordering here ensures that central lines always appear above any + // fill bars/error bars. + plotter: [ + Dygraph.Plotters.fillPlotter, + Dygraph.Plotters.errorPlotter, + Dygraph.Plotters.linePlotter + ], + // per-axis options axes: { x: { @@ -388,6 +408,12 @@ Dygraph.prototype.__init__ = function(div, file, attrs) { // TODO(nikhilk): Add any other stackedGraph checks here. } + // These two options have a bad interaction. See issue 359. + if (attrs.showRangeSelector && attrs.animatedZooms) { + this.warn('You should not set animatedZooms=true when using the range selector.'); + attrs.animatedZooms = false; + } + // Dygraphs has many options, some of which interact with one another. // To keep track of everything, we maintain two sets of options: // @@ -409,6 +435,7 @@ Dygraph.prototype.__init__ = function(div, file, attrs) { this.datasetIndex_ = []; this.registeredEvents_ = []; + this.eventListeners_ = {}; // Create the containing DIV and other interactive elements this.createInterface_(); @@ -416,8 +443,8 @@ Dygraph.prototype.__init__ = function(div, file, attrs) { // Activate plugins. this.plugins_ = []; for (var i = 0; i < Dygraph.PLUGINS.length; i++) { - var plugin = Dygraph.PLUGINS[i]; - var pluginInstance = new plugin(); + var Plugin = Dygraph.PLUGINS[i]; + var pluginInstance = new Plugin(); var pluginDict = { plugin: pluginInstance, events: {}, @@ -436,7 +463,6 @@ Dygraph.prototype.__init__ = function(div, file, attrs) { // At this point, plugins can no longer register event handlers. // Construct a map from event -> ordered list of [callback, plugin]. - this.eventListeners_ = {}; for (var i = 0; i < this.plugins_.length; i++) { var plugin_dict = this.plugins_[i]; for (var eventName in plugin_dict.events) { @@ -462,7 +488,7 @@ Dygraph.prototype.__init__ = function(div, file, attrs) { * @private */ Dygraph.prototype.cascadeEvents_ = function(name, extra_props) { - if (!name in this.eventListeners_) return true; + if (!(name in this.eventListeners_)) return true; // QUESTION: can we use objects & prototypes to speed this up? var e = { @@ -498,11 +524,13 @@ Dygraph.prototype.cascadeEvents_ = function(name, extra_props) { * Axis is an optional parameter. Can be set to 'x' or 'y'. * * The zoomed status for an axis is set whenever a user zooms using the mouse - * or when the dateWindow or valueRange are updated (unless the isZoomedIgnoreProgrammaticZoom - * option is also specified). + * or when the dateWindow or valueRange are updated (unless the + * isZoomedIgnoreProgrammaticZoom option is also specified). */ Dygraph.prototype.isZoomed = function(axis) { - if (axis == null) return this.zoomed_x_ || this.zoomed_y_; + if (axis === null || axis === undefined) { + return this.zoomed_x_ || this.zoomed_y_; + } if (axis === 'x') return this.zoomed_x_; if (axis === 'y') return this.zoomed_y_; throw "axis parameter is [" + axis + "] must be null, 'x' or 'y'."; @@ -550,7 +578,7 @@ Dygraph.prototype.attr_ = function(name, seriesName) { } if (seriesName === this.highlightSet_ && this.user_attrs_.hasOwnProperty('highlightSeriesOpts')) { - sources.push(this.user_attrs_['highlightSeriesOpts']); + sources.push(this.user_attrs_.highlightSeriesOpts); } } } @@ -931,7 +959,6 @@ Dygraph.prototype.createInterface_ = function() { if (this.attr_('showRangeSelector')) { // The range selector must be created here so that its canvases and contexts get created here. // For some reason, if the canvases and contexts don't get created here, things don't work in IE. - // The range selector also sets xAxisHeight in order to reserve space. this.rangeSelector_ = new DygraphRangeSelector(this); } @@ -949,12 +976,12 @@ Dygraph.prototype.createInterface_ = function() { } var dygraph = this; - + this.mouseMoveHandler = function(e) { dygraph.mouseMove_(e); }; this.addEvent(this.mouseEventElement_, 'mousemove', this.mouseMoveHandler); - + this.mouseOutHandler = function(e) { dygraph.mouseOut_(e); }; @@ -983,7 +1010,7 @@ Dygraph.prototype.destroy = function() { node.removeChild(node.firstChild); } }; - + for (var idx = 0; idx < this.registeredEvents_.length; idx++) { var reg = this.registeredEvents_[idx]; Dygraph.removeEvent(reg.elem, reg.type, reg.fn); @@ -1226,6 +1253,10 @@ Dygraph.prototype.createDragInterface_ = function() { boundedDates: null, // [minDate, maxDate] boundedValues: null, // [[minValue, maxValue] ...] + // We cover iframes during mouse interactions. See comments in + // dygraph-utils.js for more info on why this is a good idea. + tarp: new Dygraph.IFrameTarp(), + // contextB is the same thing as this context object but renamed. initializeMouseDown: function(event, g, contextB) { // prevents mouse drags from selecting page text. @@ -1241,6 +1272,7 @@ Dygraph.prototype.createDragInterface_ = function() { contextB.dragStartX = g.dragGetX_(event, contextB); contextB.dragStartY = g.dragGetY_(event, contextB); contextB.cancelNextDblclick = false; + contextB.tarp.cover(); } }; @@ -1280,6 +1312,8 @@ Dygraph.prototype.createDragInterface_ = function() { delete self.axes_[i].dragValueRange; } } + + context.tarp.uncover(); }; this.addEvent(document, 'mouseup', this.mouseUpHandler_); @@ -1502,7 +1536,8 @@ Dygraph.prototype.doUnzoom_ = function() { newValueRanges = []; for (i = 0; i < this.axes_.length; i++) { var axis = this.axes_[i]; - newValueRanges.push(axis.valueRange != null ? axis.valueRange : axis.extremeRange); + newValueRanges.push(axis.valueRange !== null ? + axis.valueRange : axis.extremeRange); } } @@ -1704,7 +1739,7 @@ Dygraph.prototype.findStackedPoint = function(domX, domY) { } } // Stop if the point (domX, py) is above this series' upper edge - if (setIdx == 0 || py < domY) { + if (setIdx === 0 || py < domY) { closestPoint = p1; closestSeries = setIdx; } @@ -1853,8 +1888,10 @@ Dygraph.prototype.updateSelection_ = function(opt_animFraction) { ctx.fillStyle = 'rgba(255,255,255,' + alpha + ')'; ctx.fillRect(0, 0, this.width_, this.height_); } - var setIdx = this.datasetIndexFromSetName_(this.highlightSet_); - this.plotter_._drawLine(ctx, setIdx); + + // Redraw only the highlighted series in the interactive canvas (not the + // static plot canvas, which is where series are usually drawn). + this.plotter_._renderLineChart(this.highlightSet_, ctx); } else if (this.previousVerticalX_ >= 0) { // Determine the maximum highlight circle size. var maxCircleSize = 0; @@ -1931,7 +1968,7 @@ Dygraph.prototype.setSelection = function(row, opt_seriesName, opt_locked) { point = this.layout_.unstackPointAtIndex(setIdx, row); } - if (!(point.yval === null)) this.selPoints_.push(point); + if (point.yval !== null) this.selPoints_.push(point); } } } else { @@ -2075,7 +2112,7 @@ Dygraph.prototype.extremeValues_ = function(series) { // With custom bars, maxY is the max of the high values. for (j = 0; j < series.length; j++) { y = series[j][1][0]; - if (!y) continue; + if (y === null || isNaN(y)) continue; var low = y - series[j][1][1]; var high = y + series[j][1][2]; if (low > y) low = y; // this can happen with custom bars, @@ -2363,7 +2400,7 @@ Dygraph.prototype.renderGraph_ = function(is_initial_draw) { var e = { canvas: this.hidden_, - drawingContext: this.hidden_ctx_, + drawingContext: this.hidden_ctx_ }; this.cascadeEvents_('willDrawChart', e); this.plotter_.render(); @@ -2650,7 +2687,7 @@ Dygraph.prototype.computeYAxisRanges_ = function(extremes) { * This is where undesirable points (i.e. negative values on log scales and * missing values through which we wish to connect lines) are dropped. * TODO(danvk): the "missing values" bit above doesn't seem right. - * + * * @private */ Dygraph.prototype.extractSeries_ = function(rawData, i, logScale) { @@ -2899,7 +2936,8 @@ Dygraph.prototype.parseFloat_ = function(x, opt_line_no, opt_line) { */ Dygraph.prototype.parseCSV_ = function(data) { var ret = []; - var lines = data.split("\n"); + var line_delimiter = Dygraph.detectLineDelimiter(data); + var lines = data.split(line_delimiter || "\n"); var vals, j; // Use the default delimiter or fall back to a tab if that makes sense. @@ -3113,7 +3151,7 @@ Dygraph.prototype.parseDataTable_ = function(data) { num = Math.floor((num - 1) / 26); } return shortText; - } + }; var cols = data.getNumberOfColumns(); var rows = data.getNumberOfRows(); @@ -3255,7 +3293,8 @@ Dygraph.prototype.start_ = function() { this.predraw_(); } else if (typeof data == 'string') { // Heuristic: a newline means it's CSV data. Otherwise it's an URL. - if (data.indexOf('\n') >= 0) { + var line_delimiter = Dygraph.detectLineDelimiter(data); + if (line_delimiter) { this.loadedEvent_(data); } else { var req = new XMLHttpRequest();