马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
准备工作
首先,确保你已经:
- 注册了 Mapbox 账号并获取了访问令牌(access token)
- 创建了 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 封装,可以如许实现:
[code]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 => (
<Marker
key={point.id}
longitude={point.longitude}
latitude={point.latitude}
>
<button
style={{ background: 'none', border: 'none', cursor: 'pointer' }}
onClick={e => {
e.preventDefault();
setSelectedPoint(point);
}}
>
<div style={{ color: 'red', fontSize: '24px' }}>
|