diff --git a/src/index.js b/src/index.js
index 2900ccf8e..65c2ae4dd 100644
--- a/src/index.js
+++ b/src/index.js
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
import Chart from 'chart.js';
import isEqual from 'lodash/isEqual';
import find from 'lodash/find';
-
+import keyBy from 'lodash/keyBy';
class ChartComponent extends React.Component {
static getLabelAsKey = d => d.label;
@@ -160,36 +160,35 @@ class ChartComponent extends React.Component {
let currentDatasets = (this.chartInstance.config.data && this.chartInstance.config.data.datasets) || [];
const nextDatasets = data.datasets || [];
- // use the key provider to work out which series have been added/removed/changed
- const currentDatasetKeys = currentDatasets.map(this.props.datasetKeyProvider);
- const nextDatasetKeys = nextDatasets.map(this.props.datasetKeyProvider);
- const newDatasets = nextDatasets.filter(d => currentDatasetKeys.indexOf(this.props.datasetKeyProvider(d)) === -1);
-
- // process the updates (via a reverse for loop so we can safely splice deleted datasets out of the array
- for (let idx = currentDatasets.length - 1; idx >= 0; idx -= 1) {
- const currentDatasetKey = this.props.datasetKeyProvider(currentDatasets[idx]);
- if (nextDatasetKeys.indexOf(currentDatasetKey) === -1) {
- // deleted series
- currentDatasets.splice(idx, 1);
+ const currentDatasetsIndexed = keyBy(
+ currentDatasets,
+ this.props.datasetKeyProvider
+ );
+
+ // We can safely replace the dataset array, as long as we retain the _meta property
+ // on each dataset.
+ this.chartInstance.config.data.datasets = nextDatasets.map(next => {
+ const current =
+ currentDatasetsIndexed[this.props.datasetKeyProvider(next)];
+ if (current && current.type === next.type) {
+ // The data array must be edited in place. As chart.js adds listeners to it.
+ current.data.splice(next.data.length);
+ next.data.forEach((point, pid) => {
+ current.data[pid] = next.data[pid];
+ });
+ const { data, ...otherProps } = next;
+ // Merge properties. Notice a weakness here. If a property is removed
+ // from next, it will be retained by current and never disappears.
+ // Workaround is to set value to null or undefined in next.
+ return {
+ ...current,
+ ...otherProps
+ };
} else {
- const retainedDataset = find(nextDatasets, d => this.props.datasetKeyProvider(d) === currentDatasetKey);
- if (retainedDataset) {
- // update it in place if it is a retained dataset
- currentDatasets[idx].data.splice(retainedDataset.data.length);
- retainedDataset.data.forEach((point, pid) => {
- currentDatasets[idx].data[pid] = retainedDataset.data[pid];
- });
- const {data, ...otherProps} = retainedDataset;
- currentDatasets[idx] = {
- data: currentDatasets[idx].data,
- ...currentDatasets[idx],
- ...otherProps
- };
- }
+ return next;
}
- }
- // finally add any new series
- newDatasets.forEach(d => currentDatasets.push(d));
+ });
+
const { datasets, ...rest } = data;
this.chartInstance.config.data = {
diff --git a/stories/UpdatingChart.js b/stories/UpdatingChart.js
new file mode 100644
index 000000000..7817a3b29
--- /dev/null
+++ b/stories/UpdatingChart.js
@@ -0,0 +1,167 @@
+import React from 'react';
+import { Bar } from 'react-chartjs-2';
+import { storiesOf } from '@kadira/storybook';
+
+const srcData = [
+ {
+ year: 2015,
+ data: [
+ 536531,
+ 1017273,
+ 1496702,
+ 1882366,
+ 2228939,
+ 2515784,
+ 2753399,
+ 2966478,
+ 3236838,
+ 3613068,
+ 4047828,
+ 4547209
+ ],
+ color: 'hsla(50,100%,59.21569%,1)'
+ },
+ {
+ year: 2016,
+ data: [
+ 551503,
+ 1057792,
+ 1521903,
+ 1908192,
+ 2191201,
+ 2412114,
+ 2634171,
+ 2900548,
+ 3159543,
+ 3552987,
+ 4052115,
+ 4553624
+ ],
+ color: 'hsla(104,46.15384%,54.11765%,1)'
+ },
+ {
+ year: 2017,
+ data: [
+ 546988,
+ 1031054,
+ 1526958,
+ 1929360,
+ 2219497,
+ 2472468,
+ 2654013,
+ 2876660,
+ 3125501,
+ 3464636,
+ 3911575,
+ 3976944
+ ],
+ color: 'hsla(191,100%,36.66667%,1)'
+ }
+];
+
+const options = {
+ responsive: true,
+ tooltips: {
+ mode: 'label'
+ },
+ elements: {
+ line: {
+ fill: false,
+ lineTension: 0
+ }
+ },
+ scales: {
+ yAxes: [
+ {
+ tics: { min: 0 }
+ }
+ ]
+ },
+ legend: {
+ display: true,
+ position: 'bottom',
+ reverse: true,
+ onClick: null
+ }
+};
+
+storiesOf('Updating chart Example', module).add('Line & Bar', () => {
+ const labels = [
+ 'January',
+ 'February',
+ 'March',
+ 'April',
+ 'May',
+ 'June',
+ 'July',
+ 'August',
+ 'September',
+ 'October',
+ 'November',
+ 'December'
+ ];
+
+ const Chart = ({ data }) => {
+ const config = {
+ labels: labels,
+ datasets: data.map((series, idx, arr) => {
+ let { year, data, color } = series;
+ return {
+ id: year,
+ type: idx < arr.length - 1 ? 'line' : 'bar',
+ label: year,
+ data: data,
+ backgroundColor: color,
+ borderColor: color
+ };
+ })
+ };
+ return