Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updating data & options #78

Closed
Techn1x opened this issue Jul 5, 2017 · 14 comments · Fixed by #104
Closed

Updating data & options #78

Techn1x opened this issue Jul 5, 2017 · 14 comments · Fixed by #104

Comments

@Techn1x
Copy link
Contributor

Techn1x commented Jul 5, 2017

So from what I've read, it seems with the use of chartjs 2.0+, chart.js should just automatically determine what data values have changed and then animate the change to those new values (rather than doing the entire initial load animation).

Similarly, from chartjs 2.5+, the same should occur with options.

Using ember-cli-charts with 3.3.0 should have both of these features since it uses chartjs 2.6.

Due to this new feature, updating data/options in ember-cli-chart has been simplified down to essentially just

chart.config.data = data;
chart.config.options = options;
chart.update();

However, at least for me, it seems that it doesn't work at all. When some value in data changes, it replaces the entire chart.config.data with the new data which causes the animation to reload from the beginning (rather than just animating the changed value).

Similarly, changing a single option and then replacing the entire chart.config.options actually doesn't seem to apply the new options at all.

The following example snippets work though, if they are placed in the update chart function of ember-cli-chart instead of the existing chart.config.data = data; and chart.config.options = options; statements;
Changing data (example, works)

myChart.config.data.datasets[0].data = [36, 19, 3, 5, 2, 3];

Changing options (example, works)

myChart.config.options.legend = {
    display: true,
    position: 'bottom'
};

or

myChart.config.options.legend.position = 'bottom';

Am I missing something here? Is data/options changing working for anyone else without having to resort to modify the individual datasets/options?

Thanks

@aomran
Copy link
Collaborator

aomran commented Jul 5, 2017

I experimented with their live demo here: http://www.chartjs.org/samples/latest/charts/pie.html

Replacing the data object as a whole doesn't work. If you copy the object, modify it and then assign it again then it will work ... which defeats the purpose. I suggest creating a ticket in the chartjs repo.

@Techn1x
Copy link
Contributor Author

Techn1x commented Jul 6, 2017

Thanks, will do.

For the moment, to get the data change animation to work properly, I am just overriding the ember-cli-chart updateChart() function and doing the following

updateChart: function() {
	...
	// Need to iterate over the data and set on a much lower level, or else the chart does a full redraw
		
	// If chart data has been set previously, just update
	if (chart.config.data && chart.config.data.datasets && chart.config.data.datasets.length > 0) {
		// For the datasets in the new data
		for (var i = 0; i < data.datasets.length; i++) {
			// Add new datasets to chart data if not there already
			if(!chart.config.data.datasets[i]) {
				chart.config.data.datasets[i] = data.datasets[i];	// Add new dataset
			} else {
				// Else replace existing chart datasets on a key by key basis
				Object.keys(data.datasets[i]).forEach((key) => {
					chart.config.data.datasets[i][key] = data.datasets[i][key];
				});
			}
		}
		// If chart data had more datasets than our new data, delete the extra datasets
		while(chart.config.data.datasets.length > data.datasets.length) {
			chart.config.data.datasets.pop();
		}
	} else {
		// First load
		chart.config.data = data;
	}
	...
}

Somewhere else..

buildNewData: function() {
	newdata = { ... };
	this.set('chartObject.data',newdata);
}
{{ember-chart type=type data=chartObject.data}}

But this is obviously inherently unreliable and I thought this was what chartjs 2.0+ was supposed to avoid...

@tchan
Copy link

tchan commented Aug 2, 2017

@aomran How do I get the chart instance in Ember to call update() on it?
I'm looking at these examples https://jsfiddle.net/red_stapler/u5aanta8/1/
where they do

var myLineChart = Chart.Line(canvas,{
	data:data,
  options:option
});

and then do something like

myLineChart.data.datasets[0].data[7] = 60;
myLineChart.data.labels[7] = "Newly Added";
myLineChart.update();

Just wondering what is the ember equivalent for this or if you can point me in the right direction

@Techn1x
Copy link
Contributor Author

Techn1x commented Aug 2, 2017

Hi @tchan ,

If you have chart data defined like this

chartdata: {
	labels: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
	datasets: [{
		label: "DFM Alerts",
		backgroundColor: "rgba(255,99,132,0.2)",
		borderColor: "rgba(255,99,132,0.8)",
		data: [65, 59, 80, 81, 56, 55, 40, 10, 57, 105, 39, 56]
	}, {
		label: "TPMS Alerts",
		backgroundColor: "rgba(54,162,235,0.2)",
		borderColor: "rgba(54,162,235,0.8)",
		data: [28, 48, 40, 19, 86, 27, 90, 32, 26, 49, 41, 5]
	}]
}

And an ember-chart declared like this

{{ember-chart data=chartdata}}

And you then need to modify that data, do it like so..

var cdata = this.get('chartdata');
cdata.datasets[0].data[7] = 60;
cdata.labels[7] = "New August";
this.set('chartdata',cdata);

This will then trigger an observer in the ember-chart, which will set the data and then call update() for you
See here;
https://github.com/aomran/ember-cli-chart/blob/master/addon/components/ember-chart.js#L32-L39

