React Leaflet函数式组件实现本地Shapefile文件加载需求
实现本地Shapefile(.shp/.shx/.qml)加载到React-Leaflet地图
首先需要安装依赖包:
npm install react-leaflet leaflet leaflet.shapefile xml-js
以下是完整的函数式组件实现:
import React, { useState, useRef, useEffect } from 'react'; import { MapContainer, TileLayer } from 'react-leaflet'; import L from 'leaflet'; import 'leaflet.shapefile'; import { xml2js } from 'xml-js'; const ShapefileLoaderMap = () => { const [selectedFiles, setSelectedFiles] = useState({ shp: null, shx: null, qml: null }); const mapRef = useRef(null); const shapeLayerRef = useRef(null); // 处理本地文件选择 const handleFileChange = (e) => { const files = Array.from(e.target.files); const fileMap = {}; files.forEach(file => { const ext = file.name.split('.').pop().toLowerCase(); if (['shp', 'shx', 'qml'].includes(ext)) { fileMap[ext] = file; } }); setSelectedFiles(prev => ({ ...prev, ...fileMap })); }; // 加载Shapefile并应用QML样式 useEffect(() => { if (!selectedFiles.shp || !selectedFiles.shx || !mapRef.current) return; // 移除已存在的旧图层 if (shapeLayerRef.current) { mapRef.current.removeLayer(shapeLayerRef.current); } // 读取shp和shx文件的ArrayBuffer const shpReader = new FileReader(); const shxReader = new FileReader(); shpReader.onload = function() { shxReader.onload = function() { // 创建Shapefile图层 const shapeLayer = L.shapefile({ shp: shpReader.result, shx: shxReader.result }); // 解析并应用QML样式(如果存在) if (selectedFiles.qml) { const qmlReader = new FileReader(); qmlReader.onload = function() { const qmlJson = xml2js(qmlReader.result, { compact: true }); const styleProps = {}; // 提取QML中的基础样式属性 if (qmlJson.qml?.renderer?.symbol) { const symbol = qmlJson.qml.renderer.symbol; styleProps.fillColor = symbol.fill?.$.color || '#3388ff'; styleProps.color = symbol.stroke?.$.color || '#000000'; styleProps.weight = parseInt(symbol.stroke?.$.width) || 1; styleProps.fillOpacity = parseFloat(symbol.fill?.$.opacity) || 0.5; } shapeLayer.setStyle(styleProps); }; qmlReader.readAsText(selectedFiles.qml); } // 添加图层到地图并保存引用 shapeLayer.addTo(mapRef.current); shapeLayerRef.current = shapeLayer; // 自动适配地图视野到图层范围 mapRef.current.fitBounds(shapeLayer.getBounds()); }; shxReader.readAsArrayBuffer(selectedFiles.shx); }; shpReader.readAsArrayBuffer(selectedFiles.shp); // 组件卸载时清理图层 return () => { if (shapeLayerRef.current) { mapRef.current?.removeLayer(shapeLayerRef.current); } }; }, [selectedFiles]); return ( <div style={{ height: '80vh', width: '100%' }}> <div style={{ padding: '10px' }}> <input type="file" multiple accept=".shp,.shx,.qml" onChange={handleFileChange} /> <p>请选择.shp、.shx(必填)和.qml(可选)文件</p> </div> <MapContainer ref={mapRef} center={[51.505, -0.09]} zoom={13} style={{ height: '100%', width: '100%' }} > <TileLayer attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors' url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" /> </MapContainer> </div> ); }; export default ShapefileLoaderMap;
关键逻辑说明
- 文件选择:通过
multiple属性支持批量选择文件,按扩展名分类存储核心的.shp/.shx文件和可选的.qml样式文件。 - Shapefile解析:利用
FileReader读取本地文件的ArrayBuffer,通过leaflet.shapefile库解析并创建地图图层。 - QML样式适配:将XML格式的QML转为JSON对象,提取填充色、边框色等基础样式属性并应用到图层,可根据实际QML结构扩展样式解析逻辑。
- 图层管理:维护图层引用,确保重新加载时移除旧图层,避免重复叠加;组件卸载时自动清理资源。
内容的提问来源于stack exchange,提问作者Sammith Gowda
相关产品推荐
相关产品推荐

