可视化我们已不再陌生,地图也很常用。有很多公司业务范围可能仅限于某个市区,所以画一个 china 地图意义不大,就只需要绘制某个省份或者市区的地图,然后统计各个区域的一个分布情况,具体的效果如图所示:
一、实现原理:
绘制地图之前,我们先需要明白实现原理是啥样的,然后按照具体的实现步骤,依次实现效果。如果不明白原理,每次完成的都是复制粘贴。
1、开始之前,先确认自己的地图需要分几层,及其作用。
2、该效果实现,需要三层地图实现效果。
- 一层放在最底层,设置地图的边框,对应地图里最外层的蓝色地图线。
- 二层放在中间,实现基本的地图层,显示对应各个区域的名称。
- 三层放在最外层,实现数据标记,对应地图里圆圈和数据。
3、拖动或缩放的时候出现错位,使其同步缩放和拖动。
二、Echarts 使用五部曲:
1、下载并引入 echarts
Echarts 已更新到了 5.0 版本,安装完记得检查下自己的版本是否是 5.0 。
npm install echarts --save
- 1.
下载地图的 json 数据。
可以下载中国以及各个省、市、区地图数据。免费的文件下载地址:
http://datav.aliyun.com/portal/school/atlas/area_selector#&lat=30.332329214580188&lng=106.72278672066881&zoom=3.5。
下载对应的省份或者市区的地图数据。
引入:
import * as echarts from "echarts"
import chinaJSON from '../../assets/json/china.json'
- 1.
- 2.
2、准备容器
给元素定义宽高确定的容器用来装地图。
<template>
<div ref="xian"></div>
</template>
- 1.
- 2.
- 3.
3、实例化 echarts 对象
import * as echarts from 'echarts'
import xianJSON from '../../assets/json/xian.json'
const xian = ref()
var myChart = echarts.init(xian.value)
// 创建了一个 myChart 对象
- 1.
- 2.
- 3.
- 4.
- 5.
如果是绘制的地图,需要先引入和注册地图:
echarts.registerMap('xa', xianJSON)
- 1.
4、指定配置项和数据
var option = {
// 存放需要绘制图片类型,以及样式设置
}
- 1.
- 2.
- 3.
5、给 echarts 对象设置配置项
myChart.setOption(option)
- 1.
三、具体实现步骤
步骤1:绘制基本地图层,显示各个区域。
具体代码为:
<template>
<div>
<div ref="xian"
style="width: 100%;height: 800px;border: solid 1px red;background: #011868;"
></div>
</div>
</template>
<script lang="ts" setup>
import { ref, onMounted } from 'vue'
import * as echarts from 'echarts'
import xianJSON from '../../assets/json/xian.json'
const xian = ref()
onMounted(() => {
drwaMap()
})
function drwaMap() {
var myChart = echarts.init(xian.value)
echarts.registerMap('xa', xianJSON)
var option = {
geo: {
map: 'xa',
zoom: 1,
roam: true,
center: [109.00853, 34.11078],
label: {
show: true,
color: 'rgba(255,255,255,0.2)',
},
itemStyle: {
normal: {
areaColor: '#080b1a',
borderColor: 'rgba(0,116,255,0.2)',
borderWidth: 2,
borderType: 'dashed',
},
emphasis: {
areaColor: '#4f6ee9',
color: 'rgba(255,255,255,0.8)',
},
},
},
}
myChart.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.
步骤2:底层绘制一个地图层,设置地图外层边框。
添加 series 属性,再绘制一个地图层,利用 z 放到最底层。
series: [
//绘制一个新地图
{
type: 'map',
map: 'xa',
zoom: 1,
roam: true,
center: [109.00853, 34.11078],
z: -1, // 置于底层
itemStyle: {
normal: {
areaColor: '#2e488f',
borderColor: '#0074ff',
borderWidth: 5,//设置外层边框线粗细
},
},
},
],
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
步骤3:添加分布的数据点标记。
给 series 中再添加一个配置项:
{
type: 'effectScatter', // 特效散点图
coordinateSystem: 'geo',
symbol: 'circle',
// symbolSize 设置标记点的大小,
//把大小限制再 30 - 50 之间
symbolSize: function (val) {
return 30 + (val[2] / 100) * 20
},
colorBy: 'series',
//显示name并设置样式
label: {
show: true,
formatter: function (data) {
return data.value[2]
},
color: '#080b1a',
fontSize: '16',
offset: [0, 0],
align: 'center',
},
//涟漪效果设置
rippleEffect: {
color: '#32479d',
number: 3,
period: 4,
scale: 2,
brushType: 'stroke',
},
itemStyle: {
normal: {
color: '#00e6ff',
borderColor: '#32479d',
borderWidth: 2,
},
},
data: [
{ name: '蓝田', value: [109.423479, 34.181634, 50] },
{ name: '长安区', value: [108.923479, 34.110134, 30] },
{ name: '周至县', value: [108.123479, 34.010134, 2] },
{ name: '鄠邑区', value: [108.573479, 34.100134, 4] },
{ name: '临潼区', value: [109.283479, 34.510134, 3] },
{ name: '高陵区', value: [109.059479, 34.550134, 1] },
],
- 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.
步骤4:处理放大缩小时不同步的问题。
捕捉 georoam 事件,上层的 geo 缩放、偏移的时候,让下层的 map 跟着上层同步进行。添加代码:
myChart.on('georoam', function (params) {
var option = myChart.getOption() //获得option对象
if (params.zoom != null && params.zoom != undefined) {
//捕捉到缩放时
option.series[0].zoom = option.geo[0].zoom //下层geo的缩放等级跟着上层的geo一起改变
option.series[0].center = option.geo[0].center //下层的geo的中心位置随着上层geo一起改变
} else {
//捕捉到拖曳时
option.series[0].center = option.geo[0].center //下层的geo的中心位置随着上层geo一起改变
}
myChart.setOption(option) //设置option
})
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
四、完整源码
<template>
<div>
<div
ref="xian"
style="
width: 100%;
height: 800px;
border: solid 1px red;
background: #0c0b2a;
"
></div>
</div>
</template>
<script lang="ts" setup>
import { ref, onMounted } from 'vue'
import * as echarts from 'echarts'
import xianJSON from '../../assets/json/xian.json'
const xian = ref()
onMounted(() => {
drwaMap()
})
function drwaMap() {
var myChart = echarts.init(xian.value)
echarts.registerMap('xa', xianJSON)
var option = {
geo: {
map: 'xa',
zoom: 1,
roam: true,
center: [109.00853, 34.11078],
label: {
show: true,
color: 'rgba(255,255,255,0.2)',
},
itemStyle: {
normal: {
areaColor: '#080b1a',
borderColor: 'rgba(0,116,255,0.2)',
borderWidth: 2,
borderType: 'dashed',
},
emphasis: {
areaColor: '#4f6ee9',
color: 'rgba(255,255,255,0.8)',
},
},
},
series: [
//绘制一个新地图
{
type: 'map',
map: 'xa',
zoom: 1,
roam: true,
center: [109.00853, 34.11078],
z: -1,
itemStyle: {
normal: {
areaColor: '#2e488f',
borderColor: '#0074ff',
borderWidth: 5,
},
},
},
{
type: 'effectScatter', // 特效散点图
coordinateSystem: 'geo',
symbol: 'circle',
symbolSize: function (val) {
return 30 + (val[2] / 100) * 20
},
colorBy: 'series',
//显示name并设置样式
label: {
show: true,
formatter: function (data) {
return data.value[2]
},
color: '#080b1a',
fontSize: '16',
offset: [0, 0],
align: 'center',
},
//涟漪效果设置
rippleEffect: {
color: '#32479d',
number: 3,
period: 4,
scale: 2,
brushType: 'stroke',
},
itemStyle: {
normal: {
color: '#00e6ff',
borderColor: '#32479d',
borderWidth: 2,
},
},
data: [
{ name: '蓝田', value: [109.423479, 34.181634, 50] },
{ name: '长安区', value: [108.923479, 34.110134, 30] },
{ name: '周至县', value: [108.123479, 34.010134, 2] },
{ name: '鄠邑区', value: [108.573479, 34.100134, 4] },
{ name: '临潼区', value: [109.283479, 34.510134, 3] },
{ name: '高陵区', value: [109.059479, 34.550134, 1] },
],
},
],
}
myChart.setOption(option)
// 同步缩放、偏移
myChart.on('georoam', function (params) {
var option = myChart.getOption() //获得option对象
if (params.zoom != null && params.zoom != undefined) {
//捕捉到缩放时
option.series[0].zoom = option.geo[0].zoom //下层geo的缩放等级跟着上层的geo一起改变
option.series[0].center = option.geo[0].center //下层的geo的中心位置随着上层geo一起改变
} else {
//捕捉到拖曳时
option.series[0].center = option.geo[0].center //下层的geo的中心位置随着上层geo一起改变
}
myChart.setOption(option) //设置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.
- 107.
- 108.
- 109.
- 110.
- 111.
- 112.
- 113.
- 114.
- 115.
- 116.
- 117.
- 118.
- 119.
- 120.
- 121.
- 122.
- 123.
- 124.
- 125.