From c1780ad0fcfaa98acb399c976176ebefb25c8794 Mon Sep 17 00:00:00 2001 From: Robert Konigsberg Date: Sat, 17 Nov 2012 18:41:17 -0600 Subject: [PATCH] Add dygraph-options.js. Add code to compare behavior. Looks like it's only working in very limited cases. --- dygraph-dev.js | 1 + dygraph-options.js | 118 +++++++++++++++++++++++++++++++++++++++++++++++++++++ dygraph.js | 23 ++++++++++- 3 files changed, 140 insertions(+), 2 deletions(-) create mode 100644 dygraph-options.js diff --git a/dygraph-dev.js b/dygraph-dev.js index 4ca6bb3..b90796c 100644 --- a/dygraph-dev.js +++ b/dygraph-dev.js @@ -20,6 +20,7 @@ "rgbcolor/rgbcolor.js", "stacktrace.js", "dashed-canvas.js", + "dygraph-options.js", "dygraph-layout.js", "dygraph-canvas.js", "dygraph.js", diff --git a/dygraph-options.js b/dygraph-options.js new file mode 100644 index 0000000..562fa24 --- /dev/null +++ b/dygraph-options.js @@ -0,0 +1,118 @@ +/** + * @fileoverview DygraphOptions is responsible for parsing and returning information about options. + * + * Still tightly coupled to Dygraphs, we could remove some of that, you know. + */ + +"use strict"; + +/* + * Interesting member variables: + * dygraph_ - the graph. + * global - global attributes (common among all graphs, AIUI) + * global_user - attributes set by the user + * axes + * series - { seriesName -> { idx, yAxis, options } + * labels - used as mapping from index to series name. + */ + +/** + * @constructor + * + * This parses attributes into an object that can be easily queried. + * + * @param {Dyraph} dygraph The chart to which these options belong. + */ +var DygraphOptions = function(dygraph) { + this.dygraph_ = dygraph; + this.axes = []; + this.series = {}; + + // Once these two objects are initialized, you can call find(); + this.global = this.dygraph_.attrs_; + this.global_user = this.dygraph_.user_attrs_ || {}; + + // Get a list of series names. + this.labels = this.find("labels").slice(1); + + var axisId = 0; // 0-offset; there's always one. + // Go through once, add all the series, and for those with {} axis options, add a new axis. + for (var idx = 0; idx < this.labels.length; idx++) { + var seriesName = this.labels[idx]; + + var optionsForSeries = this.global_user[seriesName] || {}; + var yAxis = 0; + + var axis = optionsForSeries["axis"]; + if (typeof(axis) == 'object') { + yAxis = ++axisId; + } + this.series[seriesName] = { idx: idx, yAxis: yAxis, options : optionsForSeries }; + } + + // Go through one more time and assign series to an axis defined by another + // series, e.g. { 'Y1: { axis: {} }, 'Y2': { axis: 'Y1' } } + for (var idx = 0; idx < this.labels.length; idx++) { + var seriesName = this.labels[idx]; + var optionsForSeries = this.series[seriesName]["options"]; + var axis = optionsForSeries["axis"]; + + if (typeof(axis) == 'string') { + if (!this.series.hasOwnProperty(axis)) { + this.dygraph_.error("Series " + seriesName + " wants to share a y-axis with " + + "series " + axis + ", which does not define its own axis."); + return null; + } + this.series[seriesName].yAxis = this.series[axis].yAxis; + } + } + + // This doesn't support reading from the 'x' axis, only 'y' and 'y2. + // Read from the global "axes" option. + if (this.global_user.hasOwnProperty("axes")) { + var axis_opts = this.global_user.axes; + + this.axes.push(axis_opts["y"] || {}); + this.axes.push(axis_opts["y2"] || {}); + } else { + this.axes.push(axis_opts["y"] || {}); // There has to be at least one axis. + } +}; + +DygraphOptions.prototype.find = function(name) { + if (this.global_user.hasOwnProperty(name)) { + return this.global_user[name]; + } + if (this.global.hasOwnProperty(name)) { + return this.global[name]; + } + return null; +} + +DygraphOptions.prototype.findForAxis = function(name, axis) { + + var axisIdx = (axis == "y2" || axis == 1) ? 1 : 0; + + var axisOptions = this.axes[axisIdx]; + if (axisOptions.hasOwnProperty(name)) { + return axisOptions[name]; + } + return this.find(name); +} + +DygraphOptions.prototype.findForSeries = function(name, series) { + // Honors indexes as series. + var seriesName = (typeof(series) == "number") ? this.labels[series] : series; + + if (!this.series.hasOwnProperty(seriesName)) { + throw "Unknown series: " + series; + } + + var seriesObj = this.series[seriesName]; + var seriesOptions = seriesObj["options"]; + if (seriesOptions.hasOwnProperty(name)) { + return seriesOptions[name]; + } + return this.findForAxis(name, seriesObj["yAxis"]); +} + diff --git a/dygraph.js b/dygraph.js index 621ea32..4189750 100644 --- a/dygraph.js +++ b/dygraph.js @@ -437,6 +437,8 @@ Dygraph.prototype.__init__ = function(div, file, attrs) { this.registeredEvents_ = []; this.eventListeners_ = {}; + this.attributes_ = new DygraphOptions(this); + // Create the containing DIV and other interactive elements this.createInterface_(); @@ -568,6 +570,12 @@ Dygraph.prototype.attr_ = function(name, seriesName) { } // + // Building an array which we peruse in backwards order to find the correct value. + // Options are checked in this order: + // series, axis, user attrs, global attrs. + // TODO(konigsberg): Can this be made faster by starting with the series and working outward, + // rather than building an array? + var sources = []; sources.push(this.attrs_); if (this.user_attrs_) { @@ -576,6 +584,8 @@ Dygraph.prototype.attr_ = function(name, seriesName) { if (this.user_attrs_.hasOwnProperty(seriesName)) { sources.push(this.user_attrs_[seriesName]); } + + // TODO(konigsberg): This special case ought to be documented. if (seriesName === this.highlightSet_ && this.user_attrs_.hasOwnProperty('highlightSeriesOpts')) { sources.push(this.user_attrs_.highlightSeriesOpts); @@ -591,7 +601,15 @@ Dygraph.prototype.attr_ = function(name, seriesName) { break; } } - return ret; + + var computedValue = seriesName ? this.attributes_.findForSeries(name, seriesName) : this.attributes_.find(name); + + if (ret !== computedValue) { + console.log("Mismatch", name, seriesName, ret, computedValue); + } else { + console.log("Match", name, seriesName, ret, computedValue); + } + return computedValue; }; /** @@ -2179,7 +2197,8 @@ Dygraph.prototype.predraw_ = function() { // rolling averages. this.rolledSeries_ = [null]; // x-axis is the first series and it's special for (var i = 1; i < this.numColumns(); i++) { - var logScale = this.attr_('logscale', i); // TODO(klausw): this looks wrong + // var logScale = this.attr_('logscale', i); // TODO(klausw): this looks wrong // konigsberg thinks so too. + var logScale = this.attr_('logscale'); var series = this.extractSeries_(this.rawData_, i, logScale); series = this.rollingAverage(series, this.rollPeriod_); this.rolledSeries_.push(series); -- 2.7.4