PDA

View Full Version : Problem with inheritance of axes/series in a Chart component?



mx_starter
22 Nov 2014, 1:43 AM
Morning guys,
can you pls. help me with the following issue:

I have a simple column-series chart component, which is placed inside an Ext.window to visualize my data reports.
Everything is looking fine with this, except that when i close the window (closeAction is 'destroy') and then instantiate it again, the old series of the chart are somehow preserved and the chart shows one more column with different color, but absolutely the same values. If i close the window again and re-create it - the columns become 3 and so on.

The chart, in fact, is declared using Ext.define() and the series and axes are declared like this (the code is minimized):



axes:
[
{
type: 'Numeric',
position: 'left',
fields: [],
title: 'Sample Values'
}
],


series:
[
{
type: 'column',
axis: 'left',
xField: 'name',
yField: []
}
]


As you can see, the fields property of the one axis and the yField property of the series are declared as empty arrays.

I do so, because the chart is groupped and the fields count is generated dynamically, they are not known every time the chart is instantiated. In other words, i visualize the working time for employee and the chart can show multiple employee at once (but does not know how many here, it depends on how many employee the user is selected).

That is why, i actually use a separate function (declared within the Ext.define() call), which is called in the chart's initComponent() method and which simply fills these two properties/empty arrays with the appropriate field items every time the chart component is instantiated. Note that this function actually is working on a config object properties - the axes and series are not even created at the time this function is called.

And all this logic is working quite good for me when the chart is shown for the first time. But, when i show it again, then the fields and yField properties contain the fields from the previous call plus these added in the second one and the data gets duplicated on the screen.

I suppose this is due to the fact, that the axes and the series objects are not being destroyed when the chart component is destroyed and are being reused every time preserving its values.

That is why i need your advice - at least, i think that i took a wrong way using initComponent() as a hook for my logic. But this was the only way i found to show the chart which is dynamic, e.g. the series count is unknown and is determined dynamically.

All chart examples in the API docs are beautiful, indeed, but they all use fixed amount of series/fields and are configured with them. Which is impossible in my case.

So any - ideas / advices how to proceed?

Thanks.

mx_starter
22 Nov 2014, 1:53 AM
And may be the correct question is - what happens with the axes/series objects of a Ext.chart.Chart when the chart component is destroyed? Are they somehow being preserved and why/where could be seen with the console/firebug?

bluehipy
23 Nov 2014, 3:50 AM
Charts have some issues. Many :)

The dynamic aspect is not really well handled.

How so ever in your case is probably from how you initiate / destroy the chart. If series seams to get added you probably use the same collections, static references maybe,

Check to see if series , axis fields get cleared correctly or be sure to really destroy and recreate the chart.

Your code sample is not necessarily eloquent :)

mx_starter
23 Nov 2014, 5:01 AM
Charts have some issues. Many :)

The dynamic aspect is not really well handled.

How so ever in your case is probably from how you initiate / destroy the chart. If series seams to get added you probably use the same collections, static references maybe,

Check to see if series , axis fields get cleared correctly or be sure to really destroy and recreate the chart.

Your code sample is not necessarily eloquent :)



As I said, the chart is within a Window, configured with auto destroy: true

So the entire chart is destroyed, also. It can be found within the component manager when the window is closed

bluehipy
23 Nov 2014, 6:28 AM
Chart, series and axis are different instances. Mybae the chart gets destroyed but series not.You should post the way you are coding this.

mx_starter
23 Nov 2014, 11:58 PM
Chart, series and axis are different instances. Mybae the chart gets destroyed but series not.You should post the way you are coding this.

This is exactly what happens, i think.
Well, the code is somehow complicated, but here it is (i have removed the unnecessary parts):

The chart definition:


