From: Robert Konigsberg Date: Sun, 25 Nov 2012 04:11:14 +0000 (-0500) Subject: Merge branch 'remove-old-options' into new-series-option, make new style axis specifi... X-Git-Tag: v1.0.0~157^2~3 X-Git-Url: https://adrianiainlam.tk/git/?a=commitdiff_plain;h=6ad8b6a444ae32d026264409698f496506b3d33b;p=dygraphs.git Merge branch 'remove-old-options' into new-series-option, make new style axis specification work. Conflicts: dygraph-options.js --- 6ad8b6a444ae32d026264409698f496506b3d33b diff --cc auto_tests/tests/per_series.js index bba18ad,4831ded..8d81c7b --- a/auto_tests/tests/per_series.js +++ b/auto_tests/tests/per_series.js @@@ -47,96 -48,3 +47,102 @@@ perSeriesTestCase.prototype.testPerSeri assertEquals([255,0,0,38], sampler.colorAtCoordinate(6.5, 0.5)); }; +perSeriesTestCase.prototype.testOldStyleSeries = function() { + var opts = { + pointSize : 5, + Y: { pointSize : 4 }, + }; + var graph = document.getElementById("graph"); + var data = "X,Y,Z\n1,0,0\n"; + g = new Dygraph(graph, data, opts); + + assertEquals(5, g.getOption("pointSize")); + assertEquals(4, g.getOption("pointSize", "Y")); + assertEquals(5, g.getOption("pointSize", "Z")); +}; + +perSeriesTestCase.prototype.testNewStyleSeries = function() { + var opts = { + pointSize : 5, + series : { + Y: { pointSize : 4 } + }, + }; + var graph = document.getElementById("graph"); + var data = "X,Y,Z\n1,0,0\n"; + g = new Dygraph(graph, data, opts); + + assertEquals(5, g.getOption("pointSize")); + assertEquals(4, g.getOption("pointSize", "Y")); + assertEquals(5, g.getOption("pointSize", "Z")); +}; + +perSeriesTestCase.prototype.testNewStyleSeriesTrumpsOldStyle = function() { + var opts = { + pointSize : 5, + Z : { pointSize : 6 }, + series : { + Y: { pointSize : 4 } + }, + }; + var graph = document.getElementById("graph"); + var data = "X,Y,Z\n1,0,0\n"; + g = new Dygraph(graph, data, opts); + + assertEquals(5, g.getOption("pointSize")); + assertEquals(4, g.getOption("pointSize", "Y")); + assertEquals(5, g.getOption("pointSize", "Z")); + + // Erase the series object, and Z will become visible again. + g.updateOptions({ series : undefined }); + assertEquals(5, g.getOption("pointSize")); + assertEquals(6, g.getOption("pointSize", "Z")); + assertEquals(5, g.getOption("pointSize", "Y")); +}; + ++// TODO(konigsberg): move to multiple_axes.js +perSeriesTestCase.prototype.testAxisInNewSeries = function() { + var opts = { - logscale: true, + series : { + D : { axis : 'y2' }, + C : { axis : 1 }, + B : { axis : 0 }, + E : { axis : 'y' } + } + }; + var graph = document.getElementById("graph"); + var data = "X,A,B,C,D,E\n0,1,2,3,4,5\n"; + g = new Dygraph(graph, data, opts); + - assertEquals(5, g.getOption("pointSize")); - assertEquals(4, g.getOption("pointSize", "Y")); - assertEquals(5, g.getOption("pointSize", "Z")); ++ assertEquals(["A", "B", "E"], g.attributes_.seriesForAxis(0)); ++ assertEquals(["C", "D"], g.attributes_.seriesForAxis(1)); +}; + ++// TODO(konigsberg): move to multiple_axes.js +perSeriesTestCase.prototype.testAxisInNewSeries_withAxes = function() { + var opts = { + series : { + D : { axis : 'y2' }, + C : { axis : 1 }, + B : { axis : 0 }, + E : { axis : 'y' } + }, + axes : { - y : {}, - y2 : {} ++ y : { pointSize : 7 }, ++ y2 : { pointSize : 6 } + } + }; + var graph = document.getElementById("graph"); + var data = "X,A,B,C,D,E\n0,1,2,3,4,5\n"; + g = new Dygraph(graph, data, opts); + - assertEquals(5, g.getOption("pointSize")); - assertEquals(4, g.getOption("pointSize", "Y")); - assertEquals(5, g.getOption("pointSize", "Z")); ++ assertEquals(["A", "B", "E"], g.attributes_.seriesForAxis(0)); ++ assertEquals(["C", "D"], g.attributes_.seriesForAxis(1)); ++ ++ assertEquals(1.5, g.getOption("pointSize")); ++ assertEquals(7, g.getOption("pointSize", "A")); ++ assertEquals(7, g.getOption("pointSize", "B")); ++ assertEquals(6, g.getOption("pointSize", "C")); ++ assertEquals(6, g.getOption("pointSize", "D")); ++ assertEquals(7, g.getOption("pointSize", "E")); +}; diff --cc dygraph-options.js index 82daff6,dd7bb6b..f734c5d --- a/dygraph-options.js +++ b/dygraph-options.js @@@ -88,99 -55,63 +88,102 @@@ DygraphOptions.axisToIndex_ = function( DygraphOptions.prototype.reparseSeries = function() { this.labels = this.get("labels").slice(1); - this.axes_ = [ {} ]; // Always one axis at least. + this.axes_ = [ { series : [], options : {}} ]; // Always one axis at least. this.series_ = {}; - 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]; + // Traditionally, per-series options were specified right up there with the options. For instance + // { + // labels: [ "X", "foo", "bar" ], + // pointSize: 3, + // foo : {}, // options for foo + // bar : {} // options for bar + // } + // + // Moving forward, series really should be specified in the series element, separating them. + // like so: + // + // { + // labels: [ "X", "foo", "bar" ], + // pointSize: 3, + // series : { + // foo : {}, // options for foo + // bar : {} // options for bar + // } + // } + // + // So, if series is found, it's expected to contain per-series data, otherwise we fall + // back. + var oldStyleSeries = !this.user_["series"]; + + if (oldStyleSeries) { + 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.user_[seriesName] || {}; + + var yAxis = 0; + var axis = optionsForSeries["axis"]; + if (typeof(axis) == 'object') { + yAxis = ++axisId; - this.axes_[yAxis] = axis; ++ this.axes_[yAxis] = { series : [ seriesName ], options : axis }; + } + - var optionsForSeries = this.user_[seriesName] || {}; - var yAxis = 0; ++ // Associate series without axis options with axis 0. ++ if (!axis) { // undefined ++ this.axes_[0].series.push(seriesName); ++ } + - var axis = optionsForSeries["axis"]; - if (typeof(axis) == 'object') { - yAxis = ++axisId; - this.axes_[yAxis] = { series : [ seriesName ], options : axis }; + this.series_[seriesName] = { idx: idx, yAxis: yAxis, options : optionsForSeries }; } - - // Associate series without axis options with axis 0. - if (!axis) { // undefined - this.axes_[0].series.push(seriesName); + + // 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; ++ var yAxis = this.series_[axis].yAxis; ++ this.series_[seriesName].yAxis = yAxis; ++ this.axes_[yAxis].series.push(seriesName); + } } + } else { + var maxYAxis = 0; - this.series_[seriesName] = { idx: idx, yAxis: yAxis, options : optionsForSeries }; - } + for (var idx = 0; idx < this.labels.length; idx++) { + var seriesName = this.labels[idx]; + var optionsForSeries = this.user_.series[seriesName] || {}; + var yAxis = DygraphOptions.axisToIndex_(optionsForSeries["axis"]); + + maxYAxis = Math.max(yAxis, maxYAxis); - // 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] = { + idx: idx, + yAxis: yAxis, + options : optionsForSeries }; - } + - for (; maxYAxis >= 0; maxYAxis--) { - this.axes_[maxYAxis] = {}; ++ if (!this.axes_[yAxis]) { ++ this.axes_[yAxis] = { series : [ seriesName ], options : {} }; ++ } else { ++ this.axes_[yAxis].series.push(seriesName); + } - var yAxis = this.series_[axis].yAxis; - this.series_[seriesName].yAxis = yAxis; - this.axes_[yAxis].series.push(seriesName); } } // This doesn't support reading from the 'x' axis, only 'y' and 'y2. - if (this.user_["axes"]) { - // Read from the global "axes" option. - if (this.user_.hasOwnProperty("axes")) { -- var axis_opts = this.user_.axes; -- -- if (axis_opts.hasOwnProperty("y")) { - Dygraph.update(this.axes_[0], axis_opts.y); - Dygraph.update(this.axes_[0].options, axis_opts.y); -- } -- -- if (axis_opts.hasOwnProperty("y2")) { - this.axes_[1] = this.axes_[1] || {}; - Dygraph.update(this.axes_[1], axis_opts.y2); - this.axes_[1] = this.axes_[1] || {}; // FIX - Dygraph.update(this.axes_[1].options, axis_opts.y2); -- } ++ var axis_opts = this.user_["axes"] || {}; ++ Dygraph.update(this.axes_[0].options, axis_opts["y"] || {}); ++ if (this.axes_.length > 1) { ++ Dygraph.update(this.axes_[1].options, axis_opts["y2"] || {}); } }; @@@ -253,3 -184,32 +256,48 @@@ DygraphOptions.prototype.getForSeries return this.getForAxis(name, seriesObj["yAxis"]); }; + + /** + * Returns the number of y-axes on the chart. + * @return {Number} the number of axes. + */ + DygraphOptions.prototype.numAxes = function() { + return this.axes_.length; + } + + /** + * Return the y-axis for a given series, specified by name. + */ + DygraphOptions.prototype.axisForSeries = function(seriesName) { + return this.series_[seriesName].yAxis; + } + + /** + * Returns the options for the specified axis. + */ + DygraphOptions.prototype.axisOptions = function(yAxis) { + return this.axes_[yAxis].options; + } + + /** + * Return the series associated with an axis. + */ + DygraphOptions.prototype.seriesForAxis = function(yAxis) { + return this.axes_[yAxis].series; + } ++ ++/** ++ * Return the list of all series, in their columnar order. ++ */ ++DygraphOptions.prototype.seriesNames = function() { ++ return this.labels_; ++} ++ ++/* Are we using this? */ ++/** ++ * Return the index of the specified series. ++ * @param {string} series the series name. ++ */ ++DygraphOptions.prototype.indexOfSeries = function(series) { ++ return this.series_[series].idx; ++} diff --cc dygraph.js index 720443a,4b275d9..1193e74 --- a/dygraph.js +++ b/dygraph.js @@@ -2436,16 -2434,15 +2434,16 @@@ Dygraph.prototype.computeYAxes_ = funct } } -- this.axes_ = [{ yAxisId : 0, g : this }]; // always have at least one y-axis. - this.seriesToAxisMap_ = {}; -- -- // Get a list of series names. -- var labels = this.attr_("labels"); -- var series = {}; -- for (i = 1; i < labels.length; i++) series[labels[i]] = (i - 1); ++ // this.axes_ doesn't match this.attributes_.axes_.options. It's used for ++ // data computation as well as options storage. ++ this.axes_ = []; ++ for (axis = 0; axis < this.attributes_.numAxes(); axis++) { ++ this.axes_.push({ yAxisId : i, g : this }); ++ } // all options which could be applied per-axis: -- var axisOptions = [ ++ // TODO(konigsberg) ++ var globalAxisOptions = [ 'includeZero', 'valueRange', 'labelsKMB', @@@ -2458,48 -2455,30 +2456,22 @@@ ]; // Copy global axis options over to the first axis. -- for (i = 0; i < axisOptions.length; i++) { -- var k = axisOptions[i]; ++ for (i = 0; i < globalAxisOptions.length; i++) { ++ var k = globalAxisOptions[i]; v = this.attr_(k); if (v) this.axes_[0][k] = v; } // Go through once and add all the axes. -- for (seriesName in series) { -- if (!series.hasOwnProperty(seriesName)) continue; -- axis = this.attr_("axis", seriesName); -- if (axis === null) { - this.seriesToAxisMap_[seriesName] = 0; -- continue; -- } -- if (typeof(axis) == 'object') { -- // Add a new axis, making a copy of its per-axis options. -- opts = {}; -- Dygraph.update(opts, this.axes_[0]); -- Dygraph.update(opts, { valueRange: null }); // shouldn't inherit this. -- var yAxisId = this.axes_.length; -- opts.yAxisId = yAxisId; -- opts.g = this; -- Dygraph.update(opts, axis); -- this.axes_.push(opts); - this.seriesToAxisMap_[seriesName] = yAxisId; - } - } - - // Go through one more time and assign series to an axis defined by another - // series, e.g. { 'Y1: { axis: {} }, 'Y2': { axis: 'Y1' } } - for (seriesName in series) { - if (!series.hasOwnProperty(seriesName)) continue; - axis = this.attr_("axis", seriesName); - if (typeof(axis) == 'string') { - if (!this.seriesToAxisMap_.hasOwnProperty(axis)) { - this.error("Series " + seriesName + " wants to share a y-axis with " + - "series " + axis + ", which does not define its own axis."); - return null; - } - var idx = this.seriesToAxisMap_[axis]; - this.seriesToAxisMap_[seriesName] = idx; -- } ++ ++ // This seems to be right - starting at 1. I think this gets simpler now. ++ for (axis = 1; axis < this.attributes_.numAxes(); axis++) { ++ // Add a new axis, making a copy of its per-axis options. ++ opts = {}; ++ Dygraph.update(opts, this.axes_[0]); ++ Dygraph.update(opts, { valueRange: null }); // shouldn't inherit this. ++ Dygraph.update(opts, this.attributes_.axisOptions(axis)); ++ this.axes_[axis] = opts; } if (valueWindows !== undefined) { @@@ -2523,7 -2502,7 +2495,6 @@@ } } } -- }; /** @@@ -2559,25 -2532,24 +2524,20 @@@ Dygraph.prototype.axisPropertiesForSeri * This fills in the valueRange and ticks fields in each entry of this.axes_. */ Dygraph.prototype.computeYAxisRanges_ = function(extremes) { -- // Build a map from axis number -> [list of series names] - var seriesForAxis = [], series; - for (series in this.seriesToAxisMap_) { - if (!this.seriesToAxisMap_.hasOwnProperty(series)) continue; - var idx = this.seriesToAxisMap_[series]; - while (seriesForAxis.length <= idx) seriesForAxis.push([]); - seriesForAxis[idx].push(series); - } - var seriesForAxis = []; + var series; + var numAxes = this.attributes_.numAxes(); - for (var yAxis = 0; yAxis < numAxes; yAxis++) { - seriesForAxis[yAxis] = this.attributes_.seriesForAxis(yAxis); - } // Compute extreme values, a span and tick marks for each axis. - for (var i = 0; i < this.axes_.length; i++) { + for (var i = 0; i < numAxes; i++) { var axis = this.axes_[i]; -- if (!seriesForAxis[i]) { ++ series = this.attributes_.seriesForAxis(i); ++ ++ if (series.length == 0) { // If no series are defined or visible then use a reasonable default axis.extremeRange = [0, 1]; } else { // Calculate the extremes of extremes. -- series = seriesForAxis[i]; var minY = Infinity; // extremes[series[0]][0]; var maxY = -Infinity; // extremes[series[0]][1]; var extremeMinY, extremeMaxY;