import Mapbox from 'mapbox-gl'; import React, { forwardRef, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react' import { useEvents } from '../../hooks/useEvents' import { usePropsReactive } from '../../hooks/usePropsReactive' import { MapContext } from './context' import { allProps, converterMap, setterMap } from './config' import { MapEventList, MapEventMap } from './constant' import type { MapContextValue } from './context' import type { MapProps, MapboxOptionKeys, MapboxMap, MapOptions } from './types' export const Map = forwardRef((props, ref) => { const { className, loading, containerStyle, children } = props const containerRef = useRef(null) const [mapInstance, setMapInstance] = useState() const style: React.CSSProperties = useMemo( () => ({ position: 'relative', width: '100%', height: '100%', ...containerStyle, }), [containerStyle], ) /** 获取创建地图的参数 */ const getCreateOptions = (props: MapProps) => { const container = containerRef.current as HTMLDivElement const options: Partial> = { container, } allProps.forEach((key) => { if (key in props && key !== 'container') options[key] = props[key] }) return options as MapOptions } /** 创建地图实例 */ const createInstance = () => { const options = getCreateOptions(props) return Promise.resolve(new Mapbox.Map(options)) } const { current: contextValue } = useRef({} as MapContextValue) const { onInstanceCreated } = usePropsReactive(props, mapInstance!, { setterMap, converterMap, }) useEvents(mapInstance!, props, { eventMap: MapEventMap, eventList: MapEventList, }) useImperativeHandle(ref, () => mapInstance as MapboxMap, [mapInstance]) useEffect(() => { if (!containerRef.current) return createInstance().then((map) => { onInstanceCreated() contextValue.map = map setMapInstance(map) }) }, [containerRef]) const CHILD_CONTAINER_STYLE = { height: '100%', } return (
{!mapInstance && loading} {mapInstance && (
{children}
)}
) }) Map.displayName = 'Map'