You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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='&copy; <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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 10:20:25