From: Jukka Kurkela Date: Mon, 29 Nov 2021 21:38:11 +0000 (+0200) Subject: Category: Track automatically added labels (#9921) X-Git-Tag: v3.6.1~3 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=93452501d15b004c447a24a3ff5a9e2bc33fc2e9;p=thirdparty%2FChart.js.git Category: Track automatically added labels (#9921) * Category: Track automatically added labels * Use correct yAxisKey (does not change anything) --- diff --git a/src/scales/scale.category.js b/src/scales/scale.category.js index 681e07e8e..ecf9c8bd3 100644 --- a/src/scales/scale.category.js +++ b/src/scales/scale.category.js @@ -1,14 +1,20 @@ import Scale from '../core/core.scale'; import {isNullOrUndef, valueOrDefault, _limitValue} from '../helpers'; -const addIfString = (labels, raw, index) => typeof raw === 'string' - ? labels.push(raw) - 1 - : isNaN(raw) ? null : index; +const addIfString = (labels, raw, index, addedLabels) => { + if (typeof raw === 'string') { + index = labels.push(raw) - 1; + addedLabels.unshift({index, label: raw}); + } else if (isNaN(raw)) { + index = null; + } + return index; +}; -function findOrAddLabel(labels, raw, index) { +function findOrAddLabel(labels, raw, index, addedLabels) { const first = labels.indexOf(raw); if (first === -1) { - return addIfString(labels, raw, index); + return addIfString(labels, raw, index, addedLabels); } const last = labels.lastIndexOf(raw); return first !== last ? index : first; @@ -24,6 +30,21 @@ export default class CategoryScale extends Scale { /** @type {number} */ this._startValue = undefined; this._valueRange = 0; + this._addedLabels = []; + } + + init(scaleOptions) { + const added = this._addedLabels; + if (added.length) { + const labels = this.getLabels(); + for (const {index, label} of added) { + if (labels[index] === label) { + labels.splice(index, 1); + } + } + this._addedLabels = []; + } + super.init(scaleOptions); } parse(raw, index) { @@ -32,7 +53,7 @@ export default class CategoryScale extends Scale { } const labels = this.getLabels(); index = isFinite(index) && labels[index] === raw ? index - : findOrAddLabel(labels, raw, valueOrDefault(index, raw)); + : findOrAddLabel(labels, raw, valueOrDefault(index, raw), this._addedLabels); return validIndex(index, labels.length - 1); } diff --git a/test/specs/core.datasetController.tests.js b/test/specs/core.datasetController.tests.js index 05bef5b65..c3835bcaf 100644 --- a/test/specs/core.datasetController.tests.js +++ b/test/specs/core.datasetController.tests.js @@ -249,6 +249,124 @@ describe('Chart.DatasetController', function() { expect(parsedYValues).toEqual([20, 30]); }); + describe('labels array synchronization', function() { + const data1 = [ + {x: 'One', name: 'One', y: 1, value: 1}, + {x: 'Two', name: 'Two', y: 2, value: 2} + ]; + const data2 = [ + {x: 'Three', name: 'Three', y: 3, value: 3}, + {x: 'Four', name: 'Four', y: 4, value: 4}, + {x: 'Five', name: 'Five', y: 5, value: 5} + ]; + [ + true, + false, + { + xAxisKey: 'name', + yAxisKey: 'value' + } + ].forEach(function(parsing) { + describe('when parsing is ' + JSON.stringify(parsing), function() { + it('should remove old labels when data is updated', function() { + const chart = acquireChart({ + type: 'line', + data: { + datasets: [{ + data: data1 + }] + }, + options: { + parsing + } + }); + + chart.data.datasets[0].data = data2; + chart.update(); + + const meta = chart.getDatasetMeta(0); + const labels = meta.iScale.getLabels(); + expect(labels).toEqual(data2.map(n => n.x)); + }); + + it('should not remove any user added labels', function() { + const chart = acquireChart({ + type: 'line', + data: { + datasets: [{ + data: data1 + }] + }, + options: { + parsing + } + }); + + chart.data.labels.push('user-added'); + chart.data.datasets[0].data = []; + chart.update(); + + const meta = chart.getDatasetMeta(0); + const labels = meta.iScale.getLabels(); + expect(labels).toEqual(['user-added']); + }); + + it('should not remove any user defined labels', function() { + const chart = acquireChart({ + type: 'line', + data: { + datasets: [{ + data: data1 + }], + labels: ['user1', 'user2'] + }, + options: { + parsing + } + }); + + const meta = chart.getDatasetMeta(0); + + expect(meta.iScale.getLabels()).toEqual(['user1', 'user2'].concat(data1.map(n => n.x))); + + chart.data.datasets[0].data = data2; + chart.update(); + + expect(meta.iScale.getLabels()).toEqual(['user1', 'user2'].concat(data2.map(n => n.x))); + }); + + it('should keep up with multiple datasets', function() { + const chart = acquireChart({ + type: 'line', + data: { + datasets: [{ + data: data1 + }, { + data: data2 + }], + labels: ['One', 'Three'] + }, + options: { + parsing + } + }); + + const scale = chart.scales.x; + + expect(scale.getLabels()).toEqual(['One', 'Three', 'Two', 'Four', 'Five']); + + chart.data.datasets[0].data = data2; + chart.data.datasets[1].data = data1; + chart.update(); + + expect(scale.getLabels()).toEqual(['One', 'Three', 'Four', 'Five', 'Two']); + }); + + }); + }); + }); + + it('should synchronize metadata when data are inserted or removed and parsing is on', function() { const data = [0, 1, 2, 3, 4, 5]; const chart = acquireChart({