From a84347b0353bf1ffc4759ed4fc10066500854692 Mon Sep 17 00:00:00 2001 From: Evert Timberg Date: Sat, 10 Apr 2021 13:31:14 -0400 Subject: [PATCH] Handle animating stacked bars from null values (#8872) * Handle animating stacked bars from null values * Skipped bars / points should be in the reset state --- src/controllers/controller.bar.js | 3 ++- src/controllers/controller.line.js | 6 ++++-- test/specs/controller.bar.tests.js | 20 ++++++++++++++++++++ test/specs/controller.line.tests.js | 21 +++++++++++++++++++++ 4 files changed, 47 insertions(+), 3 deletions(-) diff --git a/src/controllers/controller.bar.js b/src/controllers/controller.bar.js index 873cb954716..abe98841c58 100644 --- a/src/controllers/controller.bar.js +++ b/src/controllers/controller.bar.js @@ -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 = { diff --git a/src/controllers/controller.line.js b/src/controllers/controller.line.js index f0f0e39d588..2c72604954f 100644 --- a/src/controllers/controller.line.js +++ b/src/controllers/controller.line.js @@ -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; diff --git a/test/specs/controller.bar.tests.js b/test/specs/controller.bar.tests.js index f9decfe4f6f..dfebd643771 100644 --- a/test/specs/controller.bar.tests.js +++ b/test/specs/controller.bar.tests.js @@ -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', diff --git a/test/specs/controller.line.tests.js b/test/specs/controller.line.tests.js index 93f857832f4..7210367ca95 100644 --- a/test/specs/controller.line.tests.js +++ b/test/specs/controller.line.tests.js @@ -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); + }); });