mirror of
https://github.com/chartjs/Chart.js.git
synced 2025-12-08 20:36:08 +00:00
Add support for line height CSS values (#4531)
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
This commit is contained in:
parent
5ad1b4ade7
commit
090196c07c
@ -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.
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
35
src/helpers/helpers.options.js
Normal file
35
src/helpers/helpers.options.js
Normal file
@ -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;
|
||||
}
|
||||
};
|
||||
@ -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');
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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,
|
||||
|
||||
27
test/specs/helpers.options.tests.js
Normal file
27
test/specs/helpers.options.tests.js
Normal file
@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -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]
|
||||
|
||||
@ -30,8 +30,9 @@ describe('Category scale tests', function() {
|
||||
},
|
||||
position: 'bottom',
|
||||
scaleLabel: {
|
||||
display: false,
|
||||
labelString: '',
|
||||
display: false
|
||||
lineHeight: 1.2
|
||||
},
|
||||
ticks: {
|
||||
beginAtZero: false,
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -27,8 +27,9 @@ describe('Logarithmic Scale tests', function() {
|
||||
},
|
||||
position: 'left',
|
||||
scaleLabel: {
|
||||
labelString: '',
|
||||
display: false,
|
||||
labelString: '',
|
||||
lineHeight: 1.2
|
||||
},
|
||||
ticks: {
|
||||
beginAtZero: false,
|
||||
|
||||
@ -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)',
|
||||
|
||||
@ -81,8 +81,9 @@ describe('Time scale tests', function() {
|
||||
},
|
||||
position: 'bottom',
|
||||
scaleLabel: {
|
||||
display: false,
|
||||
labelString: '',
|
||||
display: false
|
||||
lineHeight: 1.2
|
||||
},
|
||||
ticks: {
|
||||
beginAtZero: false,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user