news 2026/9/20 20:36:39

WebGIS空气质量可视化实战:Leaflet+ECharts构建湖南省级监测系统源码解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
WebGIS空气质量可视化实战:Leaflet+ECharts构建湖南省级监测系统源码解析

简介:这是一份面向 WebGIS 入门者、前端开发者及环保数据分析人员的可运行源码包。项目以湖南省空气质量为实际案例,演示了从百度天气接口获取实时空气质量数据,再通过 Leaflet 实现 WebGIS 可视化展示的完整流程,包含省内中、重污染地区与优质环境区域的分布对比,以及污染严重和空气质量优的前10名区县排名。压缩包共3个文件,整体仅7KB,以 HTML 单页应用为核心,辅以 inscode 在线环境配置与 gitignore 忽略规则文件,结构轻量、打开即用,便于快速查看页面效果并进行定制改造。已有46人学习下载这份源码包。读者可从中掌握天气数据请求与解析、Leaflet 地图叠加、分级设色、排名榜单渲染等关键实现技巧,并可将数据源替换为其他地区接口,复用于课程设计、毕业设计或地方环境监测可视化项目。 先说一个背景:这两年做环境数据展示的项目特别多,空气质量、水质监测、噪声监测,五花八门。但真正能落地的很少,很多项目要么打开要配半天环境,要么数据写死在地图上一动不能动。我手上这个“湖南空气质量WebGIS可视化”项目,是实打实把WebGIS、数据可视化和可运行源码三者揉在一起做的,身边不少同事拿着源码改一改就接到自己项目里用了。这篇文章就把整个实现过程、技术选型和踩坑记录完整写出来,给准备做类似可视化项目的朋友一个参考。

这个项目解决的核心问题很明确:让没有GIS基础的人,也能在浏览器里直观看到湖南省各市州的空气质量实况和变化趋势。它不是简单地把数据塞进表格,而是把地图、空气质量指数(AQI)分级、时间轴联动、统计图表全部串起来,形成一套交互完整的可视化系统。不管是做环境监测汇报、政务大屏,还是毕业论文里的系统演示,这套源码都够用。

如果你正准备做WebGIS相关的毕业设计、数据可视化课程项目,或者要快速搭一个省级区域的环境监测原型系统,这篇文章可以直接帮你避开大部分弯路。下面按我的实际开发顺序来拆解。

1. 整体设计思路:为什么选WebGIS而不是纯图表

先回答一个我经常被问的问题:这种空气质量数据,用ECharts画个柱状图、折线图不就行了吗?为什么要引入地图?

1.1 核心需求解析:空间属性决定技术路线

空气质量数据有很强的空间属性——“湖南哪个市污染最重”“长株潭一带和湘西的差异有多大”,这些问题不放到地图上,根本看不出来。柱状图只能告诉你数值排序,不能告诉你地理分布。而WebGIS天然擅长解决“数据+位置”的关联展示,这也是我坚定不移选这个方向的原因。

另一个考虑是展示效率。一张湖南省地图,14个市州按AQI颜色一铺,哪个区域红、哪个区域绿,扫一眼就清楚,领导汇报时也愿意看。相比表格和普通图表,这种方式信息传递效率高一个量级。

1.2 技术选型:Leaflet + ECharts组合的取舍

市面上的WebGIS方案大致分三类:Cesium(三维场景)、OpenLayers(功能全面)、Leaflet(轻量灵活)。

我做这个项目选的是Leaflet + ECharts的组合。原因有三:

  • Leaflet 只有40KB左右,对普通浏览器极其友好,不需要重型GIS服务器,一个静态页面就能跑起来
  • ECharts 的地图注册机制可以直接对接GeoJSON,用它来绘制湖南各市州边界非常顺手(有待实践,其实用Leaflet做边界绘制更顺滑,但这里我选择了ECharts统计图配Leaflet底图的混合方案)
  • 两者都是MIT协议,对源码分发、二次开发没有限制

如果你项目里已有天地图、高德或百度底图需求,Leaflet也都有对应插件,扩展性足够。唯一要提的是:视频宣传或大屏展示要求高的话,可以考虑Cesium,但本项目定位是“快速、可运行、易修改”,轻量组合才是正确选择。

1.3 预期效果与适用范围

最终做出来的系统,打开浏览器就是一张湖南地图,上面铺满14个市州的点位。点一个市,弹窗显示AQI数值、首要污染物、等级。底部是时间轴,拖动滑块可以看到不同日期的空气质量变化,右侧是统计面板,展示全省的优良天数比例、月度趋势。

