We've used the open source chart.js to implement our charts in lightning components but we've noticed that if the chart's data set changes, e.g. a picklist that the user can select a different value from which generates a different data set for the chart, the chart flickers between the old & new values when the mouse moves over it.
Looking around the web the solution from Chart.js is to keep a global variable in the javascript which holds the chart object when it is created & then destroy that chart object before re-creating a new one (see https://stackoverflow.com/questions/28609932/chartjs-resizing-very-quickly-flickering-on-mouseover). However I don't think that mechanism is possible from within a lightning component, but I may be wrong. Any suggestions?
[Edit -Here's a working example of the problem. After the chart is displayed if you check the checkbox & then move the mouse over the chart it will toggle between the old & new chart at certain positions. Obviously in real component I'd be calling an apex controller etc. but I thought a simplified version would be easier to understand. For it to work you'll need to create a static resource called Chart that contains the Chart.js from [http://www.chartjs.org/]
(AndeeChart.cmp)
<aura:component implements="flexipage:availableForAllPageTypes" access="global">
<ltng:require scripts="{!$Resource.Chart}" afterScriptsLoaded="{!c.init}"/>
<aura:attribute name="dataset" type="String" default="1" description="Which set of data to display in the chart. Will be either 1 or 2"/>
<div class="slds-grid slds-wrap">
<div class="slds-col slds-size--1-of-1 slds-small-size--1-of-2 slds-medium-size--1-of-4">
<ui:inputCheckbox label="Toggle Data?" click="{!c.updateDataset}"/>
</div>
<div class="slds-col slds-size--1-of-1 slds-small-size--1-of-2 slds-medium-size--3-of-4">
Chart1<br></br>
<canvas aura:id="andeeChart" id="andeeChart123"/>
</div>
</div>
(AndeeChartController.js)
({
init : function(component, event, helper) {
helper.setupChart(component);
},
updateDataset : function(component, event, helper) {
var dataset = component.get('v.dataset');
if (dataset == '1'){
dataset = '2';
} else {
dataset = '1';
}
component.set('v.dataset', dataset)
helper.setupChart(component);
}
})
(AndeeChartHelper.js)
({
setupChart : function(component) {
// Normally call apex controller to get data but hardcoded for demonstration purposes
var dataset = component.get('v.dataset');
var data;
var jsonRetVal
if (dataset == '1'){
jsonRetVal = {"chartLabels":["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],"chartData":[1.00,3.00,6.00,10.00,15.00,21.00]}
} else {
jsonRetVal = {"chartLabels":["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],"chartData":[21.00,3.00,16.00,19.00,17.00,12.00]}
}
var el = component.find('andeeChart').getElement();
var ctx = el.getContext('2d');
// Need something here to destroy any chart that is currently being displayed to stop the 'flicker'
new Chart(ctx, {
type: 'bar',
data: {
labels: jsonRetVal.chartLabels,
datasets: [
{
label: "Data",
fillColor: "rgba(220,220,220,1)",
strokeColor: "rgba(220,220,220,1)",
data: jsonRetVal.chartData
}
]
},
options: {
hover: {
mode: "none"
},
scales: {
yAxes: [{
ticks: {
beginAtZero:true
}
}]
}
}
});
}
})