PDA

View Full Version : Problems with Radar Chart, when data is JSON



Evolic
21 Aug 2012, 1:31 AM
I noticed following problem, when I used JSON data for Radar Chart:
- no chart labels are loaded
- no grid are loaded
- only max value for chart is calculated and rendered as the circles

If I use function
storeX.loadData(arrayData) with some prepared default data all above problems didn't take a place.
but it is wired to use store.loadData(arrayData) before normal storeX.load().

I also noticed that labels for ZERO values are also not rendered.
Is it a right behaviour?

I had problems with identify which part of code is related to mentioned labels so I made this post.

RadarFillJson.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<title>Filled Radar Chart</title>
<link rel="stylesheet" type="text/css" href="../../resources/css/ext-all.css" />
<link rel="stylesheet" type="text/css" href="../shared/example.css" />

<!-- GC -->

<script type="text/javascript" src="../../ext-all-debug.js"></script>
<script type="text/javascript" src="../example-data.js"></script>
<script type="text/javascript" src="RadarFillJson.js"></script>
</head>
<body id="docbody">
<h1>Radar Fill Example</h1>
<div style="margin: 10px;">
<p>
Display 3 sets of random data in a filled radar series. Reload data will randomly generate a new set of data in the store. Note this example uses a radial axis. Click or hover on the legend items to highlight and remove them from the chart. <a href="RadarFill.js">View Source</a>
</p>
</div>
</body>
</html>


RadarFillJson.js

Ext.require('Ext.chart.*');
Ext.require(['Ext.Window', 'Ext.fx.target.Sprite', 'Ext.layout.container.Fit', 'Ext.window.MessageBox']);

var storeX;
var data;

Ext.onReady(function () {

Ext.define('Overview', {
extend: 'Ext.data.Model',
fields: [{
name: 'name'
}, {
name: 'points', type: 'int'
}]
});

storeX = new Ext.data.JsonStore({
// store configs
autoDestroy: true,
storeId: 'storeX',
model: 'Overview',
proxy: {
type: 'ajax',
url: 'overview.json',
reader: {
type: 'json'//,
//root: 'images',
//idProperty: 'name'
}
}

//alternatively, a Ext.data.Model name can be given (see Ext.data.Store for an example)
//fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
});

data = [{
"name" : "Drones",
"points" : 24000
}, {
"name" : "Electronics",
"points" : 56750
}, {
"name" : "Engineering",
"points" : 23072
}, {
"name" : "Gunnery",
"points" : 15573
}, {
"name" : "Industry",
"points" : 23072
}, {
"name" : "Mechanic",
"points" : 40072
}, {
"name" : "Missiles",
"points" : 252494
}, {
"name" : "Navigation",
"points" : 23072
}, {
"name" : "Science",
"points" : 65984
}, {
"name" : "Social",
"points" : 24000
}, {
"name" : "Spaceship Command",
"points" : 105582
}, {
"name" : "Trade",
"points" : 10829
}];

// storeX.loadData(data);

storeX.load({
params: {
date: '2011-09-04'
}
});

var chart = Ext.create('Ext.chart.Chart', {
id: 'chartCmp',
xtype: 'chart',
style: 'background:#fff',
theme: 'Category2',
insetPadding: 20,
animate: true,
store: storeX,

/*legend: {
position: 'right'
},*/
axes: [{
type: 'Radial',
position: 'radial',
label: {
display: true
}
}],
series: [{
showInLegend: true,
type: 'radar',
xField: 'name',
yField: 'points',
title: 'Points',
showMarkers: true,
markerConfig: {
radius: 3,
size: 3,
fill: 'rgb(69,109,159)'
},
style: {
opacity: 0.4
},
tips: {
trackMouse: true,
// width: 74,
// height: 38,
renderer: function(storeItem, item) {
var fn = Ext.util.Format.numberRenderer('0,0');

this.setSize(230, 40);
this.setTitle('<div class="navy ar">`' + storeItem.get('name') + '` points<br/>'
+ fn(storeItem.get('points')) + '</div>');
}
}
}]
});

var win = Ext.create('Ext.Window', {
width: 700,
height: 550,
minHeight: 400,
minWidth: 550,
hidden: false,
shadow: false,
maximizable: true,
style: 'overflow: hidden;',
title: 'Filled Radar Chart',
renderTo: Ext.getBody(),
layout: 'fit',
tbar: [{
text: 'Save Chart',
handler: function() {
Ext.MessageBox.confirm('Confirm Download', 'Would you like to download the chart as an image?', function(choice){
if(choice == 'yes'){
chart.save({
type: 'image/png'
});
}
});
}
}, {
text: 'Reload Data',
handler: function() {
store1.loadData(data);
}
}, {
enableToggle: true,
pressed: true,
text: 'Animate',
toggleHandler: function(btn, pressed) {
var chart = Ext.getCmp('chartCmp');
chart.animate = pressed ? { easing: 'ease', duration: 500 } : false;
}
}],
items: [chart]
});
});


