Merge branch 'develop' into 'master'

feat(biz,map): 添加文档

See merge request web-project/zhst-lambo!37
This commit is contained in:
江志雄 2024-05-30 10:39:07 +08:00
commit ed22f8bcf9
51 changed files with 542 additions and 252 deletions

View File

@ -1,5 +1,11 @@
# @zhst/biz
## 0.25.1
### Patch Changes
- feat(zhst/map,zhst/biz): map 完善文档,biz 修改 boxSelectTree 的文档格式
## 0.25.0
### Minor Changes

View File

@ -1,6 +1,6 @@
{
"name": "@zhst/biz",
"version": "0.25.0",
"version": "0.25.1",
"description": "业务库",
"keywords": [
"business",

View File

@ -43,7 +43,6 @@ group:
| checkedTags | 选中的标签值 | string[] | [] | - |
| footer | 盒子树底部渲染(需要内容撑开) | ReactNode、string | - | - |
| tagFootRender | 标签看板底部自定义 | ReactNode、string | - | - |
| onResetTags | 标签重置 | () => void | [] | - |
| onTagExpand | 标签展开 | (e: any) => void | [] | - |
| onTabChange | tab切换监听 | function: (e) => void | - | - |

View File

@ -1,5 +1,11 @@
# @zhst/map
## 0.3.1
### Patch Changes
- feat(zhst/map,zhst/biz): map 完善文档,biz 修改 boxSelectTree 的文档格式
## 0.3.0
### Minor Changes

View File

@ -1,195 +0,0 @@
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
var _excluded = ["style", "children", "height", "width", "draw", "markerData", "sluterData", "popUpInfo", "showPopUp", "toolsBarOpen", "showMarker", "showCluster", "clusterProps", "interactiveLayerIds", "buttonList", "onMarkerClick", "onPopUpClose", "customMarkerRender", "onLoad", "onDrawCreate", "onDrawUpdate", "onDrawDelete", "onToolClick"];
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); }
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
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 from 'react-map-gl';
import classnames from 'classnames';
import { merge } from '@zhst/func';
import Tools from "./components/tools";
import DrawControl from "./components/drawControl";
import { defaultMapConfig } from "./utils/constants";
import "./index.less";
import mapboxDrawStyle from "./utils/drawStyle";
import Marker from "./components/marker";
import PopUp from "./components/popup";
import Cluster from "./components/clusters/Clusters";
import { clusterLayer } from "./components/clusters/layers";
var componentName = 'zhst-map';
var MapBox = /*#__PURE__*/forwardRef(function (props, ref) {
var _ref = props || {},
_ref$style = _ref.style,
style = _ref$style === void 0 ? {} : _ref$style,
children = _ref.children,
_ref$height = _ref.height,
height = _ref$height === void 0 ? 600 : _ref$height,
_ref$width = _ref.width,
width = _ref$width === void 0 ? '100%' : _ref$width,
draw = _ref.draw,
_ref$markerData = _ref.markerData,
markerData = _ref$markerData === void 0 ? [] : _ref$markerData,
_ref$sluterData = _ref.sluterData,
sluterData = _ref$sluterData === void 0 ? [] : _ref$sluterData,
_ref$popUpInfo = _ref.popUpInfo,
popUpInfo = _ref$popUpInfo === void 0 ? {
longitude: 0,
latitude: 0
} : _ref$popUpInfo,
showPopUp = _ref.showPopUp,
toolsBarOpen = _ref.toolsBarOpen,
_ref$showMarker = _ref.showMarker,
showMarker = _ref$showMarker === void 0 ? true : _ref$showMarker,
_ref$showCluster = _ref.showCluster,
showCluster = _ref$showCluster === void 0 ? false : _ref$showCluster,
clusterProps = _ref.clusterProps,
_ref$interactiveLayer = _ref.interactiveLayerIds,
interactiveLayerIds = _ref$interactiveLayer === void 0 ? [] : _ref$interactiveLayer,
_ref$buttonList = _ref.buttonList,
buttonList = _ref$buttonList === void 0 ? [{
label: '圆形框选',
key: 'circle',
icon: 'icon-yuan',
onClick: function onClick() {
var _drawControlRef$curre, _drawControlRef$curre2;
return (_drawControlRef$curre = drawControlRef.current) === null || _drawControlRef$curre === void 0 || (_drawControlRef$curre = _drawControlRef$curre.drawer) === null || _drawControlRef$curre === void 0 || (_drawControlRef$curre2 = _drawControlRef$curre.changeMode) === null || _drawControlRef$curre2 === void 0 ? void 0 : _drawControlRef$curre2.call(_drawControlRef$curre, 'simple_select');
}
}, {
label: '矩形框选',
key: 'rect',
icon: 'icon-fang',
onClick: function onClick() {
var _drawControlRef$curre3, _drawControlRef$curre4;
return (_drawControlRef$curre3 = drawControlRef.current) === null || _drawControlRef$curre3 === void 0 || (_drawControlRef$curre3 = _drawControlRef$curre3.drawer) === null || _drawControlRef$curre3 === void 0 || (_drawControlRef$curre4 = _drawControlRef$curre3.changeMode) === null || _drawControlRef$curre4 === void 0 ? void 0 : _drawControlRef$curre4.call(_drawControlRef$curre3, 'draw_rect');
},
popoverProps: {
placement: 'bottom',
content: '自定义内容'
}
}, {
label: '多边形框选',
key: 'more',
icon: 'icon-duobianxing',
onClick: function onClick() {
var _drawControlRef$curre5, _drawControlRef$curre6;
return (_drawControlRef$curre5 = drawControlRef.current) === null || _drawControlRef$curre5 === void 0 || (_drawControlRef$curre5 = _drawControlRef$curre5.drawer) === null || _drawControlRef$curre5 === void 0 || (_drawControlRef$curre6 = _drawControlRef$curre5.changeMode) === null || _drawControlRef$curre6 === void 0 ? void 0 : _drawControlRef$curre6.call(_drawControlRef$curre5, 'draw_polygon');
}
}, {
label: '路径框选',
key: 'path',
icon: 'icon-lujingkuangxuannor',
onClick: function onClick() {
var _drawControlRef$curre7, _drawControlRef$curre8;
return (_drawControlRef$curre7 = drawControlRef.current) === null || _drawControlRef$curre7 === void 0 || (_drawControlRef$curre7 = _drawControlRef$curre7.drawer) === null || _drawControlRef$curre7 === void 0 || (_drawControlRef$curre8 = _drawControlRef$curre7.changeMode) === null || _drawControlRef$curre8 === void 0 ? void 0 : _drawControlRef$curre8.call(_drawControlRef$curre7, 'draw_line_string');
}
}, {
label: '测距',
key: 'path',
icon: 'icon-ceju',
onClick: function onClick() {
var _drawControlRef$curre9, _drawControlRef$curre10;
return (_drawControlRef$curre9 = drawControlRef.current) === null || _drawControlRef$curre9 === void 0 || (_drawControlRef$curre9 = _drawControlRef$curre9.drawer) === null || _drawControlRef$curre9 === void 0 || (_drawControlRef$curre10 = _drawControlRef$curre9.changeMode) === null || _drawControlRef$curre10 === void 0 ? void 0 : _drawControlRef$curre10.call(_drawControlRef$curre9, 'draw_line_string');
}
}, {
label: '清除',
key: 'clear',
icon: 'icon-gongjuxiangguanbi',
onClick: function onClick() {
var _drawControlRef$curre11;
return (_drawControlRef$curre11 = drawControlRef.current) === null || _drawControlRef$curre11 === void 0 || (_drawControlRef$curre11 = _drawControlRef$curre11.drawer) === null || _drawControlRef$curre11 === void 0 ? void 0 : _drawControlRef$curre11.deleteAll();
}
}] : _ref$buttonList,
onMarkerClick = _ref.onMarkerClick,
onPopUpClose = _ref.onPopUpClose,
customMarkerRender = _ref.customMarkerRender,
onLoad = _ref.onLoad,
onDrawCreate = _ref.onDrawCreate,
onDrawUpdate = _ref.onDrawUpdate,
onDrawDelete = _ref.onDrawDelete,
onToolClick = _ref.onToolClick,
others = _objectWithoutProperties(_ref, _excluded);
var mapRef = useRef(null);
var drawControlRef = useRef(null);
// 默认绘制配置
var _useState = useState({
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'
}),
_useState2 = _slicedToArray(_useState, 1),
drawConfig = _useState2[0];
var initMarker = useMemo(function () {
return markerData.map(function (_item) {
return /*#__PURE__*/React.createElement(Marker, _extends({
customMarkerRender: customMarkerRender,
onMarkerClick: onMarkerClick
}, _item));
});
}, [markerData]);
useImperativeHandle(ref, function () {
var _drawControlRef$curre12;
return {
mapRef: mapRef.current,
drawer: (_drawControlRef$curre12 = drawControlRef.current) === null || _drawControlRef$curre12 === void 0 ? void 0 : _drawControlRef$curre12.drawer
};
});
return (
/*#__PURE__*/
//@ts-ignore
React.createElement("div", {
className: classnames("".concat(componentName))
}, /*#__PURE__*/React.createElement(Tools, {
open: toolsBarOpen,
buttonList: buttonList,
onToolClick: onToolClick
}), /*#__PURE__*/React.createElement(Map, _extends({
ref: mapRef,
onLoad: onLoad,
style: _objectSpread({
width: width,
height: height
}, style),
interactiveLayerIds: [clusterLayer.id].concat(_toConsumableArray(interactiveLayerIds))
}, merge(defaultMapConfig, others)), showMarker && initMarker, showPopUp && popUpInfo && /*#__PURE__*/React.createElement(PopUp, _extends({
onClose: onPopUpClose
}, popUpInfo)), showCluster && !showMarker && /*#__PURE__*/React.createElement(Cluster, _extends({
type: "geojson",
cluster: true,
clusterMaxZoom: 14,
clusterRadius: 50,
data: sluterData
}, clusterProps)), draw && /*#__PURE__*/React.createElement(DrawControl, _extends({
ref: drawControlRef,
onCreate: onDrawCreate,
onUpdate: onDrawUpdate,
onDelete: onDrawDelete,
onSelectionChange: function onSelectionChange(e) {
return console.log('e', e);
}
}, drawConfig)), children))
);
});
export default MapBox;

