From 0b68786c045cd254f3b041a231d7845bbd12cac0 Mon Sep 17 00:00:00 2001 From: Jukka Kurkela Date: Sat, 28 Dec 2019 16:49:34 +0200 Subject: [PATCH] Resync metasets array when indices change. (#6864) * Resync metasets array when indices change. * Make sure _metasets is initialized --- src/core/core.controller.js | 48 ++++++++++++++++--- test/specs/core.controller.tests.js | 71 +++++++++++++++++++++++++++++ 2 files changed, 112 insertions(+), 7 deletions(-) diff --git a/src/core/core.controller.js b/src/core/core.controller.js index b970f05b3..81075d127 100644 --- a/src/core/core.controller.js +++ b/src/core/core.controller.js @@ -195,6 +195,7 @@ helpers.extend(Chart.prototype, /** @lends Chart */ { me.options = config.options; me._bufferedRender = false; me._layers = []; + me._metasets = []; // Add the chart instance to the global namespace Chart.instances[me.id] = me; @@ -399,11 +400,45 @@ helpers.extend(Chart.prototype, /** @lends Chart */ { scaleService.addScalesToLayout(this); }, + /** + * Updates the given metaset with the given dataset index. Ensures it's stored at that index + * in the _metasets array by swapping with the metaset at that index if necessary. + * @param {Object} meta - the dataset metadata + * @param {number} index - the dataset index + * @private + */ + _updateMetasetIndex: function(meta, index) { + const metasets = this._metasets; + const oldIndex = meta.index; + if (oldIndex !== index) { + metasets[oldIndex] = metasets[index]; + metasets[index] = meta; + meta.index = index; + } + }, + + /** + * @private + */ + _updateMetasets: function() { + const me = this; + const metasets = me._metasets; + const numData = me.data.datasets.length; + const numMeta = metasets.length; + + if (numMeta > numData) { + for (let i = numData; i < numMeta; ++i) { + me.destroyDatasetMeta(i); + } + metasets.splice(numData, numMeta - numData); + } + me._sortedMetasets = metasets.slice(0).sort(compare2Level('order', 'index')); + }, + buildOrUpdateControllers: function() { var me = this; var newControllers = []; var datasets = me.data.datasets; - var sorted = me._sortedMetasets = []; var i, ilen; for (i = 0, ilen = datasets.length; i < ilen; i++) { @@ -417,7 +452,7 @@ helpers.extend(Chart.prototype, /** @lends Chart */ { } meta.type = type; meta.order = dataset.order || 0; - meta.index = i; + me._updateMetasetIndex(meta, i); meta.label = '' + dataset.label; meta.visible = me.isDatasetVisible(i); @@ -433,11 +468,9 @@ helpers.extend(Chart.prototype, /** @lends Chart */ { meta.controller = new ControllerClass(me, i); newControllers.push(meta.controller); } - sorted.push(meta); } - sorted.sort(compare2Level('order', 'index')); - + me._updateMetasets(); return newControllers; }, @@ -768,8 +801,8 @@ helpers.extend(Chart.prototype, /** @lends Chart */ { getDatasetMeta: function(datasetIndex) { const me = this; const dataset = me.data.datasets[datasetIndex]; - const metasets = me._metasets = me._metasets || []; - let meta = metasets[datasetIndex]; + const metasets = me._metasets; + let meta = metasets.filter(x => x._dataset === dataset).pop(); if (!meta) { meta = metasets[datasetIndex] = { @@ -782,6 +815,7 @@ helpers.extend(Chart.prototype, /** @lends Chart */ { yAxisID: null, order: dataset.order || 0, index: datasetIndex, + _dataset: dataset, _parsed: [] }; } diff --git a/test/specs/core.controller.tests.js b/test/specs/core.controller.tests.js index cc707f26b..e22fd7c4a 100644 --- a/test/specs/core.controller.tests.js +++ b/test/specs/core.controller.tests.js @@ -1276,4 +1276,75 @@ describe('Chart', function() { ]); }); }); + + describe('metasets', function() { + beforeEach(function() { + this.chart = acquireChart({ + type: 'line', + data: { + datasets: [ + {label: '1', order: 2}, + {label: '2', order: 1}, + {label: '3', order: 4}, + {label: '4', order: 3}, + ] + } + }); + }); + afterEach(function() { + const metasets = this.chart._metasets; + expect(metasets.length).toEqual(this.chart.data.datasets.length); + for (let i = 0; i < metasets.length; i++) { + expect(metasets[i].index).toEqual(i); + expect(metasets[i]._dataset).toEqual(this.chart.data.datasets[i]); + } + }); + it('should build metasets array in order', function() { + const metasets = this.chart._metasets; + expect(metasets[0].order).toEqual(2); + expect(metasets[1].order).toEqual(1); + expect(metasets[2].order).toEqual(4); + expect(metasets[3].order).toEqual(3); + }); + it('should build sorted metasets array in correct order', function() { + const metasets = this.chart._sortedMetasets; + expect(metasets[0].order).toEqual(1); + expect(metasets[1].order).toEqual(2); + expect(metasets[2].order).toEqual(3); + expect(metasets[3].order).toEqual(4); + }); + it('should be moved when datasets are removed from begining', function() { + this.chart.data.datasets.splice(0, 2); + this.chart.update(); + const metasets = this.chart._metasets; + expect(metasets[0].order).toEqual(4); + expect(metasets[1].order).toEqual(3); + }); + it('should be moved when datasets are removed from middle', function() { + this.chart.data.datasets.splice(1, 2); + this.chart.update(); + const metasets = this.chart._metasets; + expect(metasets[0].order).toEqual(2); + expect(metasets[1].order).toEqual(3); + }); + it('should be moved when datasets are inserted', function() { + this.chart.data.datasets.splice(1, 0, {label: '1.5', order: 5}); + this.chart.update(); + const metasets = this.chart._metasets; + expect(metasets[0].order).toEqual(2); + expect(metasets[1].order).toEqual(5); + expect(metasets[2].order).toEqual(1); + expect(metasets[3].order).toEqual(4); + expect(metasets[4].order).toEqual(3); + }); + it('should be replaced when dataset is replaced', function() { + this.chart.data.datasets.splice(1, 1, {label: '1.5', order: 5}); + this.chart.update(); + const metasets = this.chart._metasets; + expect(metasets[0].order).toEqual(2); + expect(metasets[1].order).toEqual(5); + expect(metasets[2].order).toEqual(4); + expect(metasets[3].order).toEqual(3); + }); + }); }); -- 2.47.2