From 10292c691299247b66626c2861f84a5a74570873 Mon Sep 17 00:00:00 2001 From: Jukka Kurkela Date: Tue, 5 Oct 2021 00:43:04 +0300 Subject: [PATCH] Linear: determine grace amount from range (#9719) --- src/core/core.scale.js | 4 +- src/helpers/helpers.options.js | 9 ++-- test/fixtures/scale.linear/grace/grace-10%.js | 29 ++++++++++++ .../fixtures/scale.linear/grace/grace-10%.png | Bin 0 -> 5801 bytes .../scale.linear/grace/grace-beginAtZero.js | 42 ++++++++++++++++++ .../scale.linear/grace/grace-beginAtZero.png | Bin 0 -> 8377 bytes test/fixtures/scale.linear/grace/grace-neg.js | 1 - test/fixtures/scale.linear/grace/grace-pos.js | 1 - test/fixtures/scale.linear/grace/grace.js | 1 - 9 files changed, 79 insertions(+), 8 deletions(-) create mode 100644 test/fixtures/scale.linear/grace/grace-10%.js create mode 100644 test/fixtures/scale.linear/grace/grace-10%.png create mode 100644 test/fixtures/scale.linear/grace/grace-beginAtZero.js create mode 100644 test/fixtures/scale.linear/grace/grace-beginAtZero.png diff --git a/src/core/core.scale.js b/src/core/core.scale.js index 68b3c1b1c..4549cadb9 100644 --- a/src/core/core.scale.js +++ b/src/core/core.scale.js @@ -387,7 +387,7 @@ export default class Scale extends Element { * - thickness of scales or legends in another orientation */ update(maxWidth, maxHeight, margins) { - const tickOpts = this.options.ticks; + const {beginAtZero, grace, ticks: tickOpts} = this.options; const sampleSize = tickOpts.sampleSize; // Update Lifecycle - Probably don't want to ever extend or overwrite this function ;) @@ -422,7 +422,7 @@ export default class Scale extends Element { this.beforeDataLimits(); this.determineDataLimits(); this.afterDataLimits(); - this._range = _addGrace(this, this.options.grace); + this._range = _addGrace(this, grace, beginAtZero); this._dataLimitsCached = true; } diff --git a/src/helpers/helpers.options.js b/src/helpers/helpers.options.js index 7453a54bc..d42b3503b 100644 --- a/src/helpers/helpers.options.js +++ b/src/helpers/helpers.options.js @@ -172,12 +172,15 @@ export function resolve(inputs, context, index, info) { /** * @param {{min: number, max: number}} minmax * @param {number|string} grace + * @param {boolean} beginAtZero * @private */ -export function _addGrace(minmax, grace) { +export function _addGrace(minmax, grace, beginAtZero) { const {min, max} = minmax; + const change = toDimension(grace, (max - min) / 2); + const keepZero = (value, add) => beginAtZero && value === 0 ? 0 : value + add; return { - min: min - Math.abs(toDimension(grace, min)), - max: max + toDimension(grace, max) + min: keepZero(min, -Math.abs(change)), + max: keepZero(max, change) }; } diff --git a/test/fixtures/scale.linear/grace/grace-10%.js b/test/fixtures/scale.linear/grace/grace-10%.js new file mode 100644 index 000000000..3001fecca --- /dev/null +++ b/test/fixtures/scale.linear/grace/grace-10%.js @@ -0,0 +1,29 @@ +module.exports = { + config: { + type: 'bar', + data: { + labels: ['a', 'b'], + datasets: [{ + data: [90, -10], + }], + }, + options: { + indexAxis: 'y', + scales: { + y: { + display: false + }, + x: { + grace: '10%' + } + } + } + }, + options: { + spriteText: true, + canvas: { + width: 512, + height: 128 + } + } +}; diff --git a/test/fixtures/scale.linear/grace/grace-10%.png b/test/fixtures/scale.linear/grace/grace-10%.png new file mode 100644 index 0000000000000000000000000000000000000000..ae3db686608fd6945c78766a55d28485648a4ea3 GIT binary patch literal 5801 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 literal 0 Hc-jL100001 diff --git a/test/fixtures/scale.linear/grace/grace-beginAtZero.js b/test/fixtures/scale.linear/grace/grace-beginAtZero.js new file mode 100644 index 000000000..77965d6c3 --- /dev/null +++ b/test/fixtures/scale.linear/grace/grace-beginAtZero.js @@ -0,0 +1,42 @@ +module.exports = { + config: { + type: 'bar', + data: { + labels: ['a', 'b'], + datasets: [{ + data: [100, 0], + backgroundColor: 'blue' + }, { + xAxisID: 'x2', + data: [0, 100], + backgroundColor: 'red' + }], + }, + options: { + indexAxis: 'y', + scales: { + y: { + display: false + }, + x: { + position: 'top', + beginAtZero: true, + grace: '10%', + }, + x2: { + position: 'bottom', + type: 'linear', + beginAtZero: false, + grace: '10%', + } + } + } + }, + options: { + spriteText: true, + canvas: { + width: 512, + height: 128 + } + } +}; diff --git a/test/fixtures/scale.linear/grace/grace-beginAtZero.png b/test/fixtures/scale.linear/grace/grace-beginAtZero.png new file mode 100644 index 0000000000000000000000000000000000000000..4f1883fd399d8581407b1b2493df546ef5cb7dee GIT binary patch literal 8377 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