适用范围既有演示汇报,也适合教学。学生用这套源码可以快速理解WebGIS的数据流——从数据获取、空间匹配到图层渲染,几行代码就能看见效果。

2. 核心实现细节:数据结构、图层渲染与联动交互

2.1 数据结构设计:GeoJSON和属性表怎么配合

这套系统里有两类核心数据:一个是湖南省各市州的边界GeoJSON,一个是每个市州的空气质量监测数据。

边界数据长这样:

{ "type": "FeatureCollection", "features": [ { "type": "Feature", "properties": { "name": "长沙市", "adcode": 430100 }, "geometry": { "type": "MultiPolygon", "coordinates": [...] } } ] }

空气质量数据则是一张平铺的属性表,字段为日期、城市、AQI、PM2.5、PM10、首要污染物等。前端拿到属性表后,按城市名和日期字段去匹配GeoJSON里的要素,这就实现了“空间数据+业务数据”的关联。

这里有一个实操要点:城市名的匹配必须统一,比如GeoJSON里是“长沙市”,数据表里也必须是“长沙市”,不能写成“长沙”或“湖南长沙”。我一开始就是因为这个匹配问题,排查了半天地图上不显示数据。建议在数据预处理阶段就清洗统一行政区划名称。

2.2 Leaflet底图加载和地图初始化

Leaflet的初始化代码非常简洁,只需要指定一个div容器和中心点坐标就行:

const map = L.map('map', { center: [27.6, 111.9], zoom: 7, zoomControl: true });

然后加载一个合适的底图瓦片。这里我用的是高德地图的瓦片服务(注意需要申请Key,也可以直接用OpenStreetMap的公开瓦片):

L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { attribution: '© OpenStreetMap contributors' }).addTo(map);

这里提醒一下:底图选择不仅要看清晰度,还要考虑偏色。我最初用了一个偏暗的地形图,结果AQI分级色(绿色、黄色、红色)在上面对比度很低,领导演示时直接说看不清。后来换成浅色底图,效果立刻不一样。给大屏或汇报项目做底图,优先选浅色、低饱和度的。

2.3 空气质量点位渲染和分级着色

这是可视化最核心的部分,也是这个项目最有看点的地方。AQI分级色我参考的是《环境空气质量指数(AQI)技术规定》(HJ 633—2012):

AQI范围等级颜色说明
0-50绿色适宜户外活动
51-100黄色可正常活动
101-150轻度污染橙色敏感人群减少外出
151-200中度污染红色减少户外活动
201-300重度污染紫色避免户外活动
>300严重污染褐红色尽量避免外出

在代码里,我做了一个函数来返回对应颜色:

function getAQIColor(aqi) { if (aqi <= 50) return '#00e400'; if (aqi <= 100) return '#ffff00'; if (aqi <= 150) return '#ff7e00'; if (aqi <= 200) return '#ff0000'; if (aqi <= 300) return '#99004c'; return '#7e0023'; }

渲染时,我用了圆形Marker来表示各市州空气质量。半径大小映射AQI值(AQI越大圆越大),颜色映射分级色。这样一套规则下来,地图上信息的视觉呈现就是一目了然的双变量映射:

L.circleMarker([lat, lng], { radius: Math.max(aqi / 8, 8), color: '#fff', weight: 1, fillColor: getAQIColor(aqi), fillOpacity: 0.8 }).bindPopup(content).addTo(layerGroup);

这里注意radius的计算方式。直接用AQI值作为radius,最大值500会让圆点太大,所以除以8再兜底最小8像素,这样既保留了数值差异感,又不会互相遮挡。

2.4 时间轴联动:从静态展示到动态演变

如果只是展示某一天的空气质量分布,那这个系统的价值就大打折扣了。我在底部加了一个时间滑动条,拖到不同日期,地图上的点位颜色和大小会实时更新。

实现思路是预加载所有日期的数据,存成一个对象:

