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

React+MapBox GL JS引入URL服务地址实现自定义图标标记地点、区域绘制功能

实现说明

  1. 自定义图标配置

    • 在 customIcons 对象中定义所有类型的图标URL

    • 支持不同类型的机房、基站和断点使用不同图标

  2. 标记创建函数

    • addCustomMarker 是一个通用函数,用于创建带有自定义图标的标记

    • 可以设置图标URL、标题和自定义CSS类

  3. 标记类型专用函数

    • addComputerRoomMarkers - 添加机房标记

    • addBaseStationMarkers - 添加基站标记

    • addBreakPointMarkers - 添加断点标记

  4. 图标样式控制

    • 通过CSS控制图标大小(32x32像素)

    • 使用 background-image 显示自定义图标

    • 添加了悬停提示(title属性)

import React, { useState, useEffect, useRef } from 'react';const MapComponent = () => {const mapContainer = useRef(null);const map = useRef(null);const [mapLoaded, setMapLoaded] = useState(false);const [markers, setMarkers] = useState([]);const [legendVisible, setLegendVisible] = useState(true);const [visibleLayers, setVisibleLayers] = useState({computerRooms: true,baseStations: true,breakPoints: true});// 模拟图标URL - 实际使用时替换为您的真实图标URLconst customIcons = {computerRoom: {core: 'https://cdn-icons-png.flaticon.com/512/149/149060.png', // 替换为您的核心机房图标edge: 'https://cdn-icons-png.flaticon.com/512/149/149025.png', // 替换为您的边缘机房图标access: 'https://cdn-icons-png.flaticon.com/512/149/149014.png' // 替换为您的接入机房图标},baseStation: {'5g': 'https://cdn-icons-png.flaticon.com/512/4618/4618295.png', // 5G基站图标'4g': 'https://cdn-icons-png.flaticon.com/512/4618/4618286.png', // 4G基站图标'3g': 'https://cdn-icons-png.flaticon.com/512/4618/4618275.png'  // 3G基站图标},breakPoint: 'https://cdn-icons-png.flaticon.com/512/1828/1828665.png' // 断点图标};// 动态加载 Mapbox GL JSuseEffect(() => {if (window.mapboxgl) {setMapLoaded(true);return;}const script = document.createElement('script');script.src = 'https://api.mapbox.com/mapbox-gl-js/v2.2.0/mapbox-gl.js';script.onload = () => {const link = document.createElement('link');link.href = 'https://api.mapbox.com/mapbox-gl-js/v2.2.0/mapbox-gl.css';link.rel = 'stylesheet';document.head.appendChild(link);setMapLoaded(true);};script.onerror = () => console.error('Failed to load Mapbox GL JS');document.head.appendChild(script);return () => {document.head.removeChild(script);};}, []);// 添加带有自定义图标的标记const addCustomMarker = (lnglat, iconUrl, title, className = '') => {if (!map.current) return null;const el = document.createElement('div');el.className = `custom-marker ${className}`;el.style.width = '32px';el.style.height = '32px';el.style.backgroundImage = `url(${iconUrl})`;el.style.backgroundSize = 'contain';el.style.backgroundRepeat = 'no-repeat';el.style.cursor = 'pointer';if (title) el.title = title;const marker = new window.mapboxgl.Marker({element: el,anchor: 'bottom' // 图标底部对准坐标点}).setLngLat(lnglat).addTo(map.current);return marker;};// 添加机房标记const addComputerRoomMarkers = (rooms) => {if (!map.current) return;const newMarkers = rooms.map(room => {const marker = addCustomMarker([room.lng, room.lat],customIcons.computerRoom[room.type],room.name,`computer-room ${room.type}`);return { id: room.id, marker, type: 'computerRoom', originalType: room.type };});setMarkers(prev => [...prev, ...newMarkers]);};// 添加基站标记const addBaseStationMarkers = (stations) => {if (!map.current) return;const newStations = stations.map(station => {const marker = addCustomMarker([station.lng, station.lat],customIcons.baseStation[station.type],`${station.name} (${station.type.toUpperCase()})`,`base-station ${station.type}`);return { id: station.id, marker, type: 'baseStation', originalType: station.type };});setMarkers(prev => [...prev, ...newStations]);};// 添加断点标记const addBreakPointMarkers = (points) => {if (!map.current) return;const newMarkers = points.map(point => {const marker = addCustomMarker([point.lng, point.lat],customIcons.breakPoint,point.title,'break-point');return { id: point.id, marker, type: 'breakPoint' };});setMarkers(prev => [...prev, ...newMarkers]);};// 切换图层可见性const toggleLayerVisibility = (layerType) => {const newVisibility = !visibleLayers[layerType];setVisibleLayers(prev => ({ ...prev, [layerType]: newVisibility }));markers.forEach(marker => {if (marker.type === layerType || (layerType === 'computerRooms' && marker.type === 'computerRoom') ||(layerType === 'baseStations' && marker.type === 'baseStation') ||(layerType === 'breakPoints' && marker.type === 'breakPoint')) {const element = marker.marker.getElement();if (element) {element.style.display = newVisibility ? 'block' : 'none';}}});};// 初始化地图useEffect(() => {if (!mapLoaded || !mapContainer.current) return;map.current = new window.mapboxgl.Map({container: mapContainer.current,style: 'mapbox://styles/mapbox/streets-v11', // 使用默认地图样式center: [111.62299, 40.80772],zoom: 10,minZoom: 7,maxZoom: 19});map.current.on('load', () => {// 添加机房标记const computerRooms = [{ id: 1, name: '核心机房', lng: 111.62, lat: 40.81, type: 'core' },{ id: 2, name: '边缘机房', lng: 111.63, lat: 40.80, type: 'edge' },{ id: 3, name: '接入机房', lng: 111.61, lat: 40.805, type: 'access' }];addComputerRoomMarkers(computerRooms);// 添加基站标记const baseStations = [{ id: 101, name: '5G基站A', lng: 111.615, lat: 40.808, type: '5g' },{ id: 102, name: '4G基站B', lng: 111.625, lat: 40.806, type: '4g' },{ id: 103, name: '3G基站C', lng: 111.635, lat: 40.804, type: '3g' }];addBaseStationMarkers(baseStations);// 添加断点标记const breakPoints = [{ id: 'bp1', lng: 111.625, lat: 40.806, title: '光缆断点1' },{ id: 'bp2', lng: 111.635, lat: 40.8045, title: '光缆断点2' }];addBreakPointMarkers(breakPoints);});return () => {if (map.current) {map.current.remove();}};}, [mapLoaded]);if (!mapLoaded) {return <div style={{display: 'flex',justifyContent: 'center',alignItems: 'center',height: '100vh',fontSize: '18px',color: '#666'}}>正在加载地图资源...</div>;}return (<div style={{ position: 'relative', width: '100%', height: '100vh' }}><div ref={mapContainer} style={{ width: '100%', height: '100%' }} />{/* 图例悬浮框 */}{legendVisible && (<div style={{position: 'absolute',bottom: '20px',right: '20px',backgroundColor: 'white',padding: '15px',borderRadius: '5px',boxShadow: '0 0 10px rgba(0,0,0,0.2)',zIndex: 1,maxWidth: '250px'}}><h3 style={{ marginTop: 0, marginBottom: '15px' }}>地图图例</h3>{/* 机房图例 */}<div style={{ marginBottom: '15px' }}><label style={{ display: 'flex', alignItems: 'center', cursor: 'pointer', marginBottom: '5px' }}><input type="checkbox" checked={visibleLayers.computerRooms}onChange={() => toggleLayerVisibility('computerRooms')}style={{ marginRight: '8px' }}/><span>显示机房</span></label><div style={{ marginLeft: '25px' }}><div style={{ display: 'flex', alignItems: 'center', marginBottom: '3px' }}><img src={customIcons.computerRoom.core} style={{ width: '20px', height: '20px', marginRight: '8px' }} alt="核心机房" /><span>核心机房</span></div><div style={{ display: 'flex', alignItems: 'center', marginBottom: '3px' }}><img src={customIcons.computerRoom.edge} style={{ width: '20px', height: '20px', marginRight: '8px' }} alt="边缘机房" /><span>边缘机房</span></div><div style={{ display: 'flex', alignItems: 'center' }}><img src={customIcons.computerRoom.access} style={{ width: '20px', height: '20px', marginRight: '8px' }} alt="接入机房" /><span>接入机房</span></div></div></div>{/* 基站图例 */}<div style={{ marginBottom: '15px' }}><label style={{ display: 'flex', alignItems: 'center', cursor: 'pointer', marginBottom: '5px' }}><input type="checkbox" checked={visibleLayers.baseStations}onChange={() => toggleLayerVisibility('baseStations')}style={{ marginRight: '8px' }}/><span>显示基站</span></label><div style={{ marginLeft: '25px' }}><div style={{ display: 'flex', alignItems: 'center', marginBottom: '3px' }}><img src={customIcons.baseStation['5g']} style={{ width: '20px', height: '20px', marginRight: '8px' }} alt="5G基站" /><span>5G基站</span></div><div style={{ display: 'flex', alignItems: 'center', marginBottom: '3px' }}><img src={customIcons.baseStation['4g']} style={{ width: '20px', height: '20px', marginRight: '8px' }} alt="4G基站" /><span>4G基站</span></div><div style={{ display: 'flex', alignItems: 'center' }}><img src={customIcons.baseStation['3g']} style={{ width: '20px', height: '20px', marginRight: '8px' }} alt="3G基站" /><span>3G基站</span></div></div></div>{/* 断点图例 */}<div><label style={{ display: 'flex', alignItems: 'center', cursor: 'pointer', marginBottom: '5px' }}><input type="checkbox" checked={visibleLayers.breakPoints}onChange={() => toggleLayerVisibility('breakPoints')}style={{ marginRight: '8px' }}/><span>显示断点</span></label><div style={{ marginLeft: '25px' }}><div style={{ display: 'flex', alignItems: 'center' }}><img src={customIcons.breakPoint} style={{ width: '20px', height: '20px', marginRight: '8px' }} alt="断点" /><span>光缆断点</span></div></div></div></div>)}{/* 显示/隐藏图例按钮 */}<button onClick={() => setLegendVisible(!legendVisible)}style={{position: 'absolute',bottom: '20px',right: legendVisible ? '280px' : '20px',zIndex: 1,padding: '6px 12px',backgroundColor: 'white',border: '1px solid #ccc',borderRadius: '4px',cursor: 'pointer',fontSize: '14px',boxShadow: '0 0 5px rgba(0,0,0,0.1)'}}>{legendVisible ? '隐藏图例' : '显示图例'}</button></div>);
};export default MapComponent;

