react + leaflet 基础底图图层组hooks封装

1、useLayerGroup.js


import { useEffect } from 'react';

const { L } = window;

const { TILE_URL, TK } = window.TDT_CONFIG;

const useLayerGroup = (layerGroup, mapInfo) => {
    const { type, projection, name, minZoom, maxZoom } = mapInfo.toJS();
    const noteType = getNoteName();
    
    useEffect(() => {
        const mapId = `base_map_${type}_layer`;
        const noteId = `base_note_${noteType}_layer`;
        const existLayers = layerGroup.getLayers();

        if (existLayers.length) {
            updateLayerGroup(existLayers, mapId, noteId);
        } else {
            addLayerGroup(mapId, noteId);
        }  
    }, [mapInfo]);

    /**
     * 图层组添加新图层
     * @param {*} mapId 
     * @param {*} noteId 
     */
    function addLayerGroup(mapId, noteId) {
        const mapLayer = getLayer(type, mapId);
        layerGroup.addLayer(mapLayer);
        if (name) {
            const noteLayer = getLayer(noteType, noteId,)
            layerGroup.addLayer(noteLayer);
        }
    }

    /**
     * 更新图层组
     * @param {*} existLayers 
     * @param {*} mapId 
     * @param {*} noteId 
     */
    function updateLayerGroup(existLayers, mapId, noteId) {
        existLayers.forEach((layer, index) => {
            const { id } = layer.options;
            if (id.startsWith('base_map')) {
                if (id !== mapId) {
                    const mapLayer = getLayer(type, mapId);
                    layerGroup.removeLayer(layer);
                    layerGroup.addLayer(mapLayer);
                    mapLayer.setZIndex(index);
                }
            }
            if (id.startsWith('base_note')) {
                if (!noteId) {
                    layerGroup.removeLayer(layer);
                } else {
                    if (id !== noteId) {
                        const noteLayer = getLayer(noteType, noteId);
                        layerGroup.removeLayer(layer);
                        layerGroup.addLayer(noteLayer);
                        noteLayer.setZIndex(index);
                    }
                }
                
            }
        });
        console.log('layerGroup', layerGroup);
    }

    /**
     * 获取图层
     * @param {*} mapType 
     * @param {*} id 
     * @returns 
     */
    function getLayer(mapType, id) {
        const url = `${TILE_URL}/DataServer?T=${mapType}_${projection}&x={x}&y={y}&l={z}&tk=${TK}`;
        const layer = L.tileLayer(url, {
            id,
            minZoom,
            maxZoom
        });
        return layer;
    }

    /**
     * 获取注记名称
     * @returns 
     */
    function getNoteName() {
        if (name) {
            return `${name.split('')[0]}${type.split('')[0]}a`;
        }
        return '';
    }
}

export default useLayerGroup

2、BaseMap.js

import React, { memo, useEffect } from 'react';
import PropTypes from 'prop-types';

import icons from '../../../constant/icons';
import useLayerGroup from '../../../hooks/useLayerGroup';

import style from './BaseMap.module.scss';
const { L } = window;

// 坐标系
L.CRS.CustomEPSG4326 = L.extend({}, L.CRS.Earth, {
    code: 'EPSG:4326',
    projection: L.Projection.LonLat,
    transformation: new L.Transformation(1 / 180, 1, -1 / 180, 0.5),
    scale: function (zoom) {
        return 256 * Math.pow(2, zoom - 1);
    }
})

// marker缓存
let plotsCache = Object.create(null);

// 高亮marker id
let hlmId = '';

// 经纬度缓存
// let lnglatCache = [];
let layerGroup = L.layerGroup();

const BaseMap = memo((props) => {
    const { map, setMap, data = [], selectedId, viewport, mapInfo, editActive, changeEditActive, setEditPanelShow } = props;
    
    useLayerGroup(layerGroup, mapInfo);

    // 实例化地图
    useEffect(() => {
        if (!map) {
            const center = viewport.get('center').toJS()
            const zoom = viewport.get('zoom')
            const map = (window.map = L.map('map', {
                layers: layerGroup,
                zoomControl: false,
                attributionControl: false,
                crs: L.CRS.CustomEPSG4326,
            }));
            map.setView(center, zoom);
            setMap(map);
        }
        // 重绘地图上的图形
        redrawPlots();
    }, [map, data])

    // 注册地图点击事件
    useEffect(() => {
        if (!map) { return; }

        if (editActive) {
            plotsCache[hlmId] && plotsCache[hlmId].setIcon(icons['edit_icon']);
            map.on('click', handleClick);
        } else {
            const name = hlmId.split('_')[1];
            plotsCache[hlmId] && plotsCache[hlmId].setIcon(icons[`${name}_highlight_icon`]);
            map.off('click', handleClick);
        }
        
        function handleClick(e) {
            const { lng, lat } = e.latlng;
            plotsCache[hlmId] && plotsCache[hlmId].setLatLng([lat, lng]);
        }

        return (() => {
            map.off('click', handleClick)
        })
    }, [map, editActive]);

    // 高亮
    useEffect(() => {
        if (!map || !selectedId || !plotsCache[selectedId]) { return }
        highLightMarker(selectedId);
    }, [selectedId]);

    // 重绘marker
    function redrawPlots() {
        if (!map || !data.length) {
            return;
        }
        removeMarker();
        addMarker();
    }

    // 添加marker
    function addMarker() {
        data.forEach(item => {
            const { lng, lat, NID, state } = item;
            const name = state ? 'release' : 'unrelease';
            const marker = L.marker([Number(lat), Number(lng)], { icon: icons[`${name}_icon`] }).addTo(map);
            const id = `${NID}_${name}`;
            marker.id = id;
            plotsCache[id] = marker;
            marker.on('click', () => {
                // 编辑状态开启->点击不同marker时需取消上次编辑内容,关闭编辑状态
                // if (editActive && id !== hlmId) {
                //     changeEditActive(false);
                //     plotsCache[hlmId] && plotsCache[hlmId].setLatLng(lnglatCache);
                // }
                if (id !== hlmId) {
                    changeEditActive(false);
                }
                highLightMarker(id);
                setEditPanelShow(true);
            })
        })
    }

    // 移除marker
    function removeMarker() {
        Object.values(plotsCache).forEach(marker => {
            map.removeLayer(marker);
        });
    }

    // 高亮marker
    function highLightMarker(id) {
        // 取消之前的高亮
        if (hlmId) {
            const prevName = hlmId.split('_')[1];
            plotsCache[hlmId].setIcon(icons[`${prevName}_icon`]); 
        }
        // 添加新高亮
        const curName = id.split('_')[1];
        plotsCache[id].setIcon(icons[`${curName}_highlight_icon`]);
        // 重置高亮maiker id 、 经纬度信息
        hlmId = id;
        // lnglatCache = [lat, lng];
    }

    return (
        <div className={style.map} id="map"></div>
    )
})

BaseMap.displayName = 'BaseMap';

BaseMap.propTypes = {
    map: PropTypes.object,
    setMap: PropTypes.func,
    editActive: PropTypes.bool,
    data: PropTypes.array,
    selectedId: PropTypes.string,
    viewport: PropTypes.object,
    mapInfo: PropTypes.object,
    setEditPanelShow: PropTypes.func,
    changeEditActive: PropTypes.func,
}

export default BaseMap

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值