当前位置: 首页 > article >正文

基于 Vue3 + ECharts + GeoJson 实现区域地图钻取功能详解

文章目录

  • 前言
  • 一、实现步骤
    • 1. 项目初始化
    • 2. 准备GeoJson数据
    • 3. 创建地图组件
    • 4. 创建主页面组件
    • 5. 使用组件
  • 二、功能亮点
  • 三、性能优化建议
  • 四、常见问题解决
  • 五、结语
  • 六、实战demo
  • 七、资源下载


前言

在数据可视化领域,地图展示是一种非常直观的表现形式。而地图钻取(Drill-down)功能可以让用户从宏观到微观逐级查看数据,提供更好的交互体验。本文将详细介绍如何使用 Vue3EChartsGeoJson 实现一个完整的区域地图钻取功能。

技术栈介绍

  • Vue3:当前最流行的前端框架之一,提供响应式数据和组件化开发体验
  • ECharts:百度开源的数据可视化库,功能强大,支持多种图表类型
  • GeoJson:一种用于表示地理空间数据的 JSON 格式标准

一、实现步骤

1. 项目初始化

首先创建一个Vue3项目:

npm init vue@latest vue3-echarts-map
cd vue3-echarts-map
npm install

安装必要的依赖:

npm install echarts axios

2. 准备GeoJson数据

地图钻取需要各级行政区划的 GeoJson 数据,可以从以下途径获取:

  • 阿里云DataV:https://datav.aliyun.com/portal/school/atlas/area_selector
  • GeoJSON:https://geojson.cn/editor?url=https://geojson.cn/api/china/330000.topo.json
  • 高德地图API
  • 自己制作或从公开数据源获取

在本例中,我们准备了中国地图、省级地图和市级地图三个级别的GeoJson数据。

3. 创建地图组件

创建 MapChart.vue 组件:

<template><div ref="chartRef" style="width: 100%; height: 600px;"></div>
</template><script setup>
import { ref, onMounted, onBeforeUnmount, watch } from 'vue';
import * as echarts from 'echarts';
import axios from 'axios';const props = defineProps({mapData: Object,chartData: Array,mapName: String,drillLevel: Number
});const emit = defineEmits(['drillDown']);const chartRef = ref(null);
let chartInstance = null;// 初始化图表
const initChart = () => {if (!chartRef.value) return;chartInstance = echarts.init(chartRef.value);// 注册地图数据echarts.registerMap(props.mapName, props.mapData);const option = {title: {text: `${props.mapName}地图`,left: 'center'},tooltip: {trigger: 'item',formatter: params => {const data = params.data;return `${params.name}<br/>${data ? `数值: ${data.value}` : ''}`;}},visualMap: {min: 0,max: 100,text: ['高', '低'],realtime: false,calculable: true,inRange: {color: ['#50a3ba', '#eac736', '#d94e5d']}},series: [{name: props.mapName,type: 'map',map: props.mapName,roam: true,emphasis: {label: {show: true}},data: props.chartData,selectedMode: 'single'}]};chartInstance.setOption(option);// 绑定点击事件实现钻取chartInstance.on('click', params => {if (props.drillLevel < 2) { // 限制钻取层级emit('drillDown', params.name);}});
};// 响应数据变化
watch(() => [props.mapData, props.chartData], () => {if (chartInstance) {initChart();}
});onMounted(() => {initChart();window.addEventListener('resize', resizeChart);
});onBeforeUnmount(() => {if (chartInstance) {chartInstance.dispose();chartInstance = null;}window.removeEventListener('resize', resizeChart);
});const resizeChart = () => {if (chartInstance) {chartInstance.resize();}
};
</script>

4. 创建主页面组件

创建 MapDrillDown.vue 作为主页面:

