Ext JS 6學習文檔-第7章-圖表
使用圖表
本章中將探索在 ExtJS 中使用不同類型的圖表並使用一個名為費用分析的示例項目結束本章所學。以下是將要所學的內容:
- 圖表類型
- 條形圖 和 柱形圖 圖表
- 區域 和 折線 圖表
- 餅圖 圖表
- 3 D 圖表
- 費用分析 – 示例項目
圖表
在第一章中提過,我說 ExtJS 是一站式的幾乎能滿足你對所有的 JavaScript 框架的需求。這當然還包括了圖表功能。
圖表類型
有三種類型的圖表:笛卡爾圖表,極坐標圖表, 和 空間圖表。
笛卡爾圖表
Ext.chart.CartesianChart (xtype: cartesian or chart)
一個笛卡爾圖表具有兩個方向:X 和 Y 。默認 X 是水平的,Y 是垂直的。使用笛卡爾坐標圖表有柱形圖,條形圖,區域,折線和散射。
極坐標圖表
Ext.chart.PolarChart (xtype: polar)
這個圖表有兩個軸:角向和徑向。圖表的標繪值用極坐標來表達,有餅圖和雷達圖。
空間圖表
Ext.chart.SpaceFillingChart (xtype: spacefilling)
這個圖表填充圖表的面積。
條形圖和柱狀圖
使用條形圖和柱狀圖,你至少需要提供 store ,axes ,series。
基本的柱狀圖
首先,我們創建一個 store 使用硬編碼的內置數據,如以下代碼所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
Ext.define('MyApp.model.Population', {
extend : 'Ext.data.Model',
fields : [ 'year', 'population' ]
});
Ext.define('MyApp.store.Population', {
extend : 'Ext.data.Store',
storeId : 'population',
model : 'MyApp.model.Population',
data : [{
"year" : "1610",
"population" : 350
},{
"year" : "1650",
"population" : 50368
},{
"year" : "1700",
"population" : 250888
},{
"year" : "1750",
"population" : 1170760
},{
"year" : "1800",
"population" : 5308483
},{
"year" : "1900",
"population" : 76212168
},{
"year" : "1950",
"population" : 151325798
},{
"year" : "2000",
"population" : 281421906
},{
"year" : "2010",
"population" : 308745538
}]
});
var store = Ext.create("MyApp.store.Population");
|
使用 Ext.chart.CartesianChart (xtype: cartesian 或 chart ) 創建圖表並應用上面所創建的 store 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
Ext.create('Ext.Container', {
renderTo : Ext.getBody(),
width : 500,
height : 500,
layout : 'fit',
items : [ {
xtype : 'chart',
insetPadding : {
top : 60,
bottom : 20,
left : 20,
right : 40
},
store : store,
axes : [ {
type : 'numeric',
position : 'left',
grid : true,
title : {
text : 'Population in Millions',
fontSize : 16
}
}, {
type : 'category',
title : {
text : 'Year',
fontSize : 16
},
position : 'bottom'
}],
series : [ {
type : 'bar',
xField : 'year',
yField : [ 'population' ]
} ],
sprites : {
type : 'text',
text : 'United States Population',
font : '25px Helvetica',
width : 120,
height : 35,
x : 100,
y : 40
}
}]
});
|
前面代碼中比較重要的是 axes ,series ,和 sprite 。axes 有三種類型:numeric ,time ,和 category 。
而在 series 中,你可以看到設置類型為 bar 。在 ExtJS 中,將會呈現為柱狀圖或條形圖, 雖然你指定了類型為 bar ,但是默認是作為柱狀圖展示的,如果你想要條形圖,需要在圖表配置中設置 flipXY 為 true 。
這里 sprites 的配置相當簡單。sprites 是一個可選項,不是必須的。sprites 這里使用的 text 的類型,就是畫出來一個圖形,設置字體 25 號,寬度 120,高度 35,並且 x 的位置為 100 ,y 的位置是 40 ,sprites 是ExtJS 中畫圖的一個對象,這里我們只是用來寫了一行字。sprites 也可以接受一個數組,但是這里我們只用一個設置。
這個 insetPadding 屬性是用於指定圖表的 padding 。
以下截圖為輸出結果:
條形圖
如之前所說,為了得到條形圖,你可以使用同樣的代碼,但要指定 flipXY 為 true 並改變相應坐標的位置,下面把原來 year 換到了左邊。如以下代碼所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
Ext.create('Ext.Container', {
renderTo : Ext.getBody(),
width : 500,
height : 500,
layout : 'fit',
items : [ {
xtype : 'chart',
flipXY : true,
insetPadding : {
top : 60,
bottom : 20,
left : 20,
right : 40
},
store : store,
axes : [ {
type : 'numeric',
position : 'bottom',
grid : true,
title : {
text : 'Population in Millions',
fontSize : 16
}
}, {
type : 'category',
title : {
text : 'Year',
fontSize : 16
},
position : 'left'
}],
series : [ {
type : 'bar',
xField : 'year',
yField : [ 'population' ]
}],
sprites : {
type : 'text',
text : 'United States Population',
font : '25px Helvetica',
width : 120,
height : 35,
x : 100,
y : 40
}
}]
});
|
下列截圖為以上的代碼的輸出結果:
堆疊條形圖
現在假設你想在柱狀圖的每一個分類上標繪兩個值。 你可以將他們堆疊起來或者在每個分類上使用兩條圖形。
我們更新柱狀圖例子來展示一個堆疊圖表。為此我們需要在 store 中額外添加一個數值字段,同時在 series 中我們需要為 yField 指定兩個字段。你也可以堆疊超過兩個字段,但是本例中我們只用兩個字段,看看下面的代碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
|
Ext.define('MyApp.model.Population', {
extend : 'Ext.data.Model',
fields : [ 'year', 'total', 'slaves' ]
});
Ext.define('MyApp.store.Population', {
extend : 'Ext.data.Store',
storeId : 'population',
model : 'MyApp.model.Population',
data : [{
"year" : "1790",
"total" : 3.9,
"slaves" : 0.7
},{
"year" : "1800",
"total" : 5.3,
"slaves" : 0.9
},{
"year" : "1810",
"total" : 7.2,
"slaves" : 1.2
},{
"year" : "1820",
"total" : 9.6,
"slaves" : 1.5
},{
"year" : "1830",
"total" : 12.9,
"slaves" : 2
},{
"year" : "1840",
"total" : 17,
"slaves" : 2.5
},{
"year" : "1850",
"total" : 23.2,
"slaves" : 3.2
},{
"year" : "1860",
"total" : 31.4,
"slaves" : 4
}]
});
var store = Ext.create("MyApp.store.Population");
Ext.create('Ext.Container', {
renderTo : Ext.getBody(),
width : 500,
height : 500,
layout : 'fit',
items : [ {
xtype : 'cartesian',
store : store,
insetPadding : {
top : 60,
bottom : 20,
left : 20,
right : 40
},
axes : [ {
type : 'numeric',
position : 'left',
grid : true,
title : {
text : 'Population in Millions',
fontSize : 16
}
}, {
type : 'category',
title : {
text : 'Year',
fontSize : 16
},
position : 'bottom'
}],
series : [ {
type : 'bar',
xField : 'year',
yField : [ 'total', 'slaves' ]
}],
sprites : {
type : 'text',
text : 'United States Slaves Distribution 1790 to 1860',
font : '20px Helvetica',
width : 120,
height : 35,
x : 60,
y : 40
}
}]
});
|
堆疊柱狀圖的輸出如下列截圖:
如果你想呈現多個字段,並且讓它們未疊加,那么只需要簡單的設置 series 的 stacked 屬性為 false 即可,請看以下輸出:
在圖表中還有很多可用的選項。讓我們瞧一瞧一些常用的選項:
- tooltip: 這個屬性可以在 series 里添加一個提示信息,鼠標放在每個柱狀圖上是會提示相應的信息。
- legend: 這可以呈現圖表的說明到任意的四個邊上
- sprites: 這個可以接收一個數組對象,上面介紹過啦,它是可以在你圖標上添加一些圖形,文本等等。
下面這是使用的相同的 store ,只是用了一些上面提的其他的選項:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
|
Ext.create('Ext.Container', {
renderTo: Ext.getBody(),
width: 500,
height: 500,
layout: 'fit',
items: [{
xtype: 'chart',
legend: { docked: 'bottom' },
insetPadding: {
top: 60,
bottom: 20,
left: 20,
right: 40
},
store: store,
axes: [{
type: 'numeric',
position: 'left',
grid: true,
title: {
text: 'Population in Millions',
fontSize: 16
},
minimum: 0,
}, {
type: 'category',
title: {
text: 'Year',
fontSize: 16
},
position: 'bottom',
}],
series: [{
type: 'bar',
xField: 'year',
stacked: false,
title: ['Total', 'Slaves'],
yField: ['total', 'slaves'],
tooltip: {
trackMouse: true,
style: 'background: #fff',
renderer: function (storeItem, item) {
this.setHtml('In ' + storeItem.get('year') + ' ' + item. field + ' population was ' + storeItem.get(item.field) + ' m');
}
}
}],
sprites: [{
type: 'text',
text: 'United States Slaves Distribution 1790 to 1860',
font: '20px Helvetica',
width: 120,
height: 35,
x: 60,
y: 40
},{
type: 'text',
text: 'Source: http://www.wikipedia.org',
fontSize: 10,
x: 12,
y: 440
}]
}]
});
|
輸出你看到頁腳,提示信息和說明信息都在下圖:
3D 柱狀圖
如果你改變 series 的類型為 bar3d ,就能獲得 3D 的柱狀圖,如下列截圖所示:
區域和折線圖
區域和折線圖也屬於是笛卡爾圖表。
區域圖表
呈現一個區域圖,使用下列代碼簡單的替換前面的例子里的 series :
1
2
3
4
5
6
7
8
9
10
11
|
series: [ {
type : 'area',
xField : 'year',
stacked : false,
title : [ 'Total', 'slaves' ],
yField : [ 'total', 'slaves' ],
style : {
stroke : "#94ae0a",
fillOpacity : 0.6,
}
} ]
|
以上代碼所示的輸出:
類似於堆疊柱狀圖,你也可以在 series 中設置 stacked 為true 來實現堆疊。如果你在之前例子上將 stacked 改為 true ,那么將獲得下列結果輸出:
折線圖
使用下列的配置在上面的例子中的 series ,折線圖顯示圖下圖:
1
2
3
4
5
6
7
8
9
10
11
|
series: [ {
type : 'line',
xField : 'year',
title : [ 'Total' ],
yField : [ 'total' ]
},{
type : 'line',
xField : 'year',
title : [ 'Slaves' ],
yField : [ 'slaves' ]
}]
|
餅圖
這是一個在很多應用中都很常用的圖表和報表工具。呈現一個餅圖使用 Ext.chart.PolarChart (xtype: polar) 。
基本的餅圖
指定類型為 pie ,還要指定 angleField 和 label 來呈現餅圖。angleField 這是角度字段,如以下代碼所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
|
Ext.define('MyApp.store.Expense', {
extend : 'Ext.data.Store',
alias : 'store.expense',
fields : [ 'cat', 'spent' ],
data : [ {
"cat" : "Restaurant",
"spent" : 100
}, {
"cat" : "Travel",
"spent" : 150
}, {
"cat" : "Insurance",
"spent" : 500
}, {
"cat" : "Rent",
"spent" : 1000
}, {
"cat" : "Groceries",
"spent" : 400
}, {
"cat" : "Utilities",
"spent" : 300
} ]
});
var store = Ext.create("MyApp.store.Expense");
Ext.create('Ext.Container',{
renderTo : Ext.getBody(),
width : 600,
height : 500,
layout : 'fit',
items : [ {
xtype : 'polar',
legend : {
docked : 'bottom'
},
insetPadding : {
top : 100,
bottom : 20,
left : 20,
right : 40
},
store : store,
series : [ {
type : 'pie',
angleField : 'spent',
label : {
field : 'cat',
},
tooltip : {
trackMouse : true,
renderer : function(storeItem, item) {
var value = ((parseFloat(storeItem.get('spent')/ storeItem.store.sum('spent')) * 100.0).toFixed(2));
this.setHtml(storeItem.get('cat') + ': ' + value + '%');
}
}
} ]
} ]
});
|
圓環餅圖
這僅需要在之前的例子中設置 donut 屬性的值為 40 ,你將獲取下列圖表。donut 這個值是半徑的百分比:
3D餅圖
在 ExtJS 6 中,對 3D 餅圖做出了一些改進。現在 3D 餅圖支持 label 和可配置的 3D 切面,例如厚度,變形等等。
我們使用同樣的 model 和 store 使用前面餅圖的例子創建一個 3D 餅圖,如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
Ext.create('Ext.Container',{
renderTo : Ext.getBody(),
width : 600,
height : 500,
layout : 'fit',
items : [ {
xtype : 'polar',
legend : {
docked : 'bottom'
},
insetPadding : {
top : 100,
bottom : 20,
left : 80,
right : 80
},
store : store,
series : [ {
type : 'pie3d',
donut : 50,
thickness : 70,
distortion : 0.5,
angleField : 'spent',
label : {
field : 'cat'
},
tooltip : {
trackMouse : true,
renderer : function(storeItem, item) {
var value = ((parseFloat(storeItem.get('spent')/ storeItem.store.sum('spent')) * 100.0).toFixed(2));
this.setHtml(storeItem.get('cat') + ': ' + value+ '%');
}
}
} ]
} ]
});
|
下面的圖片顯示了上面代碼的輸出:
費用分析器 – 示例項目
又是項目時間,現在你已經了解了 ExtJS 中不同的圖表類型,我們來創建一個示例項目名為 費用分析器。下面是最終設計效果:
我們使用 Sencha Cmd 來構建應用。運行下列命令:
1
|
sencha -sdk <path to SDK>/ext-6.0.0.415/ generate app EA ./expenseanalyzer
|
之后我們移除所有不必要的文件和代碼,添加一些額外的文件。目錄結構如下:
- 這里只有一些重要文件的代碼,完整的代碼在這里 https://github. com/ananddayalan/extjs-by-example-expense-analyzer
下列代碼是創建 grid 。這個 List 視圖繼承自 Ext.grid.Panel ,數據使用 expense store ,它有三列:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
Ext.define('EA.view.main.List', {
extend : 'Ext.grid.Panel',
xtype : 'mainlist',
maxHeight : 400,
requires : [ 'EA.store.Expense' ],
title : 'Year to date expense by category',
store : {
type : 'expense'
},
columns : {
defaults : {
flex : 1
},
items : [ {
text : 'Category',
dataIndex : 'cat'
}, {
formatter : "date('F')",
text : 'Month',
dataIndex : 'date'
}, {
text : 'Spent',
dataIndex : 'spent'
} ]
}
});
|
我並沒有在這里使用分頁。maxHeight 是用於限制 grid 的高度,同時開啟滾動條,因為有更多的數據。
以下代碼創建了 expense store 。這個 store 使用了內嵌數據。這里我們並沒有單獨為 store 創建 model :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
Ext.define('EA.store.Expense', {
extend : 'Ext.data.Store',
alias : 'store.expense',
storeId : 'expense',
fields : [ {
name : 'date',
type : 'date'
},
'cat',
'spent'
],
data : {
items : [{
"date" : "1/1/2015",
"cat" : "Restaurant",
"spent" : 100
},{
"date" : "1/1/2015",
"cat" : "Travel",
"spent" : 22
},{
"date" : "1/1/2015",
"cat" : "Insurance",
"spent" : 343
}]
},
proxy : {
type : 'memory',
reader : {
type : 'json',
rootProperty : 'items'
}
}
});
|
繼續創建柱狀圖。在柱狀圖中我們將使用另外一個 store 叫做 expensebyMonth store ,我們將從 expense 的數據填充進來。
下列 3D 柱狀圖有兩個 axis 類型: numeric 和 category 。我們使用日期字段的月部分作為 category 。renderer 屬性用於呈現日期字段的月份部分:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
|
Ext.define('EA.view.main.Bar', {
extend : 'Ext.chart.CartesianChart',
requires : [ 'Ext.chart.axis.Category',
'Ext.chart.series.Bar3D',
'Ext.chart.axis.Numeric',
'Ext.chart.interactions.ItemHighlight' ],
xtype : 'mainbar',
height : 500,
padding : {
top : 50,
bottom : 20,
left : 100,
right : 100
},
legend : {
docked : 'bottom'
},
insetPadding : {
top : 100,
bottom : 20,
left : 20,
right : 40
},
store : {
type : 'expensebyMonthStore'
},
axes : [ {
type : 'numeric',
position : 'left',
grid : true,
minimum : 0,
title : {
text : 'Spendings in $',
fontSize : 16
}
}, {
type : 'category',
position : 'bottom',
title : {
text : 'Month',
fontSize : 16
},
label : {
font : 'bold Arial',
rotate : {
degrees : 300
}
},
renderer : function(date) {
return [ "Jan", "Feb", "Mar", "Apr", "May" ][date.getMonth()];
}
} ],
series : [ {
type : 'bar3d',
xField : 'date',
stacked : false,
title : [ 'Total' ],
yField : [ 'total' ]
} ],
sprites : [ {
type : 'text',
text : 'Expense by Month',
font : '20px Helvetica',
width : 120,
height : 35,
x : 60,
y : 40
} ]
});
|
現在為上面的柱狀圖創建 store 。model 為 MyApp.model.ExpensebyMonth 。這個 store 將用來顯示每個月的花費總數。數據是通過對 expense store 的日期字段進行分組后填充的,現在我們瞧一瞧 data 屬性是如何配置填充數據的:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
Ext.define('MyApp.model.ExpensebyMonth', {
extend : 'Ext.data.Model',
fields : [ {
name : 'date',
type : 'date'
}, 'total' ]
});
Ext.define('MyApp.store.ExpensebyMonth', {
extend : 'Ext.data.Store',
alias : 'store.expensebyMonthStore',
model : 'MyApp.model.ExpensebyMonth',
data : (function() {
var data = [];
var expense = Ext.createByAlias('store.expense');
expense.group('date');
var groups = expense.getGroups();
groups.each(function(group) {
data.push({
date : group.config.groupKey,
total :group.sum('spent')
});
});
return data;
})()
});
|
以下代碼用於生成餅圖。這個圖表使用的的 store 是 expense ,但只顯示了一次選擇一個月的數據。在主視圖上添加了一個下拉框用於選擇月份。
這個 beforerender 事件是用於過濾 expense store 里用於顯示的數據,只加載一月份的數據:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
Ext.define('EA.view.main.Pie', {
extend : 'Ext.chart.PolarChart',
requires : [ 'Ext.chart.series.Pie3D' ],
xtype : 'mainpie',
height : 800,
legend : {
docked : 'bottom'
},
insetPadding : {
top : 100,
bottom : 20,
left : 80,
right : 80
},
listeners : {
beforerender : function() {
var dateFiter = new Ext.util.Filter({
filterFn : function(item) {
return item.data.date.getMonth() == 0;
}
});
Ext.getStore('expense').addFilter(dateFiter);
}
},
store : {
type : 'expense'
},
series : [ {
type : 'pie3d',
donut : 50,
thickness : 70,
distortion : 0.5,
angleField : 'spent',
label : {
field : 'cat',
}
} ]
});
|
截止目前,我們創建好了 grid ,柱狀圖,餅圖,和這個應用所需要的 store 。現在需要在主視圖上把他們聯系起來。以下代碼展示了 main 視圖的經典工具包里的片段。main 視圖是一個選項卡控件,為每個選項卡指定視圖:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
Ext.define('EA.view.main.Main', {
extend : 'Ext.tab.Panel',
xtype : 'app-main',
requires : [
'Ext.plugin.Viewport',
'Ext.window.MessageBox',
'EA.view.main.MainController',
'EA.view.main.List',
'EA.view.main.Bar',
'EA.view.main.Pie'
],
controller : 'main',
autoScroll : true,
ui : 'navigation',
// Truncated code
items : [ {
title : 'Year to Date',
iconCls : 'fa-bar-chart',
items : [ {
html : '<h3>Your average expense per month is: ' +Ext.createByAlias('store.expensebyMonthStore').average('total') +'</h3>',
height : 70,
},{
xtype : 'mainlist'
},{
xtype : 'mainbar'
}]
},{
title : 'By Month',
iconCls : 'fa-pie-chart',
items : [ {
xtype : 'combo',
value : 'Jan',
fieldLabel : 'Select Month',
store : [ 'Jan', 'Feb', 'Mar', 'Apr', 'May' ],
listeners : {
select : 'onMonthSelect'
}
}, {
xtype : 'mainpie'
} ]
} ]
});
|
總結
在本章中,我們在 ExtJS 中學習到不同的圖表。並且創建了一個示例項目來演示他們的應用。