View File

@ -1,2 +1,3 @@
export { default as MapBox } from "./MapBox";
export * from 'react-map-gl';
export { default as MapBox } from "./mapBox";
export * from 'react-map-gl';
export * from "./utils";

View File

@ -1,6 +1,6 @@
{
"name": "@zhst/map",
"version": "0.3.0",
"version": "0.3.1",
"description": "地图库",
"keywords": [
"map",

View File

@ -0,0 +1,7 @@
---
title: 版本更新日志
order: 2
toc: content
---
<embed src="../../CHANGELOG.md" ></embed>

View File

@ -0,0 +1,91 @@
import React, { useRef, useEffect, useState } from 'react';
import { MapBox, MapProps } from '@zhst/map';
import axios from 'axios';
import { FloatButton, Switch } from '@zhst/meta';
const demo = () => {
const [showCluster, setShowCluster] = useState(true)
const [sluterData, setSluterData] = useState<MapProps['clusterData']>()
const mapRef = useRef(null);
// 初始化
const handleMapLoad = (e: mapboxgl.MapboxEvent<undefined>) => {
const map = e.target;
if (!map) return
map.flyTo({
// center: [120,30],
// zoom: map?.getMaxZoom(),
});
};
const getData = async () => {
let res = await axios({
method: 'post',
url: 'http://10.0.0.120:30003/singer.DeviceService/ListCamera',
headers: {
Authorization: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MTcwNDAzNzEsImp0aSI6IjExMjgiLCJpYXQiOjE3MTY3ODExNzEsInVzZXJJZCI6MSwidXNlcm5hbWUiOiJhZG1pbiIsImRhdGFSaWdodCI6MiwiY2FtZXJhUmlnaHQiOjEsImdwdVJpZ2h0IjoxLCJ1c2VybGVhZGVySWQiOjAsIm9yZ2FuaXphdGlvbklkIjoxLCJyb2xlSWQiOjF9.XHbXIkXkfUuvqV6_qSV4d20xj-s7I0qOQZgL-zspMDc'
},
data: {"labelData":[],"filter":{"realtimeProcessingFilter":0,"cameraFilter":[{"opt":"ORNOT","cameraOpt":"CAMERAOPT_TYPE","value":"100"}]},"maxResults":50}
});
if (res.status === 200) {
let markers = []
let sluters = {
features: []
}
res.data.cameras?.forEach(camera => {
markers.push({
key: camera.id,
id: camera.id,
title: camera.name,
population: camera.id,
checked: false,
disabled: false,
showCheckBox: true,
status: ['blue', 'yellow', 'red'][Math.floor(Math.random() * 3)],
latitude: camera.latitude,
longitude: camera.longitude
})
sluters.features.push({
"geometry": {
"type": "Point",
"coordinates": [
camera.longitude,
camera.latitude,
50
]
}
})
})
setSluterData(sluters)
}
}
useEffect(() => {
getData()
}, [])
return (
<div>
<FloatButton>
<Switch value={true}/>
</FloatButton>
<MapBox
onLoad={handleMapLoad}
ref={mapRef}
showToolBar={false}
width='100%'
height='800px'
showCluster={showCluster}
clusterProps={{
data: sluterData
}}
// customMarkerRender={(_data) => <div>自定义标记</div>}
>
</MapBox>
</div>
);
};
export default demo;

View File

@ -0,0 +1,24 @@
---
category: Components
subtitle: 聚合点
title: Cluster 聚合点
toc: content
group:
title: 数据展示
order: 1
---
<code src="./demo/basic.tsx">基本用法</code>
## API
| 参数 | 说明 | 类型 | 默认值 | 版本 |
| --- | --- | --- | --- | --- |
| clusterData | 聚合数据集合 | mapboxgl.GeoJSONSourceRaw['data'] | {} | - |
| showCluster | 显示/隐藏聚合点 | boolean | {} | - |
| type | 数据接收类型对clusterData生效 | string | geojson | - |
| cluster | 是否打开聚合功能 | boolean | {} | - |
| clusterMaxZoom | 最大生效层级 | number | 14 | - |
| clusterRadius | 聚合半径 | number | 50 | - |
> 更多参数参考 react-map-gl 的 Source 组件

View File

@ -120,18 +120,13 @@ const demo = () => {
showCluster={showCluster}
// popUpInfo={popupInfo}
onPopUpClose={e => setPopupInfo(null)}
onMarkerClick={(e, status, data) => {
onMarkerCheck={(e, status, data) => {
setMarkerData(pre => pre.map(item => {
if (item.id === data.id) {
item.checked = !data?.checked
}
return item
}))
// setPopupInfo({
// longitude: data?.longitude,
// latitude: data?.latitude,
// content: '测试'
// })
}}
onZoomEnd={map => {
let zoom = map.target.getZoom() // 画面层级,用来判断标签是否显示隐藏

View File

@ -14,13 +14,14 @@ import {
import drawRectMode from 'mapbox-gl-draw-rectangle-mode'
// @ts-ignore
import drawStaticMode from '@mapbox/mapbox-gl-draw-static-mode'
// @ts-ignore
import drawCircleMode from './Draw/drawCircleMode.draw.js'
import { useControl } from 'react-map-gl';
import type { ControlPosition } from 'react-map-gl';
import { MapContextValue } from 'react-map-gl/dist/esm/components/map';
export type DrawControlProps = ConstructorParameters<typeof MapboxDraw>[0] & {
position?: ControlPosition;
onCreate?: (evt: {features: object[]}) => void;
onUpdate?: (evt: {features: object[]; action: string}) => void;
onDelete?: (evt: {features: object[]}) => void;
@ -50,7 +51,7 @@ const DrawControl = forwardRef<DrawControlRefProps, DrawControlProps>((props, re
// draw_line_select: drawLineSelectMode,
draw_rect: drawRectMode,
drag_circle: DragCircleMode,
draw_circle : CircleMode,
draw_circle : drawCircleMode,
direct_select: DirectMode,
simple_select: SimpleSelectMode,
static: drawStaticMode,
@ -101,7 +102,8 @@ const DrawControl = forwardRef<DrawControlRefProps, DrawControlProps>((props, re
DrawControl.defaultProps = {
onCreate: () => {},
onUpdate: () => {},
onDelete: () => {}
onDelete: () => {},
};
export default DrawControl

View File

@ -0,0 +1,79 @@
import React, { useRef, useEffect, useState } from 'react';
import { getDistancesByStringLine, MapBox, Marker } from '@zhst/map';
import { FloatButton, Switch } from '@zhst/meta';
const demo = () => {
const mapRef = useRef(null);
const [canDraw, setCanDraw] = useState(false)
const [toolsBarOpen, setToolsBarOpen] = useState(false)
const [rangingList, setRangingList] = useState([])
// 初始化
const handleMapLoad = (e: mapboxgl.MapboxEvent<undefined>) => {
const map = e.target;
if (!map) return
map.flyTo({
// center: [120,30],
// zoom: map?.getMaxZoom(),
});
};
useEffect(() => {
}, [])
return (
<div>
<FloatButton>
<Switch value={true}/>
</FloatButton>
<MapBox
onLoad={handleMapLoad}
ref={mapRef}
width='100%'
height='800px'
draw={canDraw}
toolsBarOpen={toolsBarOpen}
onToolClick={e => {
setCanDraw(pre => !pre)
setToolsBarOpen(pre => !pre)
}}
onDrawCreate={e => {
const geojson = e.features[0]
// 防止绘制完成后,地图自动切换到选中状态
setTimeout(async () => {
mapRef.current.drawer.changeMode('simple_select')
}, 100);
const polygonJson = getDistancesByStringLine(geojson) || []
setRangingList(polygonJson.distanceArr)
}}
onDrawDelete={e => setRangingList([])}
onDrawUpdate={e => {
const geojson = e.features[0]
const polygonJson = getDistancesByStringLine(geojson) || []
setRangingList(polygonJson.distanceArr)
}}
drawerProps={{
onActionable: e => console.log('e', e)
}}
>
{rangingList?.map((item, index) => {
return (
<Marker
key={index}
anchor="bottom"
longitude={item.to[0]}
latitude={item.to[1]}
// !! 阻止原生的冒泡
onClick={e => e.originalEvent.stopPropagation()}
>
<div style={{ padding: '3px 6px', background: '#fff', border: '1px solid #000' }} >{(item.totalLength)}km</div>
</Marker>
)
})}
</MapBox>
</div>
);
};
export default demo;

View File

@ -0,0 +1,83 @@
---
category: Components
subtitle: 地图绘制
title: Draw 地图绘制
toc: content
group:
title: 地图操作
order: 1
---
<code src="./demo/basic.tsx">基本用法</code>
## API
| 参数 | 说明 | 类型 | 默认值 | 版本 |
| --- | --- | --- | --- | --- |
| draw | 是否绘制 | boolean | false | - |
| toolsBarOpen | 工具栏是否打开 | boolean | false | - |
| onToolClick | 工具Icon点击事件 | (e: React.MouseEvent<HTMLElement, MouseEvent>) => void | false | - |
| buttonList | 工具栏按钮列表 | IButtonList | defaultButtonList | - |
| mapRef.current.drawer | 绘制组件的Ref参考@mapbox/mapbox-gl-draw | DrawControlRefProps | - | - |
| onCreate | 创建监听 | (evt: {features: object[]}) => void; | - | - |
| onUpdate | 更新监听 | (evt: {features: object[]}) => void; | - | - |
| onDelete | 删除监听 | (evt: {features: object[]}) => void; | - | - |
| onRender | 渲染监听 | (evt: {features: object[]}) => void; | - | - |
| onCombine | 组合监听 | (evt: {features: object[]}) => void; | - | - |
| onUncombine | 分离监听 | (evt: {features: object[]}) => void; | - | - |
| onModeChange | 模式切换监听 | (evt: {features: object[]}) => void; | - | - |
| onActionable | 是否绘制 | (evt: {features: object[]}) => void; | - | - |
| onSelectionChange | 选中目标切换监听 | (evt: {features: object[]}) => void; | - | - |
```js
interface IButtonList {
label: string
key: string
icon?: ReactNode | string
onClick?: () => void
}[]
// 默认按钮列表
const defaultButtonList = [
{
label: '圆形框选',
key: 'circle',
icon: 'icon-yuan',
onClick: () => drawControlRef.current?.drawer?.changeMode?.('draw_circle')
},
{
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()
}
]
```

View File

@ -1,9 +0,0 @@
.zhst-map {
position: relative;
width: auto;
height: auto;
.mapboxgl-ctrl-logo {
display: none;
}
}

View File

@ -1,2 +1,4 @@
export { default as MapBox } from './MapBox';
export { default as MapBox } from './mapBox';
export type { MapProps, MapRefProps } from './mapBox';
export * from 'react-map-gl'
export * from './utils'

View File

@ -6,15 +6,15 @@ 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 Tools, { ToolsProps } from '../tools'
import DrawControl, { DrawControlProps, DrawControlRefProps } from '../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';
import mapboxDrawStyle from '../utils/drawStyle';
import Marker, { MarkerProps } from '../marker';
import PopUp, { PopUpProps } from '../popup';
import Cluster from '../clusters/Clusters';
import { clusterLayer } from '../clusters/layers';
const componentName = 'zhst-map'
@ -29,26 +29,30 @@ export interface MapProps extends MapBoxProps {
mapRef?: MapRef
style?: CSSProperties
children?: JSX.Element | JSX.Element[] | Array<JSX.Element | undefined>
sluterData?: any;
clusterData?: mapboxgl.GeoJSONSourceRaw['data'];
draw?: boolean
showMarker?: boolean // 显示标记点
showCluster?: boolean // 显示范围统计
showToolBar?: boolean // 是否显示工具箱
buttonList?: ToolsProps['buttonList']
popUpInfo?: PopUpProps
showPopUp?: boolean
clusterProps?: ClusterProps
clusterProps?: Partial<mapboxgl.GeoJSONSourceRaw>
toolsBarOpen?: boolean
drawerProps?: DrawControlProps
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']
onMarkerClick?: MarkerProps['onClick']
onMarkerCheck?: MarkerProps['onCheck']
onPopUpClose?: (e: PopupEvent) => void;
onToolClick?: ToolsProps['onToolClick']
}
export interface MapRefProps {
drawer: DrawControlRefProps
}
const MapBox = forwardRef<MapRefProps, MapProps>((props, ref) => {
@ -59,23 +63,25 @@ const MapBox = forwardRef<MapRefProps, MapProps>((props, ref) => {
width = '100%',
draw,
markerData = [],
sluterData = [],
clusterData,
popUpInfo = {
longitude: 0,
latitude: 0
},
showPopUp,
toolsBarOpen,
showMarker = true,
showMarker = false,
showCluster = false,
showToolBar = true,
clusterProps,
drawerProps,
interactiveLayerIds = [],
buttonList = [
{
label: '圆形框选',
key: 'circle',
icon: 'icon-yuan',
onClick: () => drawControlRef.current?.drawer?.changeMode?.('simple_select')
onClick: () => drawControlRef.current?.drawer?.changeMode?.('draw_circle')
},
{
label: '矩形框选',
@ -113,6 +119,7 @@ const MapBox = forwardRef<MapRefProps, MapProps>((props, ref) => {
}
],
onMarkerClick,
onMarkerCheck,
onPopUpClose,
customMarkerRender,
onLoad,
@ -143,7 +150,8 @@ const MapBox = forwardRef<MapRefProps, MapProps>((props, ref) => {
return markerData.map((_item) => (
<Marker
customMarkerRender={customMarkerRender}
onMarkerClick={onMarkerClick}
onClick={onMarkerClick}
onCheck={onMarkerCheck}
{..._item}
/>
))
@ -152,17 +160,20 @@ const MapBox = forwardRef<MapRefProps, MapProps>((props, ref) => {
useImperativeHandle(ref, () => ({
mapRef: mapRef.current,
drawer: drawControlRef.current?.drawer,
// @ts-ignore
drawer: drawControlRef.current?.drawer!,
}))
return (
//@ts-ignore
<div className={classnames(`${componentName}`)}>
<Tools
open={toolsBarOpen}
buttonList={buttonList}
onToolClick={onToolClick}
/>
{showToolBar && (
<Tools
open={toolsBarOpen}
buttonList={buttonList}
onToolClick={onToolClick}
/>
)}
{/* @ts-ignore */}
<Map
ref={mapRef}
@ -190,11 +201,12 @@ const MapBox = forwardRef<MapRefProps, MapProps>((props, ref) => {
{/* 范围统计标点 */}
{showCluster && !showMarker && (
<Cluster
id={clusterLayer.id}
type="geojson"
cluster={true}
clusterMaxZoom={14}
clusterRadius={50}
data={sluterData}
data={clusterData}
{...clusterProps}
/>
)}
@ -205,8 +217,8 @@ const MapBox = forwardRef<MapRefProps, MapProps>((props, ref) => {
onCreate={onDrawCreate}
onUpdate={onDrawUpdate}
onDelete={onDrawDelete}
onSelectionChange={e => console.log('e', e)}
{...drawConfig}
{...drawerProps}
/>
)}
{children}

View File

@ -0,0 +1,7 @@
/**
* Created by jiangzhixiong on 2024/05/23
*/
import MapBox from './MapBox'
export type { MapProps, MapRefProps } from './MapBox'
export default MapBox

View File

View File

@ -9,11 +9,17 @@ import {
} from 'react-map-gl'
import { Checkbox, ConfigProvider, Image } from '@zhst/meta'
import classNames from 'classnames'
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'
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'
import markerBlue from '../assets/icons/marker_blue.png'
import markerEscape from '../assets/icons/marker_escape.png'
import markerGreen from '../assets/icons/marker_green.png'
import markerRedBorder from '../assets/icons/marker_red_border.png'
import markerYellow from '../assets/icons/marker_yellow.png'
import markerRedTrack from '../assets/icons/marker_red_track.png'
import './index.less'
const { ConfigContext } = ConfigProvider
@ -24,6 +30,12 @@ const PIC_MAP = new Map([
['camera_grey', cameraGrey],
['camera_red', cameraRed],
['camera_yellow', cameraYellow],
['marker_blue', markerBlue],
['marker_escape', markerEscape],
['marker_green', markerGreen],
['marker_red_border', markerRedBorder],
['marker_yellow', markerYellow],
['marker_red_track', markerRedTrack],
])
// @ts-ignore
@ -37,10 +49,9 @@ export interface MarkerProps extends MapboxMarkerProps {
showCheckBox?: boolean
showTooltip?: boolean
type?: 'camera' | 'cluster' | 'marker';
population?: string;
status?: 'blue' | 'green' | 'yellow' | 'grey' | 'red_border' | 'escape' | 'escape_border' | 'red_track'; // 摄像头状态
onClick?: (e?: MarkerEvent, data?: MarkerProps) => void;
onMarkerClick?: (e?: MouseEvent, checked?: boolean, data?: MarkerProps) => void;
onCheck?: (e?: MouseEvent, checked?: boolean, data?: MarkerProps) => void;
customMarkerRender?: (data: MarkerProps) => ReactNode
}
@ -57,7 +68,7 @@ const Marker = forwardRef<MarkerRefProps, MarkerProps>((props, ref) => {
showCheckBox,
showTooltip,
onClick,
onMarkerClick,
onCheck,
customMarkerRender,
...rest
} = props
@ -89,7 +100,7 @@ const Marker = forwardRef<MarkerRefProps, MarkerProps>((props, ref) => {
onClick={(e) => {
e.stopPropagation()
// @ts-ignore
onMarkerClick?.(e, checked, props)
onCheck?.(e, checked, props)
}}
/>
)}

View File

@ -0,0 +1,82 @@
import React, { useRef, useEffect, useState } from 'react';
import { MapBox, MarkerProps } from '@zhst/map';
import { FloatButton, Switch } from '@zhst/meta';
import axios from 'axios'
const demo = () => {
const mapRef = useRef(null);
const [markerData, setMarkerData] = useState<MarkerProps[]>([])
const [showMarker, setShowMarker] = useState(true)
// 初始化
const handleMapLoad = (e: mapboxgl.MapboxEvent<undefined>) => {
const map = e.target;
if (!map) return
map.flyTo({
// center: [120,30],
// zoom: map?.getMaxZoom(),
});
};
const getData = async () => {
let res = await axios({
method: 'post',
url: 'http://10.0.0.120:30003/singer.DeviceService/ListCamera',
headers: {
Authorization: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MTcwNDAzNzEsImp0aSI6IjExMjgiLCJpYXQiOjE3MTY3ODExNzEsInVzZXJJZCI6MSwidXNlcm5hbWUiOiJhZG1pbiIsImRhdGFSaWdodCI6MiwiY2FtZXJhUmlnaHQiOjEsImdwdVJpZ2h0IjoxLCJ1c2VybGVhZGVySWQiOjAsIm9yZ2FuaXphdGlvbklkIjoxLCJyb2xlSWQiOjF9.XHbXIkXkfUuvqV6_qSV4d20xj-s7I0qOQZgL-zspMDc'
},
data: {"labelData":[],"filter":{"realtimeProcessingFilter":0,"cameraFilter":[{"opt":"ORNOT","cameraOpt":"CAMERAOPT_TYPE","value":"100"}]},"maxResults":50}
});
if (res.status === 200) {
let markers = []
res.data.cameras?.forEach(camera => {
markers.push({
key: camera.id,
id: camera.id,
title: camera.name,
checked: false,
disabled: false,
showCheckBox: true,
status: ['blue', 'yellow', 'red'][Math.floor(Math.random() * 3)],
latitude: camera.latitude,
longitude: camera.longitude
})
})
setMarkerData(markers)
}
}
useEffect(() => {
getData()
}, [])
return (
<div>
<FloatButton>
<Switch value={true}/>
</FloatButton>
<MapBox
onLoad={handleMapLoad}
ref={mapRef}
width='100%'
height='800px'
showToolBar={false}
markerData={markerData || []}
showMarker={showMarker}
onMarkerCheck={(e, status, data) => {
console.log('marker', data)
setMarkerData(pre => pre.map(item => {
if (item.id === data.id) {
item.checked = !data?.checked
}
return item
}))
}}
>
</MapBox>
</div>
);
};
export default demo;

View File

@ -0,0 +1,53 @@
---
category: Components
subtitle: 标签
title: Marker 标签
toc: content
group:
title: 数据展示
order: 1
---
<code src="./demo/basic.tsx">基本用法</code>
## API
| 参数 | 说明 | 类型 | 默认值 | 版本 |
| --- | --- | --- | --- | --- |
| key | 键 | string | - | - |
| id | id | string | - | - |
| title | 标题 | string | - | - |
| disabled | 是否可选 | boolean | - | - |
| checked | 是否选中 | boolean | - | - |
| showCheckBox | 是否展示选择框 | boolean | - | - |
| showTooltip | 是否显示tooltip | boolean | - | - |
| type | 标签类型目前只支持camera | 'camera' 'cluster' 'marker' | camera | - |
| status | 状态值 | IStatus | blue | - |
| onClick | 点击事件 | (e?: MarkerEvent, data?: MarkerProps) => void; | - | - |
| onCheck | ☑️选中事件 | (e?: MouseEvent, checked?: boolean, data?: MarkerProps) => void; | - | - |
| customMarkerRender | 自定义marker | (data: MarkerProps) => ReactNode | - | - |
> 更多属性参考react-map-gl 组件: MarkerProps
## IStatus
```js
// 支持的状态,需要配合当前有的标记使用
type IStatus = 'blue' | 'green' | 'yellow' | 'grey' | 'red_border' | 'escape' | 'escape_border' | 'red_track'
// 目前支持的标记
const PIC_MAP = new Map([
['camera_blue', cameraBlue],
['camera_green', cameraGreen],
['camera_grey', cameraGrey],
['camera_red', cameraRed],
['camera_yellow', cameraYellow],
['marker_blue', markerBlue],
['marker_escape', markerEscape],
['marker_green', markerGreen],
['marker_red_border', markerRedBorder],
['marker_yellow', markerYellow],
['marker_red_track', markerRedTrack],
])
```

View File

@ -141,4 +141,5 @@ const mapboxDrawStyle = [
},
},
];
export default mapboxDrawStyle;

View File

@ -0,0 +1,26 @@
---
category: Components
subtitle: utils
title: utils 工具库
toc: content
group:
title: 其它
order: 4
---
## getPointByShape
获取图形中的点位,一般用来圈选使用
```js
import { getPointByShape } from '@zhst/map'
```
## getDistancesByStringLine
通过绘制的线段获取每段线的距离和总长度默认单位为km
```js
import { getDistancesByStringLine } from '@zhst/map'
```

View File

@ -1,5 +1,12 @@
# @zhst/material
## 0.19.1
### Patch Changes
- Updated dependencies
- @zhst/biz@0.25.1
## 0.19.0
### Minor Changes

View File

@ -1,6 +1,6 @@
{
"name": "@zhst/material",
"version": "0.19.0",
"version": "0.19.1",
"description": "物料库",
"keywords": [
"business",