Skip to content

Commit

Permalink
Implement scale label padding
Browse files Browse the repository at this point in the history
  • Loading branch information
andig committed Aug 25, 2017
1 parent 530c613 commit 7df8f5f
Show file tree
Hide file tree
Showing 13 changed files with 116 additions and 105 deletions.
1 change: 1 addition & 0 deletions docs/axes/labelling.md
Expand Up @@ -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

Expand Down
47 changes: 33 additions & 14 deletions src/core/core.scale.js
Expand Up @@ -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
Expand Down Expand Up @@ -391,7 +398,6 @@ module.exports = function(Chart) {

var tickFont = parseFontOptions(tickOpts);
var tickMarkLength = opts.gridLines.tickMarkLength;
var scaleLabelLineHeight = parseLineHeight(scaleLabelOpts);

// Width
if (isHorizontal) {
Expand All @@ -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;
}
}

Expand All @@ -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;
Expand All @@ -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;
}
Expand Down Expand Up @@ -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 = [];
Expand Down Expand Up @@ -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;
}
Expand Down
Binary file modified test/fixtures/core.scale/label-offset-vertical-axes.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 3 additions & 3 deletions test/specs/controller.bubble.tests.js
Expand Up @@ -134,9 +134,9 @@ describe('Bubble controller tests', function() {
var meta = chart.getDatasetMeta(0);

[
{r: 5, x: 28, y: 32},
{r: 1, x: 183, y: 484},
{r: 2, x: 338, y: 461},
{r: 5, x: 34, y: 32},
{r: 1, x: 187, y: 484},
{r: 2, x: 340, y: 461},
{r: 1, x: 492, y: 32}
].forEach(function(expected, i) {
expect(meta.data[i]._model.radius).toBe(expected.r);
Expand Down
64 changes: 32 additions & 32 deletions test/specs/controller.line.tests.js
Expand Up @@ -203,8 +203,8 @@ describe('Line controller tests', function() {


[
{x: 33, y: 484},
{x: 186, y: 32}
{x: 39, y: 484},
{x: 190, y: 32}
].forEach(function(expected, i) {
expect(meta.data[i]._datasetIndex).toBe(0);
expect(meta.data[i]._index).toBe(i);
Expand Down Expand Up @@ -250,7 +250,7 @@ describe('Line controller tests', function() {
var meta = chart.getDatasetMeta(0);
// 1 point
var point = meta.data[0];
expect(point._model.x).toBeCloseToPixel(27);
expect(point._model.x).toBeCloseToPixel(32);

// 2 points
chart.data.labels = ['One', 'Two'];
Expand All @@ -259,7 +259,7 @@ describe('Line controller tests', function() {

var points = meta.data;

expect(points[0]._model.x).toBeCloseToPixel(27);
expect(points[0]._model.x).toBeCloseToPixel(32);
expect(points[1]._model.x).toBeCloseToPixel(498);

// 3 points
Expand All @@ -269,8 +269,8 @@ describe('Line controller tests', function() {

points = meta.data;

expect(points[0]._model.x).toBeCloseToPixel(27);
expect(points[1]._model.x).toBeCloseToPixel(260);
expect(points[0]._model.x).toBeCloseToPixel(32);
expect(points[1]._model.x).toBeCloseToPixel(263);
expect(points[2]._model.x).toBeCloseToPixel(493);

// 4 points
Expand All @@ -280,8 +280,8 @@ describe('Line controller tests', function() {

points = meta.data;

expect(points[0]._model.x).toBeCloseToPixel(27);
expect(points[1]._model.x).toBeCloseToPixel(184);
expect(points[0]._model.x).toBeCloseToPixel(32);
expect(points[1]._model.x).toBeCloseToPixel(187);
expect(points[2]._model.x).toBeCloseToPixel(340);
expect(points[3]._model.x).toBeCloseToPixel(497);
});
Expand Down Expand Up @@ -311,9 +311,9 @@ describe('Line controller tests', function() {
var meta0 = chart.getDatasetMeta(0);

[
{x: 28, y: 161},
{x: 183, y: 419},
{x: 338, y: 161},
{x: 34, y: 161},
{x: 187, y: 419},
{x: 340, y: 161},
{x: 492, y: 419}
].forEach(function(values, i) {
expect(meta0.data[i]._model.x).toBeCloseToPixel(values.x);
Expand All @@ -323,9 +323,9 @@ describe('Line controller tests', function() {
var meta1 = chart.getDatasetMeta(1);

[
{x: 28, y: 32},
{x: 183, y: 97},
{x: 338, y: 161},
{x: 34, y: 32},
{x: 187, y: 97},
{x: 340, y: 161},
{x: 492, y: 471}
].forEach(function(values, i) {
expect(meta1.data[i]._model.x).toBeCloseToPixel(values.x);
Expand Down Expand Up @@ -366,9 +366,9 @@ describe('Line controller tests', function() {
var meta0 = chart.getDatasetMeta(0);

[
{x: 56, y: 161},
{x: 202, y: 419},
{x: 347, y: 161},
{x: 68, y: 161},
{x: 210, y: 419},
{x: 351, y: 161},
{x: 492, y: 419}
].forEach(function(values, i) {
expect(meta0.data[i]._model.x).toBeCloseToPixel(values.x);
Expand All @@ -378,9 +378,9 @@ describe('Line controller tests', function() {
var meta1 = chart.getDatasetMeta(1);

[
{x: 56, y: 32},
{x: 202, y: 97},
{x: 347, y: 161},
{x: 68, y: 32},
{x: 210, y: 97},
{x: 351, y: 161},
{x: 492, y: 471}
].forEach(function(values, i) {
expect(meta1.data[i]._model.x).toBeCloseToPixel(values.x);
Expand Down Expand Up @@ -438,9 +438,9 @@ describe('Line controller tests', function() {
var meta0 = chart.getDatasetMeta(0);

[
{x: 28, y: 161},
{x: 183, y: 419},
{x: 338, y: 161},
{x: 34, y: 161},
{x: 187, y: 419},
{x: 340, y: 161},
{x: 492, y: 419}
].forEach(function(values, i) {
expect(meta0.data[i]._model.x).toBeCloseToPixel(values.x);
Expand All @@ -450,9 +450,9 @@ describe('Line controller tests', function() {
var meta1 = chart.getDatasetMeta(1);

[
{x: 28, y: 32},
{x: 183, y: 97},
{x: 338, y: 161},
{x: 34, y: 32},
{x: 187, y: 97},
{x: 340, y: 161},
{x: 492, y: 471}
].forEach(function(values, i) {
expect(meta1.data[i]._model.x).toBeCloseToPixel(values.x);
Expand Down Expand Up @@ -486,9 +486,9 @@ describe('Line controller tests', function() {
var meta0 = chart.getDatasetMeta(0);

[
{x: 28, y: 161},
{x: 183, y: 419},
{x: 338, y: 161},
{x: 34, y: 161},
{x: 187, y: 419},
{x: 340, y: 161},
{x: 492, y: 419}
].forEach(function(values, i) {
expect(meta0.data[i]._model.x).toBeCloseToPixel(values.x);
Expand All @@ -498,9 +498,9 @@ describe('Line controller tests', function() {
var meta1 = chart.getDatasetMeta(1);

[
{x: 28, y: 32},
{x: 183, y: 97},
{x: 338, y: 161},
{x: 34, y: 32},
{x: 187, y: 97},
{x: 340, y: 161},
{x: 492, y: 471}
].forEach(function(values, i) {
expect(meta1.data[i]._model.x).toBeCloseToPixel(values.x);
Expand Down
12 changes: 2 additions & 10 deletions test/specs/core.helpers.tests.js
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
19 changes: 19 additions & 0 deletions 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
}
});
});
});
8 changes: 4 additions & 4 deletions test/specs/core.tooltip.tests.js
Expand Up @@ -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);
});

Expand Down Expand Up @@ -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);
});

Expand Down Expand Up @@ -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);
});

Expand Down Expand Up @@ -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);
});

Expand Down

0 comments on commit 7df8f5f

Please sign in to comment.