<template><div class="map-container"><div class="breadcrumb"><span v-for="(item, index) in breadcrumb" :key="index"@click="handleBreadcrumbClick(index)":class="{ 'active': index === breadcrumb.length - 1 }">{{ item }} {{ index < breadcrumb.length - 1 ? '>' : '' }}</span></div><button v-if="currentLevel > 0" @click="drillUp" class="drill-btn">返回上级</button><MapChart:mapData="currentMapData":chartData="currentChartData":mapName="currentMapName":drillLevel="currentLevel"@drillDown="handleDrillDown"/></div>
</template><script setup>
import { ref, onMounted } from 'vue';
import axios from 'axios';
import MapChart from './MapChart.vue';// 当前级别:0-全国,1-省级,2-市级
const currentLevel = ref(0);
const currentMapData = ref(null);
const currentChartData = ref([]);
const currentMapName = ref('中国');
const breadcrumb = ref(['中国']);// 模拟数据 - 实际项目中可以从API获取
const mockData = {china: [{ name: '广东省', value: 83 },{ name: '浙江省', value: 67 },{ name: '江苏省', value: 72 },// 其他省份数据...],guangdong: [{ name: '广州市', value: 95 },{ name: '深圳市', value: 89 },{ name: '珠海市', value: 78 },// 其他城市数据...],zhejiang: [{ name: '杭州市', value: 88 },{ name: '宁波市', value: 76 },{ name: '温州市', value: 65 },// 其他城市数据...]
};// 加载GeoJson数据
const loadGeoJson = async (name) => {try {// 实际项目中这里应该是从服务器获取GeoJson// const res = await axios.get(`/geojson/${name}.json`);// return res.data;// 这里使用模拟的GeoJson路径let geoJsonPath = '';if (name === '中国') {geoJsonPath = '/geojson/china.json';} else if (['广东省', '浙江省'].includes(name)) {geoJsonPath = `/geojson/${name}.json`;}if (geoJsonPath) {const res = await axios.get(geoJsonPath);return res.data;}return null;} catch (error) {console.error('加载GeoJson失败:', error);return null;}
};// 初始化全国地图
const initChinaMap = async () => {currentLevel.value = 0;currentMapName.value = '中国';breadcrumb.value = ['中国'];const geoJson = await loadGeoJson('中国');if (geoJson) {currentMapData.value = geoJson;currentChartData.value = mockData.china;}
};// 向下钻取
const handleDrillDown = async (name) => {if (currentLevel.value === 0) {// 从全国钻取到省份const geoJson = await loadGeoJson(name);if (geoJson) {currentLevel.value = 1;currentMapName.value = name;breadcrumb.value = ['中国', name];currentMapData.value = geoJson;currentChartData.value = mockData[name.toLowerCase()] || [];}} else if (currentLevel.value === 1) {// 从省份钻取到城市const cityData = mockData[currentMapName.value.toLowerCase()];const city = cityData.find(item => item.name === name);if (city) {currentLevel.value = 2;breadcrumb.value = ['中国', currentMapName.value, name];// 这里可以继续加载更详细的GeoJson数据}}
};// 向上钻取
const drillUp = () => {if (currentLevel.value === 1) {initChinaMap();} else if (currentLevel.value === 2) {const provinceName = breadcrumb.value[1];handleDrillDown(provinceName);}
};// 面包屑导航点击
const handleBreadcrumbClick = (index) => {if (index === 0 && currentLevel.value !== 0) {initChinaMap();} else if (index === 1 && currentLevel.value === 2) {const provinceName = breadcrumb.value[1];handleDrillDown(provinceName);}
};onMounted(() => {initChinaMap();
});
</script><style scoped>
.map-container {position: relative;width: 100%;height: 100%;
}.breadcrumb {margin-bottom: 15px;font-size: 16px;
}.breadcrumb span {cursor: pointer;margin: 0 5px;color: #666;
}.breadcrumb span.active {color: #333;font-weight: bold;
}.breadcrumb span:hover {text-decoration: underline;
}.drill-btn {position: absolute;top: 10px;right: 10px;z-index: 100;padding: 5px 10px;background-color: #409eff;color: white;border: none;border-radius: 4px;cursor: pointer;
}.drill-btn:hover {background-color: #66b1ff;
}
</style>

5. 使用组件

在App.vue中使用我们的地图组件:

<template><div id="app"><h1>区域地图钻取示例</h1><MapDrillDown /></div>
</template><script setup>
import MapDrillDown from './components/MapDrillDown.vue';
</script><style>
#app {font-family: Avenir, Helvetica, Arial, sans-serif;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;text-align: center;color: #2c3e50;margin-top: 20px;padding: 20px;
}
</style>

二、功能亮点

  1. 多级钻取:支持从全国地图钻取到省级,再钻取到市级
  2. 面包屑导航:清晰的层级导航,可以快速返回上级
  3. 响应式设计:图表随窗口大小自动调整
  4. 视觉效果:使用渐变色表示数据强度
  5. 交互体验:鼠标悬停显示详细信息,点击实现钻取

三、性能优化建议

  • GeoJson数据精简:使用简化后的 GeoJson 数据减少体积
  • 数据缓存:对已加载的 GeoJson 数据进行缓存
  • 按需加载:只在需要时加载下一级地图数据
  • 防抖处理:对窗口 resize 事件添加防抖
  • Web Worker:大数据量处理可以使用 Web Worker

四、常见问题解决

  1. 地图显示不完整:

    • 检查 GeoJson 数据是否完整
    • 确保 ECharts 正确注册了地图数据
    • 确认地图名称与注册名称一致
  2. 钻取后数据不显示:

    • 检查 mock 数据中是否有对应区域的数据
    • 确认数据格式是否符合 ECharts 要求
    • 查看控制台是否有错误信息
  3. 地图渲染性能问题:

    • 简化 GeoJson 数据
    • 使用 EChartslarge 模式
    • 考虑使用 Canvas 渲染代替 SVG

五、结语

通过本文的介绍,我们实现了一个基于 Vue3EChartsGeoJson 的区域地图钻取功能。这种技术可以广泛应用于各种需要地理数据展示的场景,如商业分析、疫情监控、物流管理等。希望本文能对你的项目开发有所帮助。

六、实战demo

集成到界面设计引擎,体验地址:https://www.nbweixin.cn/autopage/
从左边拖动一个区域地图组件即可查看效果。

在这里插入图片描述

七、资源下载

🔗全国地图geojson包 :https://download.csdn.net/download/mss359681091/90657356?spm=1001.2014.3001.5501

🔗完整demo:https://download.csdn.net/download/mss359681091/90657456?spm=1001.2014.3001.5501

相关文章:

基于 Vue3 + ECharts + GeoJson 实现区域地图钻取功能详解

文章目录 前言一、实现步骤1. 项目初始化2. 准备GeoJson数据3. 创建地图组件4. 创建主页面组件5. 使用组件 二、功能亮点三、性能优化建议四、常见问题解决五、结语六、实战demo七、资源下载 前言 在数据可视化领域&#xff0c;地图展示是一种非常直观的表现形式。而地图钻取&…...

安卓学习24 -- 网络

1 整体架构 &#xff08;出处见水印&#xff09; 这两张是能找到的比较清楚的图。目前可以看出&#xff0c;底层的网络业务&#xff0c;还是传统的linux内核提供。&#xff08;注&#xff1a;这两个图我个人觉得不是非常对。。。&#xff09; 在安卓上增加的两个比较重要的部…...

github新建一个远程仓库并添加了README.md,本地git仓库无法push

1.本地git仓库与远程仓库绑定 2.push时报错&#xff0c;本地的 main 分支落后于远程仓库的 main 分支&#xff08;即远程有更新&#xff0c;但你本地没有&#xff09;&#xff0c;需要拉取远程的仓库--->在merge合并&#xff08;解决冲突&#xff09;--->push 3.但是git …...

Python:使用web框架Flask搭建网站

Date: 2025.04.19 20:30:43 author: lijianzhan Flask 是一个轻量级的 Python Web 开发框架&#xff0c;以简洁灵活著称&#xff0c;适合快速构建中小型 Web 应用或 API 服务。以下是 Flask 的核心概念、使用方法和实践指南 Flask 的核心特点&#xff1a; 轻量级 核心代码仅约…...

FTP协议命令和响应码

文章目录 &#x1f4e6; 一、什么是 FTP 协议&#xff1f;&#x1f9fe; 二、FTP 常见命令&#xff08;客户端发送&#xff09;&#x1f4e1; 三、FTP 响应码&#xff08;服务端返回&#xff09;&#x1f4cc; 响应码分类&#xff08;第一位&#xff09;✅ 常见成功响应码&…...

*数字信号基础

数字信号基础&#xff1a;从采样到处理的完整解析 数字信号是离散时间、离散幅度的信号&#xff0c;与连续时间的模拟信号相对。它在现代通信、音频处理、图像识别等领域有广泛应用。以下是数字信号的核心概念、处理流程及关键技术。 1. 数字信号 vs. 模拟信号 特性模拟信号数…...

Kotlin delay方法解析

本文记录了kotlin协程(Android)中delay方法的字节码实现&#xff0c;并解析了delay方法如何实现挂起操作。 一、delay方法介绍 1.1、delay方法使用举例 class TestDelay {suspend fun testDelay() {Log.d("TestDelay", "before delay")delay(1000)Log.d…...

PHP框架在大规模分布式系统中的适用性如何?

随着互联网业务的指数级增长&#xff0c;大规模分布式系统已成为支撑高并发、高可用服务的核心技术架构&#xff0c;同时也成为众多互联网企业的首选架构。本文将带大家全面剖析PHP框架在分布式系统中的适用性&#xff0c;并结合实战案例帮大家提供技术选型建议。 一、PHP框架…...

【Vulkan 入门系列】创建描述符集布局和图形管线(五)

描述符集布局定义了着色器如何访问资源&#xff08;如缓冲区和图像&#xff09;&#xff0c;是渲染管线配置的关键部分。图形管线定义了从顶点数据到最终像素输出的整个处理流程&#xff0c;包括可编程阶段&#xff08;如顶点和片段着色器&#xff09;和固定功能阶段&#xff0…...

Web前端:百度首页克隆 - 前端开发练习

一、项目概述 1.1 练习目标&#xff1a;通过实现百度首页经典布局掌握HTMLCSS基础布局能力 1.2 功能要求&#xff1a; 顶部导航栏布局中央搜索区布局底部信息栏布局基础交互效果 二、技术栈 HTML5 语义化标签CSS3 样式传统布局方案&#xff08;浮动布局&#xff09;基础CSS…...

mysql中in的用法详解

MySQL 中 IN 操作符用法详解 IN 是 MySQL 中用于多值筛选的高效操作符&#xff0c;常用于 WHERE 子句&#xff0c;可替代多个 OR 条件&#xff0c;简化查询逻辑并提升可读性。以下从基础语法、应用场景、性能优化、常见问题及高级技巧进行全方位解析。 一、基础语法与优势 1.…...

MySQL为什么默认使用RR隔离级别?

大家好&#xff0c;我是锋哥。今天分享关于【MySQL为什么默认使用RR隔离级别?】面试题。希望对大家有帮助&#xff1b; MySQL为什么默认使用RR隔离级别? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 MySQL 默认使用 RR&#xff08;Repeatable Read&#xff09;…...

施磊老师基于muduo网络库的集群聊天服务器(二)

文章目录 Cmake简单介绍Cmake与MakefileCmake配置CmakeLists.txt 编写完整cmake例子文件夹杂乱问题多级目录Cmakevscode 极其推荐 的 cmake方式 Mysql环境与编程mysql简单使用User表Friend表AllGroup表GroupUser表OfflineMessage表 集群聊天项目工程目录创建网络模块代码Chatse…...

Git拉分支技巧:从零开始创建并推送分支

Git拉分支技巧&#xff1a;从零开始创建并推送分支 在团队协作开发中&#xff0c;Git 分支管理是不可或缺的技能。合理地创建、同步和推送分支&#xff0c;不仅能提高开发效率&#xff0c;还能避免代码冲突。本文将基于以下技巧&#xff0c;详细讲解如何从零开始创建并推送一个…...

Kotlin实现Android应用保活方案

Kotlin实现Android应用保活优化方案 以下的Android应用保活实现方案&#xff0c;更加符合现代Android开发规范&#xff0c;同时平衡系统限制和用户体验。 1. 前台服务方案 class OptimizedForegroundService : Service() {private val notificationId 1private val channel…...

Mysql insert一条数据的详细过程

以下是MySQL在接收到INSERT语句后存储数据的详细过程解析&#xff0c;结合存储引擎&#xff08;以InnoDB为例&#xff09;和物理存储机制分步说明。 一、SQL解析与事务启动 1.语法解析 MySQL首先解析INSERT语句&#xff0c;验证字段是否存在、数据类型是否匹配、约束&#xf…...

线性DP:最长上升子序列(子序列可不连续,子数组必须连续)

目录 Q1&#xff1a;简单遍历 Q2&#xff1a;变式&#xff08;加大数据量&#xff09; Q1&#xff1a;简单遍历 Dp问题 状态表示 f(i,j) 集合所有以第i个数结尾的上升子序列集合-f(i,j)的值存的是什么序列长度最大值max- 状态计算 &#xff08;其实质是集合的划分&#xff09;…...

C语言之文本加密程序设计

&#x1f31f; 嗨&#xff0c;我是LucianaiB&#xff01; &#x1f30d; 总有人间一两风&#xff0c;填我十万八千梦。 &#x1f680; 路漫漫其修远兮&#xff0c;吾将上下而求索。 文本加密程序设计 摘要&#xff1a;本文设计了一种文本加密程序&#xff0c;旨在提高信息安…...

生成器模式深入解析与 Spring 源码应用

摘要 本文以生成器模式为研究对象&#xff0c;采用通俗易懂的表述方式&#xff0c;详细阐释其核心概念与运行机制。通过构建游戏角色创建、电商订单生成等实际 Java 案例&#xff0c;直观呈现该模式在复杂对象构建中的应用优势。同时&#xff0c;深入剖析 Spring 框架源码&…...

云效部署实现Java项目自动化部署图解

前言 记录下使用云效部署Java项目&#xff0c;实现java项目一键化自动化部署。 云效流程说明&#xff1a; 1.云效拉取最新git代码后 2.进行maven编译打包后&#xff0c;上传到指定服务器目录 3.通过shell脚本&#xff0c;先kill java项目后&#xff0c;通过java -jar 启动项…...

0801ajax_mock-网络ajax请求1-react-仿低代码平台项目

0 vite配置proxy代理 vite.config.ts代码如下图所示&#xff1a; import { defineConfig } from "vite"; import react from "vitejs/plugin-react";// https://vite.dev/config/ export default defineConfig({plugins: [react()],server: {proxy: {&qu…...

基于Python智能体API的Word自动化排版系统:从零构建全流程模块化工作流与版本控制研究

基于Python智能体API的Word自动化排版系统:从零构建全流程模块化工作流与版本控制实践研究 1. 引言2. 研究背景与意义3. 自动排版工作流的设计原理3.1 文档内容提取与解析3.2 样式参数与格式化规则3.3 智能体API接口调用3.4 自动生成与批量处理3.5 与生成式AI的协同4. 系统架构…...

Java【网络原理】(4)HTTP协议

目录 1.前言 2.正文 2.1自定义协议 2.2HTTP协议 2.2.1抓包工具 2.2.2请求响应格式 2.2.2.1URL 2.2.2.2urlencode 2.2.3认识方法 2.2.3.1GET与POST 2.2.3.2PUT与DELETE 2.2.4请求头关键属性 3.小结 1.前言 哈喽大家好啊&#xff0c;今天来继续给大家带来Java中网络…...

每天学一个 Linux 命令(27):head

​​可访问网站查看,视觉品味拉满: http://www.616vip.cn/27/index.html head 是 Linux 中用于查看文件开头部分内容的命令,默认显示文件前 10 行,适合快速预览文件结构或日志头部信息。 命令格式 head [选项] [文件]常用选项 选项说明-n <行数>指定显示前 N 行(如…...

【2025软考高级架构师】——计算机系统基础(7)

摘要 本文主要介绍了计算机系统的组成&#xff0c;包括硬件和软件两大部分。硬件由处理器、存储器、总线、接口和外部设备等组成&#xff0c;软件则涵盖系统软件和应用软件。文章还详细阐述了冯诺依曼计算机的组成结构&#xff0c;包括 CPU、主存储器、外存等&#xff0c;并解…...

自定义 strlen 函数:递归实现字符串长度计算

目录 自定义 strlen 函数&#xff1a;递归实现字符串长度计算 一.引言 二.代码呈现 三.代码结构与功能概述 1.自定义 my_strlen 函数 1.函数参数与功能 2.代码逻辑分析 1.参数有效性检查&#xff1a; 2.递归计算字符串长度&#xff1a; 2.main 函数 1.变量定义 2.函…...

LeetCode 打家劫舍+删除并获得点数

题目描述 打家劫舍题目传送门1 删除并获得点数传送门2 思路 这两道题看似毫无关系&#xff0c;但竟然可以用桶数组联系起来&#xff01;&#xff01; 先说打家劫舍这道题 限制条件是不能走相邻的屋&#xff0c;再联想到跳台阶&#xff08;走一格或两格&#xff09;&#x…...

图解MCP:Model Context Protocol

&#x1f9e0; 向所有学习者致敬&#xff01; “学习不是装满一桶水&#xff0c;而是点燃一把火。” —— 叶芝 我的博客主页&#xff1a; https://lizheng.blog.csdn.net &#x1f310; 欢迎点击加入AI人工智能社区&#xff01; &#x1f680; 让我们一起努力&#xff0c;共创…...

【网络】数据链路层知识梳理

全是通俗易懂的讲解&#xff0c;如果你本节之前的知识都掌握清楚&#xff0c;那就速速来看我的笔记吧~ 自己写自己的八股&#xff01;让未来的自己看懂&#xff01; &#xff08;全文手敲&#xff0c;受益良多&#xff09; 数据链路层 我们来重新理解一下这个图&#xff1a;…...

积木报表查询出现jdbc.SQLServerException: 对象名 ‘user_tab_comment 的解决方法

目录 前言1. 问题所示2. 解决方法前言 🤟 找工作,来万码优才:👉 #小程序://万码优才/r6rqmzDaXpYkJZF 爬虫神器,无代码爬取,就来:bright.cn 1. 问题所示 使用帆软报表无错,后续使用积木报表查询出错: 没有显示报表: 具体错误信息如下:...