const dataCache = {}; dataCache['2024-11-01'] = [ { city: '长沙', aqi: 78, pm25: 55 }, { city: '株洲', aqi: 92, pm25: 66 }, // ... ];

拖动时间轴时,触发事件重新渲染全部点位:

slider.addEventListener('input', function() { const date = dateList[this.value]; updateMarkers(dataCache[date]); updateStatsPanel(dataCache[date]); });

联动还有一个细节:右侧统计面板和ECharts图表也绑定了同一个时间状态,这样“地图-统计图-列表”三者始终同步,演示起来非常加分。很多静态可视化和这个的区别,就在于有没有这层联动逻辑。

3. 可视化组件搭建:图表、弹窗和布局优化

3.1 ECharts统计面板:不只是画个折线图

ECharts在这个项目里承担了统计图表的职责。我做的不是简单的各城市AQI排名条形图,而是两大类:

  • 全省月度AQI趋势折线图
  • 各城市首要污染物占比环形图

第一个图用来反映整体走势,第二个图用来展示污染结构。比如长沙市的首要污染物是PM2.5还是臭氧,环形图能直接告诉你占比。

const trendChart = echarts.init(document.getElementById('trendChart')); trendChart.setOption({ xAxis: { type: 'category', data: monthList }, yAxis: { type: 'value', name: 'AQI' }, series: [{ data: monthAvgData, type: 'line', smooth: true, areaStyle: { opacity: 0.2 } }] });

这里我踩过一个坑:ECharts实例在容器被隐藏或尺寸变化时会渲染异常,尤其是嵌在大屏布局里、旁边有折叠面板时。解决办法是在窗口resize时调用chart.resize(),并且用nextTick延迟初始化隐藏的图表容器。

3.2 弹窗内容设计:数据展示的最后一公里

点地图上的圆点,弹出的信息窗口是用户感知数据的第一界面。我的popup里放了四样东西:城市名称、AQI数值与等级、PM2.5 和 PM10 数值、首要污染物。模板用字符串拼接:

const content = ` <div class="popup-card"> <h3>${data.city}</h3> <p>AQI: <strong>${data.aqi}</strong> (${level})</p> <p>PM2.5: ${data.pm25} μg/m³</p> <p>PM10: ${data.pm10} μg/m³</p> <p>首要污染物: ${data.primary}</p> </div> `;

弹窗样式需要注意一下,默认Leaflet弹窗的样式很素,需要覆写CSS,让它看起来更像一个“卡片”,而不是浏览器默认的提示框。我给弹窗加了圆角、阴影和自定义字体,整体质感提升明显。

3.3 图例和辅助信息:专业性的细节体现

地图右下角我固定放了一个AQI分级图例。这个图例非常重要,它不仅是视觉装饰,更是数据解读的规则说明。没有图例,用户看到不同颜色的圆点只能靠猜。实现方式很简单,用Leaflet的L.control自定义一个控件:

const legend = L.control({ position: 'bottomright' }); legend.onAdd = function() { const div = L.DomUtil.create('div', 'legend'); div.innerHTML = ` <div><span style="background:#00e400"></span>优</div> <div><span style="background:#ffff00"></span>良</div> <div><span style="background:#ff7e00"></span>轻度</div> <div><span style="background:#ff0000"></span>中度</div> <div><span style="background:#99004c"></span>重度</div> <div><span style="background:#7e0023"></span>严重</div> `; return div; }; legend.addTo(map);

这一块建议大家都保留,很多可视化项目最终被吐槽“看不懂颜色”,就是缺了这个细节。

4. 数据获取思路与可运行源码的组织方式

4.1 数据来源:模拟数据、公开API与爬虫的取舍

这个项目的实践数据我用了公开空气质量接口的样例行。大家在复现时,有三种数据来源可选:

  • 公开API:中国环境监测总站和部分天气平台有AQI接口,但存在跨域和请求频率限制,需要后端代理
  • 静态模拟数据:代码里内置一份比较接近真实分布的模拟数据,保证离线也能演示
  • 爬虫抓取(谨慎使用):爬取公开空气质量站点数据,注意遵守robots协议,且数据量小的情况下完全没必要

我这套系统最终在源码里配的是静态数据 + API 接口预留的方式。直接把数据文件放在public/data/目录下,前端通过fetch加载。同时留了一个api.js模块,后续如果要接真实接口,把请求地址和参数填进去就行。

这种设计是“可运行源码”最稳妥的形态——用户拿到代码后即使没有网络、没有数据库,也能立刻看到效果;想上生产,改改数据源就能用。

4.2 完整目录结构与运行环境

项目基于Vue 3 + Vite 构建,前端环境非常干净,不需要安装GIS服务端组件。目录结构如下:

air-quality-webgis/ ├── index.html ├── package.json ├── vite.config.js ├── public/ │ └── data/ │ ├── hunan.geojson │ └── air-quality.json └── src/ ├── main.js ├── App.vue ├── components/ │ ├── MapView.vue │ ├── StatsPanel.vue │ ├── TimeSlider.vue │ └── LegendControl.vue ├── utils/ │ ├── aqi.js │ └── fetchData.js └── styles/ └── main.css

MapView.vue 负责地图相关的所有逻辑,StatsPanel.vue 管图表,TimeSlider.vue 管时间轴,组件间通过事件总线或全局状态通信。这种拆分的好处是:如果你只想单独用地图模块,直接取 MapView.vue 就行,不会牵连图表逻辑。

4.3 启动和打包命令

复现这个项目,只需要三个命令:

npm install npm run dev npm run build

第一行安装依赖,第二行启动开发服务器,访问http://localhost:5173就能看到系统。第三行是打包命令,输出到dist/目录,可以直接扔到Nginx、Apache或者静态托管平台上。

开发调试时,Vite的热更新响应非常快,改完代码浏览器立即生效。这个体验对反复调整地图样式、弹窗布局来说很重要。

5. 常见问题与排查经验:这些坑我踩过

5.1 地图不显示或白屏

八成是底图瓦片请求被浏览器拦截了。跨域问题在本地开发时最常出现,打开控制台Network面板,能看到红色报错信息。解决办法:

  • 检查底图URL是否使用HTTPS
  • 换用支持跨域的底图服务
  • 在vite.config.js里配置 devServer 的 proxy 代理

5.2 GeoJSON加载后行政区划不显示

如果是ECharts地图,需要注册地图数据:echarts.registerMap('hunan', geoJson),很多新手漏掉这一步。Leaflet这边则要注意L.geoJSON(data).addTo(map)的data是否已经是一个对象而非字符串。

另一个常见的低级错误是GeoJSON坐标超出湖南范围,导致地图边界被拉伸到奇怪的位置。排查时可以打印一下layer.getBounds(),确认边界是否在[北纬24度-30度,东经108度-114度]这个区间。

5.3 弹窗打不开或数据不对

弹窗内容绑定的是点位数据,如果绑定的是初始化的第一个对象,那无论点哪个城市弹窗都一样。检查一下bindPopup是否在遍历循环中正确传递了当前项,而不是直接用var声明导致的闭包变量共享。

ES6里用let声明循环变量可以解决这个问题,但旧代码习惯用var,我在一次维护时也踩过这个坑,弹窗永远显示最后一条数据。

5.4 自适应布局和大屏适配

可视化项目经常要放到大屏上展示,分辨率可能是1920x1080或更高。我的做法是外层容器百分比布局,地图高度用calc(100vh - 其他高度)计算,图表容器用ECharts的resize监听。对于更强的大屏适配,可以上transform: scale()方案,但目前的轻量系统按百分比布局已经足够。

最后再分享一个扩展技巧:接入实时数据源

这套系统的架构决定了扩展实时数据非常方便。你只需要在api.js里加一个轮询函数,每5分钟拉取一次最新的空气质量数据,然后调用updateMarkers()刷新点位就行:

setInterval(async () => { const latest = await fetchLatestData(); updateMarkers(latest); }, 5 * 60 * 1000);

如果数据变动的频率不高,还可以用WebSocket做服务端推送,但那样需要额外的后端支持。实测下来,5分钟轮询已经能满足大多数环境监测场景的需求,而且实现成本极低。

我个人的体会是:这种“GIS + 数据可视化 + 前端工程化”的组合,在未来的环境监测、智慧城市、农业气象等领域会越来越常用,学会这套技术栈,不只是能做一个空气质量系统,很多类似场景都能复用。希望这篇内容能帮正在做类似项目的朋友少走弯路,如果有其他问题,欢迎在评论区交流,我看到了都会回复。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/20 20:35:52

Hermes部署实战:打造养成系AI私人助理

去年换了台内存稍微宽裕点的机器&#xff0c;我做的第一件事不是搭博客&#xff0c;也不是跑游戏服务端&#xff0c;而是给自己装了一个真正能"接手干活"的数字助理。这个项目叫 Hermes&#xff0c;中文社区里习惯叫它"赫耳墨斯"&#xff0c;从命名就能看出…

作者头像 李华
网站建设 2026/9/20 20:34:51

金仓SQL防火墙:数据库安全防护实战解析

1. 数据库安全防护的最后一公里十年前我刚入行时参与过一个电商项目&#xff0c;凌晨三点被电话惊醒——用户数据被拖库了。攻击者利用一个普通的查询接口&#xff0c;通过精心构造的SQL语句&#xff0c;像用吸管喝奶茶一样把整个用户表数据抽得一干二净。那次事件让我深刻认识…

作者头像 李华
网站建设 2026/9/20 20:32:11

政务信息化软件开发预算编制:从功能点到人月费率的成本估算全解析

简介&#xff1a;这是广东省省级政务信息化服务预算编制标准&#xff08;试行&#xff09;软件开发服务分册的完整版&#xff0c;面向政务信息化项目预算编制人员、软件服务提供商及评审专家&#xff0c;解决软件开发类服务预算口径不统一、测算方法不明确等问题。资源包为单个…

作者头像 李华