@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
33import Chart from 'chart.js' ;
44import isEqual from 'lodash/isEqual' ;
55import find from 'lodash/find' ;
6-
6+ import keyBy from 'lodash/keyBy' ;
77
88class ChartComponent extends React . Component {
99 static getLabelAsKey = d => d . label ;
@@ -160,36 +160,35 @@ class ChartComponent extends React.Component {
160160 let currentDatasets = ( this . chartInstance . config . data && this . chartInstance . config . data . datasets ) || [ ] ;
161161 const nextDatasets = data . datasets || [ ] ;
162162
163- // use the key provider to work out which series have been added/removed/changed
164- const currentDatasetKeys = currentDatasets . map ( this . props . datasetKeyProvider ) ;
165- const nextDatasetKeys = nextDatasets . map ( this . props . datasetKeyProvider ) ;
166- const newDatasets = nextDatasets . filter ( d => currentDatasetKeys . indexOf ( this . props . datasetKeyProvider ( d ) ) === - 1 ) ;
167-
168- // process the updates (via a reverse for loop so we can safely splice deleted datasets out of the array
169- for ( let idx = currentDatasets . length - 1 ; idx >= 0 ; idx -= 1 ) {
170- const currentDatasetKey = this . props . datasetKeyProvider ( currentDatasets [ idx ] ) ;
171- if ( nextDatasetKeys . indexOf ( currentDatasetKey ) === - 1 ) {
172- // deleted series
173- currentDatasets . splice ( idx , 1 ) ;
163+ const currentDatasetsIndexed = keyBy (
164+ currentDatasets ,
165+ this . props . datasetKeyProvider
166+ ) ;
167+
168+ // We can safely replace the dataset array, as long as we retain the _meta property
169+ // on each dataset.
170+ this . chartInstance . config . data . datasets = nextDatasets . map ( next => {
171+ const current =
172+ currentDatasetsIndexed [ this . props . datasetKeyProvider ( next ) ] ;
173+ if ( current && current . type === next . type ) {
174+ // The data array must be edited in place. As chart.js adds listeners to it.
175+ current . data . splice ( next . data . length ) ;
176+ next . data . forEach ( ( point , pid ) => {
177+ current . data [ pid ] = next . data [ pid ] ;
178+ } ) ;
179+ const { data, ...otherProps } = next ;
180+ // Merge properties. Notice a weakness here. If a property is removed
181+ // from next, it will be retained by current and never disappears.
182+ // Workaround is to set value to null or undefined in next.
183+ return {
184+ ...current ,
185+ ...otherProps
186+ } ;
174187 } else {
175- const retainedDataset = find ( nextDatasets , d => this . props . datasetKeyProvider ( d ) === currentDatasetKey ) ;
176- if ( retainedDataset ) {
177- // update it in place if it is a retained dataset
178- currentDatasets [ idx ] . data . splice ( retainedDataset . data . length ) ;
179- retainedDataset . data . forEach ( ( point , pid ) => {
180- currentDatasets [ idx ] . data [ pid ] = retainedDataset . data [ pid ] ;
181- } ) ;
182- const { data, ...otherProps } = retainedDataset ;
183- currentDatasets [ idx ] = {
184- data : currentDatasets [ idx ] . data ,
185- ...currentDatasets [ idx ] ,
186- ...otherProps
187- } ;
188- }
188+ return next ;
189189 }
190- }
191- // finally add any new series
192- newDatasets . forEach ( d => currentDatasets . push ( d ) ) ;
190+ } ) ;
191+
193192 const { datasets, ...rest } = data ;
194193
195194 this . chartInstance . config . data = {
0 commit comments