I've got stuck trying to add a legend to a Dojo chart with multiple StoreSeries. The legend is being drawn before the store series have returned and assigned a symbol.
I'm using JsonRest as the store, connecting to ASP.NET WebApi2 site to access data in SQL Server. The chart draws fine, only the legend is failing to draw correctly.
I've tracked the issue down to the legend module, in the refresh function. The array of series is populated, but none of them have been assigned a symbol at the point the legend is drawn:
var s = this.series || this.chart.series;
// AT THIS POINT s CONTAINS ALL MY SERIES
if( s.length == 0 ) {
return;
}
if ( s[0].chart.stack[0].declaredClass == "dojox.charting.plot2d.Pie" ) {
//Pie chart stuff
}
else {
arr.forEach( s, function( x ) {
// AT THIS POINT x.dyn IS STILL EMPTY = legend with labels but no symbol
this._addLabel( x.dyn, x.legend || x.name );
}, this );
}
Is there something I can do to make the legend wait for all the store series to have returned?
I've tried using all/when on various properties of the chart but they all seem to return instantly.
EDIT: Here is the code used to make the chart, I'm pretty sure I just need to find a way to check that the chart has finished rendering before adding the legend, but I haven't found the right thing to check for:
init: function() {
// Create the chart content
this._chart = new Chart( this.chartNode );
// Add plots
this._chart.addPlot( 'default', {
type: Lines,
hAxis: 'x',
vAxis: 'y'
} );
this._chart.addPlot( 'secondary', {
type: StackedAreas,
hAxis: 'x',
vAxis: 'y'
} );
// Add axis
var xAxis = {
minorTicks: false,
titleGap: 8,
titleFont: "normal normal normal 12px sans-serif",
titleOrientation: 'away'
};
var yAxis = {
vertical: true,
includeZero: true,
titleGap: 8,
titleFont: "normal normal normal 12px sans-serif",
titleOrientation: 'axis'
};
this._chart.addAxis( 'x', xAxis );
this._chart.addAxis( 'y', yAxis );
var lineStore = new ObservableStore( JsonRest( { target: this.lineUri } ) );
// Add series
var opts = {};
var plot = { plot: 'default' };
this._chart.addSeries( "Target", new StoreSeries( lineStore, opts, 'total'), plot );
this._chart.addSeries( "Threshold", new StoreSeries( lineStore, opts, 'target'), plot );
this._chart.addSeries( "YTD", new StoreSeries( lineStore, opts, 'ytd'), plot );
plot = { plot: 'secondary' };
// areaList is [{ name: 'hello', id: 0 }]
array.forEach( this.areaList, lang.hitch( this, function( area ) {
var store = new StoreSeries( new ObservableStore( JsonRest( { target: this.areaUri + '/' + String( area.id ) } ) ), {}, 'total');
this._chart.addSeries( area.name, store, plot );
}));
// Add Grid
this._chart.addPlot( 'grid', { type: Grid,
hAxis: 'x',
vAxis: 'y',
hMajorLines: true,
hMinorLines: false,
vMajorLines: true,
vMinorLines: false,
majorHLine: { color: '#ACACAC', width: 0.5 },
majorVLine: { color: '#ACACAC', width: 0.5 }
} );
// Apply theme
this._chart.setTheme( MyChartTheme );
// Draw!
this._chart.render();
// Legend
new Legend( { chart: this._chart, horizontal: false, title: 'Legend' }, this.legendNode );
},
I found a solution to the legend being created before all series were ready.
Using the deferred query results of a cache store and a memory store instead of the JsonRest store, we can wait until all series are ready before creating the legend.
This method only requires one call to the rest service, so is much faster than connecting the store series directly to the rest store (which queries once per series). There is still a delay before the chart appears on the page, and there may be issues using a memory store with large datasets. I have used this method with ~15000 records without any issues.
Corrected code: