]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
Add new option, `skipNull` to bar charts that enables skipping null values (#7849)
authorEvert Timberg <evert.timberg+github@gmail.com>
Tue, 6 Oct 2020 11:33:24 +0000 (07:33 -0400)
committerGitHub <noreply@github.com>
Tue, 6 Oct 2020 11:33:24 +0000 (07:33 -0400)
* Add new option, `skipNull` to bar charts that enables skipping null
or undefined values.

* Address code review feedback

* Fix windows CI lint issues

docs/docs/charts/bar.mdx
src/controllers/controller.bar.js
test/fixtures/controller.bar/bar-skip-null-object-data.js [new file with mode: 0644]
test/fixtures/controller.bar/bar-skip-null-object-data.png [new file with mode: 0644]
test/fixtures/controller.bar/bar-skip-null.js [new file with mode: 0644]
test/fixtures/controller.bar/bar-skip-null.png [new file with mode: 0644]
types/controllers/index.d.ts

index 7d2fd1bd5fe91e6594dfe12056bdc9f68d60cc4b..a69f40bda3725272499c868faa68ef6ba2749434 100644 (file)
@@ -186,6 +186,14 @@ If set to `'flex'`, the base sample widths are calculated automatically based on
 
 If not set (default), the base sample widths are calculated using the smallest interval that prevents bar overlapping, and bars are sized using `barPercentage` and `categoryPercentage`. This mode always generates bars equally sized.
 
+## Config Options
+
+These are the customisation options specific to Bar charts. These options are merged with the global chart configuration options, and form the options of the chart.
+
+| Name | Type | Default | Description
+| ---- | ---- | ------- | -----------
+| `skipNull` | `boolean` | `undefined` | If `true`, null or undefined values will not be drawn
+
 ## Scale Configuration
 
 The bar chart sets unique default values for the following configuration from the associated `scale` options:
index 30e092d89012c5e4eaaf72c81879c96118dd7692..dea91c865e62e127856105305d2ca7bea4906185 100644 (file)
@@ -30,9 +30,8 @@ function computeMinSampleSize(scale, pixels) {
  * mode currently always generates bars equally sized (until we introduce scriptable options?).
  * @private
  */
-function computeFitCategoryTraits(index, ruler, options) {
+function computeFitCategoryTraits(index, ruler, options, stackCount) {
        const thickness = options.barThickness;
-       const count = ruler.stackCount;
        let size, ratio;
 
        if (isNullOrUndef(thickness)) {
@@ -42,12 +41,12 @@ function computeFitCategoryTraits(index, ruler, options) {
                // When bar thickness is enforced, category and bar percentages are ignored.
                // Note(SB): we could add support for relative bar thickness (e.g. barThickness: '50%')
                // and deprecate barPercentage since this value is ignored when thickness is absolute.
-               size = thickness * count;
+               size = thickness * stackCount;
                ratio = 1;
        }
 
        return {
-               chunk: size / count,
+               chunk: size / stackCount,
                ratio,
                start: ruler.pixels[index] - (size / 2)
        };
@@ -59,7 +58,7 @@ function computeFitCategoryTraits(index, ruler, options) {
  * generates bars with different widths when data are not evenly spaced.
  * @private
  */
-function computeFlexCategoryTraits(index, ruler, options) {
+function computeFlexCategoryTraits(index, ruler, options, stackCount) {
        const pixels = ruler.pixels;
        const curr = pixels[index];
        let prev = index > 0 ? pixels[index - 1] : null;
@@ -81,7 +80,7 @@ function computeFlexCategoryTraits(index, ruler, options) {
        const size = Math.abs(next - prev) / 2 * percent;
 
        return {
-               chunk: size / ruler.stackCount,
+               chunk: size / stackCount,
                ratio: options.barPercentage,
                start
        };
@@ -271,10 +270,11 @@ export default class BarController extends DatasetController {
        /**
         * Returns the stacks based on groups and bar visibility.
         * @param {number} [last] - The dataset index
+        * @param {number} [dataIndex] - The data index of the ruler
         * @returns {string[]} The list of stack IDs
         * @private
         */
-       _getStacks(last) {
+       _getStacks(last, dataIndex) {
                const me = this;
                const meta = me._cachedMeta;
                const iScale = meta.iScale;
@@ -286,6 +286,17 @@ export default class BarController extends DatasetController {
 
                for (i = 0; i < ilen; ++i) {
                        item = metasets[i];
+
+                       if (typeof dataIndex !== 'undefined') {
+                               const val = item.controller.getParsed(dataIndex)[
+                                       item.controller._cachedMeta.vScale.axis
+                               ];
+
+                               if (isNullOrUndef(val) || isNaN(val)) {
+                                       continue;
+                               }
+                       }
+
                        // stacked   | meta.stack
                        //           | found | not found | undefined
                        // false     |   x   |     x     |     x
@@ -314,8 +325,8 @@ export default class BarController extends DatasetController {
         * Returns the effective number of stacks based on groups and bar visibility.
         * @private
         */
-       _getStackCount() {
-               return this._getStacks().length;
+       _getStackCount(index) {
+               return this._getStacks(undefined, index).length;
        }
 
        /**
@@ -429,9 +440,10 @@ export default class BarController extends DatasetController {
         */
        _calculateBarIndexPixels(index, ruler, options) {
                const me = this;
+               const stackCount = me.chart.options.skipNull ? me._getStackCount(index) : ruler.stackCount;
                const range = options.barThickness === 'flex'
-                       ? computeFlexCategoryTraits(index, ruler, options)
-                       : computeFitCategoryTraits(index, ruler, options);
+                       ? computeFlexCategoryTraits(index, ruler, options, stackCount)
+                       : computeFitCategoryTraits(index, ruler, options, stackCount);
 
                const stackIndex = me._getStackIndex(me.index, me._cachedMeta.stack);
                const center = range.start + (range.chunk * stackIndex) + (range.chunk / 2);
@@ -486,7 +498,7 @@ BarController.defaults = {
                'barThickness',
                'categoryPercentage',
                'maxBarThickness',
-               'minBarLength'
+               'minBarLength',
        ],
        hover: {
                mode: 'index'
diff --git a/test/fixtures/controller.bar/bar-skip-null-object-data.js b/test/fixtures/controller.bar/bar-skip-null-object-data.js
new file mode 100644 (file)
index 0000000..3be0fc9
--- /dev/null
@@ -0,0 +1,35 @@
+module.exports = {
+       config: {
+               type: 'bar',
+               data: {
+                       labels: [0, 1, 3, 4],
+                       datasets: [
+                               {
+                                       data: {0: 5, 1: 20, 2: 1, 3: 10},
+                                       backgroundColor: '#00ff00',
+                                       borderColor: '#ff0000'
+                               },
+                               {
+                                       data: {0: 10, 1: null, 2: 1, 3: NaN},
+                                       backgroundColor: '#ff0000',
+                                       borderColor: '#ff0000'
+                               }
+                       ]
+               },
+               options: {
+                       legend: false,
+                       skipNull: true,
+                       title: false,
+                       scales: {
+                               x: {display: false},
+                               y: {display: false}
+                       }
+               }
+       },
+       options: {
+               canvas: {
+                       height: 256,
+                       width: 512
+               }
+       }
+};
diff --git a/test/fixtures/controller.bar/bar-skip-null-object-data.png b/test/fixtures/controller.bar/bar-skip-null-object-data.png
new file mode 100644 (file)
index 0000000..0406b55
Binary files /dev/null and b/test/fixtures/controller.bar/bar-skip-null-object-data.png differ
diff --git a/test/fixtures/controller.bar/bar-skip-null.js b/test/fixtures/controller.bar/bar-skip-null.js
new file mode 100644 (file)
index 0000000..77f0290
--- /dev/null
@@ -0,0 +1,35 @@
+module.exports = {
+       config: {
+               type: 'bar',
+               data: {
+                       labels: [0, 1, 3, 4],
+                       datasets: [
+                               {
+                                       data: [5, 20, 1, 10],
+                                       backgroundColor: '#00ff00',
+                                       borderColor: '#ff0000'
+                               },
+                               {
+                                       data: [10, null, 1, undefined],
+                                       backgroundColor: '#ff0000',
+                                       borderColor: '#ff0000'
+                               }
+                       ]
+               },
+               options: {
+                       legend: false,
+                       skipNull: true,
+                       title: false,
+                       scales: {
+                               x: {display: false},
+                               y: {display: false}
+                       }
+               }
+       },
+       options: {
+               canvas: {
+                       height: 256,
+                       width: 512
+               }
+       }
+};
diff --git a/test/fixtures/controller.bar/bar-skip-null.png b/test/fixtures/controller.bar/bar-skip-null.png
new file mode 100644 (file)
index 0000000..0406b55
Binary files /dev/null and b/test/fixtures/controller.bar/bar-skip-null.png differ
index b24728cd8d29a024589e2e5cd8e19a4f8331081b..02265071c9e95b19acac43254b48dfdd736646d2 100644 (file)
@@ -79,6 +79,10 @@ export interface IBarControllerDatasetOptions
 }
 
 export interface IBarControllerChartOptions {
+  /**
+   * Should null or undefined values be omitted from drawing
+   */
+  skipNull?: boolean;
 }
 
 export interface BarController extends DatasetController {}