]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
Add support for line height CSS values (#4531)
authorSimon Brunel <simonbrunel@users.noreply.github.com>
Thu, 20 Jul 2017 17:20:54 +0000 (19:20 +0200)
committerGitHub <noreply@github.com>
Thu, 20 Jul 2017 17:20:54 +0000 (19:20 +0200)
The title plugin and scale title now accept lineHeight specified using unitless value (1.4), length ('1.4em' or '12px'), percentage ('200%') or keyword ('normal' === 1.2). The line height parsing has been refactored under the 'Chart.helpers.options' namespace. Also fix incorrect text positioning in the title plugin.

https://developer.mozilla.org/en-US/docs/Web/CSS/line-height

14 files changed:
docs/axes/labelling.md
docs/configuration/title.md
src/core/core.scale.js
src/helpers/helpers.options.js [new file with mode: 0644]
src/helpers/index.js
src/plugins/plugin.title.js
test/specs/core.helpers.tests.js
test/specs/helpers.options.tests.js [new file with mode: 0644]
test/specs/plugin.title.tests.js
test/specs/scale.category.tests.js
test/specs/scale.linear.tests.js
test/specs/scale.logarithmic.tests.js
test/specs/scale.radialLinear.tests.js
test/specs/scale.time.tests.js

index 5e4a6a76b87a607fdea431f6db7c068d944ae291..22fc2600463bcd35ac01262ffca7a8b96ad39b95 100644 (file)
@@ -10,7 +10,7 @@ The scale label configuration is nested under the scale configuration in the `sc
 | -----| ---- | --------| -----------
 | `display` | `Boolean` | `false` | If true, display the axis title.
 | `labelString` | `String` | `''` | The text for the title. (i.e. "# of People" or "Response Choices").
-| `lineHeight` | `Number` | `` | Height of an individual line of text. If not defined, the font size is used.
+| `lineHeight` | `Number|String` | `1.2` | Height of an individual line of text (see [MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/line-height))
 | `fontColor` | Color | `'#666'` | Font color for scale title.
 | `fontFamily` | `String` | `"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"` | Font family for the scale title, follows CSS font-family options.
 | `fontSize` | `Number` | `12` | Font size for scale title.
index 3952f2ca64ff79740a18712aaf879d567e09af7a..b2c04cd8fbefc7391147956f20bfb7991dff308f 100644 (file)
@@ -14,7 +14,7 @@ The title configuration is passed into the `options.title` namespace. The global
 | `fontColor` | Color | `'#666'` | Font color
 | `fontStyle` | `String` | `'bold'` | Font style
 | `padding` | `Number` | `10` | Number of pixels to add above and below the title text.
-| `lineHeight` | `Number` | `undefined` | Height of line of text. If not specified, the `fontSize` is used.
+| `lineHeight` | `Number|String` | `1.2` | Height of an individual line of text (see [MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/line-height))
 | `text` | `String/String[]`  | `''` | Title text to display. If specified as an array, text is rendered on multiple lines.
 
 ### Position
index 9626c3f0e6cb19f204072bcf50f265f0807deaae..942e4fff6b98122f43a5bfcadcec7f922748469e 100644 (file)
@@ -28,11 +28,13 @@ defaults._set('scale', {
 
        // scale label
        scaleLabel: {
+               // display property
+               display: false,
+
                // actual label
                labelString: '',
 
-               // display property
-               display: false,
+               lineHeight: 1.2
        },
 
        // label settings
@@ -77,6 +79,12 @@ module.exports = function(Chart) {
                };
        }
 
+       function parseLineHeight(options) {
+               return helpers.options.toLineHeight(
+                       helpers.valueOrDefault(options.lineHeight, 1.2),
+                       helpers.valueOrDefault(options.fontSize, defaults.global.defaultFontSize));
+       }
+
        Chart.Scale = Chart.Element.extend({
                /**
                 * Get the padding needed for the scale
@@ -310,8 +318,8 @@ module.exports = function(Chart) {
                        var isHorizontal = me.isHorizontal();
 
                        var tickFont = parseFontOptions(tickOpts);
-                       var scaleLabelLineHeight = helpers.valueOrDefault(scaleLabelOpts.lineHeight, parseFontOptions(scaleLabelOpts).size * 1.5);
                        var tickMarkLength = opts.gridLines.tickMarkLength;
+                       var scaleLabelLineHeight = parseLineHeight(scaleLabelOpts);
 
                        // Width
                        if (isHorizontal) {
@@ -738,7 +746,7 @@ module.exports = function(Chart) {
                                var scaleLabelX;
                                var scaleLabelY;
                                var rotation = 0;
-                               var halfLineHeight = helpers.valueOrDefault(scaleLabel.lineHeight, scaleLabelFont.size) / 2;
+                               var halfLineHeight = parseLineHeight(scaleLabel) / 2;
 
                                if (isHorizontal) {
                                        scaleLabelX = me.left + ((me.right - me.left) / 2); // midpoint of the width
diff --git a/src/helpers/helpers.options.js b/src/helpers/helpers.options.js
new file mode 100644 (file)
index 0000000..1aab9bb
--- /dev/null
@@ -0,0 +1,35 @@
+'use strict';
+
+/**
+ * @namespace Chart.helpers.options
+ */
+module.exports = {
+       /**
+        * Converts the given line height `value` in pixels for a specific font `size`.
+        * @param {Number|String} value - The lineHeight to parse (eg. 1.6, '14px', '75%', '1.6em').
+        * @param {Number} size - The font size (in pixels) used to resolve relative `value`.
+        * @returns {Number} The effective line height in pixels (size * 1.2 if value is invalid).
+        * @see https://developer.mozilla.org/en-US/docs/Web/CSS/line-height
+        * @since 2.7.0
+        */
+       toLineHeight: function(value, size) {
+               var matches = (''+value).match(/^(normal|(\d+(?:\.\d+)?)(px|em|%)?)$/);
+               if (!matches || matches[1] === 'normal') {
+                       return size * 1.2;
+               }
+
+               value = parseFloat(matches[2]);
+
+               switch (matches[3]) {
+               case 'px':
+                       return value;
+               case '%':
+                       value /= 100;
+                       break;
+               default:
+                       break;
+               }
+
+               return size * value;
+       }
+};
index a21c99aca1326014bf9eac601ce53f8b999840f3..632b772076a8016350b44780d3284d171b49ad2b 100644 (file)
@@ -3,4 +3,5 @@
 module.exports = require('./helpers.core');
 module.exports.easing = require('./helpers.easing');
 module.exports.canvas = require('./helpers.canvas');
+module.exports.options = require('./helpers.options');
 module.exports.time = require('./helpers.time');
index 30f8813d92a2e5cceec397894f8aa4732a34f8bc..259863b62ac096bb4dc589c31d082ab138712cac 100644 (file)
@@ -8,6 +8,7 @@ defaults._set('global', {
                display: false,
                fontStyle: 'bold',
                fullWidth: true,
+               lineHeight: 1.2,
                padding: 10,
                position: 'top',
                text: '',
@@ -114,7 +115,7 @@ module.exports = function(Chart) {
                                fontSize = valueOrDefault(opts.fontSize, defaults.global.defaultFontSize),
                                minSize = me.minSize,
                                lineCount = helpers.isArray(opts.text) ? opts.text.length : 1,
-                               lineHeight = valueOrDefault(opts.lineHeight, fontSize),
+                               lineHeight = helpers.options.toLineHeight(opts.lineHeight, fontSize),
                                textSize = display ? (lineCount * lineHeight) + (opts.padding * 2) : 0;
 
                        if (me.isHorizontal()) {
@@ -150,7 +151,8 @@ module.exports = function(Chart) {
                                        fontStyle = valueOrDefault(opts.fontStyle, globalDefaults.defaultFontStyle),
                                        fontFamily = valueOrDefault(opts.fontFamily, globalDefaults.defaultFontFamily),
                                        titleFont = helpers.fontString(fontSize, fontStyle, fontFamily),
-                                       lineHeight = valueOrDefault(opts.lineHeight, fontSize),
+                                       lineHeight = helpers.options.toLineHeight(opts.lineHeight, fontSize),
+                                       offset = lineHeight/2 + opts.padding,
                                        rotation = 0,
                                        titleX,
                                        titleY,
@@ -166,10 +168,10 @@ module.exports = function(Chart) {
                                // Horizontal
                                if (me.isHorizontal()) {
                                        titleX = left + ((right - left) / 2); // midpoint of the width
-                                       titleY = top + ((bottom - top) / 2); // midpoint of the height
+                                       titleY = top + offset;
                                        maxWidth = right - left;
                                } else {
-                                       titleX = opts.position === 'left' ? left + (fontSize / 2) : right - (fontSize / 2);
+                                       titleX = opts.position === 'left' ? left + offset : right - offset;
                                        titleY = top + ((bottom - top) / 2);
                                        maxWidth = bottom - top;
                                        rotation = Math.PI * (opts.position === 'left' ? -0.5 : 0.5);
index d0182cc6c7c664433298b3009ade389bfc1acf5a..e6f6264395a09da9dbec9c9bea1c5919bbdb8e0d 100644 (file)
@@ -128,8 +128,9 @@ describe('Core helper tests', function() {
                                        },
                                        position: 'right',
                                        scaleLabel: {
-                                               labelString: '',
                                                display: false,
+                                               labelString: '',
+                                               lineHeight: 1.2
                                        },
                                        ticks: {
                                                beginAtZero: false,
@@ -168,8 +169,9 @@ describe('Core helper tests', function() {
                                        },
                                        position: 'left',
                                        scaleLabel: {
-                                               labelString: '',
                                                display: false,
+                                               labelString: '',
+                                               lineHeight: 1.2
                                        },
                                        ticks: {
                                                beginAtZero: false,
diff --git a/test/specs/helpers.options.tests.js b/test/specs/helpers.options.tests.js
new file mode 100644 (file)
index 0000000..1b01159
--- /dev/null
@@ -0,0 +1,27 @@
+'use strict';
+
+describe('Chart.helpers.options', function() {
+       var options = Chart.helpers.options;
+
+       describe('toLineHeight', function() {
+               it ('should support keyword values', function() {
+                       expect(options.toLineHeight('normal', 16)).toBe(16 * 1.2);
+               });
+               it ('should support unitless values', function() {
+                       expect(options.toLineHeight(1.4, 16)).toBe(16 * 1.4);
+                       expect(options.toLineHeight('1.4', 16)).toBe(16 * 1.4);
+               });
+               it ('should support length values', function() {
+                       expect(options.toLineHeight('42px', 16)).toBe(42);
+                       expect(options.toLineHeight('1.4em', 16)).toBe(16 * 1.4);
+               });
+               it ('should support percentage values', function() {
+                       expect(options.toLineHeight('140%', 16)).toBe(16 * 1.4);
+               });
+               it ('should fallback to default (1.2) for invalid values', function() {
+                       expect(options.toLineHeight(null, 16)).toBe(16 * 1.2);
+                       expect(options.toLineHeight(undefined, 16)).toBe(16 * 1.2);
+                       expect(options.toLineHeight('foobar', 16)).toBe(16 * 1.2);
+               });
+       });
+});
index 3c73b55d4bca6e3408ef1fcf0136afe80b5f49fe..edeb32a8b47acf3cf26b6a7f0af12d8b80bddbd3 100644 (file)
@@ -13,6 +13,7 @@ describe('Title block tests', function() {
                        fullWidth: true,
                        weight: 2000,
                        fontStyle: 'bold',
+                       lineHeight: 1.2,
                        padding: 10,
                        text: ''
                });
@@ -43,7 +44,7 @@ describe('Title block tests', function() {
 
                expect(minSize).toEqual({
                        width: 400,
-                       height: 32
+                       height: 34.4
                });
        });
 
@@ -72,7 +73,7 @@ describe('Title block tests', function() {
                minSize = title.update(200, 400);
 
                expect(minSize).toEqual({
-                       width: 32,
+                       width: 34.4,
                        height: 400
                });
        });
@@ -84,7 +85,7 @@ describe('Title block tests', function() {
                options.text = ['line1', 'line2'];
                options.position = 'left';
                options.display = true;
-               options.lineHeight = 15;
+               options.lineHeight = 1.5;
 
                var title = new Chart.Title({
                        chart: chart,
@@ -94,7 +95,7 @@ describe('Title block tests', function() {
                var minSize = title.update(200, 400);
 
                expect(minSize).toEqual({
-                       width: 50,
+                       width: 56,
                        height: 400
                });
        });
@@ -135,7 +136,7 @@ describe('Title block tests', function() {
                        args: []
                }, {
                        name: 'translate',
-                       args: [300, 66]
+                       args: [300, 67.2]
                }, {
                        name: 'rotate',
                        args: [0]
@@ -185,7 +186,7 @@ describe('Title block tests', function() {
                        args: []
                }, {
                        name: 'translate',
-                       args: [106, 250]
+                       args: [117.2, 250]
                }, {
                        name: 'rotate',
                        args: [-0.5 * Math.PI]
@@ -218,7 +219,7 @@ describe('Title block tests', function() {
                        args: []
                }, {
                        name: 'translate',
-                       args: [126, 250]
+                       args: [117.2, 250]
                }, {
                        name: 'rotate',
                        args: [0.5 * Math.PI]
index 31c0a4e6fee9ea027a270279c384b2e2992086e2..c11f751962baaf9ffa8a93b8e7485b7ab0d51fb1 100644 (file)
@@ -30,8 +30,9 @@ describe('Category scale tests', function() {
                        },
                        position: 'bottom',
                        scaleLabel: {
+                               display: false,
                                labelString: '',
-                               display: false
+                               lineHeight: 1.2
                        },
                        ticks: {
                                beginAtZero: false,
index 5b37a0c11f7199d7726d54c2f5963866a1b8ae92..de653268d73174daa370d7f8725fa7092a446369 100644 (file)
@@ -28,8 +28,9 @@ describe('Linear Scale', function() {
                        },
                        position: 'left',
                        scaleLabel: {
-                               labelString: '',
                                display: false,
+                               labelString: '',
+                               lineHeight: 1.2
                        },
                        ticks: {
                                beginAtZero: false,
@@ -772,15 +773,15 @@ describe('Linear Scale', function() {
                expect(xScale.paddingBottom).toBeCloseToPixel(0);
                expect(xScale.paddingLeft).toBeCloseToPixel(0);
                expect(xScale.paddingRight).toBeCloseToPixel(0);
-               expect(xScale.width).toBeCloseToPixel(450);
-               expect(xScale.height).toBeCloseToPixel(46);
+               expect(xScale.width).toBeCloseToPixel(454);
+               expect(xScale.height).toBeCloseToPixel(42);
 
                expect(yScale.paddingTop).toBeCloseToPixel(0);
                expect(yScale.paddingBottom).toBeCloseToPixel(0);
                expect(yScale.paddingLeft).toBeCloseToPixel(0);
                expect(yScale.paddingRight).toBeCloseToPixel(0);
-               expect(yScale.width).toBeCloseToPixel(48);
-               expect(yScale.height).toBeCloseToPixel(434);
+               expect(yScale.width).toBeCloseToPixel(44);
+               expect(yScale.height).toBeCloseToPixel(438);
        });
 
        it('should fit correctly when display is turned off', function() {
@@ -820,7 +821,8 @@ describe('Linear Scale', function() {
                                                        drawBorder: false
                                                },
                                                scaleLabel: {
-                                                       display: false
+                                                       display: false,
+                                                       lineHeight: 1.2
                                                },
                                                ticks: {
                                                        display: false,
index 95287aa79a6f6089c4255bed812dbe0a494bfe4e..16ab3d7800d05d63cf03d9da86fa607ac95d3156 100644 (file)
@@ -27,8 +27,9 @@ describe('Logarithmic Scale tests', function() {
                        },
                        position: 'left',
                        scaleLabel: {
-                               labelString: '',
                                display: false,
+                               labelString: '',
+                               lineHeight: 1.2
                        },
                        ticks: {
                                beginAtZero: false,
index a8ac68ff13ac5e2beb2d2c1ab094177dc617ea0f..6164249d652ddadea7ca83edbc896c21d8d4de8b 100644 (file)
@@ -40,8 +40,9 @@ describe('Test the radial linear scale', function() {
                        },
                        position: 'chartArea',
                        scaleLabel: {
-                               labelString: '',
                                display: false,
+                               labelString: '',
+                               lineHeight: 1.2
                        },
                        ticks: {
                                backdropColor: 'rgba(255,255,255,0.75)',
index ff02bc8df13b3f449b6809ff584b71c54beb8194..c5ca74fa92648432c67eda812dea8d9a3672ec09 100755 (executable)
@@ -81,8 +81,9 @@ describe('Time scale tests', function() {
                        },
                        position: 'bottom',
                        scaleLabel: {
+                               display: false,
                                labelString: '',
-                               display: false
+                               lineHeight: 1.2
                        },
                        ticks: {
                                beginAtZero: false,