diff --git a/.vscode/settings.json b/.vscode/settings.json index 0e3adf1..8b4a03a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -10,6 +10,9 @@ "flvjs", "indicatorsize", "lambo", + "mapbox", + "maxzoom", + "minzoom", "remuxer", "stylelint", "transmuxer", diff --git a/packages/biz/CHANGELOG.md b/packages/biz/CHANGELOG.md index 903e306..5aeef88 100644 --- a/packages/biz/CHANGELOG.md +++ b/packages/biz/CHANGELOG.md @@ -1,5 +1,12 @@ # @zhst/biz +## 0.22.3 + +### Patch Changes + +- Updated dependencies + - @zhst/meta@0.22.0 + ## 0.22.2 ### Patch Changes diff --git a/packages/biz/package.json b/packages/biz/package.json index c45796c..ba5f7d0 100644 --- a/packages/biz/package.json +++ b/packages/biz/package.json @@ -1,6 +1,6 @@ { "name": "@zhst/biz", - "version": "0.22.2", + "version": "0.22.3", "description": "业务库", "keywords": [ "business", diff --git a/packages/map/CHANGELOG.md b/packages/map/CHANGELOG.md index 7eaf889..de0e146 100644 --- a/packages/map/CHANGELOG.md +++ b/packages/map/CHANGELOG.md @@ -1,5 +1,16 @@ # @zhst/map +## 0.3.0 + +### Minor Changes + +- zhst/map:拓展地图 api,加入 tools 组件、cluster 组价、marker 组件、draw 组件、popup 组件;zhst/mata:添加 floatButton 组件 + +### Patch Changes + +- Updated dependencies + - @zhst/meta@0.22.0 + ## 0.2.1 ### Patch Changes diff --git a/packages/map/README.md b/packages/map/README.md index ffa1663..7d430c4 100644 --- a/packages/map/README.md +++ b/packages/map/README.md @@ -2,7 +2,9 @@ ## 介绍 -地图库,基于map-box开发 +地图库,基于map-box开发,配合 @turf/turf 工具能达到地图交互体验感最大化。 + +设计的初衷是将业务中常见的一些模块抽离成组件的形式。在不影响地图原有的api的情况下,进行增量定制化开发。 ## 安装 diff --git a/packages/map/es/MapBox.js b/packages/map/es/MapBox.js index 29e7f4b..244f3dd 100644 --- a/packages/map/es/MapBox.js +++ b/packages/map/es/MapBox.js @@ -1,52 +1,195 @@ 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", "mapRef", "onLoad", "mapCenter", "mapConfig"]; -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); } +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 React from 'react'; -import { merge } from "./utils"; -import { MAP_CENTER, defaultMapConfig } from "./constants"; -var MapBox = function MapBox(props) { +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, - mapRef = _ref.mapRef, - _onLoad = _ref.onLoad, - _ref$mapCenter = _ref.mapCenter, - mapCenter = _ref$mapCenter === void 0 ? MAP_CENTER : _ref$mapCenter, - _ref$mapConfig = _ref.mapConfig, - mapConfig = _ref$mapConfig === void 0 ? {} : _ref$mapConfig, + _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(Map, _extends({ - ref: function ref(e) { - if (mapRef) { - mapRef.current = e; - } - }, - onLoad: function onLoad(e) { - _onLoad && _onLoad(e); - }, + 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: '100%', - height: 600 - }, style) - }, merge(defaultMapConfig, mapConfig), { - initialViewState: _objectSpread(_objectSpread({}, mapCenter), {}, { - zoom: 10 - }) - }, others), children) + 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; \ No newline at end of file diff --git a/packages/map/es/constants.js b/packages/map/es/constants.js deleted file mode 100644 index 13c186f..0000000 --- a/packages/map/es/constants.js +++ /dev/null @@ -1,47 +0,0 @@ -export var mapboxAccessToken = 'pk.eyJ1IjoiZGluZ2xpMTIzIiwiYSI6ImNra204ODhjczBobTgyeHJ6MmJpZHMxNWgifQ.NbKrXh_hb2gvjr5CEMDnyQ'; -export var MAP_CENTER = { - longitude: 120.2667694313269, - latitude: 30.180942826533766 -}; //地图中心 -var MapUrl = 'http://10.0.0.120:30003/map'; -export var defaultMapConfig = { - mapboxAccessToken: mapboxAccessToken, - maxZoom: 18, - minZoom: 4, - dragRotate: false, - mapStyle: { - version: 8, - name: 'Mapbox Streets', - // sprite: `${location.origin}/mapbox/sprite`, // 地图图标 - glyphs: 'mapbox://fonts/mapbox/{fontstack}/{range}.pbf', - // 字体 - sources: { - //数据源 - 'osm-tiles': { - type: 'raster', - //栅格切片。vector:矢量切片 - // Z-瓦片层级,一般支持0-18级,越大代表越清晰; - // X-瓦片列号,从西向东(0->360),依次0,1,2,……; - // Y-瓦片行号,从北向南(有些也可能是从南向北),依次0,1,2,……; - tiles: ["".concat(MapUrl, "/api/tilesets/mapfile/{z}/{x}/{y}.png")], - //在线地址,先写死120 - tileSize: 256 //切片的最小展示尺寸(可选,单位:像素,默认值为 512,即 1024/2 - } - }, - layers: [ - // 图层。图层指定了如何渲染数据源提供的数据 - { - id: 'zhstLayer', - //唯一id - type: 'raster', - //类型 栅格。circle,symbol,line... - source: 'osm-tiles', - // 'source-layer': 'osmtiles',//数据源必须是type:vector - minZoom: 4, - //最小层级 - maxZoom: 17, - //最大层级 - renderingMode: '2d' - }] - } -}; \ No newline at end of file diff --git a/packages/map/es/index.js b/packages/map/es/index.js index 1662d0f..8d9edea 100644 --- a/packages/map/es/index.js +++ b/packages/map/es/index.js @@ -1 +1,2 @@ -export { default as MapBox } from "./MapBox"; \ No newline at end of file +export { default as MapBox } from "./MapBox"; +export * from 'react-map-gl'; \ No newline at end of file diff --git a/packages/map/es/index.less b/packages/map/es/index.less index ac327e9..3369b02 100644 --- a/packages/map/es/index.less +++ b/packages/map/es/index.less @@ -1,3 +1,9 @@ -.mapboxgl-ctrl-attrib-button { - display: none; +.zhst-map { + position: relative; + width: auto; + height: auto; + + .mapboxgl-ctrl-logo { + display: none; + } } diff --git a/packages/map/es/interface.js b/packages/map/es/interface.js index 8cec2e9..e69de29 100644 --- a/packages/map/es/interface.js +++ b/packages/map/es/interface.js @@ -1 +0,0 @@ -export {}; \ No newline at end of file diff --git a/packages/map/es/utils.js b/packages/map/es/utils.js deleted file mode 100644 index 3e2ee23..0000000 --- a/packages/map/es/utils.js +++ /dev/null @@ -1,36 +0,0 @@ -var getRawType = function getRawType(val) { - return Object.prototype.toString.call(val).slice(8, -1); -}; -var isPlainObjectOrArray = function isPlainObjectOrArray(val) { - return isPlainObject(val) || Array.isArray(val); -}; -var isPlainObject = function isPlainObject(val) { - return getRawType(val) === 'Object'; -}; -export var merge = function merge(object) { - for (var _len = arguments.length, sources = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { - sources[_key - 1] = arguments[_key]; - } - for (var _i = 0, _sources = sources; _i < _sources.length; _i++) { - var source = _sources[_i]; - for (var key in source) { - if (source[key] === undefined && key in object) { - continue; - } - if (isPlainObjectOrArray(source[key])) { - if (getRawType(object[key] === getRawType(source[key]))) { - if (isPlainObject(object[key])) { - merge(object[key], source[key]); - } else { - object[key] = object[key].concat(source[key]); - } - } else { - object[key] = source[key]; - } - } else { - object[key] = source[key]; - } - } - } - return object; -}; \ No newline at end of file diff --git a/packages/map/package.json b/packages/map/package.json index 941577c..b029616 100644 --- a/packages/map/package.json +++ b/packages/map/package.json @@ -1,6 +1,6 @@ { "name": "@zhst/map", - "version": "0.2.1", + "version": "0.3.0", "description": "地图库", "keywords": [ "map", @@ -40,7 +40,6 @@ "@mapbox/mapbox-gl-draw": "^1.4.3", "@mapbox/mapbox-gl-draw-static-mode": "^1.0.1", "@turf/turf": "^6.5.0", - "@turf/union": "^6.5.0", "@zhst/hooks": "workspace:^0.13.1", "@zhst/icon": "workspace:^0.5.0", "@zhst/meta": "workspace:^", diff --git a/packages/map/src/MapBox.tsx b/packages/map/src/MapBox.tsx index 1f268d0..2405c0f 100644 --- a/packages/map/src/MapBox.tsx +++ b/packages/map/src/MapBox.tsx @@ -5,17 +5,19 @@ 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 { MAP_CENTER, defaultMapConfig } from './utils/constants'; +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[] @@ -27,14 +29,15 @@ export interface MapProps extends MapBoxProps { mapRef?: MapRef style?: CSSProperties children?: JSX.Element | JSX.Element[] | Array - mapCenter?: { - longitude: number, latitude: number - } + 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) => void onDrawCreate?: (e: { features: object[], [key: string]: any }) => void @@ -42,6 +45,7 @@ export interface MapProps extends MapBoxProps { onDrawDelete?: (e: { features: object[], [key: string]: any }) => void onMarkerClick?: MarkerProps['onMarkerClick'] onPopUpClose?: (e: PopupEvent) => void; + onToolClick?: ToolsProps['onToolClick'] } export interface MapRefProps { @@ -51,31 +55,37 @@ const MapBox = forwardRef((props, ref) => { const { style = {}, children, - mapCenter = MAP_CENTER, height = 600, width = '100%', draw, markerData = [], + sluterData = [], popUpInfo = { - ...MAP_CENTER + longitude: 0, + latitude: 0 }, showPopUp, - customMarkerRender, - showMarker, - onMarkerClick, - onPopUpClose, + toolsBarOpen, + showMarker = true, + showCluster = false, + clusterProps, + interactiveLayerIds = [], buttonList = [ { label: '圆形框选', key: 'circle', icon: 'icon-yuan', - onClick: () => drawControlRef.current?.drawer?.changeMode?.('draw_circle') + onClick: () => drawControlRef.current?.drawer?.changeMode?.('simple_select') }, { label: '矩形框选', key: 'rect', icon: 'icon-fang', - onClick: () => drawControlRef.current?.drawer?.changeMode?.('draw_rect') + onClick: () => drawControlRef.current?.drawer?.changeMode?.('draw_rect'), + popoverProps: { + placement: 'bottom', + content: '自定义内容' + } }, { label: '多边形框选', @@ -89,6 +99,12 @@ const MapBox = forwardRef((props, ref) => { 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', @@ -96,10 +112,14 @@ const MapBox = forwardRef((props, ref) => { onClick: () => drawControlRef.current?.drawer?.deleteAll() } ], + onMarkerClick, + onPopUpClose, + customMarkerRender, onLoad, onDrawCreate, onDrawUpdate, onDrawDelete, + onToolClick, ...others } = props || {}; const mapRef = useRef(null) @@ -112,6 +132,7 @@ const MapBox = forwardRef((props, ref) => { 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', @@ -119,13 +140,11 @@ const MapBox = forwardRef((props, ref) => { const initMarker = useMemo( () => { - return markerData.map((_item, index) => ( + return markerData.map((_item) => ( )) }, [markerData] @@ -140,30 +159,45 @@ const MapBox = forwardRef((props, ref) => { //@ts-ignore
{/* @ts-ignore */} {/* 标记点位 */} {showMarker && initMarker} - {/* 点位弹框 */} + + {/* 全局弹框弹框 */} {showPopUp && popUpInfo && ( )} + {/* - + */} + + {/* 范围统计标点 */} + {showCluster && !showMarker && ( + + )} {/* ---------------绘制图层--------------------- */} {draw && ( ((props, ref) => { onCreate={onDrawCreate} onUpdate={onDrawUpdate} onDelete={onDrawDelete} + onSelectionChange={e => console.log('e', e)} {...drawConfig} /> )} diff --git a/packages/map/src/assets/icons/index.ts b/packages/map/src/assets/icons/index.ts index 776b75e..da7a772 100644 --- a/packages/map/src/assets/icons/index.ts +++ b/packages/map/src/assets/icons/index.ts @@ -1,3 +1,4 @@ +// @ts-nocheck //引入地图所所有点图片 const file: { [key: string]: string } = {}; diff --git a/packages/map/src/components/clusters/Clusters.tsx b/packages/map/src/components/clusters/Clusters.tsx index 4b360dd..aa65f4a 100644 --- a/packages/map/src/components/clusters/Clusters.tsx +++ b/packages/map/src/components/clusters/Clusters.tsx @@ -1,62 +1,36 @@ /** * Created by jiangzhixiong on 2024/05/23 */ -import React, { forwardRef, useContext, useImperativeHandle } from 'react' +import React, { forwardRef, useImperativeHandle } from 'react' import { Source, Layer, SourceProps } from 'react-map-gl'; -import { ConfigProvider } from '@zhst/meta' -import {clusterLayer, clusterCountLayer, unclusteredPointLayer} from './layers'; +import { clusterLayer, clusterCountLayer } from './layers'; -const { ConfigContext } = ConfigProvider +// const { ConfigContext } = ConfigProvider -export interface ClusterProps extends SourceProps { +export interface ClusterProps { prefixCls?: string; } export interface ClusterRefProps { } -const Cluster = forwardRef((props, ref) => { +const Cluster = forwardRef((props, ref) => { const { prefixCls: customizePrefixCls, ...rest } = props - const { getPrefixCls } = useContext(ConfigContext) - const componentName = getPrefixCls('map-cluster', customizePrefixCls); + // const { getPrefixCls } = useContext(ConfigContext) + // const componentName = getPrefixCls('map-cluster', customizePrefixCls); - // const onClick = event => { - // const feature = event.features[0]; - // const clusterId = feature.properties.cluster_id; - - // const mapboxSource = mapRef.current.getSource('earthquakes') as GeoJSONSource; - - // mapboxSource.getClusterExpansionZoom(clusterId, (err, zoom) => { - // if (err) { - // return; - // } - - // mapRef.current.easeTo({ - // center: feature.geometry.coordinates, - // zoom, - // duration: 500 - // }); - // }); - // }; - - useImperativeHandle(ref, () => ({ - - })) + useImperativeHandle(ref, () => ({})) return ( - + {/* */} ) }) diff --git a/packages/map/src/components/clusters/index.tsx b/packages/map/src/components/clusters/index.tsx index 3775dff..35ddd45 100644 --- a/packages/map/src/components/clusters/index.tsx +++ b/packages/map/src/components/clusters/index.tsx @@ -1,5 +1,7 @@ /** * Created by jiangzhixiong on 2024/05/23 */ -export { default as Clusters } from './Clusters' +import Clusters from './Clusters' // export type { ClustersProps, ClustersRefProps } from './Clusters' + +export default Clusters diff --git a/packages/map/src/components/clusters/layers.ts b/packages/map/src/components/clusters/layers.ts index b4c060a..3177d1e 100644 --- a/packages/map/src/components/clusters/layers.ts +++ b/packages/map/src/components/clusters/layers.ts @@ -1,28 +1,32 @@ -import type {LayerProps} from 'react-map-gl'; +import type { LayerProps } from 'react-map-gl'; +// 绘制聚合圆形 export const clusterLayer: LayerProps = { id: 'clusters', type: 'circle', source: 'earthquakes', - filter: ['has', 'point_count'], + // "metadata": { // 元数据(可选,用于为 layer 附加任意的属性。为避免冲突,建议添加前缀,如 mapbox:) + // "mapbox:name": "test" + // }, + // "minzoom": 0, // 最小层级(可选,取值范围为 0 ~ 24。当 style 的 zoom 小于此 minzoom 时,layer 将被隐藏) + // "maxzoom": 24, // 最大层级(可选,取值范围为 0 ~ 24。当 style 的 zoom 大于此 maxzoom 时,layer 将被隐藏) + filter: ['has', 'point_count'], // 过滤(可选,用特定的表达式过滤指定的数据源的要素。具体的表达式详见 expression) paint: { - 'circle-color': ['step', ['get', 'point_count'], '#51bbd6', 100, '#f1f075', 750, '#f28cb1'], - 'circle-radius': ['step', ['get', 'point_count'], 20, 100, 30, 750, 40] - } -}; - -export const clusterCountLayer: LayerProps = { - id: 'cluster-count', - type: 'symbol', - source: 'earthquakes', - filter: ['has', 'point_count'], - layout: { - 'text-field': '{point_count_abbreviated}', - 'text-font': ['DIN Offc Pro Medium', 'Arial Unicode MS Bold'], - 'text-size': 12 - } + 'circle-color': ['step', ['get', 'point_count'], '#2eacff', 200, '#f90', 750, '#f34e52'], + 'circle-radius': ['step', ['get', 'point_count'], 20, 200, 30, 750, 40], + "circle-stroke-color": "#fff", // 圆点的描边颜色(可选,默认值为 #000000) + // "circle-opacity": 1, // 圆点的不透明度(可选,取值范围为 0 ~ 1,默认值为 1) + // "circle-blur": 0, // 圆点的虚化(可选,默认值为 0。当值为 1 时,表示把圆虚化到只有圆心是不透明的) + // "circle-translate": [0, 0], // 圆点的平移(可选,通过平移 [x, y] 达到一定的偏移量。默认值为 [0, 0],单位:像素。) + // "circle-translate-anchor": "map", // 圆点的平移锚点,即相对的参考物(可选,可选值为 map、viewport,默认为 map) + // "circle-pitch-scale": "map", // 地图倾斜时圆点的缩放(可选,可选值为 map、viewport,默认为 map。值为 viewport 时,圆点不会缩放) + // "circle-pitch-alignment": "map", // 地图倾斜时圆点的对齐方式(可选,可选值为 map、viewport,默认为 map) + "circle-stroke-width": 1, // 圆点的描边宽度(可选,值 >= 0,默认值为 0,单位:像素) + // "circle-stroke-opacity": 1 // 圆点的描边不透明度(可选,取值范围为 0 ~ 1,默认值为 1) + }, }; +// 单个绘制圆形 export const unclusteredPointLayer: LayerProps = { id: 'unclustered-point', type: 'circle', @@ -35,3 +39,289 @@ export const unclusteredPointLayer: LayerProps = { 'circle-stroke-color': '#fff' } }; + + +// 绘制填充 +export const FillLayer: LayerProps = { + "id": "fill-id", // 唯一 id (必填) + "type": "fill", // 类型(必填) + "metadata": { // 元数据(可选,用于为 layer 附加任意的属性。为避免冲突,建议添加前缀,如 mapbox:) + "mapbox:name": "test" + }, + "source": "source-name", // 数据源的名称(除了 layer 的 type 为 background 外,source 必填) + "source-layer": "source-layer-name", // 数据源的图层(只有数据源 source 的 type 为 vector 时,才能设置 source-layer,其他类型的不可以设置) + "minzoom": 0, // 最小层级(可选,取值范围为 0 ~ 24。当 style 的 zoom 小于此 minzoom 时,layer 将被隐藏) + "maxzoom": 24, // 最大层级(可选,取值范围为 0 ~ 24。当 style 的 zoom 大于此 maxzoom 时,layer 将被隐藏) + "filter": [], // 过滤(可选,用特定的表达式过滤指定的数据源的要素。具体的表达式详见 expression) + "layout": { // 布局类属性 + "visibility": "visible", // 可见性(可选,可选值为 none、visible,默认值为 visible) + }, + "paint": { // 绘制类属性 + "fill-antialias": true, // 填充时是否反锯齿(可选,默认值为 true) + "fill-opacity": 1, // 填充的不透明度(可选,取值范围为 0 ~ 1,默认值为 1) + "fill-pattern": "", // 填充用的图案(可选,这里填写在 sprite 雪碧图中图标名称。为了图案能无缝填充,图标的高宽需要是 2 的倍数) + "fill-color": "#000000", // 填充的颜色(可选,默认值为 #000000。如果设置了 fill-pattern,则 fill-color 将无效) + "fill-outline-color": "#000000", // 描边的颜色(可选,默认和 fill-color 一致。如果设置了 fill-pattern,则 fill-outline-color 将无效。为了使用此属性,还需要设置 fill-antialias 为 true) + "fill-translate": [0, 0], // 填充的平移(可选,通过平移 [x, y] 达到一定的偏移量。默认值为 [0, 0],单位:像素。) + "fill-translate-anchor": "map" // 平移的锚点,即相对的参考物(可选,可选值为 map、viewport,默认为 map) + } +} + +// --------------------------------- 绘制线 ---------------------------------------- +export const LineLayer: LayerProps = { + "id": "line-id", // 唯一 id (必填) + "type": "line", // 类型(必填) + "metadata": { // 元数据(可选,用于为 layer 附加任意的属性。为避免冲突,建议添加前缀,如 mapbox:) + "mapbox:name": "test" + }, + "source": "source-name", // 数据源的名称(除了 layer 的 type 为 background 外,source 必填) + "source-layer": "source-layer-name", // 数据源的图层(只有数据源 source 的 type 为 vector 时,才能设置 source-layer,其他类型的不可以设置) + "minzoom": 0, // 最小层级(可选,取值范围为 0 ~ 24。当 style 的 zoom 小于此 minzoom 时,layer 将被隐藏) + "maxzoom": 24, // 最大层级(可选,取值范围为 0 ~ 24。当 style 的 zoom 大于此 maxzoom 时,layer 将被隐藏) + "filter": [], // 过滤(可选,用特定的表达式过滤指定的数据源的要素。具体的表达式详见 expression) + "layout": { // 布局类属性 + "visibility": "visible", // 可见性(可选,可选值为 none、visible,默认值为 visible) + "line-cap": "butt", // 线末端的显示样式(可选,可选值为 butt、round、square,默认值为 butt) + // --- butt:方型末端(仅绘制到线的端点) + // --- round:圆型末端(以线宽的 1/2 为半径,以线的端点为圆心,绘制圆型端点,会超出线的端点) + // --- square:方型末端(以线宽的 1/2 长度超出线的端点) + "line-join": "miter", // 线交叉时的显示样式(可选,可选值为 bevel、round、miter,默认值为 miter) + // --- bevel:方型交点(以线宽的 1/2 长度超出线的交点) + // --- round:圆型交点(以线宽的 1/2 为半径,以线的交点为圆心,绘制圆型交点,会超出线的交点) + // --- miter:尖型交点(以两线段的外沿相交,超出交点绘制) + "line-miter-limit": 2, // 最大斜接长度(可选,用来将 miter 尖型交点自动转为 bevel 方型交点,默认值为 2。只有 line-join 为 miter 时,才需要设置此属性) + "line-round-limit": 1.05, // 最小圆角半径(可选,用来将 round 圆型交点自动转为 miter 尖型交点,默认值为 1.05。只有 line-join 为 round 时,才需要设置此属性) + }, + "paint": { // 绘制类属性 + "line-opacity": 1, // 线的不透明度(可选,取值范围为 0 ~ 1,默认值为 1) + "line-pattern": "", // 线用的图案(可选,这里填写在 sprite 雪碧图中图标名称。为了图案能无缝填充,图标的高宽需要是 2 的倍数) + "line-color": "#000000", // 线的颜色(可选,默认值为 #000000。如果设置了 line-pattern,则 line-color 将无效) + "line-translate": [0, 0], // 线的平移(可选,通过平移 [x, y] 达到一定的偏移量。默认值为 [0, 0],单位:像素。) + "line-translate-anchor": "map", // 线的平移锚点,即相对的参考物(可选,可选值为 map、viewport,默认为 map) + "line-width": 1, // 线的宽度(可选,值 >= 0,默认值为 1,单位:像素) + "line-gap-width": 0, // 线的外部间距宽度(可选,值 >= 0,默认值为 0,单位:像素。用来在线的外部再绘制一部分,此值表示内间距) + "line-offset": 0, // 线的偏移(可选,默认值为 0,单位:像素。对于单线,则是向右的偏移量;对于多边形,正值为内缩 inset,负值为外突 outset) + "line-blur": 0, // 线的模糊度(可选,值 >= 0,默认值为 0,单位:像素) + "line-dasharray": [0, 0], // 虚线的破折号部分和间隔的长度(可选,默认值为 [0, 0]。如果设置了 line-pattern,则 line-dasharray 将无效) + // "line-gradient": "#000000", // 线的渐变色(可选。如果设置了 line-pattern 或 line-dasharray,则 line-gradient 将无效。只有数据源 source 的 type 为 geojson ,且 source 的 lineMetrics 为 true 时,line-gradient 才有效) + } +} + +// 绘制符号 +export const clusterCountLayer: LayerProps = { + id: 'cluster-count', + type: 'symbol', + source: 'earthquakes', + filter: ['has', 'point_count'], + layout: { + 'text-field': '{point_count_abbreviated}', + 'text-font': ['DIN Offc Pro Medium', 'Arial Unicode MS Bold'], + 'text-size': 12, + // "visibility": "visible", // 可见性(可选,可选值为 none、visible,默认值为 visible) + // "symbol-placement": "point", // 符号的位置(可选,可选值为 point、line、line-center,默认值为 point) + // // --- point:符号在几何形状的点上 + // // --- line:符号在几何形状的线上(几何形状只能为 LineString 或 Polygon) + // // --- line-center:符号在几何形状的线的中心点上(几何形状只能为 LineString 或 Polygon) + // "symbol-spacing": 250, // 符号之间的距离(可选,值 >= 1,默认值为 250,单位:像素。只有 symbol-placement 为 line 时才有效) + // "symbol-avoid-edges": false, // 是否避免边缘冲突(可选,默认值为 false。当为 true 时,符号不会超过切片的边缘) + // "symbol-sort-key": 1, // 排序的参考值(可选,无默认值。值越大,越在上方) + // "symbol-z-order": 'source', // z 轴上的顺序控制(可选,可选值为 viewport-y、source) + + // // 图标类属性(需要设置 icon-image) + // "icon-image": "", // 图标的图片(可选,这里填写在 sprite 雪碧图中图标名称) + // "icon-size": 1, // 图标的大小(可选,值 >= 0,默认值为 1。这里实际上是图标对应的原始图片的大小的缩放比例。值为 1 表示图标大小为原始图片的大小) + // "icon-padding": 2, // 图标的外边距(可选,值 >= 0,默认值为 2。可用于碰撞检测) + // "icon-offset": [0, 0], // 图标的偏移量(可选,默认值为 [0, 0]) + // "icon-anchor": "center", // 图标与锚点的位置关系(可选,可选值为 center、left、right、top、bottom、top-left、top-right、bottom-left、bottom-right,默认值为 center) + // "icon-rotate": 0, // 图标的顺时针旋转角度(可选,默认值为 0,单位:角度) + // "icon-allow-overlap": false, // 是否允许图标重叠(可选,默认值为 false。当值为 true 时,图标即使和其他符号触碰也会显示) + // "icon-ignore-placement": false, // 是否忽略图标位置(可选,默认值为 false。当值为 true 时,其他符号即使与此图标触碰也会显示) + // "icon-optional": false, // 图标是否可不显示(可选,默认值为 false。当值为 true 时,如果图标与文本标签碰撞,则显示文本标签) + // "icon-text-fit": "none", // 图标与文本的大小适应关系(可选,可选值为 none、width、height、both,默认值为 none) + // // --- none:图标按其本身的比例显示 + // // --- width:图标在 x 轴上缩放以适应文本的宽度 + // // --- height:图标在 y 轴上缩放以适应文本的高度 + // // --- both:图标在 x 和 y 轴上缩放以适应文本的宽高 + // "icon-text-fit-padding": [0, 0, 0, 0], // 图标与文本的内边距(可选,默认值为 [0,0,0,0],单位:像素) + // "icon-keep-upright": false, // 当 icon-rotation-alignment 为 map,且 symbol-placement 为 line 或者 line-center 时,设置为 true 的话,可以避免图标上下颠倒 + // "icon-rotation-alignment": "auto", // 地图旋转时图标的对齐方式(可选,可选值为 map、viewport、auto,默认值为 auto) + // // --- map:当 symbol-placement 为 point 时,图标与地图的东西方向对齐;当 symbol-placement 为 line 时,图标的 x 轴和线对齐 + // // --- viewport:图标的 x 轴和视口的 x 轴对齐 + // // --- auto:当 symbol-placement 为 point 时,和 viewport 一致;当 symbol-placement 为 line 时,和 map 一致 + // "icon-pitch-alignment": "auto", // 地图倾斜时图标的对齐方式(可选,可选值为 map、viewport、auto,默认值为 auto) + // // --- map:图标的 x 轴与地图平面对齐 + // // --- viewport:图标的 x 轴和视口的 x 轴对齐 + // // --- auto:当 symbol-placement 为 point 时,和 viewport 一致;当 symbol-placement 为 line 时,和 map 一致 + + // // 文本类属性(需要指定 text-field) + // "text-rotation-alignment": "auto", // 与 icon-rotation-alignment 类似 + // "text-pitch-alignment": "auto", // 与 icon-pitch-alignment 类似 + // "text-field": "", // 文本所对应的字段(可选,默认值为 "") + // "text-font": ["Open Sans Regular","Arial Unicode MS Regular"], // 文本的字体集合(可选,默认值为 ["Open Sans Regular","Arial Unicode MS Regular"]) + // "text-size": 16, // 文本的大小(可选,默认值为 16,单位:像素) + // "text-max-width": 10, // 文本的最大宽度,超过则折行(可选,默认值为 10,单位:ems) + // "text-line-height": 1.2, // 文本的行高(可选,默认值为 1.2,单位:ems) + // "text-letter-spacing": 0, // 文本的字符间距(可选,默认值为 0,单位:ems) + // "text-justify": "center", // 文本的水平对齐方式(可选,可选值为 auto、left、center、right。默认值为 center) + // "text-anchor": "center", // 文本与锚点的位置关系(可选,可选值为 center、left、right、top、bottom、top-left、top-right、bottom-left、bottom-right,默认值为 center) + // "text-max-angle": 45, // 当 symbol-placement 为 line 或 line-center 时,文本相邻字符的最大夹角,默认 45 度 + // "text-rotate": 0, // 文本的顺时针旋转角度(可选,默认值为 0,单位:角度) + // "text-padding": 2, // 文本的外边距(可选,值 >= 0,默认值为 2。可用于碰撞检测) + // "text-keep-upright": false, // 当 icon-rotation-alignment 为 map,且 symbol-placement 为 line 或者 line-center 时,设置为 true 的话,可以避免文本上下颠倒 + // "text-transform": "none", // 文本大小写转换(可选,可选值为 none、uppercase、lowercase,默认值为 none) + // "text-offset": [0, 0], // 图标的偏移量(可选,默认值为 [0, 0]) + // "text-radial-offset": 0, // 文本的径向偏移量,优先级比 text-offset 高 + // "text-allow-overlap": false, // 是否允许文本重叠(可选,默认值为 false。当值为 true 时,文本即使和其他符号触碰也会显示) + // "text-ignore-placement": false, // 是否忽略文本位置(可选,默认值为 false。当值为 true 时,其他符号即使与此文本触碰也会显示) + // "text-optional": false // 文本是否可不显示(可选,默认值为 false。当值为 true 时,如果文本与图标碰撞,则显示图标) + }, + "paint": { // 绘制类属性 + // // 图标类属性(需要设置 icon-image) + // "icon-opacity": 1, // 图标的不透明度(可选,取值范围为 0 ~ 1,默认值为 1) + "icon-color": "#fff", // 图标的颜色(可选,默认值为 #000000) + // "icon-halo-color": "rgba(0,0,0,0)", // 图标的光晕颜色(可选,默认值为 rgba(0,0,0,0)) + // "icon-halo-width": 0, // 图标的光晕宽度(可选,值 >= 0,默认值为 0,单位:像素) + // "icon-halo-blur": 0, // 图标的光晕模糊宽度(可选,值 >= 0,默认值为 0,单位:像素) + // "icon-translate": [0, 0], // 图标的平移(可选,通过平移 [x, y] 达到一定的偏移量。默认值为 [0, 0],单位:像素。) + // "icon-translate-anchor": "map", // 图标的平移锚点,即相对的参考物(可选,可选值为 map、viewport,默认为 map) + + // // 文本类属性(需要设置 text-field) + // "text-opacity": 1, // 文本的不透明度(可选,取值范围为 0 ~ 1,默认值为 1) + "text-color": "#fff", // 文本的颜色(可选,默认值为 #000000) + // "text-halo-color": "rgba(0,0,0,0)", // 文本的光晕颜色(可选,默认值为 rgba(0,0,0,0)) + // "text-halo-width": 0, // 文本的光晕宽度(可选,值 >= 0,默认值为 0,单位:像素) + // "text-halo-blur": 0, // 文本的光晕模糊宽度(可选,值 >= 0,默认值为 0,单位:像素) + // "text-translate": [0, 0], // 文本的平移(可选,通过平移 [x, y] 达到一定的偏移量。默认值为 [0, 0],单位:像素。) + // "text-translate-anchor": "map", // 文本的平移锚点,即相对的参考物(可选,可选值为 map、viewport,默认为 map) + } +}; + +// 背景 +export const backgroundLayer: LayerProps = { + "id": "background-id", // 唯一 id (必填) + "type": "background", // 类型(必填) + "metadata": { // 元数据(可选,用于为 layer 附加任意的属性。为避免冲突,建议添加前缀,如 mapbox:) + "mapbox:name": "test" + }, + "minzoom": 0, // 最小层级(可选,取值范围为 0 ~ 24。当 style 的 zoom 小于此 minzoom 时,layer 将被隐藏) + "maxzoom": 24, // 最大层级(可选,取值范围为 0 ~ 24。当 style 的 zoom 大于此 maxzoom 时,layer 将被隐藏) + "layout": { // 布局类属性 + "visibility": "visible", // 可见性(可选,可选值为 none、visible,默认值为 visible) + }, + "paint": { // 绘制类属性 + "background-color": "#000000", // 背景颜色(可选,默认值为 #000000。如果设置了 background-pattern,则 background-color 将无效) + "background-pattern": "", // 背景图案(可选,这里填写在 sprite 雪碧图中图标名称。为了背景图案能无缝填充,图标的高宽需要是 2 的倍数) + "background-opacity": 1 // 背景不透明度(可选,取值范围为 0 ~ 1,默认值为 1) + } +} + +// 栅格布局 +export const rasterLayer: LayerProps = { + "id": "raster-id", // 唯一 id (必填) + "type": "raster", // 类型(必填) + "metadata": { // 元数据(可选,用于为 layer 附加任意的属性。为避免冲突,建议添加前缀,如 mapbox:) + "mapbox:name": "test" + }, + "source": "source-name", // 数据源的名称(除了 layer 的 type 为 background 外,source 必填) + "source-layer": "source-layer-name", // 数据源的图层(只有数据源 source 的 type 为 vector 时,才能设置 source-layer,其他类型的不可以设置) + "minzoom": 0, // 最小层级(可选,取值范围为 0 ~ 24。当 style 的 zoom 小于此 minzoom 时,layer 将被隐藏) + "maxzoom": 24, // 最大层级(可选,取值范围为 0 ~ 24。当 style 的 zoom 大于此 maxzoom 时,layer 将被隐藏) + "filter": [], // 过滤(可选,用特定的表达式过滤指定的数据源的要素。具体的表达式详见 expression) + "layout": { // 布局类属性 + "visibility": "visible", // 可见性(可选,可选值为 none、visible,默认值为 visible) + }, + "paint": { // 绘制类属性 + "raster-opacity": 1, // 图片的不透明度(可选,取值范围为 0 ~ 1,默认值为 1) + "raster-hue-rotate": 0, // 在色轮上旋转色相的角度(可选,默认值为 0,单位:角度) + "raster-brightness-min": 0, // 图片的最小亮度(可选,取值范围为 0 ~ 1,默认值为 0) + "raster-brightness-max": 1, // 图片的最大亮度(可选,取值范围为 0 ~ 1,默认值为 1) + "raster-saturation": 0, // 图片的饱和度(可选,取值范围为 -1 ~ 1,默认值为 0) + "raster-contrast": 0, // 图片的对比度(可选,取值范围为 -1 ~ 1,默认值为 0) + "raster-resampling": "linear", // 采样方式(可选,可选值为 linear、nearest,默认值为 linear) + "raster-fade-duration": 300 // 切换瓦片时的渐隐时间(可选,默认值为 300,单位:毫秒) + } +} + +// 热力图 +export const heatmapLayer: LayerProps = { + "id": "heatmap-id", // 唯一 id (必填) + "type": "heatmap", // 类型(必填) + "metadata": { // 元数据(可选,用于为 layer 附加任意的属性。为避免冲突,建议添加前缀,如 mapbox:) + "mapbox:name": "test" + }, + "source": "source-name", // 数据源的名称(除了 layer 的 type 为 background 外,source 必填) + "source-layer": "source-layer-name", // 数据源的图层(只有数据源 source 的 type 为 vector 时,才能设置 source-layer,其他类型的不可以设置) + "minzoom": 0, // 最小层级(可选,取值范围为 0 ~ 24。当 style 的 zoom 小于此 minzoom 时,layer 将被隐藏) + "maxzoom": 24, // 最大层级(可选,取值范围为 0 ~ 24。当 style 的 zoom 大于此 maxzoom 时,layer 将被隐藏) + "filter": [], // 过滤(可选,用特定的表达式过滤指定的数据源的要素。具体的表达式详见 expression) + "layout": { // 布局类属性 + "visibility": "visible", // 可见性(可选,可选值为 none、visible,默认值为 visible) + }, + "paint": { // 绘制类属性 + "heatmap-opacity": 1, // 热力图的不透明度(可选,取值范围为 0 ~ 1,默认值为 1) + "heatmap-radius": 30, // 一个热力图点的影响半径(可选,值 >= 1,默认值为 30,单位:像素) + "heatmap-weight": 1, // 一个热力图点的权重(可选,值 >= 0,默认值为 1) + "heatmap-intensity": 1, // 热力图的强度,控制了所有的热力图点(可选,值 >= 0,默认值为 1) + "heatmap-color": [ // 热力图的颜色变化(可选,默认值如下) + "interpolate", ["linear"], ["heatmap-density"], + 0, "rgba(0, 0, 255, 0)", + 0.1, "royalblue", + 0.3, "cyan", + 0.5, "lime", + 0.7, "yellow", + 1, "red" + ] + } +} + +// 坡面阴影 +export const hillshadeLayer: LayerProps = { + "id": "hillshade-id", // 唯一 id (必填) + "type": "hillshade", // 类型(必填) + "metadata": { // 元数据(可选,用于为 layer 附加任意的属性。为避免冲突,建议添加前缀,如 mapbox:) + "mapbox:name": "test" + }, + "source": "source-name", // 数据源的名称(除了 layer 的 type 为 background 外,source 必填) + "source-layer": "source-layer-name", // 数据源的图层(只有数据源 source 的 type 为 vector 时,才能设置 source-layer,其他类型的不可以设置) + "minzoom": 0, // 最小层级(可选,取值范围为 0 ~ 24。当 style 的 zoom 小于此 minzoom 时,layer 将被隐藏) + "maxzoom": 24, // 最大层级(可选,取值范围为 0 ~ 24。当 style 的 zoom 大于此 maxzoom 时,layer 将被隐藏) + "filter": [], // 过滤(可选,用特定的表达式过滤指定的数据源的要素。具体的表达式详见 expression) + "layout": { // 布局类属性 + "visibility": "visible", // 可见性(可选,可选值为 none、visible,默认值为 visible) + }, + "paint": { // 绘制类属性 + "hillshade-illumination-direction": 335, // 光照的方向(可选,取值范围为 0 ~ 359,默认值为 335,单位:角度) + "hillshade-illumination-anchor": "viewport", // 光照的锚点(可选,可选值为 map、viewport,默认值为 viewport) + "hillshade-exaggeration": 0.5, // 阴影的强度(可选,取值范围为 0 ~ 1,默认值为 0.5) + "hillshade-shadow-color": "#000000", // 阴影的颜色(可选,默认值为 #000000) + "hillshade-highlight-color": "#ffffff", // 光照部分的颜色(可选,默认值为 #ffffff) + "hillshade-accent-color": "#000000" // 用于强调地形的颜色(可选,默认值为 #000000) + } +} + +// 三维填充 +export const FillExtrusionLayer: LayerProps = { + "id": "fill-extrusion-id", // 唯一 id (必填) + "type": "fill-extrusion", // 类型(必填) + "metadata": { // 元数据(可选,用于为 layer 附加任意的属性。为避免冲突,建议添加前缀,如 mapbox:) + "mapbox:name": "test" + }, + "source": "source-name", // 数据源的名称(除了 layer 的 type 为 background 外,source 必填) + "source-layer": "source-layer-name", // 数据源的图层(只有数据源 source 的 type 为 vector 时,才能设置 source-layer,其他类型的不可以设置) + "minzoom": 0, // 最小层级(可选,取值范围为 0 ~ 24。当 style 的 zoom 小于此 minzoom 时,layer 将被隐藏) + "maxzoom": 24, // 最大层级(可选,取值范围为 0 ~ 24。当 style 的 zoom 大于此 maxzoom 时,layer 将被隐藏) + "filter": [], // 过滤(可选,用特定的表达式过滤指定的数据源的要素。具体的表达式详见 expression) + "layout": { // 布局类属性 + "visibility": "visible", // 可见性(可选,可选值为 none、visible,默认值为 visible) + }, + "paint": { // 绘制类属性 + "fill-extrusion-opacity": 1, // 三维填充的不透明度(可选,取值范围为 0 ~ 1,默认值为 1) + "fill-extrusion-pattern": "", // 三维填充的图案(可选,这里填写在 sprite 雪碧图中图标名称。为了图案能无缝填充,图标的高宽需要是 2 的倍数) + "fill-extrusion-color": "#000000", // 三维填充的颜色(可选,默认值为 #000000) + "fill-extrusion-translate": [0, 0], // 三维填充的平移(可选,通过平移 [x, y] 达到一定的偏移量。默认值为 [0, 0],单位:像素。) + "fill-extrusion-translate-anchor": "map", // 平移的锚点,即相对的参考物(可选,可选值为 map、viewport,默认为 map) + "fill-extrusion-height": 0, // 三维填充的高度(可选,值 >= 0,默认值为 0,单位:米) + "fill-extrusion-base": 0, // 三维填充的底部高度(可选,值 >= 0,默认值为 0,单位:米。值必须小于等于 fill-extrusion-height) + "fill-extrusion-vertical-gradient": true, // 是否开启垂直渐变(可选,默认值为 true) + } +} diff --git a/packages/map/src/components/customOverlay/CustomOverlay.tsx b/packages/map/src/components/customOverlay/CustomOverlay.tsx index 6b86c5f..a687403 100644 --- a/packages/map/src/components/customOverlay/CustomOverlay.tsx +++ b/packages/map/src/components/customOverlay/CustomOverlay.tsx @@ -1,21 +1,22 @@ +// @ts-nocheck import * as React from 'react'; -import { useState, cloneElement } from 'react'; -import { useControl } from 'react-map-gl'; -import { createPortal } from 'react-dom'; +import {useState, cloneElement} from 'react'; +import {useControl} from 'react-map-gl'; +import {createPortal} from 'react-dom'; import type { MapboxMap, IControl } from 'react-map-gl'; - // Based on template in https://docs.mapbox.com/mapbox-gl-js/api/markers/#icontrol class OverlayControl implements IControl { _map: MapboxMap | undefined; - _container: HTMLDivElement | undefined; + _container: HTMLElement | undefined; _redraw: () => void; constructor(redraw: () => void) { this._redraw = redraw; } - onAdd(map: MapboxMap) { + // @ts-ignore + onAdd(map) { this._map = map; map.on('move', this._redraw); /* global document */ @@ -40,20 +41,20 @@ class OverlayControl implements IControl { } /** - * 自定义图层 + * A custom control that rerenders arbitrary React content whenever the camera changes */ -const CustomOverlay = (props: {children: React.ReactElement}) => { +function CustomOverlay(props: {children: React.ReactElement}) { const [, setVersion] = useState(0); - const customControl = useControl(() => { + const ctrl = useControl(() => { const forceUpdate = () => setVersion(v => v + 1); return new OverlayControl(forceUpdate); }); - const map = customControl.getMap(); + const map = ctrl.getMap(); // @ts-ignore - return map && createPortal(cloneElement(props.children, { map }), customControl.getElement()); + return map && createPortal(cloneElement(props.children, {map}), ctrl.getElement()); } export default React.memo(CustomOverlay); diff --git a/packages/map/src/components/drawControl/Draw/index.ts b/packages/map/src/components/drawControl/Draw/index.ts index 41a5a32..d1580b5 100644 --- a/packages/map/src/components/drawControl/Draw/index.ts +++ b/packages/map/src/components/drawControl/Draw/index.ts @@ -1,3 +1,4 @@ +// @ts-nocheck import '@mapbox/mapbox-gl-draw/dist/mapbox-gl-draw.css'; import MapboxDraw from '@mapbox/mapbox-gl-draw'; import type { DrawModes } from '@mapbox/mapbox-gl-draw'; diff --git a/packages/map/src/components/drawControl/DrawControl.tsx b/packages/map/src/components/drawControl/DrawControl.tsx index 9cf9a70..d3099e1 100644 --- a/packages/map/src/components/drawControl/DrawControl.tsx +++ b/packages/map/src/components/drawControl/DrawControl.tsx @@ -18,12 +18,18 @@ import { useControl } from 'react-map-gl'; import type { ControlPosition } from 'react-map-gl'; import { MapContextValue } from 'react-map-gl/dist/esm/components/map'; -type DrawControlProps = ConstructorParameters[0] & { +export type DrawControlProps = ConstructorParameters[0] & { position?: ControlPosition; onCreate?: (evt: {features: object[]}) => void; onUpdate?: (evt: {features: object[]; action: string}) => 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; }; export interface DrawControlRefProps { @@ -61,12 +67,24 @@ const DrawControl = forwardRef((props, re map.on('draw.create', e => props.onCreate?.(e)); map.on('draw.update', e => props.onUpdate?.(e)); map.on('draw.delete', e => props.onDelete?.(e)); + map.on('draw.render', e => props.onRender?.(e)); + map.on('draw.combine', e => props.onCombine?.(e)); + map.on('draw.uncombine', e => props.onUncombine?.(e)); + map.on('draw.modechange', e => props.onModeChange?.(e)); + map.on('draw.actionable', e => props.onActionable?.(e)); + map.on('draw.selectionchange', e => props.onSelectionChange?.(e)); }, (context: MapContextValue) => { const { map } = context map.off('draw.create', props.onCreate); map.off('draw.update', props.onUpdate); map.off('draw.delete', props.onDelete); + map.off('draw.render', e => props.onRender?.(e)); + map.off('draw.combine', e => props.onCombine?.(e)); + map.off('draw.uncombine', e => props.onUncombine?.(e)); + map.off('draw.modechange', e => props.onModeChange?.(e)); + map.off('draw.actionable', e => props.onActionable?.(e)); + map.off('draw.selectionchange', e => props.onSelectionChange?.(e)); }, { position: props.position diff --git a/packages/map/src/components/marker/Marker.tsx b/packages/map/src/components/marker/Marker.tsx index c332dd2..e8fe8b4 100644 --- a/packages/map/src/components/marker/Marker.tsx +++ b/packages/map/src/components/marker/Marker.tsx @@ -1,18 +1,20 @@ /** * Created by jiangzhixiong on 2024/05/23 */ -import React, { forwardRef, ReactNode, useContext, useImperativeHandle } from 'react' +import React, { forwardRef, ReactNode, useContext, useImperativeHandle, useState } from 'react' import { Marker as MapboxMarker, MarkerProps as MapboxMarkerProps, MarkerEvent } 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 './index.less' const { ConfigContext } = ConfigProvider @@ -28,13 +30,15 @@ const PIC_MAP = new Map([ export interface MarkerProps extends MapboxMarkerProps { prefixCls?: string; key: string; + id: string; title?: string; + disabled?: boolean; checked?: boolean; + showCheckBox?: boolean + showTooltip?: 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 @@ -46,41 +50,61 @@ export interface MarkerRefProps { const Marker = forwardRef((props, ref) => { const { prefixCls: customizePrefixCls, - longitude, - latitude, checked = false, type = 'camera', status = 'blue', + disabled, + showCheckBox, + showTooltip, onClick, onMarkerClick, - customMarkerRender + customMarkerRender, + ...rest } = props const { getPrefixCls } = useContext(ConfigContext) const componentName = getPrefixCls('-map-marker', customizePrefixCls); + const [showTitle, setShowTitle] = useState(showTooltip) useImperativeHandle(ref, () => ({})) return ( { e.originalEvent.stopPropagation(); + // @ts-ignore onClick?.(e, props) }} + {...rest} > {/* 自定义marker */} {customMarkerRender?.(props) || (
- { - e.stopPropagation() - // @ts-ignore - onMarkerClick?.(e, checked, props) - }}> - - + {showCheckBox && ( + { + e.stopPropagation() + // @ts-ignore + onMarkerClick?.(e, checked, props) + }} + /> + )} + setShowTitle(true)} + onMouseLeave={() => setShowTitle(false)} + src={PIC_MAP.get(`${type}_${status}`)} + preview={false} + /> + {showTitle && ( +
+ {props.title} +
+ )} +
)}
diff --git a/packages/map/src/components/marker/index.less b/packages/map/src/components/marker/index.less new file mode 100644 index 0000000..d242d6e --- /dev/null +++ b/packages/map/src/components/marker/index.less @@ -0,0 +1,35 @@ +.zhst--map-marker { + position: relative; + cursor: pointer; + + &-checkbox { + position: absolute; + top: -6px; + right: -6px; + z-index: 1; + } + + &-title { + padding: 3px 6px; + position: absolute; + left: 50%; + bottom: -36px; + transform: translateX(-50%); + white-space: nowrap; + background-color: #fff; + border-radius: 3px; + box-shadow: 3px 3px 6px 3px rgba(0, 0, 0, 20%); + + &::after { + position: absolute; + top: -12px; + left: 50%; + transform: translateX(-50%); + content: ''; + width: 0; + height: 0; + border: 6px solid; + border-color: transparent transparent #fff; + } + } +} diff --git a/packages/map/src/components/popup/PopUp.tsx b/packages/map/src/components/popup/PopUp.tsx index 48a6b8f..e87b635 100644 --- a/packages/map/src/components/popup/PopUp.tsx +++ b/packages/map/src/components/popup/PopUp.tsx @@ -18,6 +18,7 @@ export interface PopUpProps extends MapboxPopupProps { title?: string; url?: string; content?: string; + contentRender?: (props: PopUpProps) => void; } export interface PopUpRefProps { @@ -25,13 +26,12 @@ export interface PopUpRefProps { const PopUp = forwardRef((props, ref) => { const { - longitude, - latitude, - onClose, title, content, url, - prefixCls: customizePrefixCls + contentRender, + prefixCls: customizePrefixCls, + ...rest } = props const { getPrefixCls } = useContext(ConfigContext) const componentName = getPrefixCls('map-popup', customizePrefixCls); @@ -42,15 +42,15 @@ const PopUp = forwardRef((props, ref) => { -
- {title &&

{title}

} - {url && } - {content &&

{content}

} -
+ {contentRender?.(props) || ( +
+ {title &&

{title}

} + {url && } + {content &&

{content}

} +
+ )}
) }) diff --git a/packages/map/src/components/tools/Tools.tsx b/packages/map/src/components/tools/Tools.tsx index 3e009b8..a126de3 100644 --- a/packages/map/src/components/tools/Tools.tsx +++ b/packages/map/src/components/tools/Tools.tsx @@ -4,7 +4,6 @@ import React, { forwardRef, ReactNode, useContext, useImperativeHandle } from 'react' import { Button, ConfigProvider } from '@zhst/meta' -import { useToggle } from '@zhst/hooks' import classNames from 'classnames' import { IconFont } from '@zhst/icon' import './index.less' @@ -13,7 +12,8 @@ const { ConfigContext } = ConfigProvider export interface ToolsProps { prefixCls?: string - defaultValue?: boolean; + open?: boolean; + onToolClick?: (e: React.MouseEvent) => void buttonList?: { label: string key: string @@ -29,11 +29,11 @@ const Tools = forwardRef((props, ref) => { const { prefixCls: customizePrefixCls, buttonList = [], - defaultValue + onToolClick, + open } = props const { getPrefixCls } = useContext(ConfigContext) const componentName = getPrefixCls('map-tools', customizePrefixCls) - const [state, { toggle }] = useToggle(defaultValue) useImperativeHandle(ref, () => ({ @@ -41,7 +41,7 @@ const Tools = forwardRef((props, ref) => { return (
-
    +
      {buttonList.map((item) => (
    • {typeof item.icon === 'string' ? ( @@ -57,8 +57,8 @@ const Tools = forwardRef((props, ref) => { size='large' shape="circle" type="primary" - onClick={toggle} - icon={} + onClick={onToolClick} + icon={} />
) diff --git a/packages/map/src/demo/.data/mock.ts b/packages/map/src/demo/.data/mock.ts new file mode 100644 index 0000000..23bcbe0 --- /dev/null +++ b/packages/map/src/demo/.data/mock.ts @@ -0,0 +1,240 @@ +export const sluterData = { + "features": [ + { + "geometry": { + "type": "Point", + "coordinates": [ + -151.5129, + 63.1016, + 0.0 + ] + } + }, + { + "geometry": { + "type": "Point", + "coordinates": [ + -150.4048, + 63.1224, + 105.5 + ] + } + }, + { + "geometry": { + "type": "Point", + "coordinates": [ + -151.3597, + 63.0781, + 0.0 + ] + } + }, + { + "geometry": { + "type": "Point", + "coordinates": [ + -118.497, + 34.299667, + 7.64 + ] + } + }, + { + "geometry": { + "type": "Point", + "coordinates": [ + -87.6901, + 12.0623, + 46.41 + ] + } + }, + { + "geometry": { + "type": "Point", + "coordinates": [ + -151.5053, + 63.0719, + 0.0 + ] + } + }, + { + + "geometry": { + "type": "Point", + "coordinates": [ + -178.4576, + -20.2873, + 614.26 + ] + } + }, + { + + "geometry": { + "type": "Point", + "coordinates": [ + -148.789, + 63.1725, + 7.5 + ] + } + }, + { + + "geometry": { + "type": "Point", + "coordinates": [ + -120.993164, + 36.421833, + 6.37 + ] + } + }, + { + "geometry": { + "type": "Point", + "coordinates": [ + -117.0155, + 33.656333, + 12.37 + ] + } + }, + { + "geometry": { + "type": "Point", + "coordinates": [ + -151.512, + 63.0879, + 10.8 + ] + } + }, + { + "geometry": { + "type": "Point", + "coordinates": [ + -151.4378, + 63.0933, + 0.0 + ] + } + }, + { + "geometry": { + "type": "Point", + "coordinates": [ + -149.6538, + 63.2272, + 96.8 + ] + } + }, + { + "geometry": { + "type": "Point", + "coordinates": [ + -151.5325, + 63.0844, + 0.0 + ] + } + }, + { + "geometry": { + "type": "Point", + "coordinates": [ + -149.4752, + 61.8518, + 54.3 + ] + } + }, + { + "geometry": { + "type": "Point", + "coordinates": [ + -150.8597, + 61.6214, + 50.0 + ] + } + }, + { + "geometry": { + "type": "Point", + "coordinates": [ + -149.7142, + 62.9656, + 93.6 + ] + } + }, + { + "geometry": { + "type": "Point", + "coordinates": [ + -151.2484, + 61.2705, + 69.1 + ] + } + }, + { + "geometry": { + "type": "Point", + "coordinates": [ + -152.0732, + 65.5942, + 14.8 + ] + } + }, + { + "geometry": { + "type": "Point", + "coordinates": [ + -90.5445, + 13.5146, + 54.36 + ] + } + }, + { + + "geometry": { + "type": "Point", + "coordinates": [ + -118.819504, + 37.605499, + 4.14 + ] + } + }, + { + + "geometry": { + "type": "Point", + "coordinates": [ + -118.930168, + 37.636833, + -0.71 + ] + } + }, + { + + "geometry": { + "type": "Point", + "coordinates": [ + -117.509167, + 34.1555, + 16.34 + ] + } + }, + ] +} diff --git a/packages/map/src/demo/basic.tsx b/packages/map/src/demo/basic.tsx index 3c889bf..5667d42 100644 --- a/packages/map/src/demo/basic.tsx +++ b/packages/map/src/demo/basic.tsx @@ -1,12 +1,22 @@ import React, { useRef, useEffect, useState } from 'react'; -import { MapBox } from '@zhst/map'; +import { MapBox, Marker } from '@zhst/map'; import axios from 'axios'; import { FloatButton, Switch } from '@zhst/meta'; +import { MarkerProps } from '../components/marker'; +import { getDistancesByStringLine, lineToPoly } from '../utils'; +// import { sluterData } from './.data/mock.ts' const demo = () => { - const [markerData, setMarkerData] = useState([]) + const [markerData, setMarkerData] = useState([]) const [showMarker, setShowMarker] = useState(true) + const [showCluster, setShowCluster] = useState(true) + const [canDraw, setCanDraw] = useState(false) + const [toolsBarOpen, setToolsBarOpen] = useState(false) const [popupInfo, setPopupInfo] = useState() + const [sluterData, setSluterData] = useState({}) + const [showMouseTag, setShowMouseTag] = useState(false) + const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 }) + const [rangingList, setRangingList] = useState([]) const mapRef = useRef(null); // 初始化 @@ -26,19 +36,41 @@ const demo = () => { method: 'post', url: 'http://10.0.0.120:30003/singer.DeviceService/ListCamera', headers: { - Authorization: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MTY3MTI5MTAsImp0aSI6IjEwOTYiLCJpYXQiOjE3MTY0NTM3MTAsInVzZXJJZCI6MSwidXNlcm5hbWUiOiJhZG1pbiIsImRhdGFSaWdodCI6MiwiY2FtZXJhUmlnaHQiOjEsImdwdVJpZ2h0IjoxLCJ1c2VybGVhZGVySWQiOjAsIm9yZ2FuaXphdGlvbklkIjoxLCJyb2xlSWQiOjF9.6s73alRI0iB-5oT-GcQH8lZSiScPTULk14xxz2Aak6k' + 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) { - setMarkerData(res.data.cameras.map(item => ({ - key: item.id, - title: item.name, - population: item.id, - status: item.status, - latitude: item.latitude, - longitude: item.longitude - }))) + 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 + ] + } + }) + }) + setMarkerData(markers) + setSluterData(sluters) } } @@ -54,32 +86,105 @@ const demo = () => { console.log('Create', e)} + draw={canDraw} + toolsBarOpen={toolsBarOpen} + onToolClick={e => { + setCanDraw(pre => !pre) + setToolsBarOpen(pre => !pre) + }} + onDrawCreate={e => { + const geojson = e.features[0] + const polygonJson = getDistancesByStringLine(geojson) || [] + setRangingList(polygonJson.distanceArr) + }} onDrawDelete={e => console.log('Delete', e)} - onDrawUpdate={e => console.log('Update', e)} + onDrawUpdate={e => { + const geojson = e.features[0] + const polygonJson = getDistancesByStringLine(geojson) || [] + setRangingList(polygonJson.distanceArr) + }} width='100%' height='100vh' - markerData={markerData} + mapStyle={{ + sources: { + 'osm-tiles': { + 'type': 'raster', + tiles: [`http://10.0.0.120:30003/map/api/tilesets/mapfile/{z}/{x}/{y}.png`], //在线地址,先写死120 + } + }, + }} + markerData={markerData || []} showMarker={showMarker} showPopUp - popUpInfo={popupInfo} + sluterData={sluterData} + showCluster={showCluster} + // popUpInfo={popupInfo} onPopUpClose={e => setPopupInfo(null)} onMarkerClick={(e, status, data) => { - setPopupInfo({ - longitude: data?.longitude, - latitude: data?.latitude, - content: '测试' - }) + 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() // 画面层级,用来判断标签是否显示隐藏 - - console.log('zoom', zoom) - // setShowMarker(pre => !pre) + // 摄像头显示/隐藏 + setShowMarker(zoom > 5) + // 范围统计显示/隐藏 + setShowCluster(zoom < 5) + }} + onClick={e => setShowMouseTag(true)} + onDblClick={e => { + setShowMouseTag(false) + // setCanDraw(false) + }} + onMouseMove={e => { + setMousePosition({ x: e.point.x, y: e.point.y }) }} // customMarkerRender={(_data) =>
自定义标记
} - /> + > + {canDraw && ( +
{showMouseTag ? '双击完成绘制' : '单击以确定起点'}
+ )} + {rangingList?.map((item, index) => { + return ( + e.originalEvent.stopPropagation()} + > +
{(item.totalLength)}km
+
+ ) + })} + { + e.originalEvent.stopPropagation(); + }} + > +
我是自定义的DOM!
+
+
); }; diff --git a/packages/map/src/index.md b/packages/map/src/index.md index 9240a6b..5cd7e30 100644 --- a/packages/map/src/index.md +++ b/packages/map/src/index.md @@ -27,3 +27,5 @@ title: 快速上手 [mapbox-gl-draw](https://github.com/mapbox/mapbox-gl-draw) [draw 绘制模式插件](https://github.com/mapbox/mapbox-gl-draw/blob/main/docs/MODES.md#available-custom-modes) [mapboxJS](https://www.naivemap.com/mapbox-gl-js-cookbook/starter/handlers/control.html) +[mapboxAPI详解](https://juejin.cn/post/6907068992607928328) +[mapbox Expressions语法学习](https://docs.mapbox.com/help/tutorials/mapbox-gl-js-expressions/) diff --git a/packages/map/src/index.ts b/packages/map/src/index.ts index 6581359..8b8ec4d 100644 --- a/packages/map/src/index.ts +++ b/packages/map/src/index.ts @@ -1 +1,2 @@ export { default as MapBox } from './MapBox'; +export * from 'react-map-gl' diff --git a/packages/map/src/utils/constants.ts b/packages/map/src/utils/constants.ts index 7482b99..58dbfe5 100644 --- a/packages/map/src/utils/constants.ts +++ b/packages/map/src/utils/constants.ts @@ -1,20 +1,22 @@ +import { MapProps } from 'react-map-gl' + export const mapboxAccessToken = 'pk.eyJ1IjoiZGluZ2xpMTIzIiwiYSI6ImNra204ODhjczBobTgyeHJ6MmJpZHMxNWgifQ.NbKrXh_hb2gvjr5CEMDnyQ'; -export const MAP_CENTER = { - longitude: 120.2667694313269, - latitude: 30.180942826533766, -}; //地图中心 +const mapSourceUrl = 'http://10.0.0.120:30003/map'; -const MapUrl = 'http://10.0.0.120:30003/map'; -export const defaultMapConfig = { +export const defaultMapConfig: MapProps = { mapboxAccessToken, maxZoom: 18, minZoom: 4, + initialViewState: { + longitude: 120.2667694313269, + latitude: 30.180942826533766, + }, dragRotate: false, mapStyle: { version: 8, - name: 'Mapbox Streets', + name: 'zhst mapbox', // sprite: `${location.origin}/mapbox/sprite`, // 地图图标 glyphs: 'mapbox://fonts/mapbox/{fontstack}/{range}.pbf', // 字体 sources: { @@ -24,7 +26,7 @@ export const defaultMapConfig = { // Z-瓦片层级,一般支持0-18级,越大代表越清晰; // X-瓦片列号,从西向东(0->360),依次0,1,2,……; // Y-瓦片行号,从北向南(有些也可能是从南向北),依次0,1,2,……; - tiles: [`${MapUrl}/api/tilesets/mapfile/{z}/{x}/{y}.png`], //在线地址,先写死120 + tiles: [`${mapSourceUrl}/api/tilesets/mapfile/{z}/{x}/{y}.png`], //在线地址,先写死120 tileSize: 256, //切片的最小展示尺寸(可选,单位:像素,默认值为 512,即 1024/2 }, }, @@ -35,8 +37,9 @@ export const defaultMapConfig = { type: 'raster', //类型 栅格。circle,symbol,line... source: 'osm-tiles', // 'source-layer': 'osmtiles',//数据源必须是type:vector - minZoom: 4, //最小层级 - maxZoom: 17, //最大层级 + minzoom: 4, //最小层级 + maxzoom: 17, //最大层级 + // @ts-ignore renderingMode: '2d', }, ], diff --git a/packages/map/src/utils/formater.ts b/packages/map/src/utils/formater.ts new file mode 100644 index 0000000..e69de29 diff --git a/packages/map/src/utils/index.ts b/packages/map/src/utils/index.ts index c91ffad..f7222c7 100644 --- a/packages/map/src/utils/index.ts +++ b/packages/map/src/utils/index.ts @@ -1,5 +1,5 @@ +// @ts-ignore import * as turf from '@turf/turf'; -import union from '@turf/union'; // 判断参数类型 const getRawType = (val: any) => { @@ -196,14 +196,63 @@ export const lineToPoly = (geojson: { geometry: { coordinates: string | any[] } let _union; try { //todo: 新版本union和老版本行为不一致 先用老版本 后续观察原因 - // _union = turf.union(...circlePolygon, ...linesPolygon); - _union = union(...circlePolygon, ...linesPolygon); + _union = turf.union(...circlePolygon, ...linesPolygon); + // _union = union(...circlePolygon, ...linesPolygon); } catch (e) { console.error(e); } return _union; }; +/** + * 获取在图形中的点 + * @param _points 点坐标集 + * @param polygon 图形 + * @returns 在图形中的坐标集 + */ +export const getPointByShape = (_points: [number, number][], polygon: [number, number][]) => { + let points = turf.points(_points); + // TODO:首未坐标要一致 + let searchWithin = turf.polygon([polygon]); + + return turf.pointsWithinPolygon(points, searchWithin); +} + +/** + * 通过绘制的线段获取距离 + * @param geojson 点坐标集 + * @param config 额外的 turf.distance 配置(可选) + * @returns distanceArr,totalLength + */ +export const getDistancesByStringLine = ( + geojson: { geometry: { coordinates: [number, number][], [key: string]: any }, type: 'line' }, + config?: any +) => { + let distanceArr: { + distance: number, + from: [number, number], + to: [number, number], + totalLength: number | string + }[] = [] + let totalLength = 0 + for (let i = 0; i < geojson.geometry.coordinates.length - 1; i++) { + const [pointA, pointB] = [geojson.geometry.coordinates[i], geojson.geometry.coordinates[i + 1]]; + + const tempDistance = turf.distance(pointA, pointB, config); + totalLength += tempDistance + distanceArr.push({ + distance: tempDistance.toFixed(2), + totalLength: totalLength.toFixed(2), + from: pointA, + to: pointB + }) + } + return { + distanceArr, + totalLength: totalLength.toFixed(2) + } +} + /** * @description 创建 node,绑定 node 到对应父级, * @param {string} className 类名 diff --git a/packages/material/CHANGELOG.md b/packages/material/CHANGELOG.md index 5e46d4d..9e467a4 100644 --- a/packages/material/CHANGELOG.md +++ b/packages/material/CHANGELOG.md @@ -1,5 +1,13 @@ # @zhst/material +## 0.18.3 + +### Patch Changes + +- Updated dependencies + - @zhst/meta@0.22.0 + - @zhst/biz@0.22.3 + ## 0.18.2 ### Patch Changes diff --git a/packages/material/package.json b/packages/material/package.json index b9504df..e4a246c 100644 --- a/packages/material/package.json +++ b/packages/material/package.json @@ -1,6 +1,6 @@ { "name": "@zhst/material", - "version": "0.18.2", + "version": "0.18.3", "description": "物料库", "keywords": [ "business", diff --git a/packages/meta/CHANGELOG.md b/packages/meta/CHANGELOG.md index c0e8a4e..bc5ae6a 100644 --- a/packages/meta/CHANGELOG.md +++ b/packages/meta/CHANGELOG.md @@ -1,5 +1,16 @@ # @zhst/utils +## 0.22.0 + +### Minor Changes + +- zhst/map:拓展地图 api,加入 tools 组件、cluster 组价、marker 组件、draw 组件、popup 组件;zhst/mata:添加 floatButton 组件 + +### Patch Changes + +- Updated dependencies + - @zhst/meta@0.22.0 + ## 0.21.2 ### Patch Changes diff --git a/packages/meta/package.json b/packages/meta/package.json index 4c0959e..08c95c0 100644 --- a/packages/meta/package.json +++ b/packages/meta/package.json @@ -1,6 +1,6 @@ { "name": "@zhst/meta", - "version": "0.21.2", + "version": "0.22.0", "description": "原子组件", "keywords": [ "meta",