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

react+Mapbox GL实现标记地点、区域的功能

准备工作

首先,确保你已经:

  1. 注册了 Mapbox 账号并获取了访问令牌(access token)

  2. 创建了 React 项目

安装必要的依赖:

npm install mapbox-gl react-map-gl
# 或者
yarn add mapbox-gl react-map-gl

基础地图组件

首先创建一个基础地图组件:

import React, { useRef, useEffect, useState } from 'react';
import mapboxgl from 'mapbox-gl';
import 'mapbox-gl/dist/mapbox-gl.css';// 设置你的 Mapbox 访问令牌
mapboxgl.accessToken = 'YOUR_MAPBOX_ACCESS_TOKEN';const MapboxMap = () => {const mapContainer = useRef(null);const map = useRef(null);const [lng, setLng] = useState(-70.9);const [lat, setLat] = useState(42.35);const [zoom, setZoom] = useState(9);useEffect(() => {if (map.current) return; // 如果地图已经初始化,则不再重复初始化map.current = new mapboxgl.Map({container: mapContainer.current,style: 'mapbox://styles/mapbox/streets-v11',center: [lng, lat],zoom: zoom});map.current.on('move', () => {setLng(map.current.getCenter().lng.toFixed(4));setLat(map.current.getCenter().lat.toFixed(4));setZoom(map.current.getZoom().toFixed(2));});}, []);return (<div><div className="sidebar">Longitude: {lng} | Latitude: {lat} | Zoom: {zoom}</div><div ref={mapContainer} className="map-container" /></div>);
};export default MapboxMap;

添加点标记

要在地图上添加点标记,可以使用 mapboxgl.Marker

useEffect(() => {if (!map.current) return;// 添加一个点标记new mapboxgl.Marker().setLngLat([-70.9, 42.35]).addTo(map.current);// 可以添加多个标记const locations = [{ lng: -70.92, lat: 42.36, title: '地点1' },{ lng: -70.88, lat: 42.34, title: '地点2' },];locations.forEach(loc => {new mapboxgl.Marker().setLngLat([loc.lng, loc.lat]).setPopup(new mapboxgl.Popup().setHTML(`<h3>${loc.title}</h3>`)).addTo(map.current);});
}, []);

绘制区域(多边形)

要绘制多边形区域,我们需要使用 GeoJSON 数据:

useEffect(() => {if (!map.current) return;// 等待地图加载完成map.current.on('load', () => {// 添加一个多边形区域map.current.addLayer({id: 'polygon',type: 'fill',source: {type: 'geojson',data: {type: 'Feature',geometry: {type: 'Polygon',coordinates: [[[-70.92, 42.36],[-70.88, 42.36],[-70.88, 42.34],[-70.92, 42.34],[-70.92, 42.36]]]},properties: {}}},paint: {'fill-color': '#088','fill-opacity': 0.4,'fill-outline-color': '#000'}});// 添加可交互的多边形map.current.addLayer({id: 'interactive-polygon',type: 'fill',source: {type: 'geojson',data: {type: 'Feature',geometry: {type: 'Polygon',coordinates: [[[-70.95, 42.38],[-70.90, 42.38],[-70.90, 42.33],[-70.95, 42.33],[-70.95, 42.38]]]},properties: {name: '可交互区域'}}},paint: {'fill-color': '#800','fill-opacity': 0.4,'fill-outline-color': '#000'}});// 添加点击事件map.current.on('click', 'interactive-polygon', (e) => {new mapboxgl.Popup().setLngLat(e.lngLat).setHTML(`<h3>${e.features[0].properties.name}</h3>`).addTo(map.current);});// 鼠标悬停效果map.current.on('mouseenter', 'interactive-polygon', () => {map.current.getCanvas().style.cursor = 'pointer';});map.current.on('mouseleave', 'interactive-polygon', () => {map.current.getCanvas().style.cursor = '';});});
}, []);

完整示例

下面是一个完整的组件,结合了标记地点和绘制区域的功能:

import React, { useRef, useEffect, useState } from 'react';
import mapboxgl from 'mapbox-gl';
import 'mapbox-gl/dist/mapbox-gl.css';mapboxgl.accessToken = 'YOUR_MAPBOX_ACCESS_TOKEN';const MapWithMarkersAndPolygons = () => {const mapContainer = useRef(null);const map = useRef(null);const [lng, setLng] = useState(-70.9);const [lat, setLat] = useState(42.35);const [zoom, setZoom] = useState(9);useEffect(() => {if (map.current) return;map.current = new mapboxgl.Map({container: mapContainer.current,style: 'mapbox://styles/mapbox/streets-v11',center: [lng, lat],zoom: zoom});map.current.on('move', () => {setLng(map.current.getCenter().lng.toFixed(4));setLat(map.current.getCenter().lat.toFixed(4));setZoom(map.current.getZoom().toFixed(2));});// 添加标记map.current.on('load', () => {// 点标记const locations = [{ lng: -70.92, lat: 42.36, title: '地点1' },{ lng: -70.88, lat: 42.34, title: '地点2' },{ lng: -70.95, lat: 42.35, title: '地点3' }];locations.forEach(loc => {new mapboxgl.Marker().setLngLat([loc.lng, loc.lat]).setPopup(new mapboxgl.Popup().setHTML(`<h3>${loc.title}</h3>`)).addTo(map.current);});// 多边形区域map.current.addLayer({id: 'polygon',type: 'fill',source: {type: 'geojson',data: {type: 'Feature',geometry: {type: 'Polygon',coordinates: [[[-70.92, 42.36],[-70.88, 42.36],[-70.88, 42.34],[-70.92, 42.34],[-70.92, 42.36]]]},properties: {description: '静态区域'}}},paint: {'fill-color': '#088','fill-opacity': 0.4,'fill-outline-color': '#000'}});// 可交互多边形map.current.addLayer({id: 'interactive-polygon',type: 'fill',source: {type: 'geojson',data: {type: 'Feature',geometry: {type: 'Polygon',coordinates: [[[-70.95, 42.38],[-70.90, 42.38],[-70.90, 42.33],[-70.95, 42.33],[-70.95, 42.38]]]},properties: {name: '可交互区域',description: '点击我可以看到更多信息'}}},paint: {'fill-color': '#800','fill-opacity': 0.4,'fill-outline-color': '#000'}});// 添加点击事件map.current.on('click', 'interactive-polygon', (e) => {new mapboxgl.Popup().setLngLat(e.lngLat).setHTML(`<h3>${e.features[0].properties.name}</h3><p>${e.features[0].properties.description}</p>`).addTo(map.current);});// 鼠标悬停效果map.current.on('mouseenter', 'interactive-polygon', () => {map.current.getCanvas().style.cursor = 'pointer';});map.current.on('mouseleave', 'interactive-polygon', () => {map.current.getCanvas().style.cursor = '';});});}, []);return (<div><div className="sidebar">Longitude: {lng} | Latitude: {lat} | Zoom: {zoom}</div><div ref={mapContainer} className="map-container" /></div>);
};export default MapWithMarkersAndPolygons;

样式

添加一些基本样式到你的 CSS 文件中:

.map-container {position: absolute;top: 0;bottom: 0;left: 0;right: 0;
}.sidebar {position: absolute;top: 0;left: 0;margin: 12px;background-color: #404040;color: #ffffff;z-index: 1;padding: 6px;font-weight: bold;
}

使用 react-map-gl (官方 React 封装)

如果你更喜欢使用官方 React 封装,可以这样实现:

import React, { useState, useCallback } from 'react';
import ReactMapGL, { Marker, Popup, Source, Layer } from 'react-map-gl';const MapWithReactMapGL = () => {const [viewport, setViewport] = useState({latitude: 42.35,longitude: -70.9,zoom: 9,width: '100%',height: '100%'});const [selectedPoint, setSelectedPoint] = useState(null);const [selectedPolygon, setSelectedPolygon] = useState(null);const points = [{ id: 1, longitude: -70.92, latitude: 42.36, name: '地点1' },{ id: 2, longitude: -70.88, latitude: 42.34, name: '地点2' },];const polygonData = {type: 'Feature',geometry: {type: 'Polygon',coordinates: [[[-70.92, 42.36],[-70.88, 42.36],[-70.88, 42.34],[-70.92, 42.34],[-70.92, 42.36]]]},properties: {}};const handlePolygonClick = useCallback((event) => {setSelectedPolygon({lngLat: event.lngLat,feature: event.features[0]});}, []);return (<ReactMapGL{...viewport}mapboxApiAccessToken="YOUR_MAPBOX_ACCESS_TOKEN"onViewportChange={setViewport}onClick={handlePolygonClick}interactiveLayerIds={['polygon-layer']}>{/* 点标记 */}{points.map(point => (<Markerkey={point.id}longitude={point.longitude}latitude={point.latitude}><buttonstyle={{ background: 'none', border: 'none', cursor: 'pointer' }}onClick={e => {e.preventDefault();setSelectedPoint(point);}}><div style={{ color: 'red', fontSize: '24px' }}>📍</div></button></Marker>))}{/* 点标记弹出框 */}{selectedPoint && (<Popuplongitude={selectedPoint.longitude}latitude={selectedPoint.latitude}onClose={() => setSelectedPoint(null)}><div><h3>{selectedPoint.name}</h3><p>详细信息...</p></div></Popup>)}{/* 多边形区域 */}<Source id="polygon-source" type="geojson" data={polygonData}><Layerid="polygon-layer"type="fill"paint={{'fill-color': '#088','fill-opacity': 0.4,'fill-outline-color': '#000'}}/></Source>{/* 多边形弹出框 */}{selectedPolygon && (<Popuplongitude={selectedPolygon.lngLat[0]}latitude={selectedPolygon.lngLat[1]}onClose={() => setSelectedPolygon(null)}><div><h3>多边形区域</h3><p>点击了多边形</p></div></Popup>)}</ReactMapGL>);
};export default MapWithReactMapGL;

http://www.xdnf.cn/news/8530.html

相关文章:

  • python开发环境管理和包管理
  • SpringBoot3集成Oauth2.1——5资源地址配置
  • MySQL--day6--单行函数
  • 【HCIA】端口隔离
  • threadPool.submit() 和 threadPool.execute()的区别
  • nvidia Thor U与qualcomm 8295 DMPIS算力测试对比
  • 日志分析-IIS日志分析
  • Oracle常用函数
  • 关于使用高德安卓api时so文件的坑
  • 解锁 BADBOX 2.0 的 DNS 密码箱
  • IP-guard发布新版本4.87.2241.0
  • matlab2007 和 microsoft access怎么连接?
  • java将rtsp转成flv在浏览器播放
  • 【HTML-9】深入理解HTML超链接标签:从基础到高级应用
  • 第R7周:糖尿病预测模型优化探索
  • YOLO12改进-Backbone-引入Swin Transformer替换backbone
  • 地理特征类可视化图像总结
  • Java面向对象编程核心:封装、继承与多态
  • AT24C02(I2C总线)
  • C# TCP协议全面指南:从可靠传输到企业级高并发的深度实践​
  • 当 BIM 遇见 GIS:GISBox 中 Revit 数据导入的技术联动与应用场景
  • 《AI 绘画崛起,人类艺术家如何在夹缝中寻找新机遇?》
  • 复杂工况下液压挖掘机工作臂系统创新设计与性能优化
  • 如何在STM32CubeMX下为STM32工程配置调试打印功能
  • 使用pip安装ptflops报错
  • 探索Qwen2ForCausalLM 架构上进行微调
  • k8s容器入门(2) 容器化组件“可漂移“
  • 企业知识管理面临的挑战与飞书知识问答的解决方案
  • 字节开源多模态文档图像解析模型:Dolphin
  • 【FastAPI】--基础教程