From 7df8f5f5e4d9697903a2e14361c24b72d211867f Mon Sep 17 00:00:00 2001 From: andig Date: Fri, 25 Aug 2017 10:50:55 +0200 Subject: [PATCH] Implement scale label padding --- docs/axes/labelling.md | 1 + src/core/core.scale.js | 47 +++++++++---- .../core.scale/label-offset-vertical-axes.png | Bin 4434 -> 4435 bytes test/specs/controller.bubble.tests.js | 6 +- test/specs/controller.line.tests.js | 64 +++++++++--------- test/specs/core.helpers.tests.js | 12 +--- test/specs/core.scale.tests.js | 19 ++++++ test/specs/core.tooltip.tests.js | 8 +-- test/specs/scale.category.tests.js | 18 ++--- test/specs/scale.linear.tests.js | 22 +++--- test/specs/scale.logarithmic.tests.js | 12 ++-- test/specs/scale.radialLinear.tests.js | 6 +- test/specs/scale.time.tests.js | 6 +- 13 files changed, 116 insertions(+), 105 deletions(-) diff --git a/docs/axes/labelling.md b/docs/axes/labelling.md index 22fc2600463..aec8d990ff4 100644 --- a/docs/axes/labelling.md +++ b/docs/axes/labelling.md @@ -15,6 +15,7 @@ The scale label configuration is nested under the scale configuration in the `sc | `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. | `fontStyle` | `String` | `'normal'` | Font style for the scale title, follows CSS font-style options (i.e. normal, italic, oblique, initial, inherit). +| `padding` | `Number` or `Object` | `4` | Padding to apply around scale labels. Only `top` and `bottom` are implemented. ## Creating Custom Tick Formats diff --git a/src/core/core.scale.js b/src/core/core.scale.js index 6f63b92dbd7..c27983699c5 100644 --- a/src/core/core.scale.js +++ b/src/core/core.scale.js @@ -36,7 +36,14 @@ defaults._set('scale', { // actual label labelString: '', - lineHeight: 1.2 + // line height + lineHeight: 1.2, + + // top/bottom padding + padding: { + top: 4, + bottom: 4 + } }, // label settings @@ -391,7 +398,6 @@ module.exports = function(Chart) { var tickFont = parseFontOptions(tickOpts); var tickMarkLength = opts.gridLines.tickMarkLength; - var scaleLabelLineHeight = parseLineHeight(scaleLabelOpts); // Width if (isHorizontal) { @@ -410,10 +416,14 @@ module.exports = function(Chart) { // Are we showing a title for the scale? if (scaleLabelOpts.display && display) { + var scaleLabelLineHeight = parseLineHeight(scaleLabelOpts); + var scaleLabelPadding = helpers.options.toPadding(scaleLabelOpts.padding); + var deltaHeight = scaleLabelLineHeight + scaleLabelPadding.height; + if (isHorizontal) { - minSize.height += scaleLabelLineHeight; + minSize.height += deltaHeight; } else { - minSize.width += scaleLabelLineHeight; + minSize.width += deltaHeight; } } @@ -435,16 +445,17 @@ module.exports = function(Chart) { // TODO - improve this calculation var labelHeight = (sinRotation * largestTextWidth) + (tickFont.size * tallestLabelHeightInLines) - + (lineSpace * tallestLabelHeightInLines); + + (lineSpace * (tallestLabelHeightInLines - 1)) + + lineSpace; // padding minSize.height = Math.min(me.maxHeight, minSize.height + labelHeight + tickPadding); - me.ctx.font = tickFont.font; + me.ctx.font = tickFont.font; var firstLabelWidth = computeTextSize(me.ctx, labels[0], tickFont.font); var lastLabelWidth = computeTextSize(me.ctx, labels[labels.length - 1], tickFont.font); - // Ensure that our ticks are always inside the canvas. When rotated, ticks are right aligned which means that the right padding is dominated - // by the font height + // Ensure that our ticks are always inside the canvas. When rotated, ticks are right aligned + // which means that the right padding is dominated by the font height if (me.labelRotation !== 0) { me.paddingLeft = opts.position === 'bottom' ? (cosRotation * firstLabelWidth) + 3 : (cosRotation * lineSpace) + 3; // add 3 px to move away from canvas edges me.paddingRight = opts.position === 'bottom' ? (cosRotation * lineSpace) + 3 : (cosRotation * lastLabelWidth) + 3; @@ -453,15 +464,18 @@ module.exports = function(Chart) { me.paddingRight = lastLabelWidth / 2 + 3; } } else { - // A vertical axis is more constrained by the width. Labels are the dominant factor here, so get that length first - // Account for padding - + // A vertical axis is more constrained by the width. Labels are the + // dominant factor here, so get that length first and account for padding if (tickOpts.mirror) { largestTextWidth = 0; } else { - largestTextWidth += tickPadding; + // use lineSpace for consistency with horizontal axis + // tickPadding is not implemented for horizontal + largestTextWidth += tickPadding + lineSpace; } + minSize.width = Math.min(me.maxWidth, minSize.width + largestTextWidth); + me.paddingTop = tickFont.size / 2; me.paddingBottom = tickFont.size / 2; } @@ -663,6 +677,7 @@ module.exports = function(Chart) { var scaleLabelFontColor = helpers.valueOrDefault(scaleLabel.fontColor, globalDefaults.defaultFontColor); var scaleLabelFont = parseFontOptions(scaleLabel); + var scaleLabelPadding = helpers.options.toPadding(scaleLabel.padding); var labelRotationRadians = helpers.toRadians(me.labelRotation); var itemsToDraw = []; @@ -840,10 +855,14 @@ module.exports = function(Chart) { if (isHorizontal) { scaleLabelX = me.left + ((me.right - me.left) / 2); // midpoint of the width - scaleLabelY = options.position === 'bottom' ? me.bottom - halfLineHeight : me.top + halfLineHeight; + scaleLabelY = options.position === 'bottom' + ? me.bottom - halfLineHeight - scaleLabelPadding.bottom + : me.top + halfLineHeight + scaleLabelPadding.top; } else { var isLeft = options.position === 'left'; - scaleLabelX = isLeft ? me.left + halfLineHeight : me.right - halfLineHeight; + scaleLabelX = isLeft + ? me.left + halfLineHeight + scaleLabelPadding.top + : me.right - halfLineHeight - scaleLabelPadding.top; scaleLabelY = me.top + ((me.bottom - me.top) / 2); rotation = isLeft ? -0.5 * Math.PI : 0.5 * Math.PI; } diff --git a/test/fixtures/core.scale/label-offset-vertical-axes.png b/test/fixtures/core.scale/label-offset-vertical-axes.png index 2f6b18c8c23939f2b79177a937ba2458298f826b..05785b8bc597181170ffe7bae4e472f35f8a0620 100644 GIT binary patch literal 4435 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 literal 4434 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