]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
Add `grace` option for linear scale (#8581)
authorJukka Kurkela <jukka.kurkela@gmail.com>
Sat, 6 Mar 2021 22:18:49 +0000 (00:18 +0200)
committerGitHub <noreply@github.com>
Sat, 6 Mar 2021 22:18:49 +0000 (17:18 -0500)
* Add `grace` option for linear scale

* cc

12 files changed:
docs/docs/axes/cartesian/linear.mdx
src/controllers/controller.doughnut.js
src/core/core.scale.js
src/helpers/helpers.core.js
src/helpers/helpers.options.js
src/scales/scale.linearbase.js
test/fixtures/scale.linear/grace-neg.js [new file with mode: 0644]
test/fixtures/scale.linear/grace-neg.png [new file with mode: 0644]
test/fixtures/scale.linear/grace-pos.js [new file with mode: 0644]
test/fixtures/scale.linear/grace-pos.png [new file with mode: 0644]
test/fixtures/scale.linear/grace.js [new file with mode: 0644]
test/fixtures/scale.linear/grace.png [new file with mode: 0644]

index ac1418389a369d8bb14c0330a0a0b43ddb60cd29..da7a3b4dc17f866a76ae01daa94592c9f0a9a1da 100644 (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
index a8a3fbcbdf1ddb71b937ebe85ee062735e7c61b2..427316c32b6ebed80c8ba979eac46528ae546142 100644 (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;
index ec8a42ae832f36d762ad45e8310b2d341fe4edfa..ca7b278ddd45c0f0afd8e338b58fbe9bbe2e99a2 100644 (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,
index 78ce4740970b4d429c4b8338ff6198f59abc4296..cf3170ea9ea18d79a5b2e279c84e408679dfa125 100644 (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;
index 604c09603ab7601c2707b0d91833d771b1b920dd..25302133a4a2d5bcb653c473d0469d3cfc41a93e 100644 (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)
+  };
+}
index fe954a43f01bd35a422db80a0e2b6ec705dad3eb..1dbaf285aa0c3d944beee95cbfe59a5dbcefec34 100644 (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
diff --git a/test/fixtures/scale.linear/grace-neg.js b/test/fixtures/scale.linear/grace-neg.js
new file mode 100644 (file)
index 0000000..f606202
--- /dev/null
@@ -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
+    }
+  }
+};
diff --git a/test/fixtures/scale.linear/grace-neg.png b/test/fixtures/scale.linear/grace-neg.png
new file mode 100644 (file)
index 0000000..fbe444b
Binary files /dev/null and b/test/fixtures/scale.linear/grace-neg.png differ
diff --git a/test/fixtures/scale.linear/grace-pos.js b/test/fixtures/scale.linear/grace-pos.js
new file mode 100644 (file)
index 0000000..76d6c69
--- /dev/null
@@ -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
+    }
+  }
+};
diff --git a/test/fixtures/scale.linear/grace-pos.png b/test/fixtures/scale.linear/grace-pos.png
new file mode 100644 (file)
index 0000000..e6b6545
Binary files /dev/null and b/test/fixtures/scale.linear/grace-pos.png differ
diff --git a/test/fixtures/scale.linear/grace.js b/test/fixtures/scale.linear/grace.js
new file mode 100644 (file)
index 0000000..8f3f09f
--- /dev/null
@@ -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
+    }
+  }
+};
diff --git a/test/fixtures/scale.linear/grace.png b/test/fixtures/scale.linear/grace.png
new file mode 100644 (file)
index 0000000..b7556e4
Binary files /dev/null and b/test/fixtures/scale.linear/grace.png differ