]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
Delay data to elements synchronization to update (#9105)
authorJukka Kurkela <jukka.kurkela@gmail.com>
Sat, 15 May 2021 12:22:15 +0000 (15:22 +0300)
committerGitHub <noreply@github.com>
Sat, 15 May 2021 12:22:15 +0000 (08:22 -0400)
src/core/core.datasetController.js
test/specs/core.datasetController.tests.js

index f55b2fa2c0284988ab2bc84fee2a7ff2879bcc76..6f1dc0efa1a04d1e59a76681977af16256565363 100644 (file)
@@ -228,6 +228,7 @@ export default class DatasetController {
     this._drawCount = undefined;
     this.enableOptionSharing = false;
     this.$context = undefined;
+    this._syncList = [];
 
     this.initialize();
   }
@@ -242,6 +243,9 @@ export default class DatasetController {
   }
 
   updateIndex(datasetIndex) {
+    if (this.index !== datasetIndex) {
+      clearStacks(this._cachedMeta);
+    }
     this.index = datasetIndex;
   }
 
@@ -316,6 +320,7 @@ export default class DatasetController {
     const me = this;
     const dataset = me.getDataset();
     const data = dataset.data || (dataset.data = []);
+    const _data = me._data;
 
     // In order to correctly handle data addition/deletion animation (an thus simulate
     // real-time charts), we need to monitor these data modifications and synchronize
@@ -323,14 +328,19 @@ export default class DatasetController {
 
     if (isObject(data)) {
       me._data = convertObjectDataToArray(data);
-    } else if (me._data !== data) {
-      if (me._data) {
+    } else if (_data !== data) {
+      if (_data) {
         // This case happens when the user replaced the data array instance.
-        unlistenArrayEvents(me._data, me);
-        clearStacks(me._cachedMeta);
+        unlistenArrayEvents(_data, me);
+        // Discard old elements, parsed data and stacks
+        const meta = me._cachedMeta;
+        clearStacks(meta);
+        meta._parsed = [];
+        meta.data = [];
       }
       if (data && Object.isExtensible(data)) {
         listenArrayEvents(data, me);
+        me._syncList = [];
       }
       me._data = data;
     }
@@ -356,6 +366,7 @@ export default class DatasetController {
     me._dataCheck();
 
     // make sure cached _stacked status is current
+    const oldStacked = meta._stacked;
     meta._stacked = isStacked(meta.vScale, meta);
 
     // detect change in stack option
@@ -371,7 +382,7 @@ export default class DatasetController {
     me._resyncElements(resetNewElements);
 
     // if stack changed, update stack values for the whole dataset
-    if (stackChanged) {
+    if (stackChanged || oldStacked !== meta._stacked) {
       updateStacks(me, meta._parsed);
     }
   }
@@ -905,17 +916,28 @@ export default class DatasetController {
         */
   _resyncElements(resetNewElements) {
     const me = this;
-    const numMeta = me._cachedMeta.data.length;
-    const numData = me._data.length;
+    const data = me._data;
+    const elements = me._cachedMeta.data;
+
+    // Apply changes detected through array listeners
+    for (const [method, arg1, arg2] of me._syncList) {
+      me[method](arg1, arg2);
+    }
+    me._syncList = [];
+
+    const numMeta = elements.length;
+    const numData = data.length;
+    const count = Math.min(numData, numMeta);
 
     if (numData > numMeta) {
       me._insertElements(numMeta, numData - numMeta, resetNewElements);
     } else if (numData < numMeta) {
       me._removeElements(numData, numMeta - numData);
-    }
-    // Re-parse the old elements (new elements are parsed in _insertElements)
-    const count = Math.min(numData, numMeta);
-    if (count) {
+    } else if (count) {
+      // TODO: It is not optimal to always parse the old data
+      // This is done because we are not detecting direct assignments:
+      // chart.data.datasets[0].data[5] = 10;
+      // chart.data.datasets[0].data[5].y = 10;
       me.parse(0, count);
     }
   }
@@ -975,36 +997,36 @@ export default class DatasetController {
         */
   _onDataPush() {
     const count = arguments.length;
-    this._insertElements(this.getDataset().data.length - count, count);
+    this._syncList.push(['_insertElements', this.getDataset().data.length - count, count]);
   }
 
   /**
         * @private
         */
   _onDataPop() {
-    this._removeElements(this._cachedMeta.data.length - 1, 1);
+    this._syncList.push(['_removeElements', this._cachedMeta.data.length - 1, 1]);
   }
 
   /**
         * @private
         */
   _onDataShift() {
-    this._removeElements(0, 1);
+    this._syncList.push(['_removeElements', 0, 1]);
   }
 
   /**
         * @private
         */
   _onDataSplice(start, count) {
-    this._removeElements(start, count);
-    this._insertElements(start, arguments.length - 2);
+    this._syncList.push(['_removeElements', start, count]);
+    this._syncList.push(['_insertElements', start, arguments.length - 2]);
   }
 
   /**
         * @private
         */
   _onDataUnshift() {
-    this._insertElements(0, arguments.length);
+    this._syncList.push(['_insertElements', 0, arguments.length]);
   }
 }
 
index b0cc393981f5e72e55fe581f511811a71e0abd8d..773bbf54e970500b63961368916432a7a7481af7 100644 (file)
@@ -268,6 +268,7 @@ describe('Chart.DatasetController', function() {
     last = meta.data[5];
     data.push(6, 7, 8);
     data.push(9);
+    chart.update();
     expect(meta.data.length).toBe(10);
     expect(meta.data[0]).toBe(first);
     expect(meta.data[5]).toBe(last);
@@ -275,6 +276,7 @@ describe('Chart.DatasetController', function() {
 
     last = meta.data[9];
     data.pop();
+    chart.update();
     expect(meta.data.length).toBe(9);
     expect(meta.data[0]).toBe(first);
     expect(meta.data.indexOf(last)).toBe(-1);
@@ -284,6 +286,7 @@ describe('Chart.DatasetController', function() {
     data.shift();
     data.shift();
     data.shift();
+    chart.update();
     expect(meta.data.length).toBe(6);
     expect(meta.data.indexOf(first)).toBe(-1);
     expect(meta.data[5]).toBe(last);
@@ -293,6 +296,7 @@ describe('Chart.DatasetController', function() {
     second = meta.data[1];
     last = meta.data[5];
     data.splice(1, 4, 10, 11);
+    chart.update();
     expect(meta.data.length).toBe(4);
     expect(meta.data[0]).toBe(first);
     expect(meta.data[3]).toBe(last);
@@ -301,6 +305,7 @@ describe('Chart.DatasetController', function() {
 
     data.unshift(12, 13, 14, 15);
     data.unshift(16, 17);
+    chart.update();
     expect(meta.data.length).toBe(10);
     expect(meta.data[6]).toBe(first);
     expect(meta.data[9]).toBe(last);
@@ -333,12 +338,14 @@ describe('Chart.DatasetController', function() {
     last = controller.getParsed(5);
     data.push({x: 6, y: 6}, {x: 7, y: 7}, {x: 8, y: 8});
     data.push({x: 9, y: 9});
+    chart.update();
     expect(meta.data.length).toBe(10);
     expect(controller.getParsed(0)).toBe(first);
     expect(controller.getParsed(5)).toBe(last);
 
     last = controller.getParsed(9);
     data.pop();
+    chart.update();
     expect(meta.data.length).toBe(9);
     expect(controller.getParsed(0)).toBe(first);
     expect(controller.getParsed(9)).toBe(undefined);
@@ -348,12 +355,14 @@ describe('Chart.DatasetController', function() {
     data.shift();
     data.shift();
     data.shift();
+    chart.update();
     expect(meta.data.length).toBe(6);
     expect(controller.getParsed(5)).toBe(last);
 
     first = controller.getParsed(0);
     last = controller.getParsed(5);
     data.splice(1, 4, {x: 10, y: 10}, {x: 11, y: 11});
+    chart.update();
     expect(meta.data.length).toBe(4);
     expect(controller.getParsed(0)).toBe(first);
     expect(controller.getParsed(3)).toBe(last);
@@ -361,6 +370,7 @@ describe('Chart.DatasetController', function() {
 
     data.unshift({x: 12, y: 12}, {x: 13, y: 13}, {x: 14, y: 14}, {x: 15, y: 15});
     data.unshift({x: 16, y: 16}, {x: 17, y: 17});
+    chart.update();
     expect(meta.data.length).toBe(10);
     expect(controller.getParsed(6)).toBe(first);
     expect(controller.getParsed(9)).toBe(last);
@@ -390,6 +400,7 @@ describe('Chart.DatasetController', function() {
     expect(meta._parsed.map(p => p.y)).toEqual(data1);
 
     data1.push(9);
+    chart.update();
     expect(meta.data.length).toBe(4);
 
     chart.data.datasets[0].data = data0;