Add grace option for linear scale (#8581)

* Add `grace` option for linear scale

* cc
This commit is contained in:
Jukka Kurkela 2021-03-07 00:18:49 +02:00 committed by GitHub
parent 1e6a3fb8e6
commit 7ccf9e2d4d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 155 additions and 5 deletions

View File

@ -18,6 +18,7 @@ Namespace: `options.scales[scaleId]`
| Name | Type | Description
| ---- | ---- | -----------
| `beginAtZero` | `boolean` | if true, scale will include 0 if it is not already included.
| `grace` | `number`\|`string` | Percentage (string ending with `%`) or amount (number) for added room in the scale range above and below data. [more...](#grace)
<CommonCartesian />
<CommonAll />
@ -58,6 +59,45 @@ let options = {
};
```
## Grace
If the value is string ending with `%`, its treat as percentage. If number, its treat as value.
The value is added to the maximum data value and subtracted from the minumum data. This extends the scale range as if the data values were that much greater.
import { useEffect, useRef } from 'react';
```jsx live
function example() {
const canvas = useRef(null);
useEffect(() => {
const cfg = {
type: 'bar',
data: {
labels: ['Positive', 'Negative'],
datasets: [{
data: [100, -50],
backgroundColor: 'rgb(255, 99, 132)'
}],
},
options: {
scales: {
y: {
type: 'linear',
grace: '5%'
}
},
plugins: {
legend: false
}
}
};
const chart = new Chart(canvas.current.getContext('2d'), cfg);
return () => chart.destroy();
});
return <div className="chartjs-wrapper"><canvas ref={canvas} className="chartjs"></canvas></div>;
}
```
## Internal data format
Internally, the linear scale uses numeric data

View File

@ -1,6 +1,6 @@
import DatasetController from '../core/core.datasetController';
import {formatNumber} from '../core/core.intl';
import {isArray, toPercentage, toPixels, valueOrDefault} from '../helpers/helpers.core';
import {isArray, toPercentage, toDimension, valueOrDefault} from '../helpers/helpers.core';
import {toRadians, PI, TAU, HALF_PI, _angleBetween} from '../helpers/helpers.math';
/**
@ -123,7 +123,7 @@ export default class DoughnutController extends DatasetController {
const maxWidth = (chartArea.width - spacing) / ratioX;
const maxHeight = (chartArea.height - spacing) / ratioY;
const maxRadius = Math.max(Math.min(maxWidth, maxHeight) / 2, 0);
const outerRadius = toPixels(me.options.radius, maxRadius);
const outerRadius = toDimension(me.options.radius, maxRadius);
const innerRadius = Math.max(outerRadius * cutout, 0);
const radiusLength = (outerRadius - innerRadius) / me._getVisibleDatasetWeightTotal();
me.offsetX = offsetX * outerRadius;

View File

@ -26,6 +26,12 @@ defaults.set('scale', {
*/
bounds: 'ticks',
/**
* Addition grace added to max and reduced from min data value.
* @since 3.0.0
*/
grace: 0,
// grid line settings
gridLines: {
display: true,

View File

@ -90,7 +90,7 @@ export const toPercentage = (value, dimension) =>
parseFloat(value) / 100
: value / dimension;
export const toPixels = (value, dimension) =>
export const toDimension = (value, dimension) =>
typeof value === 'string' && value.endsWith('%') ?
parseFloat(value) / 100 * dimension
: +value;

View File

@ -1,5 +1,5 @@
import defaults from '../core/core.defaults';
import {isArray, isObject, valueOrDefault} from './helpers.core';
import {isArray, isObject, toDimension, valueOrDefault} from './helpers.core';
import {toFontString} from './helpers.canvas';
const LINE_HEIGHT = new RegExp(/^(normal|(\d+(?:\.\d+)?)(px|em|%)?)$/);
@ -175,3 +175,16 @@ export function resolve(inputs, context, index, info) {
}
}
}
/**
* @param {{min: number, max: number}} minmax
* @param {number|string} grace
* @private
*/
export function _addGrace(minmax, grace) {
const {min, max} = minmax;
return {
min: min - Math.abs(toDimension(grace, min)),
max: max + toDimension(grace, max)
};
}

View File

@ -2,6 +2,7 @@ import {isNullOrUndef} from '../helpers/helpers.core';
import {almostEquals, almostWhole, niceNum, _decimalPlaces, _setMinAndMaxByKey, sign} from '../helpers/helpers.math';
import Scale from '../core/core.scale';
import {formatNumber} from '../core/core.intl';
import {_addGrace} from '../helpers/helpers.options';
/**
* Generate a set of linear ticks
@ -205,7 +206,7 @@ export default class LinearScaleBase extends Scale {
precision: tickOpts.precision,
stepSize: tickOpts.stepSize
};
const ticks = generateTicks(numericGeneratorOptions, me);
const ticks = generateTicks(numericGeneratorOptions, _addGrace(me, opts.grace));
// At this point, we need to update our max and min given the tick values,
// since we probably have expanded the range of the scale

30
test/fixtures/scale.linear/grace-neg.js vendored Normal file
View File

@ -0,0 +1,30 @@
module.exports = {
description: 'https://github.com/chartjs/Chart.js/issues/7734',
config: {
type: 'bar',
data: {
labels: ['a'],
datasets: [{
data: [-0.18],
}],
},
options: {
indexAxis: 'y',
scales: {
y: {
display: false
},
x: {
grace: '5%'
}
}
}
},
options: {
spriteText: true,
canvas: {
width: 512,
height: 128
}
}
};

BIN
test/fixtures/scale.linear/grace-neg.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

30
test/fixtures/scale.linear/grace-pos.js vendored Normal file
View File

@ -0,0 +1,30 @@
module.exports = {
description: 'https://github.com/chartjs/Chart.js/issues/7734',
config: {
type: 'bar',
data: {
labels: ['a'],
datasets: [{
data: [0.18],
}],
},
options: {
indexAxis: 'y',
scales: {
y: {
display: false
},
x: {
grace: '5%'
}
}
}
},
options: {
spriteText: true,
canvas: {
width: 512,
height: 128
}
}
};

BIN
test/fixtures/scale.linear/grace-pos.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

30
test/fixtures/scale.linear/grace.js vendored Normal file
View File

@ -0,0 +1,30 @@
module.exports = {
description: 'https://github.com/chartjs/Chart.js/issues/7734',
config: {
type: 'bar',
data: {
labels: ['a', 'b'],
datasets: [{
data: [1.2, -0.2],
}],
},
options: {
indexAxis: 'y',
scales: {
y: {
display: false
},
x: {
grace: 0.3
}
}
}
},
options: {
spriteText: true,
canvas: {
width: 512,
height: 128
}
}
};

BIN
test/fixtures/scale.linear/grace.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB