]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
Handle animating stacked bars from null values (#8872)
authorEvert Timberg <evert.timberg+github@gmail.com>
Sat, 10 Apr 2021 17:31:14 +0000 (13:31 -0400)
committerGitHub <noreply@github.com>
Sat, 10 Apr 2021 17:31:14 +0000 (20:31 +0300)
* Handle animating stacked bars from null values

* Skipped bars / points should be in the reset state

src/controllers/controller.bar.js
src/controllers/controller.line.js
test/specs/controller.bar.tests.js
test/specs/controller.line.tests.js

index 873cb954716cb1535e9b0b9b9b54b81ce0af0bc0..abe98841c5874e375bfff2fad3906aa2fb423e4a 100644 (file)
@@ -266,7 +266,8 @@ export default class BarController extends DatasetController {
     me.updateSharedOptions(sharedOptions, mode, firstOpts);
 
     for (let i = start; i < start + count; i++) {
-      const vpixels = reset ? {base, head: base} : me._calculateBarValuePixels(i);
+      const parsed = me.getParsed(i);
+      const vpixels = reset || isNullOrUndef(parsed[vScale.axis]) ? {base, head: base} : me._calculateBarValuePixels(i);
       const ipixels = me._calculateBarIndexPixels(i, ruler);
 
       const properties = {
index f0f0e39d588d53a14d2d81a32498cabdff2ab4c4..2c72604954fbe0c078e5764c8b422283f46eec78 100644 (file)
@@ -1,4 +1,5 @@
 import DatasetController from '../core/core.datasetController';
+import {isNullOrUndef} from '../helpers';
 import {_limitValue, isNumber} from '../helpers/helpers.math';
 import {_lookupByKey} from '../helpers/helpers.collection';
 
@@ -59,9 +60,10 @@ export default class LineController extends DatasetController {
       const point = points[i];
       const parsed = me.getParsed(i);
       const properties = directUpdate ? point : {};
+      const nullData = isNullOrUndef(parsed.y);
       const x = properties.x = xScale.getPixelForValue(parsed.x, i);
-      const y = properties.y = reset ? yScale.getBasePixel() : yScale.getPixelForValue(_stacked ? me.applyStack(yScale, parsed, _stacked) : parsed.y, i);
-      properties.skip = isNaN(x) || isNaN(y);
+      const y = properties.y = reset || nullData ? yScale.getBasePixel() : yScale.getPixelForValue(_stacked ? me.applyStack(yScale, parsed, _stacked) : parsed.y, i);
+      properties.skip = isNaN(x) || isNaN(y) || nullData;
       properties.stop = i > 0 && (parsed.x - prevParsed.x) > maxGapLength;
       properties.parsed = parsed;
 
index f9decfe4f6fb73efdb99da1dbb34c77c12c7d78c..dfebd643771e47eaf62f90e5ac99c45767812f46 100644 (file)
@@ -30,6 +30,26 @@ describe('Chart.controllers.bar', function() {
     expect(meta.controller.index).toBe(0);
   });
 
+  it('should set null bars to the reset state', function() {
+    var chart = window.acquireChart({
+      type: 'bar',
+      data: {
+        datasets: [{
+          data: [10, null, 0, -4],
+          label: 'dataset1',
+        }],
+        labels: ['label1', 'label2', 'label3', 'label4']
+      }
+    });
+
+    var meta = chart.getDatasetMeta(0);
+    var bar = meta.data[1];
+    var {x, y, base} = bar.getProps(['x', 'y', 'base'], true);
+    expect(isNaN(x)).toBe(false);
+    expect(isNaN(y)).toBe(false);
+    expect(isNaN(base)).toBe(false);
+  });
+
   it('should use the first scale IDs if the dataset does not specify them', function() {
     var chart = window.acquireChart({
       type: 'bar',
index 93f857832f4a0a7b2186201347f0c9c09f79a90e..7210367ca95e0c2fc0026444330429770149e69b 100644 (file)
@@ -917,4 +917,25 @@ describe('Chart.controllers.line', function() {
     }
     expect(createChart).not.toThrow();
   });
+
+  it('should set skipped points to the reset state', function() {
+    var chart = window.acquireChart({
+      type: 'line',
+      data: {
+        datasets: [{
+          data: [10, null, 0, -4],
+          label: 'dataset1',
+          pointBorderWidth: [1, 2, 3, 4]
+        }],
+        labels: ['label1', 'label2', 'label3', 'label4']
+      }
+    });
+
+    var meta = chart.getDatasetMeta(0);
+    var point = meta.data[1];
+    var {x, y} = point.getProps(['x', 'y'], true);
+    expect(point.skip).toBe(true);
+    expect(isNaN(x)).toBe(false);
+    expect(isNaN(y)).toBe(false);
+  });
 });