相关文章:

  • react+Mapbox GL实现标记地点、区域的功能
  • PostGIS实现栅格数据导出TIFF应用实践【ST_AsTiff】
  • RK3399 Android13设备插拔无线鼠标键盘设备出现APP或系统界面刷新现象
  • RISC-V 开发板 MUSE Pi Pro OpenCV结合Gstreamer实时显示CSI摄像头
  • 从负债到上岸:湖北理元理律师事务所的专业债务规划之道
  • 开源工具自建AI大模型底座:打造你的专属智能助理
  • 数据分析概述and环境配置
  • 驱动开发学习20250523
  • Unity 打包程序全屏置顶无边框
  • Docker端口映射与容器互联
  • 从 Docker 到 runC
  • 微信小程序:列表项上同样的css样式在IOS上字体大小不一样
  • uniapp uts 插件开发指南
  • 电路图识图基础知识-电气符号(二)
  • Nginx-配置详解
  • 【论文精读】2023 CVPRW--EAVSR现实世界视频超分辨率(RealWorld VSR)
  • 响应面法(Response Surface Methodology ,RSM)
  • 鸿蒙Ability对比Android的Fragment
  • CSS2相关知识点
  • IvorySQL-WASM:免安装的数据库探索之旅
  • 天元建设集团有限公司股份/郑州官网网站优化公司
  • 做那种事免费网站/滕州百度推广
  • 网站建设截图/今日新闻头条
  • 杨庄网站建设/新品怎么推广效果最好
  • 高明网站制作/深圳快速seo排名优化
  • 原创 网站 源码/优化网站怎么做