feat(@zhst/map): 添加popup功能
3
global.d.ts
vendored
@ -1 +1,4 @@
|
||||
declare module '*.less';
|
||||
declare module '*.png';
|
||||
declare module '*.jpg';
|
||||
declare module '*.jpeg';
|
||||
|
@ -1,48 +1,47 @@
|
||||
import 'mapbox-gl/dist/mapbox-gl.css';
|
||||
import '@mapbox/mapbox-gl-draw/dist/mapbox-gl-draw.css';
|
||||
import React, { forwardRef, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react';
|
||||
import Map from 'react-map-gl';
|
||||
import React, { forwardRef, useImperativeHandle, useMemo, useRef, useState } from 'react';
|
||||
import Map, { PopupEvent } from 'react-map-gl';
|
||||
import { CSSProperties } from "react";
|
||||
import { MapboxMap, MapRef, MapStyle } from "react-map-gl";
|
||||
import { MapRef, MapStyle, MapProps as MapBoxProps } from "react-map-gl";
|
||||
import classnames from 'classnames'
|
||||
import Tools, { ToolsProps } from './components/tools'
|
||||
import DrawControl, { DrawControlProps, DrawControlRefProps } from './components/drawControl';
|
||||
import { MAP_CENTER, defaultMapConfig } from './utils/constants';
|
||||
import './index.less';
|
||||
import mapboxDrawStyle from './utils/drawStyle';
|
||||
import Marker from './components/marker';
|
||||
import Marker, { MarkerProps } from './components/marker';
|
||||
import PopUp, { PopUpProps } from './components/popup';
|
||||
|
||||
const componentName = 'zhst-map'
|
||||
|
||||
export interface IMarkerData {
|
||||
key: string;
|
||||
title: string;
|
||||
population: string;
|
||||
status: string;
|
||||
latitude: number;
|
||||
longitude: number;
|
||||
}
|
||||
|
||||
export interface MapProps extends Partial<MapboxMap> {
|
||||
mapboxAccessToken?: string; //token
|
||||
markerData?: IMarkerData[]
|
||||
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>;
|
||||
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>
|
||||
mapCenter?: {
|
||||
longitude: number, latitude: number
|
||||
}
|
||||
draw?: boolean;
|
||||
draw?: boolean
|
||||
showMarker?: boolean // 显示标记点
|
||||
buttonList?: ToolsProps['buttonList']
|
||||
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;
|
||||
popUpInfo?: PopUpProps
|
||||
showPopUp?: 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;
|
||||
}
|
||||
|
||||
export interface MapRefProps {
|
||||
@ -57,6 +56,14 @@ const MapBox = forwardRef<MapRefProps, MapProps>((props, ref) => {
|
||||
width = '100%',
|
||||
draw,
|
||||
markerData = [],
|
||||
popUpInfo = {
|
||||
...MAP_CENTER
|
||||
},
|
||||
showPopUp,
|
||||
customMarkerRender,
|
||||
showMarker,
|
||||
onMarkerClick,
|
||||
onPopUpClose,
|
||||
buttonList = [
|
||||
{
|
||||
label: '圆形框选',
|
||||
@ -102,12 +109,10 @@ const MapBox = forwardRef<MapRefProps, MapProps>((props, ref) => {
|
||||
const [drawConfig] = useState<DrawControlProps>({
|
||||
displayControlsDefault: false,
|
||||
position: 'top-left',
|
||||
|
||||
styles: mapboxDrawStyle,
|
||||
// Select which mapbox-gl-draw control buttons to add to the map.
|
||||
controls: {
|
||||
polygon: true,
|
||||
trash: true
|
||||
},
|
||||
controls: false,
|
||||
// The user does not have to click the polygon control button first.
|
||||
defaultMode: 'draw_polygon',
|
||||
})
|
||||
@ -116,13 +121,14 @@ const MapBox = forwardRef<MapRefProps, MapProps>((props, ref) => {
|
||||
() => {
|
||||
return markerData.map((_item, index) => (
|
||||
<Marker
|
||||
key={_item.key || index}
|
||||
key={_item.key || String(index)}
|
||||
customMarkerRender={customMarkerRender}
|
||||
onMarkerClick={onMarkerClick}
|
||||
latitude={_item.latitude}
|
||||
longitude={_item.longitude}
|
||||
/>
|
||||
))
|
||||
},
|
||||
[markerData]
|
||||
}, [markerData]
|
||||
);
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
@ -145,7 +151,15 @@ const MapBox = forwardRef<MapRefProps, MapProps>((props, ref) => {
|
||||
style={{ width: width, height: height, ...style }}
|
||||
{...others}
|
||||
>
|
||||
{initMarker}
|
||||
{/* 标记点位 */}
|
||||
{showMarker && initMarker}
|
||||
{/* 点位弹框 */}
|
||||
{showPopUp && popUpInfo && (
|
||||
<PopUp
|
||||
onClose={onPopUpClose}
|
||||
{...popUpInfo}
|
||||
/>
|
||||
)}
|
||||
{/* <CustomOverlay
|
||||
>
|
||||
<Button>定制图层</Button>
|
||||
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 4.6 KiB |
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 4.6 KiB |
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 5.1 KiB |
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
@ -1,19 +1,43 @@
|
||||
/**
|
||||
* Created by jiangzhixiong on 2024/05/23
|
||||
*/
|
||||
import React, { forwardRef, useContext, useImperativeHandle } from 'react'
|
||||
import React, { forwardRef, ReactNode, useContext, useImperativeHandle } from 'react'
|
||||
import {
|
||||
Marker as MapboxMarker,
|
||||
MarkerProps as MapboxMarkerProps
|
||||
MarkerProps as MapboxMarkerProps,
|
||||
MarkerEvent
|
||||
} from 'react-map-gl'
|
||||
import { ConfigProvider, Image } from '@zhst/meta'
|
||||
import markerPic from '../../assets/icons/marker_monitor.png'
|
||||
import { Checkbox, ConfigProvider, Image } from '@zhst/meta'
|
||||
import cameraBlue from '../../assets/icons/camera_blue.png'
|
||||
import cameraGreen from '../../assets/icons/camera_green.png'
|
||||
import cameraGrey from '../../assets/icons/camera_grey.png'
|
||||
import cameraRed from '../../assets/icons/camera_red.png'
|
||||
import cameraYellow from '../../assets/icons/camera_yellow.png'
|
||||
|
||||
const { ConfigContext } = ConfigProvider
|
||||
|
||||
const PIC_MAP = new Map([
|
||||
['camera_blue', cameraBlue],
|
||||
['camera_green', cameraGreen],
|
||||
['camera_grey', cameraGrey],
|
||||
['camera_red', cameraRed],
|
||||
['camera_yellow', cameraYellow],
|
||||
])
|
||||
|
||||
// @ts-ignore
|
||||
export interface MarkerProps extends MapboxMarkerProps {
|
||||
prefixCls?: string;
|
||||
key: string;
|
||||
title?: string;
|
||||
checked?: boolean;
|
||||
type?: 'camera' | 'cluster' | 'marker';
|
||||
population?: string;
|
||||
status?: 'blue' | 'green' | 'yellow' | 'grey' | 'red_border' | 'escape' | 'escape_border' | 'red_track'; // 摄像头状态
|
||||
latitude: number;
|
||||
longitude: number;
|
||||
onClick?: (e?: MarkerEvent, data?: MarkerProps) => void;
|
||||
onMarkerClick?: (e?: MouseEvent, checked?: boolean, data?: MarkerProps) => void;
|
||||
customMarkerRender?: (data: MarkerProps) => ReactNode
|
||||
}
|
||||
|
||||
export interface MarkerRefProps {
|
||||
@ -22,27 +46,43 @@ export interface MarkerRefProps {
|
||||
const Marker = forwardRef<MarkerRefProps, MarkerProps>((props, ref) => {
|
||||
const {
|
||||
prefixCls: customizePrefixCls,
|
||||
key,
|
||||
longitude,
|
||||
latitude,
|
||||
onClick
|
||||
checked = false,
|
||||
type = 'camera',
|
||||
status = 'blue',
|
||||
onClick,
|
||||
onMarkerClick,
|
||||
customMarkerRender
|
||||
} = props
|
||||
const { getPrefixCls } = useContext(ConfigContext)
|
||||
const componentName = getPrefixCls('-map-marker', customizePrefixCls);
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
|
||||
}))
|
||||
useImperativeHandle(ref, () => ({}))
|
||||
|
||||
return (
|
||||
<MapboxMarker
|
||||
key={key}
|
||||
longitude={Number(longitude)}
|
||||
latitude={Number(latitude)}
|
||||
anchor="bottom"
|
||||
onClick={onClick}
|
||||
// @ts-ignore
|
||||
onClick={e => {
|
||||
e.originalEvent.stopPropagation();
|
||||
onClick?.(e, props)
|
||||
}}
|
||||
>
|
||||
<Image src={markerPic} preview={false} />
|
||||
{/* 自定义marker */}
|
||||
{customMarkerRender?.(props) || (
|
||||
<div className={componentName}>
|
||||
<Checkbox value={checked} onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
// @ts-ignore
|
||||
onMarkerClick?.(e, checked, props)
|
||||
}}>
|
||||
<Image src={PIC_MAP.get(`${type}_${status}`)} preview={false} />
|
||||
</Checkbox>
|
||||
</div>
|
||||
)}
|
||||
</MapboxMarker>
|
||||
)
|
||||
})
|
||||
|
@ -3,16 +3,21 @@
|
||||
*/
|
||||
import React, { forwardRef, useContext, useImperativeHandle } from 'react'
|
||||
import {
|
||||
PopUp as MapboxPopUp,
|
||||
Popup as MapboxPopUp,
|
||||
PopupProps as MapboxPopupProps
|
||||
} from 'react-map-gl'
|
||||
import { ConfigProvider } from '@zhst/meta'
|
||||
import { ConfigProvider, Image } from '@zhst/meta'
|
||||
import './index.less'
|
||||
import classNames from 'classnames'
|
||||
|
||||
const { ConfigContext } = ConfigProvider
|
||||
|
||||
export interface PopUpProps extends MapboxPopupProps {
|
||||
prefixCls?: string;
|
||||
size?: number;
|
||||
title?: string;
|
||||
url?: string;
|
||||
content?: string;
|
||||
}
|
||||
|
||||
export interface PopUpRefProps {
|
||||
@ -23,24 +28,28 @@ const PopUp = forwardRef<PopUpRefProps, PopUpProps>((props, ref) => {
|
||||
longitude,
|
||||
latitude,
|
||||
onClose,
|
||||
title,
|
||||
content,
|
||||
url,
|
||||
prefixCls: customizePrefixCls
|
||||
} = props
|
||||
const { getPrefixCls } = useContext(ConfigContext)
|
||||
const componentName = getPrefixCls('map-popup', customizePrefixCls);
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
|
||||
}))
|
||||
useImperativeHandle(ref, () => ({}))
|
||||
|
||||
return (
|
||||
<MapboxPopUp
|
||||
anchor="top"
|
||||
className={componentName}
|
||||
longitude={Number(longitude)}
|
||||
latitude={Number(latitude)}
|
||||
onClose={onClose}
|
||||
>
|
||||
<div className={componentName}>
|
||||
popup
|
||||
<div className={classNames(`${componentName}-container`)}>
|
||||
{title && <h2>{title}</h2>}
|
||||
{url && <Image src={url} />}
|
||||
{content && <p>{content}</p>}
|
||||
</div>
|
||||
</MapboxPopUp>
|
||||
)
|
||||
|
11
packages/map/src/components/popup/index.less
Normal file
@ -0,0 +1,11 @@
|
||||
.zhst-map-popup {
|
||||
.mapboxgl-popup-content {
|
||||
padding: 12px 6px 6px;
|
||||
}
|
||||
|
||||
&-container {
|
||||
p {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
/**
|
||||
* Created by jiangzhixiong on 2024/05/23
|
||||
*/
|
||||
export { default as PopUp } from './PopUp'
|
||||
import PopUp from './PopUp'
|
||||
export type { PopUpProps, PopUpRefProps } from './PopUp'
|
||||
|
||||
export default PopUp
|
||||
|
@ -1,9 +1,12 @@
|
||||
import React, { useRef, useEffect, useState } from 'react';
|
||||
import { MapBox } from '@zhst/map';
|
||||
import axios from 'axios';
|
||||
import { FloatButton, Switch } from '@zhst/meta';
|
||||
|
||||
const demo = () => {
|
||||
const [markerData, setMarkerData] = useState([])
|
||||
const [showMarker, setShowMarker] = useState(true)
|
||||
const [popupInfo, setPopupInfo] = useState()
|
||||
const mapRef = useRef(null);
|
||||
|
||||
// 初始化
|
||||
@ -44,16 +47,40 @@ const demo = () => {
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<MapBox
|
||||
onLoad={handleMapLoad}
|
||||
ref={mapRef}
|
||||
onDrawCreate={e => console.log('Create', e)}
|
||||
onDrawDelete={e => console.log('Delete', e)}
|
||||
onDrawUpdate={e => console.log('Update', e)}
|
||||
width='100%'
|
||||
height='100vh'
|
||||
markerData={markerData}
|
||||
/>
|
||||
<div>
|
||||
<FloatButton>
|
||||
<Switch value={true}/>
|
||||
</FloatButton>
|
||||
<MapBox
|
||||
onLoad={handleMapLoad}
|
||||
ref={mapRef}
|
||||
// draw
|
||||
onDrawCreate={e => console.log('Create', e)}
|
||||
onDrawDelete={e => console.log('Delete', e)}
|
||||
onDrawUpdate={e => console.log('Update', e)}
|
||||
width='100%'
|
||||
height='100vh'
|
||||
markerData={markerData}
|
||||
showMarker={showMarker}
|
||||
showPopUp
|
||||
popUpInfo={popupInfo}
|
||||
onPopUpClose={e => setPopupInfo(null)}
|
||||
onMarkerClick={(e, status, data) => {
|
||||
setPopupInfo({
|
||||
longitude: data?.longitude,
|
||||
latitude: data?.latitude,
|
||||
content: '测试'
|
||||
})
|
||||
}}
|
||||
onZoomEnd={map => {
|
||||
let zoom = map.target.getZoom() // 画面层级,用来判断标签是否显示隐藏
|
||||
|
||||
console.log('zoom', zoom)
|
||||
// setShowMarker(pre => !pre)
|
||||
}}
|
||||
// customMarkerRender={(_data) => <div>自定义标记</div>}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -32,6 +32,6 @@
|
||||
// "@zhst/meta" 全局使用的工具包,不建议写到 npm 包中去
|
||||
]
|
||||
},
|
||||
"include": [".dumirc.ts", "src/**/*", "packages/**/*"],
|
||||
"include": [".dumirc.ts", "src/**/*", "packages/**/*", "global.d.ts"],
|
||||
"exclude": ["node_modules", "lib", "es", ".dumi"]
|
||||
}
|
||||
|