]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
Category: Track automatically added labels (#9921)
authorJukka Kurkela <jukka.kurkela@gmail.com>
Mon, 29 Nov 2021 21:38:11 +0000 (23:38 +0200)
committerGitHub <noreply@github.com>
Mon, 29 Nov 2021 21:38:11 +0000 (23:38 +0200)
* Category: Track automatically added labels

* Use correct yAxisKey (does not change anything)

src/scales/scale.category.js
test/specs/core.datasetController.tests.js

index 681e07e8e72a767b110450c876c63f1d3a7a1f95..ecf9c8bd3dff0b30506403db9a23d5fdd6b4ec0c 100644 (file)
@@ -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);
   }
 
index 05bef5b65b6a42826f45d7e46d2dce881191fd34..c3835bcafe0f6bf07f88a4c4e2fcb7adcdd3859d 100644 (file)
@@ -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({