From 48dc3815c2cd342aab3d47978b5351e2ce5bcf43 Mon Sep 17 00:00:00 2001 From: Robert Konigsberg Date: Mon, 31 Dec 2012 13:27:14 -0500 Subject: [PATCH] axisLabelFontSize can now be configured per-axis. --- auto_tests/tests/axis_labels.js | 47 +++++++++++++++++++++++++++++ dygraph-options.js | 65 ++++++++++++++++++++++++++--------------- dygraph.js | 3 ++ experimental/palette/options.js | 2 +- plugins/axes.js | 44 +++++++++++++++++++--------- 5 files changed, 124 insertions(+), 37 deletions(-) diff --git a/auto_tests/tests/axis_labels.js b/auto_tests/tests/axis_labels.js index 00f3913..98f48bb 100644 --- a/auto_tests/tests/axis_labels.js +++ b/auto_tests/tests/axis_labels.js @@ -577,6 +577,53 @@ AxisLabelsTestCase.prototype.testIncludeZero = function() { assertEquals(['500','600','700','800','900','1000'], Util.getYLabels()); } +AxisLabelsTestCase.prototype.testAxisLabelFontSize = function() { + var graph = document.getElementById("graph"); + var g = new Dygraph(graph, AxisLabelsTestCase.simpleData, {}); + + // Be sure we're dealing with a 14-point default. + assertEquals(14, Dygraph.DEFAULT_ATTRS.axisLabelFontSize); + + Util.assertFontSizes(graph, "dygraph-axis-label-x", 14); + Util.assertFontSizes(graph, "dygraph-axis-label-y", 14); + + g.updateOptions({ axisLabelFontSize : 8}); + Util.assertFontSizes(graph, "dygraph-axis-label-x", 8); + Util.assertFontSizes(graph, "dygraph-axis-label-y", 8); + + g.updateOptions({ + axisLabelFontSize : null, + axes : { + x : { axisLabelFontSize : 5 }, + } + }); + + Util.assertFontSizes(graph, "dygraph-axis-label-x", 5); + Util.assertFontSizes(graph, "dygraph-axis-label-y", 14); + + g.updateOptions({ + axes : { + y : { axisLabelFontSize : 20 }, + } + }); + + Util.assertFontSizes(graph, "dygraph-axis-label-x", 5); + Util.assertFontSizes(graph, "dygraph-axis-label-y", 20); + + g.updateOptions({ + series : { + Y2 : { axis : "y2" } // copy y2 series to y2 axis. + }, + axes : { + y2 : { axisLabelFontSize : 12 }, + } + }); + + Util.assertFontSizes(graph, "dygraph-axis-label-x", 5); + Util.assertFontSizes(graph, "dygraph-axis-label-y1", 20); + Util.assertFontSizes(graph, "dygraph-axis-label-y2", 12); +} + AxisLabelsTestCase.prototype.testAxisLabelFontSizeNull = function() { var graph = document.getElementById("graph"); var g = new Dygraph(graph, AxisLabelsTestCase.simpleData, diff --git a/dygraph-options.js b/dygraph-options.js index f059ff9..81f7667 100644 --- a/dygraph-options.js +++ b/dygraph-options.js @@ -11,7 +11,8 @@ * dygraph_ - the graph. * global_ - global attributes (common among all graphs, AIUI) * user - attributes set by the user - * axes_ - array of axis index to { series : [ series names ] , options : { axis-specific options. } + * yAxes_ - array of axis index to { series : [ series names ] , options : { axis-specific options. } + * xAxis_ - { options : { axis-specific options. } * series_ - { seriesName -> { idx, yAxis, options }} * labels_ - used as mapping from index to series name. */ @@ -28,7 +29,8 @@ */ var DygraphOptions = function(dygraph) { this.dygraph_ = dygraph; - this.axes_ = []; + this.yAxes_ = []; + this.xAxis_ = {}; this.series_ = {}; // Once these two objects are initialized, you can call get(); @@ -92,7 +94,8 @@ DygraphOptions.axisToIndex_ = function(axis) { DygraphOptions.prototype.reparseSeries = function() { this.labels = this.get("labels").slice(1); - this.axes_ = [ { series : [], options : {}} ]; // Always one axis at least. + this.yAxes_ = [ { series : [], options : {}} ]; // Always one axis at least. + this.xAxis_ = { options : {} }; this.series_ = {}; // Traditionally, per-series options were specified right up there with the options. For instance @@ -131,12 +134,12 @@ DygraphOptions.prototype.reparseSeries = function() { var axis = optionsForSeries["axis"]; if (typeof(axis) == 'object') { yAxis = ++axisId; - this.axes_[yAxis] = { series : [ seriesName ], options : axis }; + this.yAxes_[yAxis] = { series : [ seriesName ], options : axis }; } // Associate series without axis options with axis 0. if (!axis) { // undefined - this.axes_[0].series.push(seriesName); + this.yAxes_[0].series.push(seriesName); } this.series_[seriesName] = { idx: idx, yAxis: yAxis, options : optionsForSeries }; @@ -157,7 +160,7 @@ DygraphOptions.prototype.reparseSeries = function() { } var yAxis = this.series_[axis].yAxis; this.series_[seriesName].yAxis = yAxis; - this.axes_[yAxis].series.push(seriesName); + this.yAxes_[yAxis].series.push(seriesName); } } } else { @@ -171,20 +174,20 @@ DygraphOptions.prototype.reparseSeries = function() { yAxis: yAxis, options : optionsForSeries }; - if (!this.axes_[yAxis]) { - this.axes_[yAxis] = { series : [ seriesName ], options : {} }; + if (!this.yAxes_[yAxis]) { + this.yAxes_[yAxis] = { series : [ seriesName ], options : {} }; } else { - this.axes_[yAxis].series.push(seriesName); + this.yAxes_[yAxis].series.push(seriesName); } } } - // This doesn't support reading from the 'x' axis, only 'y' and '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"] || {}); + Dygraph.update(this.yAxes_[0].options, axis_opts["y"] || {}); + if (this.yAxes_.length > 1) { + Dygraph.update(this.yAxes_[1].options, axis_opts["y2"] || {}); } + Dygraph.update(this.xAxis_.options, axis_opts["x"] || {}); }; /** @@ -223,19 +226,35 @@ DygraphOptions.prototype.getGlobalDefault_ = function(name) { * * @param {String} name the name of the option. * @param {String|number} axis the axis to search. Can be the string representation - * ("y", "y2") or the axis number (0, 1). + * ("x", "y", "y2") or the y-axis number (0, 1). (x-axis can't be specified by number.') */ DygraphOptions.prototype.getForAxis = function(name, axis) { - var axisIdx = 0; + var axisIdx; + var axisString; + + // Since axis can be a number or a string, straighten everything out here. if (typeof(axis) == 'number') { axisIdx = axis; + axisString = axisIdx == 0 ? "y" : "y2"; } else { - // TODO(konigsberg): Accept only valid axis strings? - axisIdx = (axis == "y2") ? 1 : 0; + if (axis == "y1") { axis = "y"; } // Standardize on 'y'. Is this bad? I think so. + if (axis == "y") { + axisIdx = 0; + } else if (axis == "y2") { + axisIdx = 1; + } else if (axis == "x") { + axisIdx = -1; // simply a placeholder for below. + } else { + throw "Unknown axis " + axis; + } + axisString = axis; } + + var userAxis = (axisIdx == -1) ? this.xAxis_ : this.yAxes_[axisIdx]; + // Search the user-specified axis option first. - if (this.axes_[axisIdx]) { - var axisOptions = this.axes_[axisIdx].options; + if (userAxis) { // This condition could be removed if we always set up this.yAxes_ for y2. + var axisOptions = userAxis.options; if (axisOptions.hasOwnProperty(name)) { return axisOptions[name]; } @@ -248,7 +267,6 @@ DygraphOptions.prototype.getForAxis = function(name, axis) { } // Default axis options third. - var axisString = axis == 0 ? "y" : "y2"; var defaultAxisOptions = Dygraph.DEFAULT_ATTRS.axes[axisString]; if (defaultAxisOptions.hasOwnProperty(name)) { return defaultAxisOptions[name]; @@ -294,7 +312,7 @@ DygraphOptions.prototype.getForSeries = function(name, series) { * @return {Number} the number of axes. */ DygraphOptions.prototype.numAxes = function() { - return this.axes_.length; + return this.yAxes_.length; }; /** @@ -307,15 +325,16 @@ DygraphOptions.prototype.axisForSeries = function(seriesName) { /** * Returns the options for the specified axis. */ +// TODO(konigsberg): this is y-axis specific. Support the x axis. DygraphOptions.prototype.axisOptions = function(yAxis) { - return this.axes_[yAxis].options; + return this.yAxes_[yAxis].options; }; /** * Return the series associated with an axis. */ DygraphOptions.prototype.seriesForAxis = function(yAxis) { - return this.axes_[yAxis].series; + return this.yAxes_[yAxis].series; }; /** diff --git a/dygraph.js b/dygraph.js index 2bccd60..d7c558b 100644 --- a/dygraph.js +++ b/dygraph.js @@ -598,6 +598,9 @@ Dygraph.prototype.getOption = function(name, opt_seriesName) { return this.attr_(name, opt_seriesName); }; +Dygraph.prototype.getOptionForAxis = function(name, axis) { + return this.attributes_.getForAxis(name, axis); +} /** * @private * @param String} axis The name of the axis (i.e. 'x', 'y' or 'y2') diff --git a/experimental/palette/options.js b/experimental/palette/options.js index c91439d..bb74957 100644 --- a/experimental/palette/options.js +++ b/experimental/palette/options.js @@ -69,7 +69,7 @@ var opts = { }, axisLabelFontSize : { type : "int", - // scope : [ "x", "y", "y2" ] + scope : [ "global", "x", "y", "y2" ] }, axisLabelFormatter : { type : "function(numberOrDate, granularity, opts, dygraph)", diff --git a/plugins/axes.js b/plugins/axes.js index 1f9c256..40b826c 100644 --- a/plugins/axes.js +++ b/plugins/axes.js @@ -52,7 +52,7 @@ axes.prototype.layout = function(e) { if (g.getOption('xAxisHeight')) { h = g.getOption('xAxisHeight'); } else { - h = g.getOption('axisLabelFontSize') + 2 * g.getOption('axisTickSize'); + h = g.getOptionForAxis('axisLabelFontSize', 'x') + 2 * g.getOption('axisTickSize'); } var x_axis_rect = e.reserveSpaceBottom(h); } @@ -101,18 +101,34 @@ axes.prototype.willDrawChart = function(e) { var label, x, y, tick, i; - var labelStyle = { - position: "absolute", - fontSize: g.getOption('axisLabelFontSize') + "px", - zIndex: 10, - color: g.getOption('axisLabelColor'), - width: g.getOption('axisLabelWidth') + "px", - // height: this.attr_('axisLabelFontSize') + 2 + "px", - lineHeight: "normal", // Something other than "normal" line-height screws up label positioning. - overflow: "hidden" + var makeLabelStyle = function(axis) { + return { + position: "absolute", + fontSize: g.getOptionForAxis('axisLabelFontSize', axis) + "px", + zIndex: 10, + color: g.getOption('axisLabelColor'), + width: g.getOption('axisLabelWidth') + "px", + // height: g.getOptionForAxis('axisLabelFontSize', 'x') + 2 + "px", + lineHeight: "normal", // Something other than "normal" line-height screws up label positioning. + overflow: "hidden" + }; + } + + var labelStyles = { + x : makeLabelStyle('x'), + y : makeLabelStyle('y'), + y2 : makeLabelStyle('y2'), }; + var makeDiv = function(txt, axis, prec_axis) { + /* + * This seems to be called with the following three sets of axis/perc_axis: + * x: undefined + * y: y1 + * y: y2 + */ var div = document.createElement("div"); + var labelStyle = labelStyles[prec_axis == 'y2' ? 'y2' : axis]; for (var name in labelStyle) { if (labelStyle.hasOwnProperty(name)) { div.style[name] = labelStyle[name]; @@ -149,6 +165,7 @@ axes.prototype.willDrawChart = function(e) { sgn = -1; prec_axis = 'y2'; } + var fontSize = g.getOptionForAxis('axisLabelFontSize', prec_axis); y = area.y + tick[1] * area.h; /* Tick marks are currently clipped, so don't bother drawing them. @@ -160,10 +177,10 @@ axes.prototype.willDrawChart = function(e) { */ label = makeDiv(tick[2], 'y', num_axes == 2 ? prec_axis : null); - var top = (y - g.getOption('axisLabelFontSize') / 2); + var top = (y - fontSize / 2); if (top < 0) top = 0; - if (top + g.getOption('axisLabelFontSize') + 3 > canvasHeight) { + if (top + fontSize + 3 > canvasHeight) { label.style.bottom = "0px"; } else { label.style.top = top + "px"; @@ -185,7 +202,8 @@ axes.prototype.willDrawChart = function(e) { // tick on the x-axis. Shift the bottom tick up a little bit to // compensate if necessary. var bottomTick = this.ylabels_[0]; - var fontSize = g.getOption('axisLabelFontSize'); + // Interested in the y2 axis also? + var fontSize = g.getOptionForAxis('axisLabelFontSize', "y"); var bottom = parseInt(bottomTick.style.top, 10) + fontSize; if (bottom > canvasHeight - fontSize) { bottomTick.style.top = (parseInt(bottomTick.style.top, 10) - -- 2.7.4