mosaicmap/app/map-context.tsx
2025-08-19 22:49:28 +08:00

176 lines
4.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'use client'
import React, { createContext, useContext, useRef, useState, ReactNode } from 'react'
import { Map } from 'maplibre-gl';
// 定义MapContext的类型
interface MapContextType {
mapRef: React.RefObject<Map | null>
layers: React.RefObject<any[]>
mapState: MapState
currentDatetime: Date | null
timelineDatetime: Date | null
setMap: (map: Map, layers: any[]) => void
flyTo: (options: { center: [number, number]; zoom: number; duration?: number }) => void
zoomIn: () => void
zoomOut: () => void
zoomTo: (zoom: number) => void
reset: () => void
clearMap: () => void
setTime: (date: Date) => void
setTimelineTime: (date: Date) => void
isMapReady: boolean
}
// 创建Context
const MapContext = createContext<MapContextType | undefined>(undefined)
// Provider组件的Props类型
interface MapProviderProps {
children: ReactNode
}
interface MapState {
zoomLevel: number
}
// MapProvider组件
export function MapProvider({ children }: MapProviderProps) {
const mapRef = useRef<Map | null>(null)
const [isMapReady, setIsMapReady] = useState(false)
const [mapState, setMapState] = useState<MapState>({
zoomLevel: 11
});
const layersRef = useRef<any[]>([])
const [currentDatetime, setCurrentDatetime] = useState<Date | null>(null)
const [timelineDatetime, setTimelineDatetime] = useState<Date | null>(null)
const setMap = (map: Map, layers: any[]) => {
// 如果已经有地图实例,先清理旧的
if (mapRef.current) {
// console.log('Cleaning up previous map instance...');
mapRef.current = null;
}
// 监听视图的缩放变化
map.on('zoom', () => {
setMapState(prevState => ({
...prevState,
zoomLevel: map.getZoom() || 11
}));
});
// 监听视图的中心点变化
map.on('move', () => {
const center = map.getCenter()
setMapState(prevState => ({
...prevState,
center: center
}));
});
mapRef.current = map;
layersRef.current = layers;
setIsMapReady(true);
}
const flyTo = (options: { center: [number, number]; zoom: number; duration?: number }) => {
if (mapRef.current) {
mapRef.current.flyTo({
center: options.center,
zoom: options.zoom,
duration: options.duration || 1000
})
}
}
const zoomIn = () => {
if (mapRef.current) {
mapRef.current.zoomIn()
}
}
const zoomOut = () => {
if (mapRef.current) {
mapRef.current.zoomOut()
}
}
const zoomTo = (zoom: number) => {
if (mapRef.current) {
mapRef.current.zoomTo(zoom)
}
}
const setTime = (date: Date) => {
setCurrentDatetime(date)
}
const reset = () => {
if (mapRef.current) {
mapRef.current.flyTo({
center: [103.851959, 1.290270],
zoom: 11,
duration: 1000
})
}
}
const clearMap = () => {
if (mapRef.current) {
// console.log('Clearing map instance...');
mapRef.current.remove();
mapRef.current = null;
layersRef.current = [];
setIsMapReady(false);
setMapState({
zoomLevel: 11
});
}
}
const value: MapContextType = {
timelineDatetime,
setTimelineTime: setTimelineDatetime,
setTime,
currentDatetime,
mapRef,
layers: layersRef,
mapState,
setMap,
flyTo,
zoomIn,
zoomOut,
zoomTo,
reset,
clearMap,
isMapReady
}
return (
<MapContext.Provider value={value}>
{children}
</MapContext.Provider>
)
}
// 自定义Hook用于使用MapContext
export function useMap() {
const context = useContext(MapContext)
if (context === undefined) {
throw new Error('useMap必须在MapProvider内部使用')
}
return context
}
// 便捷的Hook直接返回map实例
export function useMapInstance() {
const { mapRef } = useMap()
return mapRef.current
}