overview.json

[{
"name" : "Drones",
"points" : 24000,
}, {
"name" : "Electronics",
"points" : 56750,
}, {
"name" : "Engineering",
"points" : 23072,
}, {
"name" : "Gunnery",
"points" : 15573,
}, {
"name" : "Industry",
"points" : 23072,
}, {
"name" : "Mechanic",
"points" : 40072,
}, {
"name" : "Missile",
"points" : 252494,
}, {
"name" : "Navigation",
"points" : 23072,
}, {
"name" : "Science",
"points" : 65984,
}, {
"name" : "Social",
"points" : 24000,
}, {
"name" : "Spaceship",
"points" : 105582,
}, {
"name" : "Trade",
"points" : 10829,
}]

scottmartin
21 Aug 2012, 11:40 AM
Can you specify if you are using Ext4.1.1 GA?

Scott.

vietits
22 Aug 2012, 12:04 AM
The problem with your chart in case you load data from json file is that the chart is drawn before store has completed loading data. Try to create and draw chart when store complete loading data from json file.

Evolic
22 Aug 2012, 10:51 AM
I am using Ext 4.1.1
I can provide the screenshots if you don't understand my problem.

From my point of view there is something wrong, becasue some part of chart is rendered correctly (data), and some not (categories and grid).

vietits
22 Aug 2012, 7:08 PM
The problem here is because there is a difference in drawing chart between the first time and next times. In the first time of drawing, the chart will create sprites for its axes and its series. From that on, each time the chart needs to be redrawn, it will only change values of these sprites to reflect their new values but not re-create sprites. These sprites include:

Sprite for axes:

Sprites for circle: Number of these sprites is determined by steps which is default set to 10.
Sprites for radial lines: Number of these sprites is determined by the number of records in store.
Sprites for labels:

Sprites for scales: Number of these sprites is determined by steps (as sprites for circle above).
Sprites for categories: Number of these sprites is determined by the number of records in store.


Sprites for series.
So, if at the first time of drawing chart store has no data (as in case of asynchronous loading data from server), there will be no sprite for radial lines and categories.

That's the reason why I said in my previous post that you should wait for store completes its loading data before draw chart. Below are some other solutions to fix this problem:

- Create and draw chart with some 'fake' data in store provided that number of records will be equal to the real number of records. After that, call store.load(...) to load data from server. Example:


