Vue 3 + Echarts 实现可视化地图落点和简易的聚合功能

Vue 3 + Echarts 实现可视化地图落点和简易的聚合功能

前言

前几天在正常摸鱼的时候领导突然派发一个紧急需求,要将我们大屏项目中的静态背景图换成可视化地图,由于我们的项目是内嵌在甲方系统中,所以要求我们的可视化地图要做的和甲方一样,看了下甲方的系统截图就是用echarts简单的绘制.本来可以直接找他们前端要代码的,但那样就体现不出我存在的价值,还是自己写了一个.

准备工作

1.安装echarts

首先就是查阅 echarts官方文档 在我们的项目中安装 echarts

  1. NPM 安装 ECharts
npm install echarts --save
  1. 项目中引入 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等等可基于此代码自行拓展

猜你喜欢

转载自blog.csdn.net/zw7518/article/details/129690191
今日推荐