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 bc4d1ec9c7b..f48b67a5ec1 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 2f6b18c8c23..05785b8bc59 100644 Binary files a/test/fixtures/core.scale/label-offset-vertical-axes.png and b/test/fixtures/core.scale/label-offset-vertical-axes.png differ diff --git a/test/specs/core.helpers.tests.js b/test/specs/core.helpers.tests.js index 1b5edb89edf..dc865fb01b2 100644 --- a/test/specs/core.helpers.tests.js +++ b/test/specs/core.helpers.tests.js @@ -128,11 +128,7 @@ describe('Core helper tests', function() { }, position: 'right', offset: false, - scaleLabel: { - display: false, - labelString: '', - lineHeight: 1.2 - }, + scaleLabel: Chart.defaults.scale.scaleLabel, ticks: { beginAtZero: false, minRotation: 0, @@ -170,11 +166,7 @@ describe('Core helper tests', function() { }, position: 'left', offset: false, - scaleLabel: { - display: false, - labelString: '', - lineHeight: 1.2 - }, + scaleLabel: Chart.defaults.scale.scaleLabel, ticks: { beginAtZero: false, minRotation: 0, diff --git a/test/specs/core.scale.tests.js b/test/specs/core.scale.tests.js index 58e5a33faeb..dc2da042aca 100644 --- a/test/specs/core.scale.tests.js +++ b/test/specs/core.scale.tests.js @@ -1,3 +1,22 @@ describe('Core.scale', function() { describe('auto', jasmine.specsFromFixtures('core.scale')); + + it('should provide default scale label options', function() { + expect(Chart.defaults.scale.scaleLabel).toEqual({ + // display property + display: false, + + // actual label + labelString: '', + + // actual label + lineHeight: 1.2, + + // top/bottom padding + padding: { + top: 4, + bottom: 4 + } + }); + }); }); diff --git a/test/specs/core.tooltip.tests.js b/test/specs/core.tooltip.tests.js index b1896da3338..73d943bd853 100755 --- a/test/specs/core.tooltip.tests.js +++ b/test/specs/core.tooltip.tests.js @@ -143,7 +143,7 @@ describe('Core.Tooltip', function() { }] })); - expect(tooltip._view.x).toBeCloseToPixel(263); + expect(tooltip._view.x).toBeCloseToPixel(266); expect(tooltip._view.y).toBeCloseToPixel(155); }); @@ -341,7 +341,7 @@ describe('Core.Tooltip', function() { }] })); - expect(tooltip._view.x).toBeCloseToPixel(263); + expect(tooltip._view.x).toBeCloseToPixel(266); expect(tooltip._view.y).toBeCloseToPixel(312); }); @@ -494,7 +494,7 @@ describe('Core.Tooltip', function() { }] })); - expect(tooltip._view.x).toBeCloseToPixel(211); + expect(tooltip._view.x).toBeCloseToPixel(214); expect(tooltip._view.y).toBeCloseToPixel(190); }); @@ -574,7 +574,7 @@ describe('Core.Tooltip', function() { }] })); - expect(tooltip._view.x).toBeCloseToPixel(263); + expect(tooltip._view.x).toBeCloseToPixel(266); expect(tooltip._view.y).toBeCloseToPixel(155); }); diff --git a/test/specs/scale.category.tests.js b/test/specs/scale.category.tests.js index 8d8d32cd424..1665235ae8d 100644 --- a/test/specs/scale.category.tests.js +++ b/test/specs/scale.category.tests.js @@ -30,11 +30,7 @@ describe('Category scale tests', function() { }, position: 'bottom', offset: false, - scaleLabel: { - display: false, - labelString: '', - lineHeight: 1.2 - }, + scaleLabel: Chart.defaults.scale.scaleLabel, ticks: { beginAtZero: false, minRotation: 0, @@ -215,7 +211,7 @@ describe('Category scale tests', function() { }); var xScale = chart.scales.xScale0; - expect(xScale.getPixelForValue(0, 0, 0)).toBeCloseToPixel(23); + expect(xScale.getPixelForValue(0, 0, 0)).toBeCloseToPixel(23 + 6); // plus lineHeight expect(xScale.getValueForPixel(23)).toBe(0); expect(xScale.getPixelForValue(0, 4, 0)).toBeCloseToPixel(487); @@ -224,7 +220,7 @@ describe('Category scale tests', function() { xScale.options.offset = true; chart.update(); - expect(xScale.getPixelForValue(0, 0, 0)).toBeCloseToPixel(69); + expect(xScale.getPixelForValue(0, 0, 0)).toBeCloseToPixel(69 + 6); // plus lineHeight expect(xScale.getValueForPixel(69)).toBe(0); expect(xScale.getPixelForValue(0, 4, 0)).toBeCloseToPixel(441); @@ -258,8 +254,8 @@ describe('Category scale tests', function() { }); var xScale = chart.scales.xScale0; - expect(xScale.getPixelForValue('tick_1', 0, 0)).toBeCloseToPixel(23); - expect(xScale.getPixelForValue('tick_1', 1, 0)).toBeCloseToPixel(139); + expect(xScale.getPixelForValue('tick_1', 0, 0)).toBeCloseToPixel(23 + 6); // plus lineHeight + expect(xScale.getPixelForValue('tick_1', 1, 0)).toBeCloseToPixel(143); }); it ('Should get the correct pixel for a value when horizontal and zoomed', function() { @@ -293,13 +289,13 @@ describe('Category scale tests', function() { }); var xScale = chart.scales.xScale0; - expect(xScale.getPixelForValue(0, 1, 0)).toBeCloseToPixel(23); + expect(xScale.getPixelForValue(0, 1, 0)).toBeCloseToPixel(23 + 6); // plus lineHeight expect(xScale.getPixelForValue(0, 3, 0)).toBeCloseToPixel(496); xScale.options.offset = true; chart.update(); - expect(xScale.getPixelForValue(0, 1, 0)).toBeCloseToPixel(102); + expect(xScale.getPixelForValue(0, 1, 0)).toBeCloseToPixel(102 + 6); // plus lineHeight expect(xScale.getPixelForValue(0, 3, 0)).toBeCloseToPixel(417); }); diff --git a/test/specs/scale.linear.tests.js b/test/specs/scale.linear.tests.js index ed6f9c1f96e..60dd07698c0 100644 --- a/test/specs/scale.linear.tests.js +++ b/test/specs/scale.linear.tests.js @@ -28,11 +28,7 @@ describe('Linear Scale', function() { }, position: 'left', offset: false, - scaleLabel: { - display: false, - labelString: '', - lineHeight: 1.2 - }, + scaleLabel: Chart.defaults.scale.scaleLabel, ticks: { beginAtZero: false, minRotation: 0, @@ -695,8 +691,8 @@ describe('Linear Scale', function() { var xScale = chart.scales.xScale0; expect(xScale.getPixelForValue(1, 0, 0)).toBeCloseToPixel(501); // right - paddingRight - expect(xScale.getPixelForValue(-1, 0, 0)).toBeCloseToPixel(31); // left + paddingLeft - expect(xScale.getPixelForValue(0, 0, 0)).toBeCloseToPixel(266); // halfway*/ + expect(xScale.getPixelForValue(-1, 0, 0)).toBeCloseToPixel(31 + 6); // left + paddingLeft + lineSpace + expect(xScale.getPixelForValue(0, 0, 0)).toBeCloseToPixel(266 + 6 / 2); // halfway*/ expect(xScale.getValueForPixel(501)).toBeCloseTo(1, 1e-2); expect(xScale.getValueForPixel(31)).toBeCloseTo(-1, 1e-2); @@ -754,7 +750,7 @@ describe('Linear Scale', function() { expect(xScale.paddingBottom).toBeCloseToPixel(0); expect(xScale.paddingLeft).toBeCloseToPixel(0); expect(xScale.paddingRight).toBeCloseToPixel(0); - expect(xScale.width).toBeCloseToPixel(468); + expect(xScale.width).toBeCloseToPixel(468 - 6); // minus lineSpace expect(xScale.height).toBeCloseToPixel(28); var yScale = chart.scales.yScale0; @@ -762,7 +758,7 @@ describe('Linear Scale', function() { expect(yScale.paddingBottom).toBeCloseToPixel(0); expect(yScale.paddingLeft).toBeCloseToPixel(0); expect(yScale.paddingRight).toBeCloseToPixel(0); - expect(yScale.width).toBeCloseToPixel(30); + expect(yScale.width).toBeCloseToPixel(30 + 6); // plus lineSpace expect(yScale.height).toBeCloseToPixel(452); // Extra size when scale label showing @@ -774,15 +770,15 @@ describe('Linear Scale', function() { expect(xScale.paddingBottom).toBeCloseToPixel(0); expect(xScale.paddingLeft).toBeCloseToPixel(0); expect(xScale.paddingRight).toBeCloseToPixel(0); - expect(xScale.width).toBeCloseToPixel(454); - expect(xScale.height).toBeCloseToPixel(42); + expect(xScale.width).toBeCloseToPixel(440); + expect(xScale.height).toBeCloseToPixel(50); expect(yScale.paddingTop).toBeCloseToPixel(0); expect(yScale.paddingBottom).toBeCloseToPixel(0); expect(yScale.paddingLeft).toBeCloseToPixel(0); expect(yScale.paddingRight).toBeCloseToPixel(0); - expect(yScale.width).toBeCloseToPixel(44); - expect(yScale.height).toBeCloseToPixel(438); + expect(yScale.width).toBeCloseToPixel(58); + expect(yScale.height).toBeCloseToPixel(430); }); it('should fit correctly when display is turned off', function() { diff --git a/test/specs/scale.logarithmic.tests.js b/test/specs/scale.logarithmic.tests.js index 98d0fbf09c4..9640b1d3d62 100644 --- a/test/specs/scale.logarithmic.tests.js +++ b/test/specs/scale.logarithmic.tests.js @@ -27,11 +27,7 @@ describe('Logarithmic Scale tests', function() { }, position: 'left', offset: false, - scaleLabel: { - display: false, - labelString: '', - lineHeight: 1.2 - }, + scaleLabel: Chart.defaults.scale.scaleLabel, ticks: { beginAtZero: false, minRotation: 0, @@ -720,9 +716,9 @@ describe('Logarithmic Scale tests', function() { var xScale = chart.scales.xScale; expect(xScale.getPixelForValue(80, 0, 0)).toBeCloseToPixel(495); // right - paddingRight - expect(xScale.getPixelForValue(1, 0, 0)).toBeCloseToPixel(37); // left + paddingLeft - expect(xScale.getPixelForValue(10, 0, 0)).toBeCloseToPixel(278); // halfway - expect(xScale.getPixelForValue(0, 0, 0)).toBeCloseToPixel(37); // 0 is invalid, put it on the left. + expect(xScale.getPixelForValue(1, 0, 0)).toBeCloseToPixel(37 + 6); // left + paddingLeft + lineSpace + expect(xScale.getPixelForValue(10, 0, 0)).toBeCloseToPixel(278 + 6 / 2); // halfway + expect(xScale.getPixelForValue(0, 0, 0)).toBeCloseToPixel(37 + 6); // 0 is invalid, put it on the left. expect(xScale.getValueForPixel(495)).toBeCloseToPixel(80); expect(xScale.getValueForPixel(48)).toBeCloseTo(1, 1e-4); diff --git a/test/specs/scale.radialLinear.tests.js b/test/specs/scale.radialLinear.tests.js index 70c75f02ad7..707ce0b7c52 100644 --- a/test/specs/scale.radialLinear.tests.js +++ b/test/specs/scale.radialLinear.tests.js @@ -40,11 +40,7 @@ describe('Test the radial linear scale', function() { }, position: 'chartArea', offset: false, - scaleLabel: { - display: false, - labelString: '', - lineHeight: 1.2 - }, + scaleLabel: Chart.defaults.scale.scaleLabel, ticks: { backdropColor: 'rgba(255,255,255,0.75)', backdropPaddingY: 2, diff --git a/test/specs/scale.time.tests.js b/test/specs/scale.time.tests.js index 3c757243d56..b6554e60d9a 100755 --- a/test/specs/scale.time.tests.js +++ b/test/specs/scale.time.tests.js @@ -73,11 +73,7 @@ describe('Time scale tests', function() { }, position: 'bottom', offset: false, - scaleLabel: { - display: false, - labelString: '', - lineHeight: 1.2 - }, + scaleLabel: Chart.defaults.scale.scaleLabel, bounds: 'data', distribution: 'linear', ticks: {