Vue 3 + Echarts 实现可视化地图落点和简易的聚合功能
前言
前几天在正常摸鱼的时候领导突然派发一个紧急需求,要将我们大屏项目中的静态背景图换成可视化地图,由于我们的项目是内嵌在甲方系统中,所以要求我们的可视化地图要做的和甲方一样,看了下甲方的系统截图就是用echarts简单的绘制.本来可以直接找他们前端要代码的,但那样就体现不出我存在的价值,还是自己写了一个.
准备工作
1.安装echarts
首先就是查阅 echarts官方文档 在我们的项目中安装 echarts
- NPM 安装 ECharts
npm install echarts --save
- 项目中引入 ECharts
import * as Echarts from 'echarts';
2.获取地图json数据
通过 阿里云数据可视化平台 下载全国地图的json数据
3.新建组件引入地图数据
import MAP from '../utils/china.json';
开发工作
代码示例
<!--
* @Description:
本来最开始只要求展示一个地图,地图做出来后领导有要求实现落点并且点击跳转至区域地图,然后领导看了一眼说是数据太多展示标题不好看要求来个聚合功能,为了和甲方一致,咱们这边接着提出要求:原始比例不让拖拽只能缩放,触发放大后才能拖拽,缩小回原始比例再禁止拖拽.领导的新点子还没想到目前先做成这个样子
* @version:
1. 后端人力资源紧张,领导要求数据暂时前端写死糊弄大领导
2. 通过缩放比例,修改渲染参数以达到简易点聚合功能
3. 点击落点跳转详细的区域地图,区域地图在父组件调用,使用的百度地图
* @Author: Riddler
* @Date: 2023-03-20 15:14:50
-->
<template>
<div class='container' @dblclick='dblclickFn'>
<div class='map_ref' ref='map_ref'></div>
</div>
</template>
<script setup>
import * as Echarts from 'echarts';
import 'echarts/extension/bmap/bmap';
import MAP from './china.json'; // 从阿里云数据可视化平台下载的地图数据
import { defineEmits, ref, reactive, onMounted, onUnmounted, getCurrentInstance } from 'vue';
import symbolIcon from '@/assets/cockpit/frame_blue.png'
defineEmits({
"mapDetailFn": null
})
const inst = getCurrentInstance();
let chartInstance;
// 初始固定地图中心点
let centerLayout = reactive([106.55, 36.57]);
// 给一个默认缩放值
const zoomSize = ref(1);
let chartData = [
{name:"浙富西溪堂-5幢", value: [119.997408,30.283855]},
{name:"利尔达物联网科技园", value: [119.998619,30.282151]},
{name:"江南故事", value: [120.008594, 30.288959]},
];
let option = {
// 关闭动画效果,默认开启的动画会导致一个问题,在聚合需求时缩放过程中坐标点会不准,有偏移和闪烁的现象
animation: false,
// 取消背景色,不然会盖住项目中的背景
backgroundColor:'',
// 地图配置
geo: [
{
type: 'map',
map: 'china',
top: '5%',
bottom: '5%',
// 缩放值
zoom: zoomSize.value,
// 中心点
center: centerLayout,
// 是否缩放拖拽,初始设置为只能缩放禁止拖拽
roam: 'scale',
// 缩放区间
scaleLimit: {
min: 1,
// max: 100 // 实现需求中发现有些地点离得太近图标会有重合和遮挡,干脆就不设置放大的限制
},
// 这边的需求省份名都不展示了
label: {
normal: {
show: false,
},
emphasis: {
show: false
}
},
// 每个省份的颜色
itemStyle: {
normal: {
borderWidth: 1,
// 地图边界颜色
borderColor: 'rgba(49, 167, 250)',
// 地图区域背景颜色
areaColor: 'rgba(0, 0, 0, 0)',
},
// 鼠标放上去高亮的样式
emphasis: {
show: false,
// 鼠标放上去地图区域背景颜色
areaColor: 'rgba(0, 0, 0, 0)',
}
},
}
],
series: [
{
type: 'scatter',
coordinateSystem: 'geo',
// 落点icon大小
symbolSize: 18,
// 落点改为icon图片
symbol: 'image://' + symbolIcon,
label: {
show: true,
normal: {
show: false,
formatter: function(params) {
return params.name ? params.name : ''
},
color: '#79bbff',
position: 'right',
},
emphasis: {
show: false,
color: '#000000',
position: 'right',
}
},
data: [],
}
]
}
const initChart = () => {
// 初始化图表
chartInstance = Echarts.init(inst?.refs.map_ref, 'dark')
// 获取echarts适量地图数据
Echarts.registerMap('china', MAP)
// 配置对象
option.series[0].data = chartData
// 生成图表
chartInstance.setOption(option)
// 监听点击事件
chartInstance.on('click', function(params) {
if ( params.componentType=== 'series') inst.emit('mapDetailFn', params.data.tenant); // 调用父组件方法实现点击跳转
})
// 初始让它适配一下
screenAdapter();
}
let roamStatus = true;
let scaleStatus = true;
const mapZoomChange = () => {
// 监听地图缩放
chartInstance.on('georoam', params => {
if (params.dy || params.dx) return; // 拖拽事件不处理
let _option = chartInstance.getOption();
// 获取到缩放值
let _zoom = _option.geo[0].zoom;
// 监听到缩放事件将中心置为 undefined 解决缩放渲染时产生的中心偏移问题
option.geo[0].center = undefined;
option.geo[0].zoom = _zoom;
// 我这边设置缩放值大于4的时候展示落点的标题
if (_zoom > 4) {
// 设置一个状态字段让地图放大达到要求时只更新一次,否则高频率更新地图卡顿非常明显
if (roamStatus) {
// 直接修改option中的配置达到展示标题的目的,节省了操作数据的繁琐
option.series[0].label.normal.show = true;
option.series[0].label.emphasis.show = true;
chartInstance.setOption(option);
roamStatus = false;
} else return
return
} else {
// 触发放大后允许拖拽
if (_zoom > 1) {
if (scaleStatus) {
// roam设置为 true 允许缩放和拖拽
option.geo[0].roam = true;
chartInstance.setOption(option)
scaleStatus = false
}
}
// 缩放到初始比例时禁止拖拽
if (_zoom == 1.4) {
option.geo[0].roam = 'scale';
// 固定中心点让地图回到初始位置
option.geo[0].center = centerLayout;
chartInstance.setOption(option);
scaleStatus = true;
}
if (roamStatus) return
else {
option.series[0].label.normal.show = false;
option.series[0].label.emphasis.show = false;
chartInstance.setOption(option);
roamStatus = true;
}
return
}
})
}
// 适配
const screenAdapter = () => {
chartInstance.resize()
}
// 双击事件
const dblclickFn= () => {
// 以防后续有双击之类的需求
}
onMounted(() => {
// 初始化地图
initChart();
// 缩小监听事件
mapZoomChange()
// 开启监听让地图适配
window.addEventListener('resize', screenAdapter)
})
// 组件卸载时关闭监听事件
onUnmounted(() => {
window.removeEventListener('resize', screenAdapter);
})
</script>
<style lang="scss" scoped>
.container {
width: 100%;
height: 100%;
.map_ref {
width: 100%;
height: 100%;
}
}
</style>
效果展示
展示在页面上的效果就是这样,缩小状态在对应坐标点落上icon
放大后展示标题
如需增加其它诸如点击事件,移入展示tooltip等等可基于此代码自行拓展