Unfortunately this method of updating the data will cause a full refresh/redraw of the graph, (which is what this github issue is about) - in which case you then need to override updateChart() like I have above (but worry about this when you have the update working first)

Hope that helps!

@aomran
Copy link
Collaborator

aomran commented Aug 2, 2017

@tchan yeah you could subclass and implement your update function. I've gone down that road before, and unfortunately, the code gets messy when trying to do this for all chart types. This library is a small wrapper around the Chartjs project -- if anyone has a fix for the update issue then, please contribute upstream to that project. It would be good not to have to mutate every data point manually.

@tchan
Copy link

tchan commented Aug 3, 2017

Yeah, I can't get the update working... :(
This is my data parameter where I initialize the data array as []

  actionTypeData: computed('labels', 'data', function() {
    return {
      labels: get(this, 'labels'),
      datasets: [{
          backgroundColor: ['#60C0DC', '#EEAC57', '#5FB760', '#D75452'],
          borderWidth: 1,
          data: []
      }]
    };
  })

I then have a computed function (sorry it's a bit shit) that gets data from an api call, and pushes the values into the original data array but it doesn't seem to be updating.

  data: computed(function() {

    let _this = this;
    let actionTypeData = get(this, 'actionTypeData');
    // console.log('actionTypeData', actionTypeData.datasets[0].data);
    let data = actionTypeData.datasets[0].data;
    let ajax = get(this, 'ajax');
    let promise = ajax.request(`/api/bison/reporting/action/1/`);
    var model = PromiseArray.create({ promise });
    let arr = [];
    model.then(function(item) {
      // console.log('item:', item);
        item.forEach(function(action) {
          // console.log('action', action);
          actionTypeData.datasets[0].data.push(action.cnt);
        });

        // console.log('actionTypeData', actionTypeData.datasets[0].data);
        _this.set('actionTypeData', actionTypeData);
        // console.log(actionTypeData);
        return arr;
    })
  }),

@Techn1x
Copy link
Contributor Author

Techn1x commented Aug 4, 2017

Show me your line in handlebars?
Something like {{ember-chart ... }}

Assuming it's set like {{ember-chart data=actionTypeData}}, and you're definitely sure that the computed function data is being called, try doing a this.set('actionTypeData',null) and then setting this.set('actionTypeData',actionTypeData) - see if that works. Just trying to make sure the updateChart() observer is being called.

@tchan
Copy link

tchan commented Aug 5, 2017

@Techn1x That did the trick. I had something silly instead... apologies

@Techn1x
Copy link
Contributor Author

Techn1x commented Aug 5, 2017

No problem at all, glad it worked in the end

@tchan
Copy link

tchan commented Sep 13, 2017

@Techn1x have you had any issues for your charts not redrawing/updating since the 2.7 release of chartjs (a few days ago)?

When I set the data to null and then re-set it to something else the updateChart() observer is no longer being called. I'll try to get an ember-twiddle up when I have time.

Ember twiddle: https://ember-twiddle.com/29454f72774bb45efb331483dd9e93c9?openFiles=templates.application.hbs%2C

@Techn1x
Copy link
Contributor Author

Techn1x commented Sep 13, 2017

Hmm, not entirely sure what has broken here or why. Not currently in a position to check my own webapp at the moment to see if it updates either.

If you need it to work though, first update ember-cli-chart to 3.3.2 (this swaps from using observers to using didUpdateAttrs() component lifecycle hook which should be better)

Now I noticed that for some reason in the twiddle, even after going to 3.3.2, didUpdateAttrs() isn't being called automatically when you set the new testData, this could be because it's technically the same object I guess? (not sure) but if you want to fix it, add the line this.notifyPropertyChange('testData'); after you do the this.set('testData',cdata);. This will fire the didUpdateAttrs() hook and cause the chart to update

@tchan
Copy link

tchan commented Sep 14, 2017

How strange. It causes the update but I'm also after the animation just for the user experience. Also interested to know if your web app was affected, please keep me updated (if you remember :) )

@Techn1x
Copy link
Contributor Author

Techn1x commented Sep 14, 2017

3.3.2 also introduced an animate attribute on the ember-chart component (by default it's false)

So also set animate=true like so;
{{ember-chart type='pie' data=testData height=300 width=300 options=options animate=true}}

@alltouch
Copy link

We got same error in our project. I checked docs for chart.js and found where issue comes from.

Here is link to PR implemented what we want:
chartjs/Chart.js#3587

Here is whole update function from that PR:

function updateConfig(chart) {
+		var newOptions = chart.options;
+
+		// Update Scale(s) with options
+		if (newOptions.scale) {
+			chart.scale.options = newOptions.scale;
+		} else if (newOptions.scales) {
+			newOptions.scales.xAxes.concat(newOptions.scales.yAxes).forEach(function(scaleOptions) {
+				chart.scales[scaleOptions.id].options = scaleOptions;
+			});
+		}
+
+		// Tooltip
+		chart.tooltip._options = newOptions.tooltips;
+	}

So if we want to explain Chart.js to refresh it we need update chart.options variable instead of chart.config.options variable which ember-cli-chart set when we provide new data to it.

P.S. i will implement fix for it. but don't know how much time it will take for me.

jandillmann added a commit to jandillmann/ember-cli-chart that referenced this issue Jan 10, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants