From ae0c8dd4573649d209d69799f2360662faf498ac Mon Sep 17 00:00:00 2001 From: LeeLenaleee <39033624+LeeLenaleee@users.noreply.github.com> Date: Sun, 31 Jan 2021 21:19:40 +0100 Subject: [PATCH] align text inside chart for far-aligned labels passing test (#8359) * align text inside chart for far-aligned labels * added fix for failing test on suggestion of @kurkle Co-authored-by: Marcel Samyn --- src/core/core.scale.js | 34 ++++++++++++++++-- .../cross-align-left-far-clipped.js | 32 +++++++++++++++++ .../cross-align-left-far-clipped.png | Bin 0 -> 11746 bytes .../cross-align-right-far-clipped.js | 33 +++++++++++++++++ .../cross-align-right-far-clipped.png | Bin 0 -> 12101 bytes 5 files changed, 96 insertions(+), 3 deletions(-) create mode 100644 test/fixtures/core.scale/crossAlignment/cross-align-left-far-clipped.js create mode 100644 test/fixtures/core.scale/crossAlignment/cross-align-left-far-clipped.png create mode 100644 test/fixtures/core.scale/crossAlignment/cross-align-right-far-clipped.js create mode 100644 test/fixtures/core.scale/crossAlignment/cross-align-right-far-clipped.png diff --git a/src/core/core.scale.js b/src/core/core.scale.js index 785d2d868..94b15468b 100644 --- a/src/core/core.scale.js +++ b/src/core/core.scale.js @@ -1,6 +1,6 @@ import defaults from './core.defaults'; import Element from './core.element'; -import {_alignPixel, _measureText, renderText} from '../helpers/helpers.canvas'; +import {_alignPixel, _measureText, renderText, clipArea, unclipArea} from '../helpers/helpers.canvas'; import {callback as call, each, finiteOrDefault, isArray, isFinite, isNullOrUndef, isObject, valueOrDefault} from '../helpers/helpers.core'; import {_factorize, toDegrees, toRadians, _int16Range, HALF_PI} from '../helpers/helpers.math'; import {toFont, resolve, toPadding} from '../helpers/helpers.options'; @@ -1468,6 +1468,7 @@ export default class Scale extends Element { const labelSizes = me._getLabelSizes(); const tickAndPadding = tl + padding; const widest = labelSizes.widest.width; + const lineSpace = labelSizes.highest.offset * 0.8; let textAlign; let x; @@ -1486,7 +1487,7 @@ export default class Scale extends Element { x -= (widest / 2); } else { textAlign = 'left'; - x -= widest; + x = me.left + lineSpace; } } } else if (position === 'right') { @@ -1503,7 +1504,7 @@ export default class Scale extends Element { x += widest / 2; } else { textAlign = 'right'; - x += widest; + x = me.right - lineSpace; } } } else { @@ -1513,6 +1514,23 @@ export default class Scale extends Element { return {textAlign, x}; } + /** + * @private + */ + _computeLabelArea() { + const me = this; + const chart = me.chart; + const position = me.options.position; + + if (position === 'left' || position === 'right') { + return {top: 0, left: me.left, bottom: chart.height, right: me.right}; + } if (position === 'top' || position === 'bottom') { + return {top: me.top, left: 0, bottom: me.bottom, right: chart.width}; + } + + return null; + } + /** * @protected */ @@ -1604,6 +1622,12 @@ export default class Scale extends Element { } const ctx = me.ctx; + + const area = me._computeLabelArea(); + if (area) { + clipArea(ctx, area); + } + const items = me._labelItems || (me._labelItems = me._computeLabelItems(chartArea)); let i, ilen; @@ -1614,6 +1638,10 @@ export default class Scale extends Element { let y = item.textOffset; renderText(ctx, label, 0, y, tickFont, item); } + + if (area) { + unclipArea(ctx); + } } /** diff --git a/test/fixtures/core.scale/crossAlignment/cross-align-left-far-clipped.js b/test/fixtures/core.scale/crossAlignment/cross-align-left-far-clipped.js new file mode 100644 index 000000000..27a936dce --- /dev/null +++ b/test/fixtures/core.scale/crossAlignment/cross-align-left-far-clipped.js @@ -0,0 +1,32 @@ +module.exports = { + config: { + type: 'bar', + data: { + datasets: [{ + data: [1, 2, 3], + }], + labels: ['Long long long long label 1', 'Label 2', 'Less more longer label 3'] + }, + options: { + indexAxis: 'y', + scales: { + y: { + position: 'left', + ticks: { + crossAlign: 'far', + }, + afterFit: axis => { + axis.width = 64; + }, + }, + } + } + }, + options: { + spriteText: true, + canvas: { + height: 256, + width: 512 + } + } +}; diff --git a/test/fixtures/core.scale/crossAlignment/cross-align-left-far-clipped.png b/test/fixtures/core.scale/crossAlignment/cross-align-left-far-clipped.png new file mode 100644 index 0000000000000000000000000000000000000000..75258b70be7eb52771cf8f4972133da61a6be10d GIT binary patch literal 11746 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 bdz=W(acYZOT;{(8fqxpR+7}AWoBIC;s}M?f literal 0 Hc-jL100001 diff --git a/test/fixtures/core.scale/crossAlignment/cross-align-right-far-clipped.js b/test/fixtures/core.scale/crossAlignment/cross-align-right-far-clipped.js new file mode 100644 index 000000000..893b293d4 --- /dev/null +++ b/test/fixtures/core.scale/crossAlignment/cross-align-right-far-clipped.js @@ -0,0 +1,33 @@ +module.exports = { + config: { + type: 'bar', + data: { + datasets: [{ + data: [1, 2, 3], + }], + labels: ['Long long long long label 1', 'Label 2', 'Less more longer label 3'] + }, + options: { + indexAxis: 'y', + scales: { + y: { + position: 'right', + ticks: { + crossAlign: 'far', + }, + afterFit: axis => { + axis.width = 64; + }, + }, + } + } + }, + options: { + spriteText: true, + canvas: { + height: 256, + width: 512 + } + }, + tolerance: 0.1 +}; diff --git a/test/fixtures/core.scale/crossAlignment/cross-align-right-far-clipped.png b/test/fixtures/core.scale/crossAlignment/cross-align-right-far-clipped.png new file mode 100644 index 0000000000000000000000000000000000000000..53395107ed5a3a0d962a7873d1ed202fb1b9076e GIT binary patch literal 12101 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 YLTycPjpwY*5ctwi(@{-7apTT^06d9X)Bpeg literal 0 Hc-jL100001 -- 2.47.3