nicecode-v2/packages/map/src/MapBox.tsx
2024-05-29 14:43:41 +08:00

219 lines
6.2 KiB
TypeScript

import 'mapbox-gl/dist/mapbox-gl.css';
import '@mapbox/mapbox-gl-draw/dist/mapbox-gl-draw.css';
import React, { forwardRef, useImperativeHandle, useMemo, useRef, useState } from 'react';
import Map, { PopupEvent } from 'react-map-gl';
import { CSSProperties } from "react";
import { MapRef, MapStyle, MapProps as MapBoxProps } from "react-map-gl";
import classnames from 'classnames'
import { merge } from '@zhst/func'
import Tools, { ToolsProps } from './components/tools'
import DrawControl, { DrawControlProps, DrawControlRefProps } from './components/drawControl';
import { defaultMapConfig } from './utils/constants';
import './index.less';
import mapboxDrawStyle from './utils/drawStyle';
import Marker, { MarkerProps } from './components/marker';
import PopUp, { PopUpProps } from './components/popup';
import Cluster, { ClusterProps } from './components/clusters/Clusters';
import { clusterLayer } from './components/clusters/layers';
const componentName = 'zhst-map'
export interface MapProps extends MapBoxProps {
mapboxAccessToken?: string //token
markerData?: MarkerProps[]
minZoom?: number //最小层级
maxZoom?: number //最大层级
mapStyle?: MapStyle //地图样式
height?: number | string
width?: string | number
mapRef?: MapRef
style?: CSSProperties
children?: JSX.Element | JSX.Element[] | Array<JSX.Element | undefined>
sluterData?: any;
draw?: boolean
showMarker?: boolean // 显示标记点
showCluster?: boolean // 显示范围统计
buttonList?: ToolsProps['buttonList']
popUpInfo?: PopUpProps
showPopUp?: boolean
clusterProps?: ClusterProps
toolsBarOpen?: boolean
customMarkerRender?: MarkerProps['customMarkerRender']
onLoad?: (e: mapboxgl.MapboxEvent<undefined>) => void
onDrawCreate?: (e: { features: object[], [key: string]: any }) => void
onDrawUpdate?: (e: { features: object[], [key: string]: any }) => void
onDrawDelete?: (e: { features: object[], [key: string]: any }) => void
onMarkerClick?: MarkerProps['onMarkerClick']
onPopUpClose?: (e: PopupEvent) => void;
onToolClick?: ToolsProps['onToolClick']
}
export interface MapRefProps {
}
const MapBox = forwardRef<MapRefProps, MapProps>((props, ref) => {
const {
style = {},
children,
height = 600,
width = '100%',
draw,
markerData = [],
sluterData = [],
popUpInfo = {
longitude: 0,
latitude: 0
},
showPopUp,
toolsBarOpen,
showMarker = true,
showCluster = false,
clusterProps,
interactiveLayerIds = [],
buttonList = [
{
label: '圆形框选',
key: 'circle',
icon: 'icon-yuan',
onClick: () => drawControlRef.current?.drawer?.changeMode?.('simple_select')
},
{
label: '矩形框选',
key: 'rect',
icon: 'icon-fang',
onClick: () => drawControlRef.current?.drawer?.changeMode?.('draw_rect'),
popoverProps: {
placement: 'bottom',
content: '自定义内容'
}
},
{
label: '多边形框选',
key: 'more',
icon: 'icon-duobianxing',
onClick: () => drawControlRef.current?.drawer?.changeMode?.('draw_polygon')
},
{
label: '路径框选',
key: 'path',
icon: 'icon-lujingkuangxuannor',
onClick: () => drawControlRef.current?.drawer?.changeMode?.('draw_line_string')
},
{
label: '测距',
key: 'path',
icon: 'icon-ceju',
onClick: () => drawControlRef.current?.drawer?.changeMode?.('draw_line_string')
},
{
label: '清除',
key: 'clear',
icon: 'icon-gongjuxiangguanbi',
onClick: () => drawControlRef.current?.drawer?.deleteAll()
}
],
onMarkerClick,
onPopUpClose,
customMarkerRender,
onLoad,
onDrawCreate,
onDrawUpdate,
onDrawDelete,
onToolClick,
...others
} = props || {};
const mapRef = useRef<MapRef>(null)
const drawControlRef = useRef<DrawControlRefProps>(null)
// 默认绘制配置
const [drawConfig] = useState<DrawControlProps>({
displayControlsDefault: false,
position: 'top-left',
styles: mapboxDrawStyle,
// Select which mapbox-gl-draw control buttons to add to the map.
// @ts-ignore
controls: false,
// The user does not have to click the polygon control button first.
defaultMode: 'draw_polygon',
})
const initMarker = useMemo(
() => {
return markerData.map((_item) => (
<Marker
customMarkerRender={customMarkerRender}
onMarkerClick={onMarkerClick}
{..._item}
/>
))
}, [markerData]
);
useImperativeHandle(ref, () => ({
mapRef: mapRef.current,
drawer: drawControlRef.current?.drawer,
}))
return (
//@ts-ignore
<div className={classnames(`${componentName}`)}>
<Tools
open={toolsBarOpen}
buttonList={buttonList}
onToolClick={onToolClick}
/>
{/* @ts-ignore */}
<Map
ref={mapRef}
onLoad={onLoad}
style={{ width: width, height: height, ...style }}
interactiveLayerIds={[clusterLayer.id!, ...interactiveLayerIds]}
{...merge(defaultMapConfig, others)}
>
{/* 标记点位 */}
{showMarker && initMarker}
{/* 全局弹框弹框 */}
{showPopUp && popUpInfo && (
<PopUp
onClose={onPopUpClose}
{...popUpInfo}
/>
)}
{/* <CustomOverlay
>
<Button>自定义图层</Button>
</CustomOverlay> */}
{/* 范围统计标点 */}
{showCluster && !showMarker && (
<Cluster
type="geojson"
cluster={true}
clusterMaxZoom={14}
clusterRadius={50}
data={sluterData}
{...clusterProps}
/>
)}
{/* ---------------绘制图层--------------------- */}
{draw && (
<DrawControl
ref={drawControlRef}
onCreate={onDrawCreate}
onUpdate={onDrawUpdate}
onDelete={onDrawDelete}
onSelectionChange={e => console.log('e', e)}
{...drawConfig}
/>
)}
{children}
</Map>
</div>
);
});
export default MapBox;