Ext.define('acm.COMPONENTS.acmChart', {
extend: 'Ext.chart.Chart',
alias: 'widget.acmChart',
id: 'acmChart',animate: {duration: 500},background: {fill: '#fff'},legend: {position: 'right'}
,store: {}
,initComponent: function()
{
var me = this;
me.store = me.prepareStore();
me.callParent(arguments);
}
,axes:
[
{
title: 'Workong hours',
type: 'Numeric',position: 'left', grid: true,
fields: []
},
{
type: 'Category',
grid: true, position: 'bottom',
label: {rotate: {degrees: 270} },
fields: ['itemName']
}
],

series:
[
{
type: 'column',
xField: 'itemName',
yField: [],
title: []
}

]

//prepares the store for the chart
,prepareStore: function()
{
var me = this;
me.prepareAxes(); //prepares the axes
me.prepareSeries(); //prepares the series

//code truncated...


var store = Ext.create('Ext.data.Store', {
autoDestroy: true,
fields: storeFields, //storeFields generated within the truncated code
storeId: 'chartStore',
data: chartData //chartData generated within the truncated code
});

return store;
}

//set up the axes config
,prepareAxes: function()
{
var me = this;

//code truncated...

Ext.each( nodesArray, //nodesArray generated within the truncated code
function(item)
{
me.axes[0].fields.push(item.internalId);
}
);

}

//set up the series config
,prepareSeries: function(nodesArray)
{
var me = this;

//code truncated...

Ext.each( nodesArray, //nodesArray generated within the truncated code
function(item)
{
me.series[0].yField.push(item.internalId);
me.series[0].title.push(item.data.itemName);
}
);

}

});


And the window definition:


Ext.define('acm.COMPONENTS.acmChartWindow', {
extend: 'Ext.window.Window',
alias: 'widget.acmChartWindow',
id: 'acmChartWindow'
,title: 'Title'
,modal: true,closable: true, autoScroll: true, maximizable: true
,width: 800, height: 600, minHeight: 400, minWidth: 550
,autoShow: true, layout: 'fit'


,initComponent: function()
{
var me = this;
me.callParent(arguments);
me.add( {xtype: 'acmChart'} );
}

});


And the window is instantiated using Ext.create().

The result is:
The window is shown and hidden afterwards.

Then i type in the console:

acm.COMPONENTS.acmChart.prototype.series[0].yField

only to see that this array contains the fields from the last call.

mx_starter
24 Nov 2014, 12:15 AM
Something that i missed out:Note that i can easily overcome this by setting the appropriate properties to empty arrays, for example like this:


me.series[0].yField = [];
me.series[0].title = [];
me.axes[0].fields = [];

within the prepare methods, but this seems to be a wrong way to make the things happen.I simply want these series/axes instances to be destroyed when the chart is closedand i'm not sure where to begin from.

bluehipy
24 Nov 2014, 1:30 AM
First of all, a define should never have an id specified :) It is a class not an instance. With an id specified in there all of your instances have the same id.

bluehipy
24 Nov 2014, 1:39 AM
The window has the same id problem.
But your issue is related to the way you are trying to extend the chart.
Properties declared outside of a config are actually static properties. For the simple types you can't really notice it, but for the complex types, as axes and series are, you do notice it, as in your case.

In your base class these properties: axes and series already exists, so in your subclass you should not override them like that. If you want to have specific axes and series, you should do it in your initComponent override.



initComponent: function () {
var me = this;

Ext.apply(me, {
axes:[
{position:'left',...}
]
});

me.callParent(arguments);
}


The way you were doing this have been adding axes and series into prototype rather then into instance.

mx_starter
24 Nov 2014, 3:44 AM
First of all, a define should never have an id specified :) It is a class not an instance. With an id specified in there all of your instances have the same id.

Correct, in fact they have been added for these specifics testing purposes (it is more easily within the console to use Ext.getCmp() ).
But - it is good to be noted anyway :)

mx_starter
24 Nov 2014, 3:47 AM
The way you were doing this have been adding axes and series into prototype rather then into instance.

It seems you are right. The way was wrong from the beginnig and i will start to refactor it immediately. Thanks for your kindly suggestions.

mx_starter
24 Nov 2014, 4:33 AM
Corrected and it is now working as it needs to.
@bluehipy, it will be my pleasure to give you a beer/s should you have your way in Sofia.
Thanks, mate.

bluehipy
24 Nov 2014, 5:05 AM
My pleasure @mx_starter :) I 'm glad it worked for you ;)