—— 分享前端技术,记录生活点滴

Vue基于ECharts绘制全国热力图,支持下钻市县

  3月份完成一个需求,要求根据全国用户数量,生成热力地图,并且点击省份可下钻到市县。第一时间想到ECharts,ECharts并不陌生:

  一个使用 JavaScript 实现的开源可视化库,可以流畅的运行在 PC 和移动设备上,兼容当前绝大部分浏览器(IE8/9/10/11,Chrome,Firefox,Safari等),底层依赖轻量级的矢量图形库 ZRender,提供直观,交互丰富,可高度个性化定制的数据可视化图表。

  花点时间完成后,写在这里总结下。总体不难,个别难在数据获取:

  • 需要有地图json数据
  • 需要后端配合数据返回(数据格式具体参考官方文档)

  先看效果图。

echarts

  接下来简单讲下思路。注:代码为子组件代码,父组件不再展示,父子组件通过props传递id值,用于展示不同产品的用户数量,文中涉及到的productId逻辑为博主业务实现需要,读者可忽略。另外代码中的axios请求已全局Qs化并做catch、finally处理,读者直接套用时请注意完善。

  1. 首先是包的引入。引入方式不唯一,博主在项目中直接使用npm引入echarts,版本是@4.2.0(当然大家可以引入最新版本),之后在热力图展示页面使用require按需加载。

  2. 在mounted钩子内引入依赖,然后初始化地图,同时初始化热力图,并且为地图元素绑定点击事件。

  3. 点击地图后,根据回调参数去判断当前点击的单元是省还是县市。如果是省,则下钻县市数据,重绘当前省对应的地图,否则,重绘初始化状态的全国地图。

  以下是完整代码。已逐行进行注释说明,有不明白的地方欢迎在评论区提问。

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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
<template>
<section>
<!-- 务必为容器设置宽高 -->
<div id="area" :style="{width:'100%',height:'600px'}" ref="echarts"></div>
</section>
</template>
<script>
export default {
name: 'UserAreaDistribution',
data() {
return {
echarts: null, // echarts引入对象
mainChart: {}, // echarts的实例化对象
option: {}, // echarts基础配置项
dataFiled: [], // 热力区间配置项
data: [] // echarts展示数据
provinces: {
// 此处key值用于地图文字标注,value值便于与json文件名对应
// 23个省(山西陕西注意区分)
"台湾": "taiwan",
"河北": "hebei",
"山西": "shanxi",
"辽宁": "liaoning",
"吉林": "jilin",
"黑龙江": "heilongjiang",
"江苏": "jiangsu",
"浙江": "zhejiang",
"安徽": "anhui",
"福建": "fujian",
"江西": "jiangxi",
"山东": "shandong",
"河南": "henan",
"湖北": "hubei",
"湖南": "hunan",
"广东": "guangdong",
"海南": "hainan",
"四川": "sichuan",
"贵州": "guizhou",
"云南": "yunnan",
"陕西": "shanxi1",
"甘肃": "gansu",
"青海": "qinghai",
// 5个自治区
"新疆": "xinjiang",
"广西": "guangxi",
"内蒙古": "neimenggu",
"宁夏": "ningxia",
"西藏": "xizang",
// 4个直辖市
"北京": "beijing",
"天津": "tianjin",
"上海": "shanghai",
"重庆": "chongqing",
// 2个特别行政区
"香港": "xianggang",
"澳门": "aomen"
}
}
},
props: {
// 接收父组件传递的id值,自有业务需要,读者可忽略
productId: {
type: String,
default: ''
}
},
watch: {
// 更换显示不同产品的数据,自有业务需要,读者可忽略
productId(val) {
this.getHotMap();
}
},
methods: {
// 获取省份数据
getHotMap() {
// 接口获取对应productId产品的数据,应包含data和dataFiled
// 此处的接口需要与后端沟通,按照ECharts文档内的数据格式返回,便于渲染
this.$http.post('xxx', { productId }).then(res => {
if(res.data.data && res.data.dataFiled) {
this.data = eval(res.data.data);
this.dataFiled = eval(res.data.dataFiled);
this.renderMap('China', this.data, this.dataFiled);
} else {
this.$message.warning(res.data.message);
this.renderMap('China', [], []);
}
})
},
// 根据省份下钻市县数据
getHotMapByProvince(type, province, data) {
return new Promise((resolve, reject) => {
// 此处的接口需要与后端沟通,按照ECharts文档内的数据格式返回,便于渲染
this.$http.post('xxx', { provinceName: province, productId: this.productId }).then(res => {
if(res.data.status) {
let b = JSON.parse(res.data.data);
let dataFiled_province = eval(res.data.dataFiled);
let d = [];
// 根据数据格式制造市县地图数据
for(var i = 0, l = data.features.length; i < l; i++) {
var featuresName = data.features[i].properties.name;
d.push({ name: featuresName, value: '0' });
for( var item in b ) {
if (featuresName.includes(item)) {
this.$set(d, i, { name: featuresName, value: b[item].toString() })
}
}
}
// 此处使用Promise返回,也可直接调用renderMap方法
resolve({data: d, dataFiled: dataFiled_province});
} else {
this.$message.warning(res.data.message);
reject(res.data.message);
}
}).catch(res => {
reject(res);
}).finally(_ => {
// 隐藏loading
this.mainChart.hideLoading();
})
})
},
// 地图重绘方法
renderMap(position, data, dataFiled) {
this.option = {
title: {
text: '用户区域分布',
subtext: position == 'China' ? '全国' : position,
x: 'center'
},
tooltip: { trigger: 'item' },
dataRange: {
left: '15%',
ybottom: '20%',
splitList: dataFiled,
color: ['#E0022B', '#E09107', '#A3E00B']
},
toolbox: {
show: true,
orient: 'vertical',
right: '15%',
top: '20%',
itemSize: 25,
itemGap: 20,
feature: {
restore: { title: '重置' },
saveAsImage: { name: '用户区域分布(' + (position == 'China' ? '全国' : position) + ')' }
}
},
roamController: {
show: true,
x: 'right',
mapTypeControl: { 'China': true }
},
series: [{
name: '用户区域分布',
type: 'map',
mapType: position,
roam: position == 'China' ? false : true,
zoom: 1,
center: position == 'China' && [112, 38], // 如果是全国总览则以太原为中心
scaleLimit: { min: 0.5, max: 2 },
itemStyle: {
normal: { label: { show: true, textStyle: { color: "rgb(128, 128, 128)" } } },
emphasis: { label: { show: true } }
},
data: data
}],
animationDuration: 1000,
animationEasing: 'cubicOut',
animationDurationUpdate: 1000
}
// 渲染地图
this.mainChart.setOption(this.option);
}
},
mounted() {
this.$nextTick(_ => {
// 引入 ECharts 主模块
this.echarts = require('echarts');
// 初始化地图
this.mainChart = this.echarts.init(document.getElementById('area'));
// 绘制全国地图(从本地引入全国地图省级数据)
this.$http.get('static/map/China.json').then(res => {
if (res.data.status) {
// 注册全国地图
this.echarts.registerMap('China', res.data);
// if(this.productId) { // 此处判断为自有业务需要,读者可忽略
// 绘制热力图
this.getHotMap();
// }
}
});
// 地图点击事件
this.mainChart.on('click', (params) => {
// 如果点击的单元是省,则下钻市县数据
if(params.name in this.provinces) {
// 地图展开到市级
this.$http.get('static/map/province/' + this.provinces[params.name] + '.json').then(res => {
if (res.data.status) {
// 显示loading
this.mainChart.showLoading();
// 注册对应省的地图
this.echarts.registerMap(params.name, res.data);
// if(this.productId) { // 此处判断为自有业务需要,读者可忽略
// Promise获取市县级数据
this.getHotMapByProvince(params.name, res.data).then(response => {
// 重绘地图
this.renderMap(params.name, response.data, response.dataFiled);
})
// }
}
});
} else {
// 如果没有点击省,则地图收起,展示全国总览,重绘地图
this.renderMap('China', this.data, this.dataFiled);
}
});
})
}
}
</script>

  以上就是本次分享的全部内容,需要地图json数据的小伙伴请在下方留言。如有错误,欢迎指正,欢迎关注阿晋的网络日志。

支付宝打赏 微信打赏

如果觉得我的文章对您有用,请随意赞赏 :)