From d0c3910871966e227d08a5ea7d80b55981a19e88 Mon Sep 17 00:00:00 2001 From: Dan Vanderkam Date: Tue, 3 Jan 2012 18:36:28 -0500 Subject: [PATCH] Fix Issue 202: Second Y-Axis Label Option name is "y2label". This results in a label on the right-hand side of the chart which is rotated in the opposite way of the label on the left-hand side. It gets CSS classes "dygraph-label dygraph-y2label" (the primary y-axis label gets "dygraph-label dygraph-ylabel"). --- auto_tests/tests/multiple_axes.js | 51 +++++++++++++++++++++++++++++++++++++++ dygraph-canvas.js | 48 +++++++++++++++++++++++++----------- dygraph-layout.js | 5 ++++ dygraph-options-reference.js | 6 +++++ tests/two-axes.html | 8 ++++-- 5 files changed, 102 insertions(+), 16 deletions(-) diff --git a/auto_tests/tests/multiple_axes.js b/auto_tests/tests/multiple_axes.js index ed9b362..2c0f18f 100644 --- a/auto_tests/tests/multiple_axes.js +++ b/auto_tests/tests/multiple_axes.js @@ -167,3 +167,54 @@ MultipleAxesTestCase.prototype.testTwoAxisVisibility = function() { assertTrue(document.getElementsByClassName("dygraph-axis-label-y").length > 0); assertTrue(document.getElementsByClassName("dygraph-axis-label-y2").length > 0); }; + +// verifies that all four chart labels (title, x-, y-, y2-axis label) can be +// used simultaneously. +MultipleAxesTestCase.prototype.testMultiChartLabels = function() { + var data = MultipleAxesTestCase.getData(); + + var el = document.getElementById("graph"); + el.style.border = '1px solid black'; + el.style.marginLeft = '200px'; + el.style.marginTop = '200px'; + + g = new Dygraph( + el, + data, + { + labels: [ 'Date', 'Y1', 'Y2', 'Y3', 'Y4' ], + width: 640, + height: 350, + 'Y3': { + axis: { } + }, + 'Y4': { + axis: 'Y3' // use the same y-axis as series Y3 + }, + xlabel: 'x-axis', + ylabel: 'y-axis', + y2label: 'y2-axis', + title: 'Chart title' + } + ); + + // returns all text in tags w/ a given css class, sorted. + function getTexts(css_class) { + var texts = []; + var els = document.getElementsByClassName(css_class); + for (var i = 0; i < els.length; i++) { + texts[i] = els[i].textContent; + } + texts.sort(); + return texts; + } + + assertEquals(["Chart title", "x-axis", "y-axis", "y2-axis"], + getTexts("dygraph-label")); + assertEquals(["Chart title"], getTexts("dygraph-title")); + assertEquals(["x-axis"], getTexts("dygraph-xlabel")); + assertEquals(["y-axis"], getTexts("dygraph-ylabel")); + assertEquals(["y2-axis"], getTexts("dygraph-y2label")); + + // TODO(danvk): check relative positioning here: title on top, y left of y2. +}; diff --git a/dygraph-canvas.js b/dygraph-canvas.js index e2d304c..acf011f 100644 --- a/dygraph-canvas.js +++ b/dygraph-canvas.js @@ -485,21 +485,26 @@ DygraphCanvasRenderer.prototype._renderChartLabels = function() { this.chartLabels.xlabel = div; } - if (this.attr_('ylabel')) { + var that = this; + function createRotatedDiv(axis, classes, html) { var box = { left: 0, - top: this.area.y, - width: this.attr_('yLabelWidth'), - height: this.area.h + top: that.area.y, + width: that.attr_('yLabelWidth'), + height: that.area.h }; // TODO(danvk): is this outer div actually necessary? div = document.createElement("div"); div.style.position = 'absolute'; - div.style.left = box.left; + if (axis == 1) { + div.style.left = box.left; + } else { + div.style.right = box.left; + } div.style.top = box.top + 'px'; div.style.width = box.width + 'px'; div.style.height = box.height + 'px'; - div.style.fontSize = (this.attr_('yLabelWidth') - 2) + 'px'; + div.style.fontSize = (that.attr_('yLabelWidth') - 2) + 'px'; var inner_div = document.createElement("div"); inner_div.style.position = 'absolute'; @@ -511,11 +516,12 @@ DygraphCanvasRenderer.prototype._renderChartLabels = function() { // CSS rotation is an HTML5 feature which is not standardized. Hence every // browser has its own name for the CSS style. - inner_div.style.transform = 'rotate(-90deg)'; // HTML5 - inner_div.style.WebkitTransform = 'rotate(-90deg)'; // Safari/Chrome - inner_div.style.MozTransform = 'rotate(-90deg)'; // Firefox - inner_div.style.OTransform = 'rotate(-90deg)'; // Opera - inner_div.style.msTransform = 'rotate(-90deg)'; // IE9 + var val = 'rotate(' + (axis == 1 ? '-' : '') + '90deg)'; + inner_div.style.transform = val; // HTML5 + inner_div.style.WebkitTransform = val; // Safari/Chrome + inner_div.style.MozTransform = val; // Firefox + inner_div.style.OTransform = val; // Opera + inner_div.style.msTransform = val; // IE9 if (typeof(document.documentMode) !== 'undefined' && document.documentMode < 9) { @@ -523,20 +529,34 @@ DygraphCanvasRenderer.prototype._renderChartLabels = function() { // using a BasicImage transform. This uses a different origin of rotation // than HTML5 rotation (top left of div vs. its center). inner_div.style.filter = - 'progid:DXImageTransform.Microsoft.BasicImage(rotation=3)'; + 'progid:DXImageTransform.Microsoft.BasicImage(rotation=' + + (axis == 1 ? '3' : '1') + ')'; inner_div.style.left = '0px'; inner_div.style.top = '0px'; } class_div = document.createElement("div"); - class_div.className = 'dygraph-label dygraph-ylabel'; - class_div.innerHTML = this.attr_('ylabel'); + class_div.className = classes; + class_div.innerHTML = html; inner_div.appendChild(class_div); div.appendChild(inner_div); + return div; + } + + var div; + if (this.attr_('ylabel')) { + div = createRotatedDiv(1, 'dygraph-label dygraph-ylabel', + this.attr_('ylabel')); this.container.appendChild(div); this.chartLabels.ylabel = div; } + if (this.attr_('y2label')) { + div = createRotatedDiv(2, 'dygraph-label dygraph-y2label', + this.attr_('y2label')); + this.container.appendChild(div); + this.chartLabels.y2label = div; + } }; diff --git a/dygraph-layout.js b/dygraph-layout.js index 6f8f2fd..328da81 100644 --- a/dygraph-layout.js +++ b/dygraph-layout.js @@ -99,6 +99,11 @@ DygraphLayout.prototype.computePlotArea_ = function() { // doesn't, the yAxisLabelWidth option can be increased. } + if (this.attr_('y2label')) { + // same logic applies here as for ylabel. + // TODO(danvk): make yAxisLabelWidth a per-axis property + } + // Add space for range selector, if needed. if (this.attr_('showRangeSelector')) { area.h -= this.attr_('rangeSelectorHeight') + 4; diff --git a/dygraph-options-reference.js b/dygraph-options-reference.js index b5825e6..92846ee 100644 --- a/dygraph-options-reference.js +++ b/dygraph-options-reference.js @@ -476,6 +476,12 @@ Dygraph.OPTIONS_REFERENCE = // "default": "null", "description": "Text to display to the left of the chart's y-axis. You can supply any HTML for this value, not just text. If you wish to style it using CSS, use the 'dygraph-label' or 'dygraph-ylabel' classes. The text will be rotated 90 degrees by default, so CSS rules may behave in unintuitive ways. No additional space is set aside for a y-axis label. If you need more space, increase the width of the y-axis tick labels using the yAxisLabelWidth option. If you need a wider div for the y-axis label, either style it that way with CSS (but remember that it's rotated, so width is controlled by the 'height' property) or set the yLabelWidth option." }, + "y2label": { + "labels": ["Chart labels"], + "type": "string", + "default": "null", + "description": "Text to display to the right of the chart's secondary y-axis. This label is only displayed if a secondary y-axis is present. See this test for an example of how to do this. The comments for the 'ylabel' option generally apply here as well. This label gets a 'dygraph-y2label' instead of a 'dygraph-ylabel' class." + }, "yLabelWidth": { "labels": ["Chart labels"], "type": "integer", diff --git a/tests/two-axes.html b/tests/two-axes.html index 834fd2f..bb4a34a 100644 --- a/tests/two-axes.html +++ b/tests/two-axes.html @@ -53,7 +53,10 @@ // set axis-related properties here labelsKMB: true } - } + }, + ylabel: 'Primary y-axis', + y2label: 'Secondary y-axis', + yAxisLabelWidth: 60 } ); @@ -62,7 +65,8 @@ data, { labels: [ 'Date', 'Y1', 'Y2', 'Y3', 'Y4' ], - labelsKMB: true + labelsKMB: true, + ylabel: 'Primary y-axis' } ); -- 2.7.4