Echart

数据看板首要问题,就是我们要解决数据分组的问题。你可以存储到浏览器的websql中通过sql语句groupBy来进行分组统计,或者你自己用js对数据进行分组。由于数据量有限,也就几百个吧,这里采取js方式对数据进行内存分组统计。

1
2
3
4
5
6
7
8
9
export const groupBy = (list, fn) => {
const groups = {};
list.forEach(function(o) {
const group = JSON.stringify(fn(o));
groups[group] = groups[group] || [];
groups[group].push(o);
});
return groups;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//引入柱形图,扇形图,地图用于数据可视化展示
import {
ChartPie,
ChartBar,
ChartMap
} from '@/components/charts';
import moment from "moment";
export default {
name: 'orderScreen',
components: {
ChartPie,
ChartBar,
ChartMap
},
}

统计图的数据处理准备

上面,我们定义了一个groupBy方法,传递参数list数据源,fn匿名函数块。通过此方法来将数据源处理返回 {key1:[ ],key2:[ ],…keyN:[ ]} 字典。
另外我们抽出一个业务公共方法processGroupByProperty:只需传递属性名,我们对每个分组集合进行统计金额。最后返回排名前n的数据.{“group1”:money1,”group2”:money2,groupN:”money”} 用于柱形图显示。

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
processGroupByProperty:function(propertyName){
let dataSource = this.dataList;
let chartBarMap = {}; //图表chart需要用的map

//先分组
let groupDic = groupBy(dataSource, (itemObj) => {
return itemObj[propertyName]
});
//统计总和,把对象装到数组,再对数组排序,再取前10装到map
let groupSortArr = [];
Object.keys(groupDic).forEach(function(key) {
let itemArr = groupDic[key];
let sumActualFee = itemArr.reduce(function(total, currentValue) {
return total + currentValue.actualFee;
}, 0);
let keyStr = key.replace('"', '').replace('"', '');
groupSortArr.push({
"name": keyStr,
"value": sumActualFee
});
});
groupSortArr.sort(function(a, b) {
return b.value - a.value
});

let arrCount = groupSortArr.length > 10 ? 10 : groupSortArr.length;
for (let i = arrCount-1; i >= 0; i--) {
let item = groupSortArr[i];
chartBarMap[item.name] = item.value;
}
return chartBarMap;
},

以下方法局部显示了业务各个柱状图的显示处理调用:
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
webSqlOrder: function() {
let dataSource = this.dataList;

//统计总金额。
let totalActualFee = dataSource.reduce(function(total, currentValue) {
return total + currentValue.actualFee;
}, 0);

let totalValueStr = totalActualFee.toFixed(2);
if(totalValueStr.indexOf(".00") > 0){
totalValueStr = totalValueStr.replace(".00","");
}

let tongjiListItem = [{
title: '订单数量',
icon: 'md-person-add',
count: dataSource.length,
color: '#2d8cf0'
},
{
title: '订单总金额',
icon: 'md-locate',
count: totalValueStr,
color: '#19be6b'
},
];
this.inforCardData = tongjiListItem;

//商品名统计
this.productDescMap = this.processGroupByProperty("productDesc");
this.$refs.orderProductDescChartBar.initial(this.productDescMap);

//服务商top10
this.orderUnionMap = this.processGroupByProperty("orderUnion");
this.$refs.orderUnionChartBar.initial(this.orderUnionMap);

//服务商贡献top10
this.shareUnionMap = this.processGroupByProperty("shareUnion");
this.$refs.shareUnionChartBar.initial(this.shareUnionMap);

//...等等
}

以下方法是统计订单各个类型的订单数情况,用于扇形图分布展示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//订单状态分类
this.orderTypeList = [];
let that = this;
//分组
let orderStatusTextDic = groupBy(dataSource, (itemObj) => {
return itemObj.orderStatusText
});
//统计总和
Object.keys(orderStatusTextDic).forEach(function(key) {
let itemArr = orderStatusTextDic[key];
let keyStr = key.replace('"', '').replace('"', '');
that.orderTypeList.push({
name: keyStr,
value: itemArr.length
});
});
this.$refs.orderStatusChartPie.initial(this.orderTypeList);

以下方法是统计各个身份的订单金额用于地图分布:

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
tongjiTypeListByProperty:function(propertyName){
let dataSource = this.dataList;
let typeList = [];
//分组
let groupDic = groupBy(dataSource, (itemObj) => {
return itemObj[propertyName]
});

//统计总和
Object.keys(groupDic).forEach(function(key) {
if (key !== undefined) {
let itemArr = groupDic[key];
let sumActualFee = itemArr.reduce(function(total, currentValue) {
return total + currentValue.actualFee;
}, 0);

let keyStr = key.replace('"', '').replace('"', '');
typeList.push({
name: keyStr,
value: sumActualFee
});
}
});
return typeList;
},

//地图分布图
this.areaList = this.tongjiTypeListByProperty("userProvince");
this.$refs.orderChartMap.initial(this.areaList);

柱形图

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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
<template>
<div ref="dom" class="charts chart-bar"></div>
</template>

<script>
import echarts from 'echarts'
import tdTheme from './theme.json'
echarts.registerTheme('tdTheme', tdTheme)
export default {
name: 'ChartBar',
props: {
text: String,
subtext: String
},
data () {
return {
dom: null,
mapData: null,
}
},
methods: {
initial: function (dataObj) {
this.mapData = dataObj;
this.layoutChartBar();
},
layoutChartBar:function(){
this.$nextTick(() => {
let xAxisData = Object.keys(this.mapData)
let seriesData = Object.values(this.mapData)
let option = {
title: {
text: this.text,
subtext: this.subtext,
x: 'center'
},
tooltip: {
trigger: 'item',
formatter:function(datas) {
let valueStr = datas.value.toFixed(2);
if(valueStr.indexOf(".00") > 0){
valueStr = valueStr.replace(".00","");
}
return datas.name +": "+ valueStr +"元";
}
},
grid: {
left: '3%',
right: '9%',
bottom: '3%',
containLabel: true
},
xAxis: {
type: 'value',
splitLine: {
show: true,
lineStyle:{
color: ['#f7f7f7'],
width: 1,
type: 'solid',
}
}
},
yAxis: {
type: 'category',
data: xAxisData,
scale: true,
axisLabel: {
margin: 2,
interval: 0,
formatter: function(value) {
if (value.length > 6) {
return value.substring(0, 6) + "...";
} else {
return value;
}
}
},
splitLine: {
show: true,
lineStyle:{
color: ['#f7f7f7'],
width: 1,
type: 'solid',
}
}
},
series: [{
data: seriesData,
type: 'bar',
barWidth:13,
itemStyle:{
normal:{
label:{
show:true ,
position:'right',
textStyle:{
color:'gray',
fontSize:12
},
formatter:function(datas) {
let valueStr = datas.value.toFixed(2);
if(valueStr.indexOf(".00") > 0){
valueStr = valueStr.replace(".00","");
}
return valueStr;
}
}
}
}
}]
}
this.dom = echarts.init(this.$refs.dom, 'tdTheme');
this.dom.setOption(option);
})
}
},
}
</script>

扇形图

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
<template>
<div ref="dom" class="charts chart-pie"></div>
</template>

<script>
import echarts from 'echarts'
import tdTheme from './theme.json'
echarts.registerTheme('tdTheme', tdTheme)
export default {
name: 'ChartPie',
props: {
text: String,
subtext: String
},
data () {
return {
dom: null,
listData:[]
}
},
methods: {
resize () {
this.dom.resize()
},
initial: function (list) {

//测试数据
// var arr = [{ value: 335, name: '直接访问1' },
// { value: 310, name: '邮件营销1' },
// { value: 234, name: '联盟广告1' },
// { value: 135, name: '视频广告1' },
// { value: 1548, name: '搜索引擎1' }];

this.listData = list;
this.layoutPieData();
},
layoutPieData:function(){

this.$nextTick(() => {
let legend = this.listData.map(_ => _.name)
let option = {
title: {
text: this.text,
subtext: this.subtext,
x: 'center'
},
tooltip: {
trigger: 'item',
formatter: '{b} :{c} (占比{d}%)'
},
legend: {
orient: 'vertical',
left: 'left',
data: legend
},
series: [
{
label: {
show: false,
position: 'center'
},
emphasis: {
label: {
show: true,
fontSize: '28',
fontWeight: 'normal'
}
},
type: 'pie',
radius: ['50%', '70%'],
data: this.listData,
labelLine:{
show:false
},
itemStyle: {
emphasis: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
}
this.dom = echarts.init(this.$refs.dom, 'tdTheme')
this.dom.setOption(option)
})
}
}
}
</script>

地图

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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
<template>
<div ref="dom" class="charts chart-map"></div>
</template>

<script>
import echarts from 'echarts'
import tdTheme from './theme.json'
import 'echarts/map/js/china.js';
echarts.registerTheme('tdTheme', tdTheme)
export default {
name: 'ChartMap',
props: {
text: String,
subtext: String
},
data () {
return {
dom: null,
listData:[]
}
},
methods: {
resize () {
this.dom.resize()
},
initial: function (list) {

this.listData = list;
this.layoutPieData();
},
layoutPieData:function(){

this.$nextTick(() => {
let option = {
title: {
text: this.text,
subtext: this.subtext,
x: 'center'
},

tooltip: {
formatter:function(params,ticket, callback){

let valueStr = "0";
if (!isNaN(params.value)) {
valueStr = params.value.toFixed(2);
if(valueStr.indexOf(".00") > 0){
valueStr = valueStr.replace(".00","");
}
}

return params.seriesName+'<br />'+params.name+':'+valueStr +"元"
}
},
visualMap: {
min: 0,
max: 1500,
left: 'left',
top: 'bottom',
text: ['高','低'],
inRange: {
color: ['#e0ffff', '#006edd']
},
show:false
},
geo: {
map: 'china',
roam: false,
zoom:1.23,
label: {
normal: {
show: true,
fontSize:'10',
color: 'rgba(0,0,0,0.7)'
}
},
itemStyle: {
normal:{
borderColor: 'rgba(0, 0, 0, 0.2)'
},
emphasis:{
areaColor: '#F3B329',
shadowOffsetX: 0,
shadowOffsetY: 0,
shadowBlur: 20,
borderWidth: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
},
series : [
{
name: '订单总金额',
type: 'map',
geoIndex: 0,
data:this.listData
}
],
};
this.dom = echarts.init(this.$refs.dom, 'tdTheme');
this.dom.setOption(option);
})
}
}
}
</script>

页面布局

以下是柱形图,扇形图,地图 三种统计图组件的显示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<div class="weui-panel weui-panel_access"  >
<div class="weui-panel__bd">
<ChartBar ref="orderShopChartBar" style="height:300px" text="店铺销售金额 Top10" />
</div>
</div>
<div class="weui-panel weui-panel_access" >
<div class="weui-panel__bd">
<ChartPie ref="orderStatusChartPie" style="height:300px" text="订单状态对比" />
</div>
</div>
<div class="weui-panel weui-panel_access" >
<div class="weui-panel__bd">
<ChartMap ref="orderChartMap" style="height:300px" text="订单交易数据分布图" />
</div>
</div>

Package.json配置

1
2
3
4
"dependencies": {
"echarts": "^4.7.0",
...
}

Echart官网
Echart主题下载

评论