Ext.onReady(function(){
var fakeData = [];
for (var i = 0; i < 12 ; i++ ){
fakeData.push({name: '', points: 0});
}


Ext.define('Overview', {
extend: 'Ext.data.Model',
fields: [{
name: 'name'
}, {
name: 'points', type: 'int'
}]
});


var storeX = new Ext.data.Store({
autoDestroy: true,
storeId: 'storeX',
model: 'Overview',
data: fakeData,
proxy: {
type: 'ajax',
url: 'overview.json',
reader: {
type: 'json'
}
}
});


var chart = Ext.create('Ext.chart.Chart', {
id: 'chartCmp',
xtype: 'chart',
style: 'background:#fff',
theme: 'Category2',
insetPadding: 20,
animate: false,
store: storeX,


/*legend: {
position: 'right'
},*/
axes: [{
type: 'radial',
position: 'bottom',
label: {
display: true
}
}],
series: [{
showInLegend: true,
type: 'radar',
xField: 'name',
yField: 'points',
title: 'Points',
showMarkers: true,
markerConfig: {
radius: 3,
size: 3,
fill: 'rgb(69,109,159)'
},
style: {
opacity: 0.4
},
tips: {
trackMouse: true,
// width: 74,
// height: 38,
renderer: function(storeItem, item) {
var fn = Ext.util.Format.numberRenderer('0,0');


this.setSize(230, 40);
this.setTitle('<div class="navy ar">`' + storeItem.get('name') + '` points<br/>'
+ fn(storeItem.get('points')) + '</div>');
}
}
}]
});

var win = Ext.create('Ext.Window', {
width: 550,
height: 300,
minHeight: 300,
minWidth: 550,
hidden: false,
shadow: false,
maximizable: true,
style: 'overflow: hidden;',
title: 'Filled Radar Chart',
renderTo: Ext.getBody(),
layout: 'fit',
tbar: [{
text: 'Save Chart',
handler: function() {
Ext.MessageBox.confirm('Confirm Download', 'Would you like to download the chart as an image?', function(choice){
if(choice == 'yes'){
chart.save({
type: 'image/png'
});
}
});
}
}, {
text: 'Load Inline Data',
handler: function() {
storeX.loadData([{
"name" : "Drones",
"points" : 0
}, {
"name" : "Electronics",
"points" : 0
}, {
"name" : "Engineering",
"points" : 0
}, {
"name" : "Gunnery",
"points" : 0
}, {
"name" : "Industry",
"points" : 0
}, {
"name" : "Mechanic",
"points" : 40072
}, {
"name" : "Missiles",
"points" : 252494
}, {
"name" : "Navigation",
"points" : 23072
}, {
"name" : "Science",
"points" : 65984
}, {
"name" : "Social",
"points" : 14000
}, {
"name" : "Spaceship Command",
"points" : 205582
}, {
"name" : "Trade",
"points" : 20829
}]);
}
}, {
text: 'Load Json Data',
handler: function() {
storeX.load();
}
}, {
enableToggle: true,
pressed: true,
text: 'Animate',
toggleHandler: function(btn, pressed) {
var chart = Ext.getCmp('chartCmp');
chart.animate = pressed ? { easing: 'ease', duration: 500 } : false;
}
}],
items: [chart]
});
});

- Force the chart to re-create sprites and other initialization again each time redrawing. This way, you can change number of records each time of loading. Example:


Ext.onReady(function(){
Ext.define('Overview', {
extend: 'Ext.data.Model',
fields: [{
name: 'name'
}, {
name: 'points', type: 'int'
}]
});


var storeX = new Ext.data.Store({
autoDestroy: true,
storeId: 'storeX',
model: 'Overview',
proxy: {
type: 'ajax',
url: 'overview.json',
reader: {
type: 'json'
}
}
});


var chart = Ext.create('Ext.chart.Chart', {
id: 'chartCmp',
xtype: 'chart',
style: 'background:#fff',
theme: 'Category2',
insetPadding: 20,
animate: false,
store: storeX,


/*legend: {
position: 'right'
},*/
axes: [{
type: 'radial',
position: 'bottom',
label: {
display: true
}
}],
series: [{
showInLegend: true,
type: 'radar',
xField: 'name',
yField: 'points',
title: 'Points',
showMarkers: true,
markerConfig: {
radius: 3,
size: 3,
fill: 'rgb(69,109,159)'
},
style: {
opacity: 0.4
},
tips: {
trackMouse: true,
// width: 74,
// height: 38,
renderer: function(storeItem, item) {
var fn = Ext.util.Format.numberRenderer('0,0');


this.setSize(230, 40);
this.setTitle('<div class="navy ar">`' + storeItem.get('name') + '` points<br/>'
+ fn(storeItem.get('points')) + '</div>');
}
}
}],
listeners: {
beforerefresh: function(chart){
chart.surface.removeAll(true);
chart.axes.each(function(axis){
axis.sprites = null;
axis.labelArray = null;
});
chart.series.each(function(series){
series.radar = null;
});
}
}
});

var win = Ext.create('Ext.Window', {
width: 550,
height: 300,
minHeight: 300,
minWidth: 550,
hidden: false,
shadow: false,
maximizable: true,
style: 'overflow: hidden;',
title: 'Filled Radar Chart',
renderTo: Ext.getBody(),
layout: 'fit',
tbar: [{
text: 'Save Chart',
handler: function() {
Ext.MessageBox.confirm('Confirm Download', 'Would you like to download the chart as an image?', function(choice){
if(choice == 'yes'){
chart.save({
type: 'image/png'
});
}
});
}
}, {
text: 'Load Inline Data',
handler: function() {
storeX.loadData([{
"name" : "Drones",
"points" : 0
}, {
"name" : "Electronics",
"points" : 0
}, {
"name" : "Engineering",
"points" : 0
}, {
"name" : "Gunnery",
"points" : 0
}, {
"name" : "Industry",
"points" : 0
}, {
"name" : "Mechanic",
"points" : 40072
}, {
"name" : "Missiles",
"points" : 252494
}, {
"name" : "Navigation",
"points" : 23072
}, {
"name" : "Science",
"points" : 65984
}, {
"name" : "Social",
"points" : 14000
}, {
"name" : "Spaceship Command",
"points" : 205582
}, {
"name" : "Trade",
"points" : 20829
}]);
}
}, {
text: 'Load Json Data',
handler: function() {
storeX.load();
}
}, {
enableToggle: true,
pressed: true,
text: 'Animate',
toggleHandler: function(btn, pressed) {
var chart = Ext.getCmp('chartCmp');
chart.animate = pressed ? { easing: 'ease', duration: 500 } : false;
}
}],
items: [chart]
});
});

