| | |
| | | const DEFAULT_MAP_LONGITUDE = 116.397128; |
| | | const DEFAULT_MAP_LATITUDE = 39.916527; |
| | | const MAP_INCLUDE_POINTS_PADDING = [10, 10, 10, 10]; |
| | | // includePoints 缩放动画的预估时长,动画结束后再显示地图,避免“先展示再放大”的跳动 |
| | | const MAP_FIT_ANIMATION_DURATION = 700; |
| | | const POLYGON_STROKE_COLOR = '#A1B1FF'; |
| | | const SELECTED_POLYGON_FILL_COLOR = '#6d7fd933'; |
| | | const UNSELECTED_POLYGON_FILL_COLOR = '#6d7fd91a'; |
| | |
| | | // 地图是否处于加载/切换中:为 true 时用占位图覆盖地图,避免定位跳动可见 |
| | | const [isMapLoading, setIsMapLoading] = useState<boolean>(true); |
| | | const lastPolygonTapTimeRef = useRef(0); |
| | | // 标记当前正在等待 includePoints 之后的区域稳定 |
| | | const fitPendingRef = useRef(false); |
| | | // 占位图兜底显示的定时器(防止 regionchange end 未触发导致一直卡在占位图) |
| | | // 显示地图的定时器(等 includePoints 缩放动画结束后再显示,并兜底防止卡在占位图) |
| | | const revealTimerRef = useRef<any>(null); |
| | | |
| | | // 显示地图(隐藏占位图),并清理相关标记与兜底定时器 |
| | | // 显示地图(隐藏占位图),并清理兜底定时器 |
| | | const revealMap = () => { |
| | | fitPendingRef.current = false; |
| | | if (revealTimerRef.current) { |
| | | clearTimeout(revealTimerRef.current); |
| | | revealTimerRef.current = null; |
| | | } |
| | | setIsMapLoading(false); |
| | | }; |
| | | |
| | | // 地图区域变化:等 includePoints 触发的缩放动画结束后再显示地图 |
| | | const handleRegionChange = (e: any) => { |
| | | if (e?.type === 'end' && fitPendingRef.current) { |
| | | revealMap(); |
| | | } |
| | | }; |
| | | |
| | | useEffect(() => { |
| | |
| | | if (!cityCode) return; |
| | | // 进入/切换城市:先用占位图盖住地图,避免定位与缩放过程的跳动被看到 |
| | | setIsMapLoading(true); |
| | | fitPendingRef.current = false; |
| | | if (revealTimerRef.current) { |
| | | clearTimeout(revealTimerRef.current); |
| | | revealTimerRef.current = null; |
| | |
| | | const points = extractPointsFromPolygons(newPolygons); |
| | | if (points.length > 0) { |
| | | setTimeout(() => { |
| | | // includePoints 会触发缩放动画,标记后在 regionchange end 时再显示地图 |
| | | fitPendingRef.current = true; |
| | | mapCtx.includePoints({ |
| | | points: points, |
| | | padding: MAP_INCLUDE_POINTS_PADDING |
| | | }); |
| | | // 兜底:若 regionchange end 未如期触发,超时后也显示地图 |
| | | revealTimerRef.current = setTimeout(() => revealMap(), 900); |
| | | // includePoints 的缩放动画结束后再显示地图,避免“先展示再放大” |
| | | revealTimerRef.current = setTimeout(() => revealMap(), MAP_FIT_ANIMATION_DURATION); |
| | | }, 500); |
| | | } else { |
| | | revealMap(); |
| | |
| | | style={{ width: '100%', height: '65%' }} |
| | | onPolygonTap={handlePolygonTap} |
| | | onTap={handleMapTap} |
| | | onRegionChange={handleRegionChange} |
| | | > |
| | | {isMapLoading && <View className="map-placeholder-grid" />} |
| | | </Map> |