Mapbox地图标记位置偏移且缩放时趋近真实位置的问题求助
Mapbox地图标记位置偏移且缩放时趋近真实位置的问题求助
我在用Mapbox开发地图组件时遇到了一个棘手的问题,想请大家帮忙分析一下原因:
- 我通过props传入的
boundaryCoordinates绘制的多边形完全正常,精度很高,和预期位置完全吻合; - 但同样作为props传入的标记点(markers)却总是偏离实际位置,而且当我放大地图时,标记点会逐渐向真实位置靠近,不过由于地图有最大缩放限制,没法确认最终是否能完全对齐;
- 还有个有意思的现象:如果不传入
boundaryCoordinates,代码会自动取第一个标记点的坐标,加上偏移量生成一个方形多边形,这时候标记点显示完全正常,说明标记点的经纬度数据本身应该是没问题的。
以下是我的完整组件代码,麻烦大家帮忙看看哪里可能出了问题:
"use client"; import { Button } from "@/components/ui/button"; import { LocateIcon } from "lucide-react"; import mapboxgl from "mapbox-gl"; import { useEffect, useRef, useState } from "react"; mapboxgl.accessToken = process.env.NEXT_PUBLIC_MAPBOX_TOKEN!; interface PropertyMarker { id: string; latitude: number; longitude: number; } interface Coordinate { longitude: number; latitude: number; } interface MapboxListingsMapProps { markers: PropertyMarker[]; initialZoom?: number; boundaryCoordinates?: Coordinate[]; height:number } export default function MapboxListingsMap({ markers, initialZoom = 12, boundaryCoordinates = [], height }: MapboxListingsMapProps) { const mapContainerRef = useRef<HTMLDivElement>(null); const mapRef = useRef<mapboxgl.Map | null>(null); const [zoom, setZoom] = useState(initialZoom); const initialCenter = useRef<[number, number] | null>(null); useEffect(() => { if (!markers.length) return; initialCenter.current = [markers[0].longitude, markers[0].latitude]; }, [markers]); useEffect(() => { if (!markers.length || !initialCenter.current) return; const map = new mapboxgl.Map({ container: mapContainerRef.current!, style: "mapbox://styles/mapbox/light-v9", // Start with a light style center: initialCenter.current, zoom: initialZoom, }); mapRef.current = map; map.on("load", () => { // Change map background to rgb(246, 246, 244) map.setPaintProperty('background', 'background-color', 'rgb(246, 246, 244)'); // Add boundary polygon if coordinates are provided if (boundaryCoordinates.length > 0) { const formattedCoordinates = boundaryCoordinates.map(coord => [ coord.longitude, coord.latitude ]); if (formattedCoordinates.length > 0 && (formattedCoordinates[0][0] !== formattedCoordinates[formattedCoordinates.length - 1][0] || formattedCoordinates[0][1] !== formattedCoordinates[formattedCoordinates.length - 1][1])) { formattedCoordinates.push(formattedCoordinates[0]); } map.addSource('boundary', { 'type': 'geojson', 'data': { 'type': 'Feature', 'geometry': { 'type': 'Polygon', 'coordinates': [formattedCoordinates] }, 'properties': {} } }); } else if (initialCenter.current) { map.addSource('boundary', { 'type': 'geojson', 'data': { 'type': 'Feature', 'geometry': { 'type': 'Polygon', 'coordinates': [[ [initialCenter.current[0] - 0.02, initialCenter.current[1] - 0.02], [initialCenter.current[0] + 0.02, initialCenter.current[1] - 0.02], [initialCenter.current[0] + 0.02, initialCenter.current[1] + 0.02], [initialCenter.current[0] - 0.02, initialCenter.current[1] + 0.02], [initialCenter.current[0] - 0.02, initialCenter.current[1] - 0.02] ]] }, 'properties': {} } }); } if (map.getSource('boundary')) { map.addLayer({ 'id': 'boundary-line', 'type': 'line', 'source': 'boundary', 'layout': {}, 'paint': { 'line-color': '#EB5C60', 'line-width': 1 } }); } markers.forEach(({ id, latitude, longitude }) => { const el = document.createElement("div"); el.className = "marker"; el.style.width = "20px"; el.style.height = "20px"; el.style.backgroundColor = "#2f80ed"; el.style.borderRadius = "50%"; el.style.boxShadow = "0 0 0 2px #e0e0e0"; new mapboxgl.Marker(el).setLngLat([longitude, latitude]).addTo(map); }); if (markers.length > 1) { const bounds = new mapboxgl.LngLatBounds(); markers.forEach(({ longitude, latitude }) => { bounds.extend([longitude, latitude]); }); map.fitBounds(bounds, { padding: 50, maxZoom: 14 }); } }); map.on("zoomend", () => { setZoom(map.getZoom()); }); return () => map.remove(); }, [markers, initialZoom]); const handleZoomIn = () => { if (mapRef.current) { mapRef.current.zoomTo(mapRef.current.getZoom() + 1); } }; const handleZoomOut = () => { if (mapRef.current) { mapRef.current.zoomTo(mapRef.current.getZoom() - 1); } }; const handleResetView = () => { if (mapRef.current && initialCenter.current) { mapRef.current.flyTo({ center: initialCenter.current, zoom: initialZoom, }); } }; return ( <div className={`relative w-full overflow-hidden`} style={{ height: `${height}px` }} > <div ref={mapContainerRef} className="absolute inset-0 z-0" /> <div className="absolute left-4 bottom-4 z-10 bg-[#f9f9f9]"> {/* 按钮部分代码截断不影响核心问题排查 */} </div> </div> ); }
我已经检查过标记点的经纬度格式,确认是[longitude, latitude]的顺序,和Mapbox要求的一致。多边形在两种场景下都能正确渲染,唯独传入外部边界时标记点偏移,实在想不通问题出在哪,求各位大佬指点!
内容来源于stack exchange
相关产品推荐
相关产品推荐