Evolic
23 Aug 2012, 3:21 AM
B) Thank you, that helped.

I have one more question: is there any why to add series dynamically?
Let's say I have Radar Chart with one series or without any (at the beginning)
and would like to pick up, up to 3 series from about 15.

I tried chart.series.add(config), where config was typically radar config from the samples, but it didn't work.
I need to add real series configuration dynamically.. to make something like Compare method.
The same question is related to Bar charts..

vietits
23 Aug 2012, 5:47 AM
Try this:


Ext.onReady(function(){
Ext.define('Overview', {
extend: 'Ext.data.Model',
fields: [{
name: 'name'
}, {
name: 'points', type: 'int'
}]
});


var storeX = new Ext.data.Store({
autoDestroy: true,
storeId: 'storeX',
model: 'Overview',
proxy: {
type: 'ajax',
url: 'overview.json',
reader: {
type: 'json'
}
}
});


var series = {
showInLegend: true,
type: 'radar',
xField: 'name',
yField: 'points',
title: 'Points',
showMarkers: true,
markerConfig: {
radius: 3,
size: 3,
fill: 'rgb(69,109,159)'
},
style: {
opacity: 0.4
},
tips: {
trackMouse: true,
renderer: function(storeItem, item) {
var fn = Ext.util.Format.numberRenderer('0,0');
this.setSize(230, 40);
this.setTitle('<div class="navy ar">`' + storeItem.get('name') + '` points<br/>'
+ fn(storeItem.get('points')) + '</div>');
}
}
};


var chart = Ext.create('Ext.chart.Chart', {
id: 'chartCmp',
xtype: 'chart',
style: 'background:#fff',
theme: 'Category2',
insetPadding: 20,
animate: false,
store: storeX,
axes: [{
type: 'radial',
position: 'bottom',
label: {
display: true
}
}],
listeners: {
beforerefresh: function(chart){
chart.surface.removeAll(true);
chart.axes.each(function(axis){
axis.sprites = null;
axis.labelArray = null;
});
chart.series.each(function(series){
series.radar = null;
});
}
}
});

var win = Ext.create('Ext.Window', {
width: 550,
height: 300,
minHeight: 300,
minWidth: 550,
hidden: false,
shadow: false,
maximizable: true,
style: 'overflow: hidden;',
title: 'Filled Radar Chart',
renderTo: Ext.getBody(),
layout: 'fit',
tbar: [{
text: 'Load series',
handler: function() {
chart.series.add(series);
chart.refresh();
}
}, {
text: 'Load Inline Data',
handler: function() {
storeX.loadData([{
"name" : "Drones",
"points" : 0
}, {
"name" : "Electronics",
"points" : 0
}, {
"name" : "Engineering",
"points" : 0
}, {
"name" : "Gunnery",
"points" : 0
}, {
"name" : "Industry",
"points" : 0
}, {
"name" : "Mechanic",
"points" : 40072
}, {
"name" : "Missiles",
"points" : 252494
}, {
"name" : "Navigation",
"points" : 23072
}, {
"name" : "Science",
"points" : 65984
}, {
"name" : "Social",
"points" : 14000
}, {
"name" : "Spaceship Command",
"points" : 205582
}, {
"name" : "Trade",
"points" : 20829
}]);
}
}, {
text: 'Load Json Data',
handler: function() {
storeX.load();
}
}, {
enableToggle: true,
pressed: true,
text: 'Animate',
toggleHandler: function(btn, pressed) {
var chart = Ext.getCmp('chartCmp');
chart.animate = pressed ? { easing: 'ease', duration: 500 } : false;
}
}],
items: [chart]
});
});