import React, { useEffect, useRef, useState, forwardRef, useImperativeHandle } from 'react'; import classNames from 'classnames'; import { Spin } from 'antd'; import { registerEvents, unRegisterEvents } from '../_utils/help-tools'; import { usePreviousProps } from '../_utils/hooks'; import { applyUpdatersToProps } from '../_utils/help'; import useLoadScript from './useLoadScript'; import MapContext from '../map-context'; import { IPoint, EventParamsBase } from '../_utils/point'; import './index.css'; export interface IMapProps { mapKey: string; version?: string; id?: string; mapContainerStyle?: React.CSSProperties; mapContainerClassName?: string; zoom?: number; enableDragging?: boolean; enableScrollWheelZoom?: boolean; enableDoubleClickZoom?: boolean; enableKeyboard?: boolean; inMapViewport?: boolean; viewportPoints?: IPoint[]; center?: number[] | string; children?: React.ReactNode; onClick?: ( event: Pick, ) => void; onDblClick?: (event: Pick) => void; onRightClick?: ( event: Pick, ) => void; onRightDblClick?: ( event: Pick, ) => void; onMapTypeChange?: (event: Pick) => void; onMouseMove?: ( event: Pick, ) => void; onMouseOver?: (event: Pick) => void; onMouseOut?: (event: Pick) => void; onMouseStart?: (event: Pick) => void; onMoving?: (event: Pick) => void; onMoveEnd?: (event: Pick) => void; onZoomStart?: (event: Pick) => void; onZoomEnd?: (event: Pick) => void; onAddOverlay?: (event: Pick) => void; onAddControl?: (event: Pick) => void; onRemoveControl?: (event: Pick) => void; onRemoveOverlay?: (event: Pick) => void; onClearOverlays?: (event: Pick) => void; onDragStart?: (event: Pick) => void; onDragging?: (event: Pick) => void; onDragEnd?: (event: Pick) => void; onAddTileLayer?: (event: Pick) => void; onRemoveTileLayer?: (event: Pick) => void; onLoad?: (event: Pick) => void; onResize?: (event: Pick) => void; onHotspotClick?: (event: Pick) => void; onHotspotOver?: (event: Pick) => void; onHotspotOut?: (event: Pick) => void; onTilesLoaded?: (event: Pick) => void; onTouchStart?: (event: Pick) => void; onTouchMove?: (event: Pick) => void; onTouchEnd?: (event: Pick) => void; onLongPress?: (event: Pick) => void; } const defaultProps: Partial = { id: `map_${Date.now()}`, zoom: 16, enableDragging: true, enableDoubleClickZoom: true, enableScrollWheelZoom: true, }; const eventMap = { onClick: 'click', onDblClick: 'dblclick', onRightClick: 'rightclick', onRightDblClick: 'rightdblclick', onMapTypeChange: 'maptypechange', onMouseMove: 'mousemove', onMouseOver: 'mouseover', onMouseOut: 'mouseout', onMouseStart: 'movestart', onMoving: 'moving', onMoveEnd: 'moveend', onZoomStart: 'zoomstart', onZoomEnd: 'zoomend', onAddOverlay: 'addoverlay', onAddControl: 'addcontrol', onRemoveControl: 'removecontrol', onRemoveOverlay: 'removeoverlay', onClearOverlays: 'clearoverlays', onDragStart: 'dragstart', onDragging: 'dragging', onDragEnd: 'dragend', onAddTileLayer: 'addtilelayer', onRemoveTileLayer: 'removetilelayer', onLoad: 'load', onResize: 'resize', onHotspotClick: 'hotspotclick', onHotspotOver: 'hotspotover', onHotspotOut: 'hotspotout', onTilesLoaded: 'tilesloaded', onTouchStart: 'touchstart', onTouchMove: 'touchmove', onTouchEnd: 'touchend', onLongPress: 'longpress', }; const updaterMap = { enableDragging(map: BMap.Map, enable: boolean) { if (enable) map.enableDragging(); else map.disableDragging(); }, enableScrollWheelZoom(map: BMap.Map, enable: boolean) { if (enable) map.enableScrollWheelZoom(); else map.disableScrollWheelZoom(); }, enableDoubleClickZoom(map: BMap.Map, enable: boolean) { if (enable) map.enableDoubleClickZoom(); else map.disableDoubleClickZoom(); }, enableKeyboard(map: BMap.Map, enable: boolean) { if (enable) map.enableKeyboard(); else map.disableKeyboard(); }, zoom(map: BMap.Map, zoom: number) { map.setZoom(zoom); }, // center(map: BMap.Map, center: string | number[]) { // if (Array.isArray(center)) { // const [lng, lat] = center; // const point = new BMap.Point(lng, lat); // map.setCenter(point); // } else { // map.setCenter(center); // } // }, }; const Map = forwardRef((props: IMapProps, ref: React.RefObject>) => { const { mapKey, version, id, children, mapContainerStyle, mapContainerClassName, zoom = 16, center, inMapViewport = true, viewportPoints = [], } = props; const { isLoaded } = useLoadScript({ mapKey, version }); const registeredEventsRef = useRef([]); const mapRef = useRef(null); const [mapOnLoad, setMapOnLoad] = useState(false); const [mapInstance, setMapInstance] = useState(null); const prevProps = usePreviousProps(props); useEffect(() => { function mapInit(map: BMap.Map) { if (typeof center === 'string') { map.centerAndZoom(center); } else if (Array.isArray(center)) { const [lng, lat] = center; const point = new BMap.Point(lng, lat); map.centerAndZoom(point, zoom); } } if (isLoaded && mapRef.current) { const map = new BMap.Map(mapRef.current); map.onload = () => { setMapOnLoad(true); }; mapInit(map); const initUpdateMap = { ...updaterMap }; // delete initUpdateMap.center; applyUpdatersToProps(initUpdateMap, {}, props, map, undefined); setMapInstance(map); } }, [isLoaded]); useEffect( function setPointsInViewport() { if (mapInstance && inMapViewport) { const bPoins: BMap.Point[] = []; viewportPoints.forEach(point => { const { lng, lat } = point; bPoins.push(new BMap.Point(lng, lat)); }); mapInstance.setViewport(bPoins); } }, [mapInstance, inMapViewport, viewportPoints], ); useEffect(function updatersToProps() { if (mapInstance) { applyUpdatersToProps(updaterMap, prevProps, props, mapInstance, undefined); } }); useEffect(function setEvents() { if (mapInstance) { // @ts-ignore registeredEventsRef.current = registerEvents(mapInstance, props, eventMap); return function clean() { registeredEventsRef.current.length > 0 && // @ts-ignore unRegisterEvents(mapInstance, registeredEventsRef.current); }; } return; }); useImperativeHandle( ref, () => { if (mapOnLoad) { return { map: mapInstance, }; } return { map: null, }; }, [mapOnLoad], ); const classes = classNames('map-box', { mapContainerClassName: !!mapContainerClassName }); return (
{isLoaded ? ( <> {' '}
{mapInstance && mapOnLoad && (
{children}
)} ) : (
)}
); }); Map.defaultProps = defaultProps; export default React.memo(Map);