219 lines
6.2 KiB
TypeScript
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;
|