@fleet-frontend/mower-maps 0.0.9-beta.1 → 0.0.9-beta.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config/constants.d.ts +2 -25
- package/dist/config/constants.d.ts.map +1 -1
- package/dist/config/styles.d.ts +2 -2
- package/dist/config/styles.d.ts.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.js +805 -602
- package/dist/index.js +804 -601
- package/dist/processor/MapDataProcessor.d.ts +1 -1
- package/dist/processor/MapDataProcessor.d.ts.map +1 -1
- package/dist/processor/PathDataProcessor.d.ts +2 -21
- package/dist/processor/PathDataProcessor.d.ts.map +1 -1
- package/dist/processor/builder/AntennaDataBuilder.d.ts +2 -1
- package/dist/processor/builder/AntennaDataBuilder.d.ts.map +1 -1
- package/dist/processor/builder/BoundaryDataBuilder.d.ts +1 -1
- package/dist/processor/builder/BoundaryDataBuilder.d.ts.map +1 -1
- package/dist/processor/builder/ChannelDataBuilder.d.ts +1 -1
- package/dist/processor/builder/ChannelDataBuilder.d.ts.map +1 -1
- package/dist/processor/builder/ChargingPileDataBuilder.d.ts +1 -1
- package/dist/processor/builder/ChargingPileDataBuilder.d.ts.map +1 -1
- package/dist/processor/builder/ObstacleDataBuilder.d.ts +2 -1
- package/dist/processor/builder/ObstacleDataBuilder.d.ts.map +1 -1
- package/dist/processor/builder/PathDataBuilder.d.ts +1 -1
- package/dist/processor/builder/PathDataBuilder.d.ts.map +1 -1
- package/dist/processor/builder/PointDataBuilder.d.ts +2 -1
- package/dist/processor/builder/PointDataBuilder.d.ts.map +1 -1
- package/dist/processor/builder/SvgElementDataBuilder.d.ts +1 -1
- package/dist/processor/builder/SvgElementDataBuilder.d.ts.map +1 -1
- package/dist/processor/builder/VisionOffDataBuilder.d.ts +2 -1
- package/dist/processor/builder/VisionOffDataBuilder.d.ts.map +1 -1
- package/dist/processor/index.d.ts +2 -1
- package/dist/processor/index.d.ts.map +1 -1
- package/dist/render/AntennaManager.d.ts +2 -24
- package/dist/render/AntennaManager.d.ts.map +1 -1
- package/dist/render/BoundaryLabelsManager.d.ts +8 -22
- package/dist/render/BoundaryLabelsManager.d.ts.map +1 -1
- package/dist/render/ChargingPileManager.d.ts +3 -18
- package/dist/render/ChargingPileManager.d.ts.map +1 -1
- package/dist/render/MowerMapOverlay.d.ts +9 -3
- package/dist/render/MowerMapOverlay.d.ts.map +1 -1
- package/dist/render/MowerMapRenderer.d.ts.map +1 -1
- package/dist/render/MowerPositionManager.d.ts +3 -6
- package/dist/render/MowerPositionManager.d.ts.map +1 -1
- package/dist/render/SvgMapView.d.ts +0 -25
- package/dist/render/SvgMapView.d.ts.map +1 -1
- package/dist/render/layers/BoundaryBorderLayer.d.ts +6 -1
- package/dist/render/layers/BoundaryBorderLayer.d.ts.map +1 -1
- package/dist/render/layers/ChannelLayer.d.ts.map +1 -1
- package/dist/render/layers/DrawLayer.d.ts +1 -1
- package/dist/render/layers/DrawLayer.d.ts.map +1 -1
- package/dist/render/layers/PathLayer.d.ts.map +1 -1
- package/dist/render/layers/SvgElementLayer.d.ts.map +1 -1
- package/dist/render/layers/index.d.ts +0 -1
- package/dist/render/layers/index.d.ts.map +1 -1
- package/dist/render/layers/types.d.ts +1 -38
- package/dist/render/layers/types.d.ts.map +1 -1
- package/dist/store/processMowingState.d.ts +1 -5
- package/dist/store/processMowingState.d.ts.map +1 -1
- package/dist/store/useSubBoundaryBorderStore.d.ts +9 -5
- package/dist/store/useSubBoundaryBorderStore.d.ts.map +1 -1
- package/dist/types/constants.d.ts +38 -0
- package/dist/types/constants.d.ts.map +1 -0
- package/dist/types/index.d.ts +6 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/layers.d.ts +50 -0
- package/dist/types/layers.d.ts.map +1 -0
- package/dist/types/processor.d.ts +26 -0
- package/dist/types/processor.d.ts.map +1 -0
- package/dist/types/realTime.d.ts +11 -1
- package/dist/types/realTime.d.ts.map +1 -1
- package/dist/types/renderer.d.ts +8 -4
- package/dist/types/renderer.d.ts.map +1 -1
- package/dist/types/store.d.ts +22 -0
- package/dist/types/store.d.ts.map +1 -0
- package/dist/types/utils.d.ts +102 -0
- package/dist/types/utils.d.ts.map +1 -0
- package/dist/utils/boundaryUtils.d.ts +1 -29
- package/dist/utils/boundaryUtils.d.ts.map +1 -1
- package/dist/utils/common.d.ts +11 -5
- package/dist/utils/common.d.ts.map +1 -1
- package/dist/utils/coordinates.d.ts +1 -7
- package/dist/utils/coordinates.d.ts.map +1 -1
- package/dist/utils/handleRealTime.d.ts +2 -7
- package/dist/utils/handleRealTime.d.ts.map +1 -1
- package/dist/utils/mapBounds.d.ts +1 -10
- package/dist/utils/mapBounds.d.ts.map +1 -1
- package/dist/utils/math.d.ts +3 -10
- package/dist/utils/math.d.ts.map +1 -1
- package/dist/utils/mower.d.ts +4 -4
- package/dist/utils/mower.d.ts.map +1 -1
- package/dist/utils/pathSegments.d.ts +1 -23
- package/dist/utils/pathSegments.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.esm.js
CHANGED
|
@@ -1,6 +1,135 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
2
|
import React, { forwardRef, useState, useRef, useMemo, useCallback, useEffect, useImperativeHandle } from 'react';
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* 常量和枚举类型定义
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* 机器人状态枚举
|
|
9
|
+
*/
|
|
10
|
+
var RobotStatus;
|
|
11
|
+
(function (RobotStatus) {
|
|
12
|
+
RobotStatus[RobotStatus["PARKED"] = 1] = "PARKED";
|
|
13
|
+
RobotStatus[RobotStatus["CHARGING"] = 2] = "CHARGING";
|
|
14
|
+
RobotStatus[RobotStatus["STANDBY"] = 3] = "STANDBY";
|
|
15
|
+
RobotStatus[RobotStatus["MOWING"] = 4] = "MOWING";
|
|
16
|
+
RobotStatus[RobotStatus["WORKING"] = 5] = "WORKING";
|
|
17
|
+
RobotStatus[RobotStatus["MAPPING"] = 6] = "MAPPING";
|
|
18
|
+
RobotStatus[RobotStatus["ERROR"] = 7] = "ERROR";
|
|
19
|
+
RobotStatus[RobotStatus["UPGRADING"] = 8] = "UPGRADING";
|
|
20
|
+
RobotStatus[RobotStatus["DISCONNECTED"] = 9] = "DISCONNECTED";
|
|
21
|
+
RobotStatus[RobotStatus["UNKNOWN"] = -1] = "UNKNOWN";
|
|
22
|
+
RobotStatus[RobotStatus["TASK_DELAY"] = 10] = "TASK_DELAY";
|
|
23
|
+
})(RobotStatus || (RobotStatus = {}));
|
|
24
|
+
/**
|
|
25
|
+
* RTK状态枚举
|
|
26
|
+
*/
|
|
27
|
+
var RTK_STATE;
|
|
28
|
+
(function (RTK_STATE) {
|
|
29
|
+
RTK_STATE[RTK_STATE["LOW_RTK"] = 1] = "LOW_RTK";
|
|
30
|
+
RTK_STATE[RTK_STATE["MIDDLE_RTK"] = 2] = "MIDDLE_RTK";
|
|
31
|
+
RTK_STATE[RTK_STATE["HIGH_RTK"] = 3] = "HIGH_RTK";
|
|
32
|
+
RTK_STATE[RTK_STATE["NO_POSTURE"] = 10] = "NO_POSTURE";
|
|
33
|
+
RTK_STATE[RTK_STATE["OUT_OF_RANGE"] = 11] = "OUT_OF_RANGE";
|
|
34
|
+
RTK_STATE[RTK_STATE["OFF_LINE"] = 19] = "OFF_LINE";
|
|
35
|
+
})(RTK_STATE || (RTK_STATE = {}));
|
|
36
|
+
/**
|
|
37
|
+
* 实时数据类型枚举
|
|
38
|
+
*/
|
|
39
|
+
var REAL_TIME_DATA_TYPE;
|
|
40
|
+
(function (REAL_TIME_DATA_TYPE) {
|
|
41
|
+
REAL_TIME_DATA_TYPE[REAL_TIME_DATA_TYPE["LOCATION"] = 1] = "LOCATION";
|
|
42
|
+
REAL_TIME_DATA_TYPE[REAL_TIME_DATA_TYPE["PROCESS"] = 2] = "PROCESS";
|
|
43
|
+
})(REAL_TIME_DATA_TYPE || (REAL_TIME_DATA_TYPE = {}));
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* 地图渲染相关常量配置
|
|
47
|
+
*/
|
|
48
|
+
/**
|
|
49
|
+
* 缩放因子 - 将米转换为像素
|
|
50
|
+
* 与Python代码中的SVG比例一致
|
|
51
|
+
*/
|
|
52
|
+
const SCALE_FACTOR = 50; // 50像素/米
|
|
53
|
+
/**
|
|
54
|
+
* 默认线宽设置
|
|
55
|
+
*/
|
|
56
|
+
const DEFAULT_LINE_WIDTHS = {
|
|
57
|
+
OBSTACLE: 2,
|
|
58
|
+
CHARGING_PILE: 2,
|
|
59
|
+
CHANNEL: 2,
|
|
60
|
+
PATH: 20,
|
|
61
|
+
VISION_OFF_AREA: 2,
|
|
62
|
+
TIME_LIMIT_OBSTACLE: 1,
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* 默认透明度设置
|
|
66
|
+
*/
|
|
67
|
+
const DEFAULT_OPACITIES = {
|
|
68
|
+
FULL: 1.0,
|
|
69
|
+
HIGH: 0.7,
|
|
70
|
+
MEDIUM: 0.6};
|
|
71
|
+
/**
|
|
72
|
+
* 默认半径设置
|
|
73
|
+
*/
|
|
74
|
+
const DEFAULT_RADII = {
|
|
75
|
+
CHARGING_PILE: 12};
|
|
76
|
+
/**
|
|
77
|
+
* 图层等级
|
|
78
|
+
*/
|
|
79
|
+
const LAYER_LEVELS = {
|
|
80
|
+
BOUNDARY: 2,
|
|
81
|
+
BOUNDARY_BORDER: 4};
|
|
82
|
+
/**
|
|
83
|
+
* 图层默认id
|
|
84
|
+
*/
|
|
85
|
+
const LAYER_DEFAULT_TYPE = {
|
|
86
|
+
CHANNEL: 'channel',
|
|
87
|
+
BOUNDARY: 'boundary',
|
|
88
|
+
PATH: 'path',
|
|
89
|
+
BOUNDARY_BORDER: 'boundary_border',
|
|
90
|
+
OBSTACLE: 'obstacle',
|
|
91
|
+
CHARGING_PILE: 'charging_pile',
|
|
92
|
+
POINT: 'point',
|
|
93
|
+
SVG: 'svg',
|
|
94
|
+
VISION_OFF_AREA: 'vision_off_area',
|
|
95
|
+
ANTENNA: 'antenna',
|
|
96
|
+
};
|
|
97
|
+
const ISOLATED_BOUNDARY_SVG = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
98
|
+
<g opacity="0.6">
|
|
99
|
+
<rect width="24" height="24" rx="12" fill="#1E1E1F" fill-opacity="0.5"/>
|
|
100
|
+
<path d="M8.20573 12.4961C6.739 11.1707 4.85775 11.2284 3.60938 11.1707C6.17744 13.0156 6.05584 15.7887 5.67404 16.9446H14.327C13.837 13.1673 15.5321 10.1289 16.4408 9.08187C15.0342 9.46118 13.5794 10.8303 13.0278 11.4674C12.8102 8.94572 13.992 5.97489 14.61 4.80469C12.5235 5.92214 11.0501 8.26056 10.4938 9.56261C9.22803 7.5947 6.83894 7.17806 5.883 6.9432C8.20573 10.2373 8.00039 11.1707 8.20573 12.4961Z" fill="white"/>
|
|
101
|
+
<mask id="path-3-outside-1_9822_43516" maskUnits="userSpaceOnUse" x="13.2344" y="7.20545" width="12.0208" height="12.0208" fill="black">
|
|
102
|
+
<rect fill="white" x="13.2344" y="7.20545" width="12.0208" height="12.0208"/>
|
|
103
|
+
<path d="M20.6852 11.1208C19.9042 10.3398 18.6378 10.3398 17.8568 11.1208L17.2733 11.7043C16.6707 12.3069 16.5358 13.1973 16.8631 13.9319L17.5916 13.2034C17.5657 12.9181 17.6619 12.6236 17.8803 12.4052L18.5674 11.7181C18.9579 11.3276 19.5911 11.3276 19.9816 11.7181L20.4056 12.1421C20.7959 12.5326 20.796 13.1658 20.4056 13.5563L19.7185 14.2434C19.5128 14.449 19.2393 14.5457 18.9699 14.5348L18.2235 15.2812C18.9538 15.596 19.8325 15.4565 20.429 14.86L21.0125 14.2765C21.7935 13.4955 21.7936 12.2291 21.0125 11.4481L20.6852 11.1208Z"/>
|
|
104
|
+
</mask>
|
|
105
|
+
<path d="M20.6852 11.1208C19.9042 10.3398 18.6378 10.3398 17.8568 11.1208L17.2733 11.7043C16.6707 12.3069 16.5358 13.1973 16.8631 13.9319L17.5916 13.2034C17.5657 12.9181 17.6619 12.6236 17.8803 12.4052L18.5674 11.7181C18.9579 11.3276 19.5911 11.3276 19.9816 11.7181L20.4056 12.1421C20.7959 12.5326 20.796 13.1658 20.4056 13.5563L19.7185 14.2434C19.5128 14.449 19.2393 14.5457 18.9699 14.5348L18.2235 15.2812C18.9538 15.596 19.8325 15.4565 20.429 14.86L21.0125 14.2765C21.7935 13.4955 21.7936 12.2291 21.0125 11.4481L20.6852 11.1208Z" fill="white"/>
|
|
106
|
+
<path d="M20.6852 11.1208L21.7458 10.0601L21.7459 10.0601L20.6852 11.1208ZM17.8568 11.1208L16.7961 10.0601L16.7962 10.0601L17.8568 11.1208ZM17.2733 11.7043L16.2126 10.6437L16.2126 10.6436L17.2733 11.7043ZM16.8631 13.9319L17.9238 14.9926L16.381 16.5354L15.493 14.5425L16.8631 13.9319ZM17.5916 13.2034L19.0855 13.0678L19.149 13.7674L18.6523 14.2641L17.5916 13.2034ZM20.4056 12.1421L21.4662 11.0814L21.4665 11.0817L20.4056 12.1421ZM18.9699 14.5348L17.9093 13.4741L18.3741 13.0093L19.0309 13.036L18.9699 14.5348ZM18.2235 15.2812L17.6298 16.6587L15.5997 15.7837L17.1628 14.2206L18.2235 15.2812ZM20.429 14.86L21.4897 15.9207L21.4897 15.9207L20.429 14.86ZM21.0125 14.2765L22.0732 15.3371L22.0732 15.3372L21.0125 14.2765ZM20.6852 11.1208L19.6246 12.1815C19.4294 11.9862 19.1127 11.9863 18.9174 12.1815L17.8568 11.1208L16.7962 10.0601C18.163 8.69337 20.379 8.6934 21.7458 10.0601L20.6852 11.1208ZM17.8568 11.1208L18.9175 12.1814L18.334 12.7649L17.2733 11.7043L16.2126 10.6436L16.7961 10.0601L17.8568 11.1208ZM17.2733 11.7043L18.334 12.7649C18.1877 12.9112 18.1488 13.1318 18.2333 13.3214L16.8631 13.9319L15.493 14.5425C14.9228 13.2629 15.1537 11.7026 16.2126 10.6437L17.2733 11.7043ZM16.8631 13.9319L15.8025 12.8713L16.531 12.1428L17.5916 13.2034L18.6523 14.2641L17.9238 14.9926L16.8631 13.9319ZM17.5916 13.2034L16.0978 13.339C16.0334 12.6302 16.2727 11.8914 16.8196 11.3445L17.8803 12.4052L18.9409 13.4658C19.051 13.3558 19.098 13.206 19.0855 13.0678L17.5916 13.2034ZM17.8803 12.4052L16.8196 11.3445L17.5067 10.6574L18.5674 11.7181L19.628 12.7788L18.9409 13.4658L17.8803 12.4052ZM18.5674 11.7181L17.5067 10.6574C18.483 9.68112 20.0659 9.68112 21.0422 10.6574L19.9816 11.7181L18.9209 12.7788C19.1162 12.974 19.4328 12.974 19.628 12.7788L18.5674 11.7181ZM19.9816 11.7181L21.0422 10.6574L21.4662 11.0814L20.4056 12.1421L19.3449 13.2027L18.9209 12.7788L19.9816 11.7181ZM20.4056 12.1421L21.4665 11.0817C22.4419 12.0577 22.4428 13.6404 21.4662 14.617L20.4056 13.5563L19.3449 12.4956C19.1493 12.6913 19.1498 13.0076 19.3446 13.2024L20.4056 12.1421ZM20.4056 13.5563L21.4662 14.617L20.7791 15.304L19.7185 14.2434L18.6578 13.1827L19.3449 12.4956L20.4056 13.5563ZM19.7185 14.2434L20.7791 15.304C20.2628 15.8204 19.5762 16.0607 18.909 16.0335L18.9699 14.5348L19.0309 13.036C18.9025 13.0308 18.7629 13.0777 18.6578 13.1827L19.7185 14.2434ZM18.9699 14.5348L20.0306 15.5954L19.2841 16.3419L18.2235 15.2812L17.1628 14.2206L17.9093 13.4741L18.9699 14.5348ZM18.2235 15.2812L18.8172 13.9037C19.0042 13.9843 19.2223 13.9455 19.3684 13.7993L20.429 14.86L21.4897 15.9207C20.4427 16.9676 18.9034 17.2077 17.6298 16.6587L18.2235 15.2812ZM20.429 14.86L19.3684 13.7994L19.9519 13.2159L21.0125 14.2765L22.0732 15.3372L21.4897 15.9207L20.429 14.86ZM21.0125 14.2765L19.9518 13.2159C20.1471 13.0206 20.1471 12.704 19.9519 12.5088L21.0125 11.4481L22.0732 10.3874C23.4401 11.7543 23.4399 13.9703 22.0732 15.3371L21.0125 14.2765ZM21.0125 11.4481L19.9519 12.5088L19.6246 12.1814L20.6852 11.1208L21.7459 10.0601L22.0732 10.3874L21.0125 11.4481Z" fill="#8E8E8F" mask="url(#path-3-outside-1_9822_43516)"/>
|
|
107
|
+
<mask id="path-5-outside-2_9822_43516" maskUnits="userSpaceOnUse" x="9.22265" y="10.388" width="12.7279" height="12.7279" fill="black">
|
|
108
|
+
<rect fill="white" x="9.22265" y="10.388" width="12.7279" height="12.7279"/>
|
|
109
|
+
<path d="M16.1708 14.5077C15.4353 14.1778 14.5422 14.3133 13.9383 14.9172L13.3548 15.5007C12.574 16.2818 12.5738 17.5481 13.3548 18.3291L13.6821 18.6564C14.4631 19.4374 15.7295 19.4373 16.5105 18.6564L17.094 18.0729C17.6895 17.4775 17.8299 16.6003 17.5173 15.8708L16.7743 16.6138C16.7828 16.8803 16.6863 17.1494 16.4829 17.3527L15.7952 18.0405C15.4046 18.4309 14.7714 18.431 14.3809 18.0405L13.957 17.6165C13.5667 17.226 13.5666 16.5927 13.957 16.2023L14.6447 15.5145C14.8654 15.2939 15.1639 15.1979 15.452 15.2266L16.1708 14.5077Z"/>
|
|
110
|
+
</mask>
|
|
111
|
+
<path d="M16.1708 14.5077C15.4353 14.1778 14.5422 14.3133 13.9383 14.9172L13.3548 15.5007C12.574 16.2818 12.5738 17.5481 13.3548 18.3291L13.6821 18.6564C14.4631 19.4374 15.7295 19.4373 16.5105 18.6564L17.094 18.0729C17.6895 17.4775 17.8299 16.6003 17.5173 15.8708L16.7743 16.6138C16.7828 16.8803 16.6863 17.1494 16.4829 17.3527L15.7952 18.0405C15.4046 18.4309 14.7714 18.431 14.3809 18.0405L13.957 17.6165C13.5667 17.226 13.5666 16.5927 13.957 16.2023L14.6447 15.5145C14.8654 15.2939 15.1639 15.1979 15.452 15.2266L16.1708 14.5077Z" fill="white"/>
|
|
112
|
+
<path d="M16.1708 14.5077L16.7847 13.1391L18.7701 14.0297L17.2315 15.5684L16.1708 14.5077ZM13.3548 15.5007L12.294 14.4402L12.2941 14.44L13.3548 15.5007ZM16.5105 18.6564L17.5712 19.7171L17.5711 19.7172L16.5105 18.6564ZM17.5173 15.8708L16.4567 14.8102L18.0236 13.2433L18.8962 15.2802L17.5173 15.8708ZM16.7743 16.6138L15.2751 16.6613L15.2545 16.0123L15.7137 15.5532L16.7743 16.6138ZM15.7952 18.0405L16.8558 19.1011L16.8556 19.1013L15.7952 18.0405ZM13.957 17.6165L12.8963 18.6772L12.8959 18.6767L13.957 17.6165ZM13.957 16.2023L12.8961 15.1418L12.8963 15.1416L13.957 16.2023ZM15.452 15.2266L16.5126 16.2872L16.0102 16.7896L15.3032 16.7192L15.452 15.2266ZM16.1708 14.5077L15.5569 15.8763C15.3688 15.792 15.1469 15.8299 14.999 15.9779L13.9383 14.9172L12.8776 13.8565C13.9375 12.7967 15.5018 12.5636 16.7847 13.1391L16.1708 14.5077ZM13.9383 14.9172L14.999 15.9779L14.4155 16.5614L13.3548 15.5007L12.2941 14.44L12.8776 13.8565L13.9383 14.9172ZM13.3548 15.5007L14.4156 16.5612C14.2202 16.7567 14.2204 17.0734 14.4155 17.2685L13.3548 18.3291L12.2941 19.3898C10.9272 18.0229 10.9277 15.8069 12.294 14.4402L13.3548 15.5007ZM13.3548 18.3291L14.4155 17.2685L14.7428 17.5958L13.6821 18.6564L12.6215 19.7171L12.2941 19.3898L13.3548 18.3291ZM13.6821 18.6564L14.7428 17.5958C14.9378 17.7908 15.2546 17.791 15.45 17.5956L16.5105 18.6564L17.5711 19.7172C16.2044 21.0836 13.9884 21.084 12.6215 19.7171L13.6821 18.6564ZM16.5105 18.6564L15.4499 17.5958L16.0334 17.0123L17.094 18.0729L18.1547 19.1336L17.5712 19.7171L16.5105 18.6564ZM17.094 18.0729L16.0334 17.0123C16.1795 16.8662 16.2185 16.6481 16.1385 16.4615L17.5173 15.8708L18.8962 15.2802C19.4413 16.5526 19.1996 18.0887 18.1547 19.1336L17.094 18.0729ZM17.5173 15.8708L18.578 16.9315L17.835 17.6745L16.7743 16.6138L15.7137 15.5532L16.4567 14.8102L17.5173 15.8708ZM16.7743 16.6138L18.2736 16.5664C18.2945 17.226 18.0544 17.9026 17.5436 18.4134L16.4829 17.3527L15.4223 16.2921C15.3182 16.3961 15.2711 16.5346 15.2751 16.6613L16.7743 16.6138ZM16.4829 17.3527L17.5436 18.4134L16.8558 19.1011L15.7952 18.0405L14.7345 16.9798L15.4223 16.2921L16.4829 17.3527ZM15.7952 18.0405L16.8556 19.1013C15.8795 20.0771 14.2967 20.0776 13.3203 19.1011L14.3809 18.0405L15.4416 16.9798C15.2461 16.7844 14.9297 16.7847 14.7347 16.9797L15.7952 18.0405ZM14.3809 18.0405L13.3203 19.1011L12.8963 18.6772L13.957 17.6165L15.0176 16.5558L15.4416 16.9798L14.3809 18.0405ZM13.957 17.6165L12.8959 18.6767C11.9207 17.7008 11.92 16.1182 12.8961 15.1418L13.957 16.2023L15.0178 17.2628C15.2133 17.0672 15.2128 16.7512 15.018 16.5563L13.957 17.6165ZM13.957 16.2023L12.8963 15.1416L13.5841 14.4539L14.6447 15.5145L15.7054 16.5752L15.0176 17.2629L13.957 16.2023ZM14.6447 15.5145L13.5841 14.4539C14.1364 13.9015 14.8848 13.6626 15.6007 13.734L15.452 15.2266L15.3032 16.7192C15.443 16.7331 15.5943 16.6862 15.7054 16.5752L14.6447 15.5145ZM15.452 15.2266L14.3913 14.1659L15.1101 13.4471L16.1708 14.5077L17.2315 15.5684L16.5126 16.2872L15.452 15.2266Z" fill="#8E8E8F" mask="url(#path-5-outside-2_9822_43516)"/>
|
|
113
|
+
<path d="M20.6852 11.1208C19.9042 10.3398 18.6378 10.3398 17.8568 11.1208L17.2733 11.7043C16.6707 12.3069 16.5358 13.1973 16.8631 13.9319L17.5916 13.2034C17.5657 12.9181 17.6619 12.6236 17.8803 12.4052L18.5674 11.7181C18.9579 11.3276 19.5911 11.3276 19.9816 11.7181L20.4056 12.1421C20.7959 12.5326 20.796 13.1658 20.4056 13.5563L19.7185 14.2434C19.5128 14.449 19.2393 14.5457 18.9699 14.5348L18.2235 15.2812C18.9538 15.596 19.8325 15.4565 20.429 14.86L21.0125 14.2765C21.7935 13.4955 21.7936 12.2291 21.0125 11.4481L20.6852 11.1208Z" fill="white"/>
|
|
114
|
+
<rect width="2.59942" height="2.97264" rx="1" transform="matrix(-0.707107 -0.707107 -0.707107 0.707107 21.1133 12.8486)" fill="#8E8E8F"/>
|
|
115
|
+
<rect width="1.91578" height="4.24403" transform="matrix(-0.707107 -0.707107 -0.707107 0.707107 19.6992 13.8066)" fill="#8E8E8F"/>
|
|
116
|
+
<rect width="2.59942" height="2.97264" rx="1" transform="matrix(-0.707107 -0.707107 -0.707107 0.707107 17.3125 16.6455)" fill="#8E8E8F"/>
|
|
117
|
+
</g>
|
|
118
|
+
</svg>`;
|
|
119
|
+
/**
|
|
120
|
+
* 遍历割草任务,下述四个字段可以在路径中唯一确定遍历的位置(当前区域、当前块、当前行、在当前行上的路程)
|
|
121
|
+
*/
|
|
122
|
+
const ACTION_BLOCK_COVER = 5;
|
|
123
|
+
/**
|
|
124
|
+
* 遍历割草块转移任务(在同一区域中的一个块转移到下一个块),下述四个字段可以在路径中唯一确定转移的位置(当前区域、前置块、当前转移路径线序号、在当前线上的路程)
|
|
125
|
+
*/
|
|
126
|
+
const ACTION_BLOCK_TRANSFER = 6;
|
|
127
|
+
/**
|
|
128
|
+
* 边界割草任务(割草任务内部的巡边任务)
|
|
129
|
+
*/
|
|
130
|
+
const ACTION_BOUNDARY_TASK = 8;
|
|
131
|
+
const SVG_MAP_VIEW_ID = 'fleet-maps-svg-map-view';
|
|
132
|
+
|
|
4
133
|
/**
|
|
5
134
|
* SVG基础MapView
|
|
6
135
|
* 使用真正的矢量SVG渲染替代Canvas位图渲染
|
|
@@ -14,7 +143,6 @@ class SvgMapView {
|
|
|
14
143
|
this.lineScale = 1; // 线条缩放系数
|
|
15
144
|
// 状态标志
|
|
16
145
|
this.destroyed = false;
|
|
17
|
-
this.showScale = false;
|
|
18
146
|
// 渲染系统 - 移除节流以确保用户操作的实时响应
|
|
19
147
|
// 拖动功能
|
|
20
148
|
this.isDragging = false;
|
|
@@ -57,6 +185,7 @@ class SvgMapView {
|
|
|
57
185
|
this.svg.setAttribute('shape-rendering', 'geometricPrecision');
|
|
58
186
|
this.svg.setAttribute('text-rendering', 'geometricPrecision');
|
|
59
187
|
this.svg.setAttribute('image-rendering', 'optimizeQuality');
|
|
188
|
+
this.svg.setAttribute('id', SVG_MAP_VIEW_ID);
|
|
60
189
|
}
|
|
61
190
|
/**
|
|
62
191
|
* 创建SVG组元素
|
|
@@ -81,7 +210,6 @@ class SvgMapView {
|
|
|
81
210
|
this.layers.sort((a, b) => a.getLevel() - b.getLevel());
|
|
82
211
|
}
|
|
83
212
|
getLayer(type) {
|
|
84
|
-
console.log('getLayer----->', this.layers, type);
|
|
85
213
|
return this.layers.find((layer) => layer.getType() === type) || null;
|
|
86
214
|
}
|
|
87
215
|
/**
|
|
@@ -119,7 +247,7 @@ class SvgMapView {
|
|
|
119
247
|
* 设置自适应视图变换 - 让SVG刚好包裹住图形
|
|
120
248
|
*/
|
|
121
249
|
fitToView(bounds) {
|
|
122
|
-
const padding =
|
|
250
|
+
const padding = 20; // 添加一些边距以避免内容贴边
|
|
123
251
|
const boundWidth = bounds.maxX - bounds.minX;
|
|
124
252
|
const boundHeight = bounds.maxY - bounds.minY;
|
|
125
253
|
// 防止宽高为0的情况
|
|
@@ -142,8 +270,8 @@ class SvgMapView {
|
|
|
142
270
|
this.viewBox = {
|
|
143
271
|
x: bounds.minX - padding,
|
|
144
272
|
y: bounds.minY - padding,
|
|
145
|
-
width: boundWidth + padding,
|
|
146
|
-
height: boundHeight + padding,
|
|
273
|
+
width: boundWidth + padding * 2,
|
|
274
|
+
height: boundHeight + padding * 2,
|
|
147
275
|
};
|
|
148
276
|
// 根据宽高比选择合适的preserveAspectRatio设置
|
|
149
277
|
if (Math.abs(contentAspectRatio - containerAspectRatio) < 0.01) {
|
|
@@ -155,42 +283,6 @@ class SvgMapView {
|
|
|
155
283
|
this.svg.setAttribute('preserveAspectRatio', 'xMidYMid meet');
|
|
156
284
|
}
|
|
157
285
|
this.updateViewBox();
|
|
158
|
-
this.refresh();
|
|
159
|
-
}
|
|
160
|
-
/**
|
|
161
|
-
* 重置变换
|
|
162
|
-
*/
|
|
163
|
-
resetTransform() {
|
|
164
|
-
this.scale = 1;
|
|
165
|
-
// 重置viewBox到默认状态
|
|
166
|
-
const containerRect = this.container.getBoundingClientRect();
|
|
167
|
-
this.viewBox = {
|
|
168
|
-
x: 0,
|
|
169
|
-
y: 0,
|
|
170
|
-
width: containerRect.width,
|
|
171
|
-
height: containerRect.height,
|
|
172
|
-
};
|
|
173
|
-
this.updateViewBox();
|
|
174
|
-
this.refresh();
|
|
175
|
-
}
|
|
176
|
-
/**
|
|
177
|
-
* 设置缩放级别
|
|
178
|
-
*/
|
|
179
|
-
setZoom(zoomLevel) {
|
|
180
|
-
if (zoomLevel <= 0)
|
|
181
|
-
return;
|
|
182
|
-
const oldScale = this.scale;
|
|
183
|
-
this.scale = zoomLevel;
|
|
184
|
-
// 调整viewBox以实现缩放
|
|
185
|
-
const scaleFactor = oldScale / this.scale;
|
|
186
|
-
const centerX = this.viewBox.x + this.viewBox.width / 2;
|
|
187
|
-
const centerY = this.viewBox.y + this.viewBox.height / 2;
|
|
188
|
-
this.viewBox.width *= scaleFactor;
|
|
189
|
-
this.viewBox.height *= scaleFactor;
|
|
190
|
-
this.viewBox.x = centerX - this.viewBox.width / 2;
|
|
191
|
-
this.viewBox.y = centerY - this.viewBox.height / 2;
|
|
192
|
-
this.updateViewBox();
|
|
193
|
-
this.refresh();
|
|
194
286
|
}
|
|
195
287
|
/**
|
|
196
288
|
* 获取当前缩放级别
|
|
@@ -198,15 +290,6 @@ class SvgMapView {
|
|
|
198
290
|
getZoom() {
|
|
199
291
|
return this.scale;
|
|
200
292
|
}
|
|
201
|
-
/**
|
|
202
|
-
* 设置线条缩放系数
|
|
203
|
-
*/
|
|
204
|
-
setLineScale(lineScale) {
|
|
205
|
-
if (lineScale <= 0)
|
|
206
|
-
return;
|
|
207
|
-
this.lineScale = lineScale;
|
|
208
|
-
this.refresh();
|
|
209
|
-
}
|
|
210
293
|
/**
|
|
211
294
|
* 获取当前线条缩放系数
|
|
212
295
|
*/
|
|
@@ -310,7 +393,7 @@ class SvgMapView {
|
|
|
310
393
|
// const layerType = layerIdParts.slice(1, -1).join('-'); // 处理类型名中可能包含连字符的情况
|
|
311
394
|
// const layerLevel = parseInt(layerIdParts[layerIdParts.length - 1]);
|
|
312
395
|
// // 查找对应的图层对象
|
|
313
|
-
// const targetLayer = this.layers.find(layer =>
|
|
396
|
+
// const targetLayer = this.layers.find(layer =>
|
|
314
397
|
// layer.getType() === layerType && layer.getLevel() === layerLevel
|
|
315
398
|
// );
|
|
316
399
|
// if (targetLayer && targetLayer.isVisible()) {
|
|
@@ -347,12 +430,6 @@ class SvgMapView {
|
|
|
347
430
|
return;
|
|
348
431
|
this.render();
|
|
349
432
|
}
|
|
350
|
-
/**
|
|
351
|
-
* 重新初始化SVG(用于容器大小变化)
|
|
352
|
-
*/
|
|
353
|
-
reinitializeSVG() {
|
|
354
|
-
this.refresh();
|
|
355
|
-
}
|
|
356
433
|
// ==================== 拖拽功能 ====================
|
|
357
434
|
/**
|
|
358
435
|
* 设置拖拽事件处理器
|
|
@@ -477,22 +554,6 @@ class SvgMapView {
|
|
|
477
554
|
return null;
|
|
478
555
|
}
|
|
479
556
|
}
|
|
480
|
-
/**
|
|
481
|
-
* 自动适配viewBox到实际内容
|
|
482
|
-
*/
|
|
483
|
-
autoFitToContent() {
|
|
484
|
-
if (this.destroyed || this.layers.length === 0)
|
|
485
|
-
return;
|
|
486
|
-
const bounds = this.getLayersGroupBounds();
|
|
487
|
-
if (bounds) {
|
|
488
|
-
this.fitToView({
|
|
489
|
-
minX: bounds.x,
|
|
490
|
-
minY: bounds.y,
|
|
491
|
-
maxX: bounds.x + bounds.width,
|
|
492
|
-
maxY: bounds.y + bounds.height,
|
|
493
|
-
});
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
557
|
/**
|
|
497
558
|
* 获取ViewBox信息
|
|
498
559
|
*/
|
|
@@ -513,13 +574,6 @@ class SvgMapView {
|
|
|
513
574
|
* 诊断SVG尺寸信息
|
|
514
575
|
*/
|
|
515
576
|
diagnosticSizeInfo() { }
|
|
516
|
-
/**
|
|
517
|
-
* 设置是否显示比例尺
|
|
518
|
-
*/
|
|
519
|
-
setShowScale(show) {
|
|
520
|
-
this.showScale = show;
|
|
521
|
-
this.refresh();
|
|
522
|
-
}
|
|
523
577
|
/**
|
|
524
578
|
* 获取SVG元素
|
|
525
579
|
*/
|
|
@@ -721,8 +775,6 @@ const create = (createState) => createState ? createImpl(createState) : createIm
|
|
|
721
775
|
|
|
722
776
|
const useSubBoundaryBorderStore = create((set, get) => ({
|
|
723
777
|
subBoundaryBorder: {},
|
|
724
|
-
// 覆盖所有数据
|
|
725
|
-
setSubBoundaryBorder: (subBoundaryBorder) => set({ subBoundaryBorder }),
|
|
726
778
|
// 追加单个数据
|
|
727
779
|
addSubBoundaryBorder: (key, element) => set((state) => ({
|
|
728
780
|
subBoundaryBorder: {
|
|
@@ -730,134 +782,28 @@ const useSubBoundaryBorderStore = create((set, get) => ({
|
|
|
730
782
|
[key]: element,
|
|
731
783
|
},
|
|
732
784
|
})),
|
|
733
|
-
// 追加多个数据
|
|
734
|
-
addMultipleSubBoundaryBorders: (borders) => set((state) => ({
|
|
735
|
-
subBoundaryBorder: {
|
|
736
|
-
...state.subBoundaryBorder,
|
|
737
|
-
...borders,
|
|
738
|
-
},
|
|
739
|
-
})),
|
|
740
785
|
// 清空所有数据
|
|
741
786
|
clearSubBoundaryBorder: () => set({ subBoundaryBorder: {} }),
|
|
787
|
+
// 障碍物
|
|
788
|
+
obstacles: {},
|
|
789
|
+
addObstacles: (key, element) => set((state) => ({
|
|
790
|
+
obstacles: {
|
|
791
|
+
...state.obstacles,
|
|
792
|
+
[key]: element,
|
|
793
|
+
},
|
|
794
|
+
})),
|
|
795
|
+
clearObstacles: () => set({ obstacles: {} }),
|
|
796
|
+
// svg数据
|
|
797
|
+
svgElements: {},
|
|
798
|
+
addSvgElements: (key, element) => set((state) => ({
|
|
799
|
+
svgElements: {
|
|
800
|
+
...state.svgElements,
|
|
801
|
+
[key]: element,
|
|
802
|
+
},
|
|
803
|
+
})),
|
|
804
|
+
clearSvgElements: () => set({ svgElements: {} }),
|
|
742
805
|
}));
|
|
743
806
|
|
|
744
|
-
/**
|
|
745
|
-
* 地图渲染相关常量配置
|
|
746
|
-
*/
|
|
747
|
-
/**
|
|
748
|
-
* 缩放因子 - 将米转换为像素
|
|
749
|
-
* 与Python代码中的SVG比例一致
|
|
750
|
-
*/
|
|
751
|
-
const SCALE_FACTOR = 50; // 50像素/米
|
|
752
|
-
/**
|
|
753
|
-
* 默认线宽设置
|
|
754
|
-
*/
|
|
755
|
-
const DEFAULT_LINE_WIDTHS = {
|
|
756
|
-
OBSTACLE: 2,
|
|
757
|
-
CHARGING_PILE: 2,
|
|
758
|
-
CHANNEL: 2,
|
|
759
|
-
PATH: 20,
|
|
760
|
-
VISION_OFF_AREA: 2,
|
|
761
|
-
TIME_LIMIT_OBSTACLE: 1,
|
|
762
|
-
};
|
|
763
|
-
/**
|
|
764
|
-
* 默认透明度设置
|
|
765
|
-
*/
|
|
766
|
-
const DEFAULT_OPACITIES = {
|
|
767
|
-
FULL: 1.0,
|
|
768
|
-
HIGH: 0.7,
|
|
769
|
-
LOW: 0.4};
|
|
770
|
-
/**
|
|
771
|
-
* 默认半径设置
|
|
772
|
-
*/
|
|
773
|
-
const DEFAULT_RADII = {
|
|
774
|
-
CHARGING_PILE: 12};
|
|
775
|
-
/**
|
|
776
|
-
* 图层等级
|
|
777
|
-
*/
|
|
778
|
-
const LAYER_LEVELS = {
|
|
779
|
-
BOUNDARY: 2,
|
|
780
|
-
BOUNDARY_BORDER: 4};
|
|
781
|
-
/**
|
|
782
|
-
* 图层默认id
|
|
783
|
-
*/
|
|
784
|
-
const LAYER_DEFAULT_TYPE = {
|
|
785
|
-
CHANNEL: 'channel',
|
|
786
|
-
BOUNDARY: 'boundary',
|
|
787
|
-
PATH: 'path',
|
|
788
|
-
BOUNDARY_BORDER: 'boundary_border',
|
|
789
|
-
OBSTACLE: 'obstacle',
|
|
790
|
-
CHARGING_PILE: 'charging_pile',
|
|
791
|
-
POINT: 'point',
|
|
792
|
-
SVG: 'svg',
|
|
793
|
-
VISION_OFF_AREA: 'vision_off_area',
|
|
794
|
-
ANTENNA: 'antenna',
|
|
795
|
-
};
|
|
796
|
-
var RobotStatus;
|
|
797
|
-
(function (RobotStatus) {
|
|
798
|
-
RobotStatus[RobotStatus["PARKED"] = 1] = "PARKED";
|
|
799
|
-
RobotStatus[RobotStatus["CHARGING"] = 2] = "CHARGING";
|
|
800
|
-
RobotStatus[RobotStatus["STANDBY"] = 3] = "STANDBY";
|
|
801
|
-
RobotStatus[RobotStatus["MOWING"] = 4] = "MOWING";
|
|
802
|
-
RobotStatus[RobotStatus["WORKING"] = 5] = "WORKING";
|
|
803
|
-
RobotStatus[RobotStatus["MAPPING"] = 6] = "MAPPING";
|
|
804
|
-
RobotStatus[RobotStatus["ERROR"] = 7] = "ERROR";
|
|
805
|
-
RobotStatus[RobotStatus["UPGRADING"] = 8] = "UPGRADING";
|
|
806
|
-
RobotStatus[RobotStatus["DISCONNECTED"] = 9] = "DISCONNECTED";
|
|
807
|
-
RobotStatus[RobotStatus["UNKNOWN"] = -1] = "UNKNOWN";
|
|
808
|
-
RobotStatus[RobotStatus["TASK_DELAY"] = 10] = "TASK_DELAY";
|
|
809
|
-
// WAITING = 'Waiting',
|
|
810
|
-
})(RobotStatus || (RobotStatus = {}));
|
|
811
|
-
// RTK状态
|
|
812
|
-
var RTK_STATE;
|
|
813
|
-
(function (RTK_STATE) {
|
|
814
|
-
RTK_STATE[RTK_STATE["LOW_RTK"] = 1] = "LOW_RTK";
|
|
815
|
-
RTK_STATE[RTK_STATE["MIDDLE_RTK"] = 2] = "MIDDLE_RTK";
|
|
816
|
-
RTK_STATE[RTK_STATE["HIGH_RTK"] = 3] = "HIGH_RTK";
|
|
817
|
-
RTK_STATE[RTK_STATE["NO_POSTURE"] = 10] = "NO_POSTURE";
|
|
818
|
-
RTK_STATE[RTK_STATE["OUT_OF_RANGE"] = 11] = "OUT_OF_RANGE";
|
|
819
|
-
RTK_STATE[RTK_STATE["OFF_LINE"] = 19] = "OFF_LINE";
|
|
820
|
-
})(RTK_STATE || (RTK_STATE = {}));
|
|
821
|
-
var REAL_TIME_DATA_TYPE;
|
|
822
|
-
(function (REAL_TIME_DATA_TYPE) {
|
|
823
|
-
REAL_TIME_DATA_TYPE[REAL_TIME_DATA_TYPE["LOCATION"] = 1] = "LOCATION";
|
|
824
|
-
REAL_TIME_DATA_TYPE[REAL_TIME_DATA_TYPE["PROCESS"] = 2] = "PROCESS";
|
|
825
|
-
})(REAL_TIME_DATA_TYPE || (REAL_TIME_DATA_TYPE = {}));
|
|
826
|
-
const ISOLATED_BOUNDARY_SVG = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
827
|
-
<g opacity="0.6">
|
|
828
|
-
<rect width="24" height="24" rx="12" fill="#1E1E1F" fill-opacity="0.5"/>
|
|
829
|
-
<path d="M8.20573 12.4961C6.739 11.1707 4.85775 11.2284 3.60938 11.1707C6.17744 13.0156 6.05584 15.7887 5.67404 16.9446H14.327C13.837 13.1673 15.5321 10.1289 16.4408 9.08187C15.0342 9.46118 13.5794 10.8303 13.0278 11.4674C12.8102 8.94572 13.992 5.97489 14.61 4.80469C12.5235 5.92214 11.0501 8.26056 10.4938 9.56261C9.22803 7.5947 6.83894 7.17806 5.883 6.9432C8.20573 10.2373 8.00039 11.1707 8.20573 12.4961Z" fill="white"/>
|
|
830
|
-
<mask id="path-3-outside-1_9822_43516" maskUnits="userSpaceOnUse" x="13.2344" y="7.20545" width="12.0208" height="12.0208" fill="black">
|
|
831
|
-
<rect fill="white" x="13.2344" y="7.20545" width="12.0208" height="12.0208"/>
|
|
832
|
-
<path d="M20.6852 11.1208C19.9042 10.3398 18.6378 10.3398 17.8568 11.1208L17.2733 11.7043C16.6707 12.3069 16.5358 13.1973 16.8631 13.9319L17.5916 13.2034C17.5657 12.9181 17.6619 12.6236 17.8803 12.4052L18.5674 11.7181C18.9579 11.3276 19.5911 11.3276 19.9816 11.7181L20.4056 12.1421C20.7959 12.5326 20.796 13.1658 20.4056 13.5563L19.7185 14.2434C19.5128 14.449 19.2393 14.5457 18.9699 14.5348L18.2235 15.2812C18.9538 15.596 19.8325 15.4565 20.429 14.86L21.0125 14.2765C21.7935 13.4955 21.7936 12.2291 21.0125 11.4481L20.6852 11.1208Z"/>
|
|
833
|
-
</mask>
|
|
834
|
-
<path d="M20.6852 11.1208C19.9042 10.3398 18.6378 10.3398 17.8568 11.1208L17.2733 11.7043C16.6707 12.3069 16.5358 13.1973 16.8631 13.9319L17.5916 13.2034C17.5657 12.9181 17.6619 12.6236 17.8803 12.4052L18.5674 11.7181C18.9579 11.3276 19.5911 11.3276 19.9816 11.7181L20.4056 12.1421C20.7959 12.5326 20.796 13.1658 20.4056 13.5563L19.7185 14.2434C19.5128 14.449 19.2393 14.5457 18.9699 14.5348L18.2235 15.2812C18.9538 15.596 19.8325 15.4565 20.429 14.86L21.0125 14.2765C21.7935 13.4955 21.7936 12.2291 21.0125 11.4481L20.6852 11.1208Z" fill="white"/>
|
|
835
|
-
<path d="M20.6852 11.1208L21.7458 10.0601L21.7459 10.0601L20.6852 11.1208ZM17.8568 11.1208L16.7961 10.0601L16.7962 10.0601L17.8568 11.1208ZM17.2733 11.7043L16.2126 10.6437L16.2126 10.6436L17.2733 11.7043ZM16.8631 13.9319L17.9238 14.9926L16.381 16.5354L15.493 14.5425L16.8631 13.9319ZM17.5916 13.2034L19.0855 13.0678L19.149 13.7674L18.6523 14.2641L17.5916 13.2034ZM20.4056 12.1421L21.4662 11.0814L21.4665 11.0817L20.4056 12.1421ZM18.9699 14.5348L17.9093 13.4741L18.3741 13.0093L19.0309 13.036L18.9699 14.5348ZM18.2235 15.2812L17.6298 16.6587L15.5997 15.7837L17.1628 14.2206L18.2235 15.2812ZM20.429 14.86L21.4897 15.9207L21.4897 15.9207L20.429 14.86ZM21.0125 14.2765L22.0732 15.3371L22.0732 15.3372L21.0125 14.2765ZM20.6852 11.1208L19.6246 12.1815C19.4294 11.9862 19.1127 11.9863 18.9174 12.1815L17.8568 11.1208L16.7962 10.0601C18.163 8.69337 20.379 8.6934 21.7458 10.0601L20.6852 11.1208ZM17.8568 11.1208L18.9175 12.1814L18.334 12.7649L17.2733 11.7043L16.2126 10.6436L16.7961 10.0601L17.8568 11.1208ZM17.2733 11.7043L18.334 12.7649C18.1877 12.9112 18.1488 13.1318 18.2333 13.3214L16.8631 13.9319L15.493 14.5425C14.9228 13.2629 15.1537 11.7026 16.2126 10.6437L17.2733 11.7043ZM16.8631 13.9319L15.8025 12.8713L16.531 12.1428L17.5916 13.2034L18.6523 14.2641L17.9238 14.9926L16.8631 13.9319ZM17.5916 13.2034L16.0978 13.339C16.0334 12.6302 16.2727 11.8914 16.8196 11.3445L17.8803 12.4052L18.9409 13.4658C19.051 13.3558 19.098 13.206 19.0855 13.0678L17.5916 13.2034ZM17.8803 12.4052L16.8196 11.3445L17.5067 10.6574L18.5674 11.7181L19.628 12.7788L18.9409 13.4658L17.8803 12.4052ZM18.5674 11.7181L17.5067 10.6574C18.483 9.68112 20.0659 9.68112 21.0422 10.6574L19.9816 11.7181L18.9209 12.7788C19.1162 12.974 19.4328 12.974 19.628 12.7788L18.5674 11.7181ZM19.9816 11.7181L21.0422 10.6574L21.4662 11.0814L20.4056 12.1421L19.3449 13.2027L18.9209 12.7788L19.9816 11.7181ZM20.4056 12.1421L21.4665 11.0817C22.4419 12.0577 22.4428 13.6404 21.4662 14.617L20.4056 13.5563L19.3449 12.4956C19.1493 12.6913 19.1498 13.0076 19.3446 13.2024L20.4056 12.1421ZM20.4056 13.5563L21.4662 14.617L20.7791 15.304L19.7185 14.2434L18.6578 13.1827L19.3449 12.4956L20.4056 13.5563ZM19.7185 14.2434L20.7791 15.304C20.2628 15.8204 19.5762 16.0607 18.909 16.0335L18.9699 14.5348L19.0309 13.036C18.9025 13.0308 18.7629 13.0777 18.6578 13.1827L19.7185 14.2434ZM18.9699 14.5348L20.0306 15.5954L19.2841 16.3419L18.2235 15.2812L17.1628 14.2206L17.9093 13.4741L18.9699 14.5348ZM18.2235 15.2812L18.8172 13.9037C19.0042 13.9843 19.2223 13.9455 19.3684 13.7993L20.429 14.86L21.4897 15.9207C20.4427 16.9676 18.9034 17.2077 17.6298 16.6587L18.2235 15.2812ZM20.429 14.86L19.3684 13.7994L19.9519 13.2159L21.0125 14.2765L22.0732 15.3372L21.4897 15.9207L20.429 14.86ZM21.0125 14.2765L19.9518 13.2159C20.1471 13.0206 20.1471 12.704 19.9519 12.5088L21.0125 11.4481L22.0732 10.3874C23.4401 11.7543 23.4399 13.9703 22.0732 15.3371L21.0125 14.2765ZM21.0125 11.4481L19.9519 12.5088L19.6246 12.1814L20.6852 11.1208L21.7459 10.0601L22.0732 10.3874L21.0125 11.4481Z" fill="#8E8E8F" mask="url(#path-3-outside-1_9822_43516)"/>
|
|
836
|
-
<mask id="path-5-outside-2_9822_43516" maskUnits="userSpaceOnUse" x="9.22265" y="10.388" width="12.7279" height="12.7279" fill="black">
|
|
837
|
-
<rect fill="white" x="9.22265" y="10.388" width="12.7279" height="12.7279"/>
|
|
838
|
-
<path d="M16.1708 14.5077C15.4353 14.1778 14.5422 14.3133 13.9383 14.9172L13.3548 15.5007C12.574 16.2818 12.5738 17.5481 13.3548 18.3291L13.6821 18.6564C14.4631 19.4374 15.7295 19.4373 16.5105 18.6564L17.094 18.0729C17.6895 17.4775 17.8299 16.6003 17.5173 15.8708L16.7743 16.6138C16.7828 16.8803 16.6863 17.1494 16.4829 17.3527L15.7952 18.0405C15.4046 18.4309 14.7714 18.431 14.3809 18.0405L13.957 17.6165C13.5667 17.226 13.5666 16.5927 13.957 16.2023L14.6447 15.5145C14.8654 15.2939 15.1639 15.1979 15.452 15.2266L16.1708 14.5077Z"/>
|
|
839
|
-
</mask>
|
|
840
|
-
<path d="M16.1708 14.5077C15.4353 14.1778 14.5422 14.3133 13.9383 14.9172L13.3548 15.5007C12.574 16.2818 12.5738 17.5481 13.3548 18.3291L13.6821 18.6564C14.4631 19.4374 15.7295 19.4373 16.5105 18.6564L17.094 18.0729C17.6895 17.4775 17.8299 16.6003 17.5173 15.8708L16.7743 16.6138C16.7828 16.8803 16.6863 17.1494 16.4829 17.3527L15.7952 18.0405C15.4046 18.4309 14.7714 18.431 14.3809 18.0405L13.957 17.6165C13.5667 17.226 13.5666 16.5927 13.957 16.2023L14.6447 15.5145C14.8654 15.2939 15.1639 15.1979 15.452 15.2266L16.1708 14.5077Z" fill="white"/>
|
|
841
|
-
<path d="M16.1708 14.5077L16.7847 13.1391L18.7701 14.0297L17.2315 15.5684L16.1708 14.5077ZM13.3548 15.5007L12.294 14.4402L12.2941 14.44L13.3548 15.5007ZM16.5105 18.6564L17.5712 19.7171L17.5711 19.7172L16.5105 18.6564ZM17.5173 15.8708L16.4567 14.8102L18.0236 13.2433L18.8962 15.2802L17.5173 15.8708ZM16.7743 16.6138L15.2751 16.6613L15.2545 16.0123L15.7137 15.5532L16.7743 16.6138ZM15.7952 18.0405L16.8558 19.1011L16.8556 19.1013L15.7952 18.0405ZM13.957 17.6165L12.8963 18.6772L12.8959 18.6767L13.957 17.6165ZM13.957 16.2023L12.8961 15.1418L12.8963 15.1416L13.957 16.2023ZM15.452 15.2266L16.5126 16.2872L16.0102 16.7896L15.3032 16.7192L15.452 15.2266ZM16.1708 14.5077L15.5569 15.8763C15.3688 15.792 15.1469 15.8299 14.999 15.9779L13.9383 14.9172L12.8776 13.8565C13.9375 12.7967 15.5018 12.5636 16.7847 13.1391L16.1708 14.5077ZM13.9383 14.9172L14.999 15.9779L14.4155 16.5614L13.3548 15.5007L12.2941 14.44L12.8776 13.8565L13.9383 14.9172ZM13.3548 15.5007L14.4156 16.5612C14.2202 16.7567 14.2204 17.0734 14.4155 17.2685L13.3548 18.3291L12.2941 19.3898C10.9272 18.0229 10.9277 15.8069 12.294 14.4402L13.3548 15.5007ZM13.3548 18.3291L14.4155 17.2685L14.7428 17.5958L13.6821 18.6564L12.6215 19.7171L12.2941 19.3898L13.3548 18.3291ZM13.6821 18.6564L14.7428 17.5958C14.9378 17.7908 15.2546 17.791 15.45 17.5956L16.5105 18.6564L17.5711 19.7172C16.2044 21.0836 13.9884 21.084 12.6215 19.7171L13.6821 18.6564ZM16.5105 18.6564L15.4499 17.5958L16.0334 17.0123L17.094 18.0729L18.1547 19.1336L17.5712 19.7171L16.5105 18.6564ZM17.094 18.0729L16.0334 17.0123C16.1795 16.8662 16.2185 16.6481 16.1385 16.4615L17.5173 15.8708L18.8962 15.2802C19.4413 16.5526 19.1996 18.0887 18.1547 19.1336L17.094 18.0729ZM17.5173 15.8708L18.578 16.9315L17.835 17.6745L16.7743 16.6138L15.7137 15.5532L16.4567 14.8102L17.5173 15.8708ZM16.7743 16.6138L18.2736 16.5664C18.2945 17.226 18.0544 17.9026 17.5436 18.4134L16.4829 17.3527L15.4223 16.2921C15.3182 16.3961 15.2711 16.5346 15.2751 16.6613L16.7743 16.6138ZM16.4829 17.3527L17.5436 18.4134L16.8558 19.1011L15.7952 18.0405L14.7345 16.9798L15.4223 16.2921L16.4829 17.3527ZM15.7952 18.0405L16.8556 19.1013C15.8795 20.0771 14.2967 20.0776 13.3203 19.1011L14.3809 18.0405L15.4416 16.9798C15.2461 16.7844 14.9297 16.7847 14.7347 16.9797L15.7952 18.0405ZM14.3809 18.0405L13.3203 19.1011L12.8963 18.6772L13.957 17.6165L15.0176 16.5558L15.4416 16.9798L14.3809 18.0405ZM13.957 17.6165L12.8959 18.6767C11.9207 17.7008 11.92 16.1182 12.8961 15.1418L13.957 16.2023L15.0178 17.2628C15.2133 17.0672 15.2128 16.7512 15.018 16.5563L13.957 17.6165ZM13.957 16.2023L12.8963 15.1416L13.5841 14.4539L14.6447 15.5145L15.7054 16.5752L15.0176 17.2629L13.957 16.2023ZM14.6447 15.5145L13.5841 14.4539C14.1364 13.9015 14.8848 13.6626 15.6007 13.734L15.452 15.2266L15.3032 16.7192C15.443 16.7331 15.5943 16.6862 15.7054 16.5752L14.6447 15.5145ZM15.452 15.2266L14.3913 14.1659L15.1101 13.4471L16.1708 14.5077L17.2315 15.5684L16.5126 16.2872L15.452 15.2266Z" fill="#8E8E8F" mask="url(#path-5-outside-2_9822_43516)"/>
|
|
842
|
-
<path d="M20.6852 11.1208C19.9042 10.3398 18.6378 10.3398 17.8568 11.1208L17.2733 11.7043C16.6707 12.3069 16.5358 13.1973 16.8631 13.9319L17.5916 13.2034C17.5657 12.9181 17.6619 12.6236 17.8803 12.4052L18.5674 11.7181C18.9579 11.3276 19.5911 11.3276 19.9816 11.7181L20.4056 12.1421C20.7959 12.5326 20.796 13.1658 20.4056 13.5563L19.7185 14.2434C19.5128 14.449 19.2393 14.5457 18.9699 14.5348L18.2235 15.2812C18.9538 15.596 19.8325 15.4565 20.429 14.86L21.0125 14.2765C21.7935 13.4955 21.7936 12.2291 21.0125 11.4481L20.6852 11.1208Z" fill="white"/>
|
|
843
|
-
<rect width="2.59942" height="2.97264" rx="1" transform="matrix(-0.707107 -0.707107 -0.707107 0.707107 21.1133 12.8486)" fill="#8E8E8F"/>
|
|
844
|
-
<rect width="1.91578" height="4.24403" transform="matrix(-0.707107 -0.707107 -0.707107 0.707107 19.6992 13.8066)" fill="#8E8E8F"/>
|
|
845
|
-
<rect width="2.59942" height="2.97264" rx="1" transform="matrix(-0.707107 -0.707107 -0.707107 0.707107 17.3125 16.6455)" fill="#8E8E8F"/>
|
|
846
|
-
</g>
|
|
847
|
-
</svg>`;
|
|
848
|
-
/**
|
|
849
|
-
* 遍历割草任务,下述四个字段可以在路径中唯一确定遍历的位置(当前区域、当前块、当前行、在当前行上的路程)
|
|
850
|
-
*/
|
|
851
|
-
const ACTION_BLOCK_COVER = 5;
|
|
852
|
-
/**
|
|
853
|
-
* 遍历割草块转移任务(在同一区域中的一个块转移到下一个块),下述四个字段可以在路径中唯一确定转移的位置(当前区域、前置块、当前转移路径线序号、在当前线上的路程)
|
|
854
|
-
*/
|
|
855
|
-
const ACTION_BLOCK_TRANSFER = 6;
|
|
856
|
-
/**
|
|
857
|
-
* 边界割草任务(割草任务内部的巡边任务)
|
|
858
|
-
*/
|
|
859
|
-
const ACTION_BOUNDARY_TASK = 8;
|
|
860
|
-
|
|
861
807
|
/**
|
|
862
808
|
* 路径图层
|
|
863
809
|
* 专门处理路径元素的渲染
|
|
@@ -908,51 +854,90 @@ class ChannelLayer extends BaseLayer {
|
|
|
908
854
|
}
|
|
909
855
|
// �� 修改:计算包含所有分区和通道的边界框
|
|
910
856
|
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
911
|
-
// 1.
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
857
|
+
// 1. 先计算所有分区的边界,如果能拿到边界的svg的大小,就使用这个如果拿不到,就根据分区去计算
|
|
858
|
+
const svg = document.getElementById(SVG_MAP_VIEW_ID);
|
|
859
|
+
if (svg && svg instanceof SVGSVGElement && svg.viewBox) {
|
|
860
|
+
const viewBox = svg.viewBox.baseVal;
|
|
861
|
+
minX = viewBox.x;
|
|
862
|
+
minY = viewBox.y;
|
|
863
|
+
maxX = viewBox.x + viewBox.width;
|
|
864
|
+
maxY = viewBox.y + viewBox.height;
|
|
865
|
+
}
|
|
866
|
+
else {
|
|
867
|
+
for (const partitionId in subBoundaryBorder) {
|
|
868
|
+
const boundaryData = subBoundaryBorder[partitionId];
|
|
869
|
+
if (boundaryData && boundaryData.coordinates && boundaryData.coordinates.length > 0) {
|
|
870
|
+
for (const coord of boundaryData.coordinates) {
|
|
871
|
+
minX = Math.min(minX, coord[0]);
|
|
872
|
+
minY = Math.min(minY, coord[1]);
|
|
873
|
+
maxX = Math.max(maxX, coord[0]);
|
|
874
|
+
maxY = Math.max(maxY, coord[1]);
|
|
875
|
+
}
|
|
920
876
|
}
|
|
921
877
|
}
|
|
922
878
|
}
|
|
923
879
|
// 2. 再计算所有通道的边界
|
|
924
880
|
for (const element of this.elements) {
|
|
925
|
-
const tunnelConnection = element.originalData?.connection;
|
|
926
|
-
if (tunnelConnection && Array.isArray(tunnelConnection)) {
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
881
|
+
// const tunnelConnection = element.originalData?.connection;
|
|
882
|
+
// if (tunnelConnection && Array.isArray(tunnelConnection)) {
|
|
883
|
+
// const clipPathId = `channel-exclude-${
|
|
884
|
+
// element.originalData?.id || Math.random().toString(36).substr(2, 9)
|
|
885
|
+
// }`;
|
|
886
|
+
// // 检查是否已存在该 clipPath
|
|
887
|
+
// const existingClipPath = defs.querySelector(`#${clipPathId}`);
|
|
888
|
+
// if (existingClipPath) continue;
|
|
889
|
+
// // 创建 clipPath
|
|
890
|
+
// const clipPath = document.createElementNS('http://www.w3.org/2000/svg', 'clipPath');
|
|
891
|
+
// clipPath.setAttribute('id', clipPathId);
|
|
892
|
+
// clipPath.setAttribute('clipPathUnits', 'userSpaceOnUse');
|
|
893
|
+
// // === 合成一个 path ===
|
|
894
|
+
// let d = `M ${minX} ${minY} L ${maxX} ${minY} L ${maxX} ${maxY} L ${minX} ${maxY} Z`;
|
|
895
|
+
// for (const partitionId of tunnelConnection) {
|
|
896
|
+
// const boundaryData = subBoundaryBorder[partitionId];
|
|
897
|
+
// if (boundaryData && boundaryData.coordinates.length >= 3) {
|
|
898
|
+
// d += ` M ${boundaryData.coordinates[0][0]} ${boundaryData.coordinates[0][1]}`;
|
|
899
|
+
// for (let i = 1; i < boundaryData.coordinates.length; i++) {
|
|
900
|
+
// d += ` L ${boundaryData.coordinates[i][0]} ${boundaryData.coordinates[i][1]}`;
|
|
901
|
+
// }
|
|
902
|
+
// d += ' Z';
|
|
903
|
+
// }
|
|
904
|
+
// }
|
|
905
|
+
// const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
|
|
906
|
+
// path.setAttribute('d', d);
|
|
907
|
+
// path.setAttribute('clip-rule', 'evenodd'); // 关键
|
|
908
|
+
// clipPath.appendChild(path);
|
|
909
|
+
// defs.appendChild(clipPath);
|
|
910
|
+
// clipPathIdsMap[element.originalData?.id.toString()] = clipPathId;
|
|
911
|
+
// } else {
|
|
912
|
+
const clipPathId = `channel-exclude-all-${element.originalData?.id || Math.random().toString(36).substr(2, 9)}`;
|
|
913
|
+
// 检查是否已存在该 clipPath
|
|
914
|
+
const existingClipPath = defs.querySelector(`#${clipPathId}`);
|
|
915
|
+
if (existingClipPath)
|
|
916
|
+
continue;
|
|
917
|
+
// 创建 clipPath
|
|
918
|
+
const clipPath = document.createElementNS('http://www.w3.org/2000/svg', 'clipPath');
|
|
919
|
+
clipPath.setAttribute('id', clipPathId);
|
|
920
|
+
clipPath.setAttribute('clipPathUnits', 'userSpaceOnUse');
|
|
921
|
+
// === 合成一个 path ===
|
|
922
|
+
let d = `M ${minX} ${minY} L ${maxX} ${minY} L ${maxX} ${maxY} L ${minX} ${maxY} Z`;
|
|
923
|
+
for (const partitionId in subBoundaryBorder) {
|
|
924
|
+
const boundaryData = subBoundaryBorder[partitionId];
|
|
925
|
+
if (boundaryData && boundaryData.coordinates.length >= 3) {
|
|
926
|
+
d += ` M ${boundaryData.coordinates[0][0]} ${boundaryData.coordinates[0][1]}`;
|
|
927
|
+
for (let i = 1; i < boundaryData.coordinates.length; i++) {
|
|
928
|
+
d += ` L ${boundaryData.coordinates[i][0]} ${boundaryData.coordinates[i][1]}`;
|
|
946
929
|
}
|
|
930
|
+
d += ' Z';
|
|
947
931
|
}
|
|
948
|
-
const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
|
|
949
|
-
path.setAttribute('d', d);
|
|
950
|
-
path.setAttribute('clip-rule', 'evenodd'); // 关键
|
|
951
|
-
clipPath.appendChild(path);
|
|
952
|
-
defs.appendChild(clipPath);
|
|
953
|
-
clipPathIdsMap[element.originalData?.id.toString()] = clipPathId;
|
|
954
932
|
}
|
|
933
|
+
const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
|
|
934
|
+
path.setAttribute('d', d);
|
|
935
|
+
path.setAttribute('clip-rule', 'evenodd'); // 关键
|
|
936
|
+
clipPath.appendChild(path);
|
|
937
|
+
defs.appendChild(clipPath);
|
|
938
|
+
clipPathIdsMap[element.originalData?.id.toString()] = clipPathId;
|
|
955
939
|
}
|
|
940
|
+
// }
|
|
956
941
|
return clipPathIdsMap;
|
|
957
942
|
}
|
|
958
943
|
/**
|
|
@@ -1023,7 +1008,7 @@ class PathLayer extends BaseLayer {
|
|
|
1023
1008
|
* 创建所有分区并集的 clipPath
|
|
1024
1009
|
*/
|
|
1025
1010
|
createUnionClipPath(svgGroup) {
|
|
1026
|
-
const { subBoundaryBorder } = useSubBoundaryBorderStore.getState();
|
|
1011
|
+
const { subBoundaryBorder, obstacles, svgElements } = useSubBoundaryBorderStore.getState();
|
|
1027
1012
|
// 确保 defs 元素存在
|
|
1028
1013
|
let defs = svgGroup.querySelector('defs');
|
|
1029
1014
|
if (!defs) {
|
|
@@ -1037,7 +1022,7 @@ class PathLayer extends BaseLayer {
|
|
|
1037
1022
|
defs.removeChild(existing);
|
|
1038
1023
|
// 合成所有分区的 path
|
|
1039
1024
|
let d = '';
|
|
1040
|
-
//
|
|
1025
|
+
// 1. 外圈(主边界,顺时针)
|
|
1041
1026
|
Object.values(subBoundaryBorder).forEach((item) => {
|
|
1042
1027
|
const bCoords = item.coordinates;
|
|
1043
1028
|
if (bCoords.length >= 3) {
|
|
@@ -1048,6 +1033,26 @@ class PathLayer extends BaseLayer {
|
|
|
1048
1033
|
d += ' Z ';
|
|
1049
1034
|
}
|
|
1050
1035
|
});
|
|
1036
|
+
// 2. 内圈(禁区,逆时针)
|
|
1037
|
+
Object.values(obstacles).forEach((item) => {
|
|
1038
|
+
const bCoords = item.coordinates;
|
|
1039
|
+
if (bCoords.length >= 3) {
|
|
1040
|
+
d += `M ${bCoords[bCoords.length - 1][0]} ${bCoords[bCoords.length - 1][1]}`;
|
|
1041
|
+
for (let i = bCoords.length - 2; i >= 0; i--) {
|
|
1042
|
+
d += ` L ${bCoords[i][0]} ${bCoords[i][1]}`;
|
|
1043
|
+
}
|
|
1044
|
+
d += ' Z ';
|
|
1045
|
+
}
|
|
1046
|
+
});
|
|
1047
|
+
// 3. svgElements(直接拼接path字符串,建议逆时针)
|
|
1048
|
+
if (Array.isArray(svgElements)) {
|
|
1049
|
+
svgElements.forEach((svgPath) => {
|
|
1050
|
+
const svgPathString = svgPath?.metadata?.svg;
|
|
1051
|
+
if (svgPathString && typeof svgPathString === 'string' && svgPathString.trim()) {
|
|
1052
|
+
d += svgPathString + ' ';
|
|
1053
|
+
}
|
|
1054
|
+
});
|
|
1055
|
+
}
|
|
1051
1056
|
const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
|
|
1052
1057
|
path.setAttribute('d', d);
|
|
1053
1058
|
const clipPath = document.createElementNS('http://www.w3.org/2000/svg', 'clipPath');
|
|
@@ -1072,7 +1077,7 @@ class PathLayer extends BaseLayer {
|
|
|
1072
1077
|
// 2. 创建一个组,应用 clipPath
|
|
1073
1078
|
const group = document.createElementNS('http://www.w3.org/2000/svg', 'g');
|
|
1074
1079
|
group.setAttribute('clip-path', `url(#${clipPathId})`);
|
|
1075
|
-
group.setAttribute('opacity', '0.
|
|
1080
|
+
group.setAttribute('opacity', '0.6'); // 统一透明度,防止叠加脏乱
|
|
1076
1081
|
// 3. 渲染所有路径
|
|
1077
1082
|
for (const element of this.elements) {
|
|
1078
1083
|
const { id, elements } = element;
|
|
@@ -1220,7 +1225,7 @@ class ObstacleLayer extends BaseLayer {
|
|
|
1220
1225
|
}
|
|
1221
1226
|
}
|
|
1222
1227
|
|
|
1223
|
-
var chargingPileImage = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGYAAABqCAYAAABOHSQZAAAACXBIWXMAACxLAAAsSwGlPZapAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAADRRSURBVHgB7X1pkF3HdV533+W9N9ubGWBmCHCwcEiBImBSBsF9EWBJlMmSIm/FilWJk3+y47J/+Icdu8oxQUflchanKhVX+YeTSiKp7ISU5FiSJZKiTFIiZZIyCqQgQBRIgdiIZQbALG/ect+93Z1zer93BuAQAiG6ig28ufdt9/Xtr893vnO6b19C3i/vl/fL++X98n55v7xf3utFSkkv8RoNnlPyT7Qw8h4v2MD42Lt3L7PPq6/j49FHH7XPcas+i/v4nv2s/XwVtCqo74XyXuxR2IDuCTb4I488ovYff/xxVd+HH36YPPvss67uc3v2qC9MmNcODw/TsSO7xMSEfj43NyerPwLHwNdWvE4p/rwGCvfJT6m8J4DBhggbhJh6IRAIwuOw/zA8/uzPvjqW0+Xd8OYWKeSHBJFboem2gC00iSCjpYMyskCEPA6HWmCUHCWUHWOMPRcNDb46TDYubtvWkhYwBAk6AIEOUAIiAAbrc1VB+qkAYyzC/TZaBW7RMrRVPEwmJgjdt++vR3Ma7ZY83w3f+BSRYgt+Fb+P/4jaqgPq46pnFP5Jf3hKCbVbuy/J96OIvUJI9JW7bv/03xLyrPronj17BP7+oUOHpKmPtB3malvPVQem4rgp9tTt27cbMJ6lw0BDz3z7x7tzkf82WMWHhZCjAAiBrW54s1XgWEAC6sP39A9Q+1/tU6oswAOkHowwRhfgxa9GTH7ugZ/b8Vyr1ZIAkASA1DfBmoSrLNV94GqAdFWAqVKVtRAEZGJiQoHxve8dH1vodH9LcIGAjAoBRGUBkcIBUdrHYwvtKpzlUM86lGgA1L4BhQVbBIYys89wH+iOks9+YOttn5uf6cptLU93hw49bKxIH9wc910D6F0HJgQDqQEMhO7e/axSTYcPD9OlpePgNzoAhgBQDCDwEAoU/bBAhPuaynBXUL2DvVjQ6qlB44MJSWpBQiCctZjn4HtgXwGjtmBFx+Azn982M/DvZ2ZmZEsBhALjcYI0Z33Ru2k57xowgZUgCIr0kb8nJh4GC9lHG40G/crfvfILXIr/JATfInkZDAeKAgk3nBpQpLEco96kcTGW1oKTogYYoupiAZF6N5LaYJgGBgFjkQKLRZF97VgUJZ/9xU/c+rlut2sAmpNIb9jBAuu54gC9K8AYUFTPRksJKQsBeeKZA1t77fwvuRAfloITjqDAtgoK0JjUwAAogI5QmAjqac0KgKBdVBdQWAT+X/sYQqvWoreMGWsJHhGCFOF+hPtfiVL6uzdsuu3ozIwGCIXCo3DIR8i7A86VBqYUgxBlJYRap/7d2VnWPnThtzjnf8gLMYpgcASEayDgdQMIN6BIBYqlML1VRoPOhRoRoPx9CI7VZFaNmTOVTDkGJhEH6oABC4I3lOVEq4Ki9mG7GEXRZ2+95d7/Njm5KJT1gEg4BD/3iPlZwxDOr/1EDUmuUFktFkFQZmb2MbSSb37zjbFOtvSHBee/pQAxIOittxq1lVw5dWHoTVuNNKBYixFOLht/Y2uyomqGx5xc9rSm6SyyNOYsBgCJPEAACOzHdv/P77/rut+dm5sUaD1HIJA9dOhRaYJgaZhC/qTgXBFgTC+x1lKyEgTla988eF3e7T0G1nGLB8I/xCXozINSVWdBHFPxM8QbjdrqNlLUpkCiTpVZyaycDVgS2A2ABQDQyFpMVH3ECNix5uDwz2/btvPoiROL4jOf2YXxzxUVBj8xMKvkmSimSxCU2dkmO3Toe9d18/wJAGCLBqLwYBRgG6KgHhQDDEcWQwpT9LXCr3inr5nDAeICTc9gtppEs5eTuUBjqi8xCxSzADFpLIXqbRmU2OyzKD423Bx48KGPfPpIt7tP7tu3j4yNfcZajwPlcgH6iYCxFovtgSpl+/bHnZNvNpvsb5949brO8vKTvOCbFSDWUgpjKfBawYVSXEKBJT04IYXBG0KDYQDC3xRlUFwsY0/MeR1JieMwYo0HfQoWph2Ocf6UGF8jjbUgOMqCFCBxrC0G9mPcxgjO4IO7fmbDUVBrkJubUMEoCgNbKWOt7xicnwQYlclFXWJyjMpSJicn2eLiYvTS/uNbW4vdb1hLKQpscACiKDyF4euB8xc8oDJHW0L5myB+UUGL0GZDq6pMy2XprMZE6rqCzqYr/gbBIYbKQnUWGV9jfEwUG6txWwXS8cGhxoN3/Oz9b05OdsTzz3fl2NgRYWntcrMFlwXMSjn8CJ2f38egQnR6ejp66SUApdtF+tpsgfCAFN5qtAWBQQgqLEA6llH+Ey1FOitxPsbGltRsbZ3CGpJy3lHt6ygTey81tFYJOpnLBFhgQj+jrEXGSHGxBiU2FgTWc3xsuPng6OjUm3fcMSlmZ2eFiXfC5Og7EgQxucyCDQEOj0GMQlB5QWXY8vI0e/XV8+Otbm8FKAUCElgL+BWJIIGVUGslCJTU1EWNxVDn5KXLkWlNSkIwrPPX+xcpLpdJgjSN2hPoaxgVlCtABIIiGAprsJSwU6CviwJf59za5oX20v+J48ZDBw/W5nfsmMSsBubbRFAhakTSmiwnIu+wYMOglQCPYhYW5PCMAWUUSDuLjp8+88fQ4B/ToGjqQhrjFhwHTEEdKFK/JsM0jAr39UNZUcnxkyDq92KAGOjs+6UH8VkCqT0WDbLS1OXeXGuXRIY9+8pfG8mqMtXvdwZuuH7m6RMnWqBGhyRkyMng4CD54he/iH7nHdHZO6IyWckMgxKJjhxpgMOfZeDw2ZPf+uFv9/vZn2oryREQCVuKWwRCAxVKZEtjPj+mA0ndIPi6axjj2V3jOddOypF/2HiO0aRLb/qz9kLAGZGls1AMMO1jDKVJFATG8TsqS5LEUFtCamnt9++6bdOfcz5TLC/3pY51johwYG4tAK2ZysJkJKZYDh2agO0kgDLATvT70fwLb1yX5/0/cNRVKHCooTPKKz5GR/1ADdwmKn1qXzt8BY3vrSYJZp/jZnCwQe6+cyf5/g9eI2fPniN+RIaUwXHfNW8i3tQeB0ERmOdUgHDtguA51oERGemOwZiUnlrLncE0NDVy7w9ee23+7z74wc6b7fYFTsgwx/wgCYOsNYzvvCMfY9P1KIk/+clheuDALKvXh9n6uBkdab31FxDVN3XDl9WXpbXA4aNvAULx1qIsxViMPXEPggPHSeTJiXXkT//k98jU5Hr11n/5r/+DPP2tF3zuzIgTn5Cxx6MONSPrNL1pyyJOFIClSJXowToxk9EI6M15NW0EuFXfzUlzbuHCX3yAdz+xbt0w5tXw/QKD7ocf1l9YiwhYk4+x1oJ+BdQGveaaaxgGj/W6jIaHG+zl/Qd+rcjzf+MthXtwSg6/kNwqMASFryKLycqo3jai5XN8/4GP3kt233+nq+Pg4AD55ree1593/fPinTK0LDusqX9IWvsixicZ2EKB4b9FnKjQ2Tm9ZZvPXzh/EPzN4VbrDDDBETI9vUReeOEF5W8grCBvV952lox19riv0/YTFDiTLi/PsV6vBd/vx3mW/9vCpVkKL4nRWkKJjKCUUjHGt5igUjqLCZ213zf1Udtf+NQDpXpeP7O59BlJwg7tX7P93fR61xHsQ0jpcnEmoUp9bi88PyVmqBc4hfGp+r1Or/8nBw++tg597/LoKNtHNNNgTs0KmEu1+5qozA5wgTImGNXDS6zfH4RAsh19+8VXfh/oaXMpRuHlEwgDSi4cIFI3ggjVlmlLvW9FADHO2dLIxz5yn6MwW9BiBuDRaXcqYYy0LsbqNUeVJV9EvDqwwgyzf/gX+hP4GALngMcqk4yPWSmhNj7SAmLz3IXZ3yyKLX/S7J+XE2kaYXYAOrcENUukDQYvYtaXtBjrpLTDf9xJ47m5GkVrWVzsjvO8+HSYkKwC5CN6D4qJ7KkMRiSJjxUqEtg2rrUeQj4GNLZauWZyHZElFDwdSuLFgyWlwA71Z0QpkFXn72KsYEiCl9lBFt6vyrBDZnn+60ePHhkH1xuBr2FDQ0MQiM9j7EfNPLgQ27UBY3swTpBD88NpRJgpxsfERDMaGRmMzl6Y/wRUYPNKS8HgMQBKhLRlGh+3pBJnSLLS4fsaqR6NlHXLzR9ctc4zjs5kKIHccQMRQc2LpDyHIKTOciZby3hR6miG4hQ9F1yBQgu9bym8efz0+d8QIo96vWE1/DE2NqbcQQDOqhZzKSpzSKJvMdYC6fBrI8a6EaUcfqz3e8Z3aJrSgNBAEusEpYvsq42Au8I4dN34UpYiEBJaOr73i//sgYtWeOa6zfpzwqkyQ17BuVtRIQNZLf3gVrmd9Ou6vkBn8BBiZTOZ/I4etmYFtfFPAY+8n326X0//IzgdEEpj4uhRQubnh+XTT8/Jxx57RB1gtYzA2zp/tBZEGNEeBSc2ONgCNZayfa8cvh8ae5MDRfWggpqEpAaDC+rHVrjUDpWHvZBK6X1HEGH7yJ7YUESSqan1QGP3XbSu+L50janzbKQCSjDdrEQitk7U0KClTaEFgc5AuCwENzk9JwikPlc8/9CnKsvZdHDfgfsJMEyr1YD2q4HVNOiOHYeonVlqf3/NwKCp4ZfR4R87ltJWa5B1u3WWZV3W7vZ+VViH7rY638Xt2IoMqStobEUfJIwJfAN5vyLdxljYXXfdeqnqAs1tMcwlXduXfAiRpU5ghqxLLVI2GBn8vvA+MBjIMzRNeXXwLwCo0+3+ar2WsoWF2bjZHARfc4xu2PBJF7DrytK1AONTL1oeNyCC/2GE1oKgvPXWuXXg6P45NxMmTBQv/UBXOHYvfE8TVcce+hbhlJJpm1L+Cl//pU99nFyqoFIbAmVW9lN+Pzx5Zx2lNrEAlP2NJL5zOIFQGm3lgcDxDGL9a97PHzp/9PRYo5EpxkH5jFZj5bOpD10DMNSlXvBZuz3L0HmhtQjRiN46M3evM2M0X10ZWgYjnKwnVtBVqMbKklZWu636ixRWlcirlaGhBnF6S6swWfrNks/yIIWdxP2sVXchUEFCVUibSjLDFUjjakCw8KJHs8nI6dkzN/dr61UbNkGhtSG/ePjwYcVI1mpC410NGDfTBfNhc3OTihdrtSWK1iJlAU4/e0hXQj0kD3uOCCJ5GQ56OWuRJYVkk7yUrKC0ELgHPno/WUu55WduChjIy1FnPcY6ifdeHhxZ+vWy5WjT1d8QFUqTgZWU5ixwR+1Ly92HBngRcd6H9htkg5BBsQrNNXxg0asBo6qHJrZ7N/bAYxScPR0YGFBOv9EoInBoO3w8wqlcMR8sSN/bHufBoLZhXA+mvmFC6WyHg2cuIZGrZXJqfXgabmtHEqsnGqhEaTtHSWrbI5RAMoJAUZse2PPWE9BaQOlF0X8QxEEE2XflDur1GYpxjW1r0znoRYGxb1qnj2qsVksgBROjDI5mF5ZwGut2bdJVELyVhNRV5Xp34jZHFfgc62RCi/mlT/08WWuZmpogVVACtUdC4vLeTP/HRnZ1CfxbaEFEigqtCT2wVxIEOiB16Saunk+fnD03WgMRMDERqwD97NmGYiRLZ0aaq1a5aBxjJXK/36dLSy0YbxmIsoiyEyfmbg4Gs/SkPDV9NZg9aWa12JSKl8ceCJV5D9ImYUxh2kqVSfArD3xsbTSG5QZQZsQ2vKVIaclSpW7oDTNbyfXXbyEfunk7ueH6reTM2TnyxFPPkieffsb1DxnUCU+JulnknvKU4TNtPcyoPMZWKjclr2F74vjpe6eu3fjViHej2sY6n4aA5+RJ7TKIqaaNZ6rAlDKmBw8eBBqZoUlS0E6nA5TWZFknu1uYsRMXPJpxeiHC3Jcog2KbK+i9rjOaMSsSgGK/cffbSORqcRajaVFOTU7Qnbdsp7fcsl2Bdj0Asdp3PgTvD4Jw+PLffN39tvQAlbLL2HbqPRfzYBtQNabjWEM6QKTyxbGATs6nxTLQWZTyAVlnLXEepPOC+OQnJ+nXvvaI+U2dBqsC43qWTVbC6Bw0fjdat24cho+zCGTyJj/cqx5SmusbTcNTuWIo2FOD9ScOC5yhH/pd2wCmi/zyLz5I3klBufy7v/MbqrEBBIrP11oe/Pge8qW/+TtTjTKtBpXXjUTtRxAICwir+FhJ3BAHPO/n2Y40jRlCin6mM5jS9lFCT5zYR7ZvPwJHfFiuajHSXzSqUvvT09MQVNZYHEd0YeECZBnqEcTv14og0JJ2fD4MJp3DL1uNswPV9rKkw5xUpr4hPv6xD69JIlfLxx/YTS6ryAAQWx/iUzWqzYIMtNpSagbbjBLFUU+nQjHLEfmh84JvgiFolucsqtfB6ySUTt+IdDZGzdCzs5iS87dooSPasWMHOXcuBf+yQBGYokhYDpwIZjldmetFq1NXnSgOVJZTOxqgcqqEBFrInbsEYNbuW65Eef673yO2itKRR1nVybLCLD23Si1M44TvgWy+FobboYP3lGsY6HbZuXPnVFuH8QyWEjBSD4qBTN5NMAVTq50H/xJTlHhJkrOYFwysZdg4clkCQ/cSiwaeBvVBZLkBnM5xNEecCCBmDj/4BpDIN5GrWZ546pmSWgst3tbcS265QoVaIAyCGqBKkA3KlkXREHT2plK6C7UaffnlWRbGM/g5Fj7BgtG+9i+vExhCxlmHVE0VjQbVdF8wyRF7eUQ1AJM+mJNeItu4xPqZFd7ENUZ4rF/7F79MrmZ55dWDoM7OElN/+7LbLb1W3XEWb6zDW0qp80Isfi20J2RPlqM07TO8zrqepqrN8Oo6G8+oyYdB3dQHkOtwgjRK5QsXLgCyywoYlM2cq+lv1YZ0ZEWc5RAaVteemHOiVn1p4W5OzX1OXjO1nqJ/uZrliaf+3io5WxNVxTDotK9Yf+it3nhNIkm5s658YOeGpqRZxGgSr6OoIW+8sUZ37fLrGCBzOedvL8vDNzFVgKOUIOXY6OhmAKaDfgZ8DGfVHyJaklSsQQaSU5YUji1VeqBBvHG1KQzL/u//gNhh51L9JLGeP5wg6E6JmMk4tr9VQKHGahytg8tnOEeaZox2eJfxdgIK7aQ+UlBCKlP+xXJdvX4OtuOk02nDFxnN1YRrSknYoVzv8ErKUph3kCvoqwRa0OFc5f7Vv/wVcjXL8999mZw5M+tUITGO32JCXBrJ1NXVlBh28FTtgXWHp/YtfBPbEIHJsh4dgVfQh9fr9RIoK1QZctxzz2F+bAgcf40CLgTVg5oFn/dxCBU/3yKuwUuW7H2Go6sAEENzvtg5XP45fkZL5AlyNcvzL7xEnMMXnqgDgnVKUcqAez0IMsSl1CZhnyS0lecUOrkGB13E8nILDr0ROsbQ6hbjv6xLlq2TSauFQoAgujkAk5IUG7MlPQSOgXWUKN0wriwdVboRQylD1UNCnlblavuW5eU2+Qb6F1ek61QlDGSAha03da/R0JeSKqkbWoPufbpex06eY1KYdLsdcBuELCwcotdcs0UatlLBegkY1NG7d+9R+yiVcYtfjsBR1Wp15axZxE6tdoIy3KFh43sQsNhpSFpZaznqZvHABlMjl1Owgc+cnSXvtHznuy85CMIO4q3BmBDV1kR1Qsa+6ZEigX2Z05fl7onnvpQDKMBGqrOrescxhTSFyuLjc3QnK1IyOH8MZwli1nPrVkILsJahDiOLiz0pEpzh28epo2dczWVwErbyzpqooy6nxmhw8uYyL/1cWPdPltsdspY0ynK7rSTuqwcOkTfeeJO88v2DBJOTf/kX/5m8k/LEk9/SAsYVL0Zse6pXhQymP5XewUueJPFxsaTBpdLeIVGclH4an2Xm60NDhDQ4IXi2P3qDkJtv9rW4WBKT9MfHJZicOQCjS5kgkYjYQC39UWeZfoL4yfK+Dk4nh+QqA1HjrSh8bkHBf5/7wuPkN3/9X5NqUUB8/xB5FQBAQH585GjpeFhe//GbYDkA7NDa8mPo8JUaC4okgVUTrZdd28oKRZsTl0RPKjFvhrNyfFIQStqoH4a/BP11rcGAjSLaSbkC5oYbPgB/T7qjrpr2n5rqykWIYcbAYpbhH+mmyhthprSWpqd1NZn6UVfpcl299JRkFVBIRQgQp4i+BNndFyA1gvmuocFBRU8v/MP3tGqqNIvtCH4QTILCegmSkT9H1lL2v3rAUVHASKbaPkfmAHJ1DiUL8SOPrqtSa3LU8LrKf40ODL1uv9ftErAg2FkgymTeeON1sJiG/U26KjBnz56lt956q5ydBYupgb2RRVKDf0UMGcxNG/a/deYsMq29pMSV8pQg3ClP6rOnYljBnXiYNMRdBON/f+FxsqJ/ak60Z+qHB4KPvQIWsFZgHv/yV0u/T1Y5XsmJu/MyFk+cenJURikJiMxOm9Vvbdk0fTgHd9BIajLLCv0hXGWtjxajF7xDZbzCx6DjwTI+foc8cwalcouOxsNS1GpyOdeXBkxMNlsgBk4Dy20wSEj/28EJyXL/poF/CTPJrrervkW9THUst5L67PfDmb9Wxu5/5QdV+121oAW+/sYREjjHkvNfQVklatCxJk7ss1W3lmJrSM3JWbTiJHl9amp8mXNfPWBnQjtgCC1Cdu3aInFCJTHjctU4RmICE6VbluVyaKhw9RPdriQAjsikrNcb36GVK7Rthd0eLXdE6Ruw1ACiFJCK0qGkUz263alhDauBhBAOfV0PSdHa1qLOHvvyV0qVC2V+CIosZZJk6ROuc5RKFRR9hRq4gNf16C5O91JDuxDEc9XGN9wwrE7cLMGlvrbq9CUt3bwqxqmvSZLKGKgMxhPk8NDQfncZNqXBtSGErHQ46hScF/CXdOuzdtbjkfPgUUst0lw2HjaOPoqnStuuknxHBYyXLt954UWvIK2RBto+oF4qA69jqiqdhRhLKl8fY+yL+vYZHx39DkqpONagYJviZRu2PjBYbLMuckXkT0yrLi8vy/Xr10sILqW+TrKugCmiSODBr7th836IXJctEMo6mOF97/c8PZuPSSKNhZgzNDwdNnUpfRMC5i1Iuvfc4aVPncCTVypKq1qA7kwKJjyC+RVPWVIvUmfBoEHNvN2qn6QaKAuCpnYPShTFrXvuue07IJdFDyoK5CMhLoTvDBOIaySOyeCR9phFV7GsiPztqg44SeBsUShUazUhzZg+ACVEc3iwBUHSK/h1ZhdmI87fEHe9nD1ZUmpf50hdgFltnhCcQDEZUU1L78vgk6YF979ygFyqfP2pp0tRvd2x+7rz6F4mpbdSGXIccRZC7cobXoh5UPBi24GBxvMyhwwxJPwTkUAn1+1ZDCzIPB9BA1ALBoXVWXXC3/z8DKQHMpksxeqnONcHiopIxIokpdxwzdSXHCjuURKMoUKRJXSIsQTn5x0/OFoK/Y2dPksMg1hprNURKfksfK21vKyl8EUKWow7BPHiA/+IQNbbutjEcpmqy05Ud00NiJ3tb5ZzlBsnJ59SU4nBP0NHF3GcCA6dfaBAH35efR9GWpz4WhUYeFPi2MDRo0fBzArHg3iwJEHUI0wC8B07btgP6mxZm6yrhAGIeVTCs6GkIj+907XyrOxMDQsa+SUDp+AosNyNXUtrxbWyoG85feasa1sL8mqHCQ5X2np9T40kVuct7TKOeqE6/UiS5OzP7twBPplxdNLYhtiWNejs3W5NZNmIxLbG5YbtQBkWB0x4fQaiR8hWUA3DoJR7AgbJAOVCINoczUcpi0iMjo582a2OZ01XVYy4oIuS8mRu6xrL+lo6ZVROcsrSg5gI2/t5WWlA76EuJgC+/fyLZIVjMwRrG986+KqCJMFXXJ+j1rcy51fM+pq4OBCBQb/PY2dGGgNseBHFoku6JE1TMTQ0LJvNcdlqTanDWovB36xOxlDb06dbEqP/LDsGHDgs07QmEA9wYsAvcHQOPwTc9rM7tn8Jxs/a4TKGnluJWbGVeW4jnjZKztu4cxtLhA1CV2huy3X+GE7uuuNSSM8cUYnNsODzr0NuzNqcDI4j5QrrM1kNGmAYxgZGErsFG+zaZ5F5wAhlkp69/547nhRYIiGKDhcRUlleQGfPBTLS4mJbYHCJJVjrbMVkDPXm9u1zEpUZvoZf1tsULKYQUcQFMBknCeUjIyOt5ljzy3o1PLcgm6E0Zv2n9zcmQxGCYi8hJ6Ry5VdQJ3+1QEjyoX8xDSwcMZHlVpscrtDZt5//h8A/UeJJ0f5WBRxJvAkFgITS2FK3X/TUrRIox5rNpwhNOHyAExj+HRiIFfPotuRyZES37eTkpLDLCFvjWHX6Eo77owA4f35YjIzkstdDKsuV00KuhE9ydbFhTIudt9z8ZXh9lprKmOVxjdUElQ/jYxuyy6CZSxZiSUmucOwOUPuMhq+41lbf+wZmjoPyf7/4FW9wJWsjblUO95r73SBYrIBj/WtpsVOqF5+rJensgx/d/Xmq2V+gVO73YWyeRRzbsiguyFOnctluZ2rxUzuvzJ7WRecub9u2C5zTN+BLk4gyHLwfw6AmJABQVVA4cCyAOgVazTVTk184cfKt3xGMU7WUlNBLSgkIk3DpD0vIKhGokw66AtT+DXutbeBqep2Q0mvONmgJY28QVNEWlqmpSchI/8BbUNAhQkXiMsnhh2wfCqzDMoL1qQYQFEbUrgi48doNX8AOjM4liaKCCFy9pSNwal6W1UU8uZ73Fhclaafq18zyWXj+q06RDcqzwMlb5PT0iFxYOAA/PsqB1gRtRFzStKC8z0kRgZlyfuedu546d/78A1wUNzOBFRR4cbxaagqzPpKF0hOXAlGz6kuA2Maw7sY3O10BiH3dxJtuIV/pglbVkurDX/vG0zLM5JXiKWM55QtjnQIMshSGuojvYN7JR+qc9BQvveosDM2/eP+dt32TIoUh7eeUFxIbZZBj2JGmfZGdFbKeQSpm8KR47rlD9j4C5gxXWbLEjKBRXM5pZmaYdjpnQAlNQZp6maVpwmQO3kRwqEMKGIASUBPdZTQyMHjorTNnPgY8n6q5/HaYubLaRSWlUgZFlhVcqKRDQAKda9vYgUdtA/riQqgAHqKN0tInDX/OfSvMeTlfEqzL7NbIjNViciiDQW3VOnfffttnx5rDC9CRC04gtGQCJ0z0wRByxvKiVhsolpY6ot3m4tprBzm0tTRLmbgqrJorQ/RwLXvkvm53WiU0N2yYBp6MgSNjDm0OOWta0ILxGEQAmuzUxsnTkxOTf216jbSrfZtlc6VTLaW8GgnblPhLt8u+RbqmtNYQ+Bj3GeoaW/tsuSL+CFJhxObFSg6/iowFOIji9bayFDBTy2NRXBpr4zWTf7Vl+tpTMoohg0VhpIQWCbQVKlp0/NiG3e5pUa+3BCpf+2t79+5VWeVLAqPLowTXs8fla3u9IxLGaIwIKAQ6sH4fZIXMCwK9ghAMYWnx4fvu+n/j4+NfdWatQFKVp0ZC6pNkHhwa+FYreav9V9qWtPI2bO3yrgOFEBoIKg+tLFmaNzYnJNwOcVbjgmjqFjNdZenfmKwfX/e1Pbvv+VvgcY4PyCsCIEluBFPR7cYc2xDTMCisTpzQagzXzzRscWmLwQ9oTa1v1QGcCQi3VbCJiFMa8zSlBVoO0FnOojiHuqH2K27fdetf1er1Ny3fMgeOX5jNLdamRh2M/LTKzTZmOQWgICvhQkKrMFYkJamoA49BYE0WzBUgmd8t/Qt9CvNxCgLBotgtWlpv1GYf+vmP/vcI2qRApw+9FkFhrFAMIxusGBmJea3WAPqq88E7Jl3OCaylJEcuCowtiCSmClAEDA9vF51OAywmBTrrwyPnUoGTKnOVOFoD22ZzaOn22279Uxh/mDULfJqbGLjAy69xHFpP0Ih20GUFJWmKo6u5l5LWJAF9ET3yJJwP8kbh00HuePYeWF7mB5TFXEeL3BK/CpRaffa+O+/8d0hdhbKSOMdwIsU/XOaK9rsJb7e7vNPpiSNH+vLMt45RbFtrLdVCyUWK9NdisvmZGbat1Yr6/XHo/Hnc7baSer2ZQqeoZYTXqOQ1RuM6GFo9kkkKcq1+6q2zG7/78kt/3Ot1J3EZRrsmZqEXKNULkwZX/YYL/riHaVnXgCGN0fI8gtBvhedpiJuuakgGBN8YJetVa/4rxcWYk8J6QWy91CLkwWSj3pjbfd/df7R16/RbYBsZdMMM4pa+BNaSfZYlCes1GlEPtVlRzOfd7lgex7McaQyXAbY3DqKVJUsuCgwh7rJyXE+Z4XrKuPISxKlxli2mWmrD4LUsahAO1XIECICJJatxImrg7tNTZ05vfOHFlx/tZd0JEPFUrZNpgFFbfXOFACCVhaNhEOjyliSkrYrjL/kYK6Vl+T1nKhVAEGO0WjvpKIzmmXH0KrMRO3+C6ktZSr0+t+fD9/3RddPTb0kzvltAmAJElMWy6OG2VmMKFFBi/QsXloosY2BUJzkunm2GWBQxVMfmL0VljhWee+45tdCzvodKVywttTn6Gsg1F5BRKzLZL0CIwYgDAWUA/YTFIBFJfs2GqdN3333nXjiBc/qEYr3Ct1sjHx6lVIa+K4V1tKSk4PxWBopJrrCBkoMvBZI0UBsGEu9TGPU39qEBfSkaNnWOy6B8ZM+9ezdPX3sGl8fTwIDPFTLnguQgV3OeyDzL+srxt1od8M11jtdczs/P2zs5yTDhu1ZgQnCI9zUtMTERc/yhgQFWxEUth5AzlxmKZ9lHcOB8ckh55pLExfTGqTP33H333nqtMWd9jllEWqrVWePA95SialbKRZXzU8SDRYKojBgcqAUudOCkFBzalBHzvyddnOIUZez8iAJEUViCS/Ye/cj99+7dsmn6FC6wBEaf45ZT0Y8AlHo97stevxAdijFLjm213OgKbDvMQW7btk36S/tWb3hK3g6ZwNfgmDRYDV4gCzHVZMzYENDacsIGilrCWdoHCoNETcrR10QJ5BoEUJ1IgQ6S+Qvzoy/94z8+PDs39xDnuVs30y/t4S+7thffVn0OFmGGF6txDgl80sqeRQPQAqlRAcrfs8zdM0bl//TFWxogSD9947677nhsfN34IqVRH8YhFYVRHkEAiTTGM0jw9+D8+z0YMYHR3xxEbX7hwgV+/fXXF3YVc4wT9+41VrvS8739sljWKaF6wANiJhSHQqNokYvR5WJwkBZDcdpH9UFZ3EdTBi+pKkzBghj0IDjn/tj42ALIyf+1ZfPmzyUQHWtKSGzUHNzQoKri/MP0aEpLPZ0GsQYt5bFcgtGPkfhl4u1Ne9S4SaSlbxwFFhJbB0/Vesq1Wmdm6+bPf+oTD/7P5ujoEloJdC6gLqLOF0GBMAJpXLEG0jy2TRS1QY21RXzTTfz5bte1pV8ac9U0yNuvImuTanoF2d8kGzYcxhsrkNde65GJIVw0bVBB3u0WNEFuqGEDxoptgHshX0Oxm+MGLz2QAMyPx8bGXzx37vxWsLyJUva5Gjuwko8xa/J7WgtlrelEXlW5gLB8Bz9a9SE28egoTKdZ3Lr9SUJGhkcO/dzu+/7Dzg/dsk/5ErySAgCJqOzDCUJnJJkEHwvn349RB5E455B/HxjogX9B+Xw9X/hxT26O58Ff7xGPPLJHhp1+VYMgayuOOkJKGx29mWXZUtRuX4COxZI4Hkz6/W6CKq0PKg0YIIVR9BqYdprCKGsOtBbj2RIZA3vFL7z44p6jx4//StbL1oerFfFQrdk1A8xFpqazBA/TgQJJXVJgat8DV6IvRkt+LSrdcQlS9/Xa3E3bbvjC3Xfc/jJ8gKMfwdWLoT0VE6DQgVCyD/0b1FeU5TkO9vJ+mqIQAiYZGgcKOwzR/vXFxIS7EUNwC5OLN/9aF8S2t3hSd1XFGy2AslA/UBSTdHx8oliAzhNlHYoGVkSARALGCA0M1UdLkhk4HhxQk7igJ1FLscv77rnn7+++845vP/33z/4K+J4P97JsnUBdBsMGdhUjHDZgCAqz19CrFcXMjUov7V/KXYs6SwvvhenG6K0AiXCcPu1svGbqyfvuvuPrY2OjLa6CLr2kdAKgKN8C25jIPk8oWA2AEqX9WLYBpME8z5eUxfT7yxxTL1u3zrrUC7FdhV7aJtZqMaXv4H1jdu/ezexdlaLoSDw4uIWdOnU0GR8fBashMARBEww+pSjSRlSDdAFJ4DRSGbEUBlkTZTkUHvr2EtHCwsLwD374o9vePHb0l7IsmxBmrc1gjRpiRzKFzVab/L60QajnbGr/u2eBqmPBWEqYMY6TuLNxasMT9957xxOjKKHgBxmOpUhUKSCFGfpLAf4TI3sMC/Ah+jn4lcFY9HUQKXJg7gJ9MIzrc7yXGVpLELNcksIuCxiTaDM39CFk9+5HGN7T8sCBVrRxYx+YgIFzGYnb7VY8NLQ+LoosBUZIsgwAilkaCZ4ylsAwKEkQHPj1OMKuCrQGPRBnRkU4D+cHBw/c9OOjx+8HsHaBHxqw62iuvItsKfiUhITXuVC3ddIafQzxqSAEI4mT9vDQ0Gs33viBJ3fesuOHmCnHBKTewjgKXpjPIpCRCAyQlXH2KIvB0fRrwBNpWgcL6ao4Bk4BBEFSpOkFA8p2sBa11rKsjrlcMWACgKi9nTtmBdByjhw5EjebN7JmcwB6/xyuzJF0uyJO0ygtABzodClaDEvBGzGaQP1wwADAAD+UUAbZanC38Jypmx8y7Kw4t/p7+/btOnXq9K52u7Op0+tuqUpp22GMhrbjY+7UKsIAYxVweOm5dePj+7ZsunYfKK1joBjbOJ8RgYDUrwAZxjUPQ0MXRFkK7jN4E5IdGQwS5yJJc/QpMfgTyEGp94eGZL642ODDw20BnUo0Gg1uKWzv3kfMON7ablVy2cDg1oCDtytRawrjLbBw4WdcAJqNDsXDkivr4RzBoQnSWsTB5UBH5WA5DIYqEBzUqLhlOJ4AYgesBhyUjLApob0YqjwEamlxYfDoyZObT506e1On21nfU6KhGOhn+XqIgQbCYA2Ysg0+rQv+4lwDonToPMdHhgfObf/gjT9sNkfaQDsEh8gRDI0rVWvF44QWNQcMfIoCBrLmKP0xMSkyvLQ16vOY5APgUyAhWTQaw2DUrRyzIc3mZLG4+COgrB18fv55OTY2Zm+JpZptraBcNjABONSMVav7k0HvYLfffjs7fHgpaja70blzeYRqDfNqcEoJrdfiROQp5MwSmg7EHLZoPdCMAEwB3VQiOAAPAFQgrYFH0rdCgq4ucLkUhgof4DKjkjhuwFU8gs2pXiP6xiNoc/o5VhWjesQAL7zmKIW5NjjFzVwNJ+EYMACCwxdUpe1BtoA7QfUFFVJxGmTWcwRF9rJC1GmRFlp9wWguL9PXrJu9r61lr3in7XvZwITfR5DsDRkQHNgCNem1H0F8QWMPxrIBNgPUJpIcEqCgmiHsgQxAAiQP0hnEQAwBUJHHeNccaDMlCHDcU6CW5RAyUJwyp0Mk1cYgHXCtY12LQOLgBAOqb+6AcRO+hDe1kswMtWFl1Wpvhbq9AIGxJUTc+ha0FG0xhcp74ZgKwfw97Kc4/pQCMF1WCEhHiaU2+J+ET07GBabyd+xoch/ZKwVG3olfCctl36PMNoOxHEXxqDzw4loMQKGCJMvqkvMeyQcXoaWH5UAqZJdGsgFMBnkLHiOBSQZjsBCEAe0VMV7hJmKIm5XlKFNAK4EtJuEjzF9j9CA5kzBCh9ErjhXiQioImlpPJUKcUKkxXSnE0zgh5EWuKoz8qKYsCLQOQAZnGAlcZAoH+9RtLQAEtBDQ+4WktYJkEFTWWdEH8VWLed463+IICnyLg/gRg4P+pnGXS19h+UktJkTIpXytIEApPTo6x3AhbaQ28IfxwEA96nRE3KPtuEFglEDyCC2IpDCC0c0TiToaQ29oeSAKCHhgC/oTR0TUnUP1j0VUeWr8Pe51l02CcTQchAJjExwjw/kihbIWOAjKCgUINf4EbzaCzwFFNV9OpVTASmCcFtL1kEEnGQDGimHIqINf4UtAXU2gLnTyP/pRJgcH5wTOwzPjKy68ulxQsLxtrmytxVRCPdBy8L5ceLPokyebHLkX1UoGkfB5ToGreb9BRiG3lGB+CVxqty+zHBJ/pAvepgvqrQfJ856MaQ94qRfFSQ+kQQb9u4tjHGAoPegHMN4h9dgHpRmYC/qBDBo3A6HQA08E3xXwGQqfydXnJD4i2gMi64L5wOd4rw/jJngsgdt+oesAj0T0e5QuZ+DU+6i6MvAx5/linkFCsinOgz8Z4ai8tm4lxaFDE8Le+xKJNmiPy29PcgVLYDWKRcp+53Y2N3canqvlG6OsXmeiaES4FnFbFFFdQpgjeCQhZZCCFfVhDFAmOIGxzvJ+hjEScBIHnwVyAJMiSq1RFWzoeWN4SRWERtD/pRpS0LrK+RWgLoyUkLOYmRmJ87DRYnCqJBAiDJX3C5wGXCONotfr88FBlM1N2D8nOrWeIPMxr88Mi+FWS1gnH/oTHLuvTqq43PJuAKOKjXOw+FhH3wHQCgOgNbWWs7pXACiyWhEzUSuiBLYpAITrFGN810OHAm1JWY0yGAlFcBAkiPlA0iU4EsoQFKLyi+be7UlC7DWPGLkKFOEcQtyIK4cCsTlOLAFAco5XMSBA8VAi1O0sYHw+TUEdZ5CfhE/i/G288gGtZG6yI+Zh0PAzn9mlphOoRqT+1pxvl2pZa7miwNhSBcguRW+tZ+fOnXT//jmGNyDA9YenpqboubwbiaIf4Z1ZIRiNQKCxuoRtAQmPOFbZfmxeu0COCshxYhC0I1Fr3GCL9M3vJ7KgubrtL14zilu8kgtgVrPthUjNfmHmY/c5Xs6ISiutNURvLhe1Wl/gxAmc0QIdSS4sTMAg135c78XdFZYEo7zUTci+MuVdAcYWCxDWGdM4FiC869DY2H10586Unjx5kp440Y/qm1I61G1AoFpjuMx6B5JttX4C1NWFgAEsSS2Lm9FGvYEWAiKgTiAOYiD91BgNHhfBg4hcqkVBMhxtSNS+AENIEAwAARJ1EufG4WUlOHkRp7HgZSY4n7hWm8NoXXS7w+JE/6Ssw7jTkAKkL5G2cGUqvBJildvDX1FQ1HHJVSiVTIG7CZ1J5dChoZ3qZnS4VD1a0MaNCT3VrbOBepeRxSaMr3cZrstpJhKqRYdwhbx8sQ90qH+j0wENNgSWhJckZmpRItVQnNvLSfDSB4GXwkukKQREX1+awevDstEAr56flq3WsBoCxhmoCMj8vL6pNR4DRx1xgMtQl+10VxQQW64KMFiq9IZbbUEPA8U9S7W81rcGnp4mBFM7i2lKa0sJXbduvZo7nSmgIPgaH6Nxp007HcjaDOO1v5iCYXQZD7q8jBMUcaEV0gCrwPtQDgwMSH3HvSGQthoQ9Bv4wOm/M+DQT53CFE2T41qgOEqL04NxJipOeqzQ1rsGRliumFxeS9FJRD3LEx84aHTo0KNqyBobApN+8/MHimaziRRTtI8SNd3nwoVlPjZG8qQz0h8cLPJMxDnQPsjuoh93C5BSJD9/fjFPMtGHTHaewTbJzqvX48kGughIryxAhLJUzM0tqOwvRuuQoIAHwXF4GMw6UuB0YKwDSn2U/Fg3rGNw0WoJoHe1rchPqdgha4z5SHCyOEKKW6Q6XFkVL9RFNacXhfgAaTROqvU6p6c3qc+n6Vl1DufPo2VNyFPQ9fEmEevW5VItIQF/QPpKTZN9daEQTuZGq9DXmu4jp09vk2a4V9UjuNX7VbGO1cpPDZhVihu+DheGDukOn5ul7RVYZAchQ8eOqedbtmyRx45p8JCO8Lk9Bs6JQwAI2UUQaE1TTlm5i1J1XstO9NR+5KcFzHumVObvquUH8VaPwZZB/MZw/7HHVOZZbfHxzDPPxI899pjahg/MTuvPPKYeUudmWOW41AbG1g/Kym2pfhrlvWQxpRL2VhncZNXip61KB7ColIg5l7D3X+zY1Wzv+5Zx5Up5wt9FenhoDeT98n65EuX/AyKt5JJq7iZLAAAAAElFTkSuQmCC";
|
|
1228
|
+
var chargingPileImage = "data:image/png;base64,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";
|
|
1224
1229
|
|
|
1225
1230
|
/**
|
|
1226
1231
|
* 充电桩图层
|
|
@@ -1410,7 +1415,7 @@ class SvgElementLayer extends BaseLayer {
|
|
|
1410
1415
|
// 在transformGroup上应用变换:平移到中心,旋转,缩放,然后居中SVG
|
|
1411
1416
|
const transform = [
|
|
1412
1417
|
`translate(${center[0]}, ${center[1]})`,
|
|
1413
|
-
`rotate(${(direction * 180) / Math.PI})`,
|
|
1418
|
+
`rotate(${-(direction * 180) / Math.PI})`,
|
|
1414
1419
|
`scale(${userScale})`,
|
|
1415
1420
|
`translate(${-originalWidth / 2}, ${-originalHeight / 2})`,
|
|
1416
1421
|
].join(' ');
|
|
@@ -1508,7 +1513,7 @@ class VisionOffLayer extends BaseLayer {
|
|
|
1508
1513
|
*/
|
|
1509
1514
|
const BOUNDARY_STYLES = {
|
|
1510
1515
|
lineColor: '#ffffff',
|
|
1511
|
-
fillColor: 'rgba(239, 255, 237, 0.
|
|
1516
|
+
fillColor: 'rgba(239, 255, 237, 0.1)', // 更鲜艳的绿色半透明填充,增强可见性
|
|
1512
1517
|
lineWidth: 2,
|
|
1513
1518
|
opacity: DEFAULT_OPACITIES.FULL,
|
|
1514
1519
|
mowingLineColor: 'rgba(99, 216, 174, 1)',
|
|
@@ -1540,10 +1545,10 @@ const DOODLE_STYLES = {
|
|
|
1540
1545
|
};
|
|
1541
1546
|
const PATH_EDGE_STYLES = {
|
|
1542
1547
|
lineWidth: DEFAULT_LINE_WIDTHS.PATH,
|
|
1543
|
-
opacity: DEFAULT_OPACITIES.
|
|
1544
|
-
edgeLineColor: 'rgba(
|
|
1548
|
+
opacity: DEFAULT_OPACITIES.MEDIUM,
|
|
1549
|
+
edgeLineColor: 'rgba(231, 238, 246)',
|
|
1545
1550
|
transLineColor: 'transparent',
|
|
1546
|
-
mowedLineColor: 'rgba(
|
|
1551
|
+
mowedLineColor: 'rgba(231, 238, 246)',
|
|
1547
1552
|
mowingLineColor: 'rgba(123, 200, 187)',
|
|
1548
1553
|
};
|
|
1549
1554
|
const CHANNEL_STYLES = {
|
|
@@ -1612,15 +1617,6 @@ function convertCoordinate(x, y) {
|
|
|
1612
1617
|
};
|
|
1613
1618
|
}
|
|
1614
1619
|
|
|
1615
|
-
/**
|
|
1616
|
-
* 路径段类型
|
|
1617
|
-
*/
|
|
1618
|
-
var PathSegmentType;
|
|
1619
|
-
(function (PathSegmentType) {
|
|
1620
|
-
PathSegmentType["EDGE"] = "edge";
|
|
1621
|
-
PathSegmentType["MOWING"] = "mowing";
|
|
1622
|
-
PathSegmentType["TRANS"] = "trans";
|
|
1623
|
-
})(PathSegmentType || (PathSegmentType = {}));
|
|
1624
1620
|
/**
|
|
1625
1621
|
* 按Python逻辑创建路径段:根据连续的两点之间的关系确定线段类型
|
|
1626
1622
|
*/
|
|
@@ -1895,26 +1891,7 @@ function generateBoundaryData(mapData, pathData) {
|
|
|
1895
1891
|
}
|
|
1896
1892
|
// 第一步:收集所有TUNNEL数据的connection信息
|
|
1897
1893
|
const connectedBoundaryIds = new Set();
|
|
1898
|
-
//
|
|
1899
|
-
for (const subMap of mapData.sub_maps) {
|
|
1900
|
-
if (!subMap.elements)
|
|
1901
|
-
continue;
|
|
1902
|
-
// 找到该子地图中所有 type 为 TUNNEL 的元素
|
|
1903
|
-
const tunnelElements = subMap.elements.filter(element => element.type === 'TUNNEL');
|
|
1904
|
-
for (const tunnelElement of tunnelElements) {
|
|
1905
|
-
const connection = tunnelElement.connection;
|
|
1906
|
-
if (connection) {
|
|
1907
|
-
// connection可能是单个数字或数组
|
|
1908
|
-
if (Array.isArray(connection)) {
|
|
1909
|
-
connection.forEach(id => connectedBoundaryIds.add(id));
|
|
1910
|
-
}
|
|
1911
|
-
else if (typeof connection === 'number') {
|
|
1912
|
-
connectedBoundaryIds.add(connection);
|
|
1913
|
-
}
|
|
1914
|
-
}
|
|
1915
|
-
}
|
|
1916
|
-
}
|
|
1917
|
-
// 1.2 遍历mapData中的tunnels字段
|
|
1894
|
+
// 遍历mapData中的tunnels字段
|
|
1918
1895
|
if (mapData.tunnels && Array.isArray(mapData.tunnels)) {
|
|
1919
1896
|
for (const tunnel of mapData.tunnels) {
|
|
1920
1897
|
const connection = tunnel.connection;
|
|
@@ -1936,6 +1913,8 @@ function generateBoundaryData(mapData, pathData) {
|
|
|
1936
1913
|
continue;
|
|
1937
1914
|
// 每个sub_map的elements是边界坐标,没有sub_map只有一个boundary数据
|
|
1938
1915
|
const boundaryElement = subMap.elements.find(element => element.type === 'BOUNDARY');
|
|
1916
|
+
// 如果当前subMap存在充电桩且充电桩存在tunnel,说明当前subMap中的boundary是初始boundary,这个boundary不为孤立区域
|
|
1917
|
+
const hasTunnelToChargingPile = subMap.elements.some(element => element.type === 'CHARGING_PILE' && element.tunnel);
|
|
1939
1918
|
// 创建基础的 boundary 数据(来自 mapData)
|
|
1940
1919
|
const boundary = {
|
|
1941
1920
|
// 从 BOUNDARY 元素复制属性
|
|
@@ -1945,7 +1924,7 @@ function generateBoundaryData(mapData, pathData) {
|
|
|
1945
1924
|
points: convertPointsFormat(boundaryElement?.points) || [],
|
|
1946
1925
|
type: boundaryElement.type,
|
|
1947
1926
|
// 判断是否为孤立子区域
|
|
1948
|
-
isIsolated: !connectedBoundaryIds.has(boundaryElement.id)
|
|
1927
|
+
isIsolated: hasTunnelToChargingPile ? false : !connectedBoundaryIds.has(boundaryElement.id)
|
|
1949
1928
|
};
|
|
1950
1929
|
// 如果有 pathData,尝试匹配对应的分区数据
|
|
1951
1930
|
if (pathData) {
|
|
@@ -1966,6 +1945,14 @@ function generateBoundaryData(mapData, pathData) {
|
|
|
1966
1945
|
return boundaryData;
|
|
1967
1946
|
}
|
|
1968
1947
|
|
|
1948
|
+
var RealTimeDataType;
|
|
1949
|
+
(function (RealTimeDataType) {
|
|
1950
|
+
RealTimeDataType[RealTimeDataType["LOCATION"] = 1] = "LOCATION";
|
|
1951
|
+
RealTimeDataType[RealTimeDataType["PROCESS"] = 2] = "PROCESS";
|
|
1952
|
+
RealTimeDataType[RealTimeDataType["PARTITION"] = 3] = "PARTITION";
|
|
1953
|
+
RealTimeDataType[RealTimeDataType["STATUS"] = 4] = "STATUS";
|
|
1954
|
+
})(RealTimeDataType || (RealTimeDataType = {}));
|
|
1955
|
+
|
|
1969
1956
|
/**
|
|
1970
1957
|
* 射线法判断点是否在多边形内部
|
|
1971
1958
|
* @param x 点的x坐标
|
|
@@ -2083,7 +2070,6 @@ const handleMultipleRealTimeData = ({ realTimeData, isMowing, pathData, partitio
|
|
|
2083
2070
|
// 割草轨迹
|
|
2084
2071
|
const { postureX, postureY, vehicleState } = item;
|
|
2085
2072
|
const currentPartitionId = getPartitionId(partitionBoundary, Number(postureX), Number(postureY));
|
|
2086
|
-
console.log('currentPartitionId===', currentPartitionId);
|
|
2087
2073
|
if (currentPartitionId && newPathData?.[currentPartitionId]) {
|
|
2088
2074
|
const currentPathData = newPathData[currentPartitionId];
|
|
2089
2075
|
newPathData[currentPartitionId] = {
|
|
@@ -2136,7 +2122,7 @@ const getProcessMowingDataFromRealTimeData = ({ realTimeData, isMowing, pathData
|
|
|
2136
2122
|
let newMowingStatus = isMowing;
|
|
2137
2123
|
let newPathData = pathData || {};
|
|
2138
2124
|
// 找到返回的第一个实时进度的点
|
|
2139
|
-
const firstProcessData = realTimeData.find((item) => item.type ===
|
|
2125
|
+
const firstProcessData = realTimeData.find((item) => item.type === RealTimeDataType.PROCESS);
|
|
2140
2126
|
if (firstProcessData) {
|
|
2141
2127
|
// console.log('firstProcessData==', firstProcessData);
|
|
2142
2128
|
const { action, subAction, currentMowBoundary, currentMowProgress } = firstProcessData;
|
|
@@ -2214,10 +2200,10 @@ function getNoPositionMowerImageByModal(mowerModal) {
|
|
|
2214
2200
|
}
|
|
2215
2201
|
return iNoPosition;
|
|
2216
2202
|
}
|
|
2217
|
-
function getMowerImage(positonConfig) {
|
|
2203
|
+
function getMowerImage(positonConfig, modelType) {
|
|
2218
2204
|
if (!positonConfig)
|
|
2219
2205
|
return '';
|
|
2220
|
-
const model =
|
|
2206
|
+
const model = modelType?.toLowerCase() || 'i';
|
|
2221
2207
|
const state = positonConfig.vehicleState;
|
|
2222
2208
|
const mowerImage = getMowerImageByModal(model);
|
|
2223
2209
|
const disabledImage = getDisabledMowerImageByModal(model);
|
|
@@ -4682,7 +4668,37 @@ var merge = createAssigner(function(object, source, srcIndex) {
|
|
|
4682
4668
|
* _.round(4060, -2);
|
|
4683
4669
|
* // => 4100
|
|
4684
4670
|
*/
|
|
4685
|
-
var round = createRound('round');
|
|
4671
|
+
var round = createRound('round');
|
|
4672
|
+
|
|
4673
|
+
/**
|
|
4674
|
+
* 工具模块类型定义
|
|
4675
|
+
*/
|
|
4676
|
+
/**
|
|
4677
|
+
* 路径段类型枚举
|
|
4678
|
+
*/
|
|
4679
|
+
var PathSegmentType;
|
|
4680
|
+
(function (PathSegmentType) {
|
|
4681
|
+
PathSegmentType["EDGE"] = "edge";
|
|
4682
|
+
PathSegmentType["MOWING"] = "mowing";
|
|
4683
|
+
PathSegmentType["TRANS"] = "trans";
|
|
4684
|
+
})(PathSegmentType || (PathSegmentType = {}));
|
|
4685
|
+
/**
|
|
4686
|
+
* 单位类型枚举
|
|
4687
|
+
*/
|
|
4688
|
+
var UnitsType;
|
|
4689
|
+
(function (UnitsType) {
|
|
4690
|
+
UnitsType["Metric"] = "Metric";
|
|
4691
|
+
UnitsType["Imperial"] = "Imperial";
|
|
4692
|
+
})(UnitsType || (UnitsType = {}));
|
|
4693
|
+
/**
|
|
4694
|
+
* 面积单位类型枚举
|
|
4695
|
+
*/
|
|
4696
|
+
var UnitsAreaType;
|
|
4697
|
+
(function (UnitsAreaType) {
|
|
4698
|
+
UnitsAreaType["SQUARE_METER"] = "m\u00B2";
|
|
4699
|
+
UnitsAreaType["SQUARE_FOOT"] = "ft\u00B2";
|
|
4700
|
+
UnitsAreaType["ACRE"] = "ac";
|
|
4701
|
+
})(UnitsAreaType || (UnitsAreaType = {}));
|
|
4686
4702
|
|
|
4687
4703
|
/**
|
|
4688
4704
|
* 默认航向相对于canvas的偏移角度: 航向默认是东
|
|
@@ -4757,17 +4773,6 @@ function formatNumberWithMetricPrefix(value, round = true, decimals = 2) {
|
|
|
4757
4773
|
return `${mathFn(value / 1000000000, decimals)}B`;
|
|
4758
4774
|
}
|
|
4759
4775
|
}
|
|
4760
|
-
var UnitsType;
|
|
4761
|
-
(function (UnitsType) {
|
|
4762
|
-
UnitsType["Metric"] = "metric";
|
|
4763
|
-
UnitsType["Imperial"] = "imperial";
|
|
4764
|
-
})(UnitsType || (UnitsType = {}));
|
|
4765
|
-
var UnitsAreaType;
|
|
4766
|
-
(function (UnitsAreaType) {
|
|
4767
|
-
UnitsAreaType["SQUARE_METER"] = "m\u00B2";
|
|
4768
|
-
UnitsAreaType["SQUARE_FOOT"] = "ft\u00B2";
|
|
4769
|
-
UnitsAreaType["ACRE"] = "ac";
|
|
4770
|
-
})(UnitsAreaType || (UnitsAreaType = {}));
|
|
4771
4776
|
/**
|
|
4772
4777
|
* 转换割草面积的方法
|
|
4773
4778
|
* @param area 面积数值(单位:m²)
|
|
@@ -4957,6 +4962,18 @@ class BoundaryBorderLayer extends BaseLayer {
|
|
|
4957
4962
|
this.level = LAYER_LEVELS.BOUNDARY_BORDER; // 中等层级
|
|
4958
4963
|
this.type = LAYER_DEFAULT_TYPE.BOUNDARY_BORDER;
|
|
4959
4964
|
this.boudaryBorderPaths = {};
|
|
4965
|
+
this.mowingBoundarys = [];
|
|
4966
|
+
}
|
|
4967
|
+
/**
|
|
4968
|
+
* 设置当前割草任务的边界
|
|
4969
|
+
*/
|
|
4970
|
+
setMowingBoundarys(mowingBoundarys) {
|
|
4971
|
+
if (!mowingBoundarys) {
|
|
4972
|
+
this.mowingBoundarys = this.elements?.map(item => item?.originalData?.id);
|
|
4973
|
+
}
|
|
4974
|
+
else {
|
|
4975
|
+
this.mowingBoundarys = mowingBoundarys;
|
|
4976
|
+
}
|
|
4960
4977
|
}
|
|
4961
4978
|
/**
|
|
4962
4979
|
* SVG渲染方法
|
|
@@ -5002,7 +5019,8 @@ class BoundaryBorderLayer extends BaseLayer {
|
|
|
5002
5019
|
* 创建直接路径(type=2)
|
|
5003
5020
|
*/
|
|
5004
5021
|
createDirectPath(svgGroup, points, style, id) {
|
|
5005
|
-
const
|
|
5022
|
+
const isMowing = this.mowingBoundarys.includes(Number(id));
|
|
5023
|
+
const strokeColor = isMowing ? style.mowingLineColor : style.lineColor;
|
|
5006
5024
|
const lineWidth = dp2px(style.lineWidth || 3);
|
|
5007
5025
|
const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
|
|
5008
5026
|
// 构建路径数据
|
|
@@ -5035,7 +5053,8 @@ class BoundaryBorderLayer extends BaseLayer {
|
|
|
5035
5053
|
* 使用PathMeasure逻辑创建平行路径(type=1)
|
|
5036
5054
|
*/
|
|
5037
5055
|
createParallelPathsWithMeasure(svgGroup, points, style, id) {
|
|
5038
|
-
const
|
|
5056
|
+
const isMowing = this.mowingBoundarys.includes(Number(id));
|
|
5057
|
+
const strokeColor = isMowing ? style.mowingLineColor : style.lineColor;
|
|
5039
5058
|
const lineWidth = dp2px(style.lineWidth || 3);
|
|
5040
5059
|
// 获取当前SVG的缩放级别,计算固定屏幕像素间距
|
|
5041
5060
|
const fixedScreenDistance = lineWidth; // 固定的屏幕像素距离
|
|
@@ -5381,6 +5400,14 @@ class BoundaryDataBuilder {
|
|
|
5381
5400
|
* 创建边界元素数据
|
|
5382
5401
|
*/
|
|
5383
5402
|
static create(type, coordinates, style) {
|
|
5403
|
+
const len = coordinates?.length || 0;
|
|
5404
|
+
const firstPoint = coordinates?.[0];
|
|
5405
|
+
const lastPoint = coordinates?.[len - 1];
|
|
5406
|
+
const isClosed = firstPoint?.[0] === lastPoint?.[0] && firstPoint?.[1] === lastPoint?.[1];
|
|
5407
|
+
// 如果地图没有闭合,则手动新增闭合点,避免border最后一部分没有闭合的情况
|
|
5408
|
+
if (!isClosed) {
|
|
5409
|
+
coordinates.push([firstPoint?.[0], firstPoint?.[1], lastPoint?.[2]]);
|
|
5410
|
+
}
|
|
5384
5411
|
return {
|
|
5385
5412
|
type,
|
|
5386
5413
|
coordinates,
|
|
@@ -5783,8 +5810,13 @@ class MapDataProcessor {
|
|
|
5783
5810
|
// 为ObstacleData创建兼容的MapElement接口
|
|
5784
5811
|
const mapElement = element;
|
|
5785
5812
|
const obstacleElement = ObstacleDataBuilder.fromMapElement(mapElement, this.mapConfig.obstacle);
|
|
5786
|
-
if (obstacleElement)
|
|
5813
|
+
if (obstacleElement) {
|
|
5787
5814
|
result.push(obstacleElement);
|
|
5815
|
+
const { addObstacles } = useSubBoundaryBorderStore.getState();
|
|
5816
|
+
addObstacles(`obstacle-${obstacleElement.originalData.id}`, {
|
|
5817
|
+
...obstacleElement,
|
|
5818
|
+
});
|
|
5819
|
+
}
|
|
5788
5820
|
}
|
|
5789
5821
|
catch (error) {
|
|
5790
5822
|
console.warn(`Error processing OBSTACLE element:`, element, error);
|
|
@@ -5845,8 +5877,13 @@ class MapDataProcessor {
|
|
|
5845
5877
|
element.direction !== undefined) {
|
|
5846
5878
|
const mapElement = element;
|
|
5847
5879
|
const svgElement = SvgElementDataBuilder.fromMapElement(mapElement, this.mapConfig.doodle);
|
|
5848
|
-
if (svgElement)
|
|
5880
|
+
if (svgElement) {
|
|
5849
5881
|
result.push(svgElement);
|
|
5882
|
+
const { addSvgElements } = useSubBoundaryBorderStore.getState();
|
|
5883
|
+
addSvgElements(`time-limit-obstacle-${svgElement.originalData.id}`, {
|
|
5884
|
+
...svgElement,
|
|
5885
|
+
});
|
|
5886
|
+
}
|
|
5850
5887
|
}
|
|
5851
5888
|
// 如果有points数据,按传统方式绘制
|
|
5852
5889
|
else if ('points' in element &&
|
|
@@ -5855,8 +5892,13 @@ class MapDataProcessor {
|
|
|
5855
5892
|
element.points.length >= 3) {
|
|
5856
5893
|
const mapElement = element;
|
|
5857
5894
|
const polygonElement = ObstacleDataBuilder.createTimeLimitObstacle(mapElement, this.mapConfig.obstacle);
|
|
5858
|
-
if (polygonElement)
|
|
5895
|
+
if (polygonElement) {
|
|
5859
5896
|
result.push(polygonElement);
|
|
5897
|
+
const { addObstacles } = useSubBoundaryBorderStore.getState();
|
|
5898
|
+
addObstacles(`time-limit-obstacle-${polygonElement.originalData.id}`, {
|
|
5899
|
+
...polygonElement,
|
|
5900
|
+
});
|
|
5901
|
+
}
|
|
5860
5902
|
}
|
|
5861
5903
|
}
|
|
5862
5904
|
catch (error) {
|
|
@@ -6006,7 +6048,6 @@ class PathDataProcessor {
|
|
|
6006
6048
|
elements,
|
|
6007
6049
|
};
|
|
6008
6050
|
});
|
|
6009
|
-
console.log('result->', result);
|
|
6010
6051
|
return result;
|
|
6011
6052
|
}
|
|
6012
6053
|
}
|
|
@@ -6016,7 +6057,7 @@ class PathDataProcessor {
|
|
|
6016
6057
|
* 专门处理边界标签的创建、定位和管理
|
|
6017
6058
|
*/
|
|
6018
6059
|
class BoundaryLabelsManager {
|
|
6019
|
-
constructor(svgView, boundaryData) {
|
|
6060
|
+
constructor(svgView, boundaryData, { unitType, language }) {
|
|
6020
6061
|
this.container = null;
|
|
6021
6062
|
this.overlayDiv = null;
|
|
6022
6063
|
this.globalClickHandler = null;
|
|
@@ -6027,6 +6068,8 @@ class BoundaryLabelsManager {
|
|
|
6027
6068
|
this.svgView = svgView;
|
|
6028
6069
|
this.boundaryData = boundaryData;
|
|
6029
6070
|
this.initializeContainer();
|
|
6071
|
+
this.unitType = unitType;
|
|
6072
|
+
this.language = language;
|
|
6030
6073
|
}
|
|
6031
6074
|
/**
|
|
6032
6075
|
* 初始化容器
|
|
@@ -6126,9 +6169,10 @@ class BoundaryLabelsManager {
|
|
|
6126
6169
|
this.currentExpandedBoundaryId === boundary.id ? 'block' : 'none';
|
|
6127
6170
|
extendedContent.style.borderTop = '1px solid rgba(255,255,255,0.2)';
|
|
6128
6171
|
extendedContent.style.paddingTop = '6px';
|
|
6172
|
+
console.log('this.unitType->', this.unitType);
|
|
6129
6173
|
// 面积信息
|
|
6130
|
-
const totalArea = convertAreaByUnits(boundary.area || 0,
|
|
6131
|
-
const finishedArea = convertAreaByUnits(boundary.finishedArea || 0,
|
|
6174
|
+
const totalArea = convertAreaByUnits(boundary.area || 0, this.unitType);
|
|
6175
|
+
const finishedArea = convertAreaByUnits(boundary.finishedArea || 0, this.unitType);
|
|
6132
6176
|
const coverageText = `Coverage: ${finishedArea.value}/${totalArea.value}`;
|
|
6133
6177
|
// 日期信息
|
|
6134
6178
|
const dateText = formatBoundaryDateText(boundary.endTime || 0);
|
|
@@ -6194,7 +6238,6 @@ class BoundaryLabelsManager {
|
|
|
6194
6238
|
this.collapseOtherLabels(boundaryId);
|
|
6195
6239
|
// 展开当前标签
|
|
6196
6240
|
extendedContent.style.display = 'block';
|
|
6197
|
-
labelDiv.style.whiteSpace = 'normal';
|
|
6198
6241
|
this.currentExpandedBoundaryId = boundaryId;
|
|
6199
6242
|
}
|
|
6200
6243
|
/**
|
|
@@ -6237,7 +6280,6 @@ class BoundaryLabelsManager {
|
|
|
6237
6280
|
* @param viewBox SVG的viewBox信息
|
|
6238
6281
|
*/
|
|
6239
6282
|
updatePositionsWithPrecomputedData(divWidth, divHeight, viewBox) {
|
|
6240
|
-
console.log('updatePositionsWithPrecomputedData----->', this.rotation);
|
|
6241
6283
|
if (!this.container || !this.svgView)
|
|
6242
6284
|
return;
|
|
6243
6285
|
const dw = parseFloat(this.svgView.getSVG().getAttribute('width')) || divWidth;
|
|
@@ -6431,12 +6473,6 @@ class BoundaryLabelsManager {
|
|
|
6431
6473
|
this.container.style.display = visible ? 'block' : 'none';
|
|
6432
6474
|
}
|
|
6433
6475
|
}
|
|
6434
|
-
/**
|
|
6435
|
-
* 获取边界数据
|
|
6436
|
-
*/
|
|
6437
|
-
getBoundaryData() {
|
|
6438
|
-
return this.boundaryData;
|
|
6439
|
-
}
|
|
6440
6476
|
/**
|
|
6441
6477
|
* 根据ID获取特定边界的标签元素
|
|
6442
6478
|
*/
|
|
@@ -6486,18 +6522,6 @@ class BoundaryLabelsManager {
|
|
|
6486
6522
|
}
|
|
6487
6523
|
});
|
|
6488
6524
|
}
|
|
6489
|
-
/**
|
|
6490
|
-
* 重置标签层级(公共方法)
|
|
6491
|
-
*/
|
|
6492
|
-
resetZIndex() {
|
|
6493
|
-
this.resetLabelZIndex();
|
|
6494
|
-
}
|
|
6495
|
-
/**
|
|
6496
|
-
* 获取层级常量(静态方法)
|
|
6497
|
-
*/
|
|
6498
|
-
static getZIndexConstants() {
|
|
6499
|
-
return BoundaryLabelsManager.Z_INDEX;
|
|
6500
|
-
}
|
|
6501
6525
|
/**
|
|
6502
6526
|
* 设置标签旋转角度,使其与地图旋转相反,保持水平状态
|
|
6503
6527
|
* @param rotation 地图的旋转角度(度)
|
|
@@ -6514,19 +6538,6 @@ class BoundaryLabelsManager {
|
|
|
6514
6538
|
labelElement.style.transform = `translate(-50%, -50%) rotate(${counterRotation}deg)`;
|
|
6515
6539
|
});
|
|
6516
6540
|
}
|
|
6517
|
-
/**
|
|
6518
|
-
* 重置标签旋转角度
|
|
6519
|
-
*/
|
|
6520
|
-
resetLabelsRotation() {
|
|
6521
|
-
if (!this.container)
|
|
6522
|
-
return;
|
|
6523
|
-
const labels = this.container.querySelectorAll('.boundary-label');
|
|
6524
|
-
labels.forEach((label) => {
|
|
6525
|
-
const labelElement = label;
|
|
6526
|
-
// 重置为默认的居中变换
|
|
6527
|
-
labelElement.style.transform = 'translate(-50%, -50%)';
|
|
6528
|
-
});
|
|
6529
|
-
}
|
|
6530
6541
|
}
|
|
6531
6542
|
// 简化的层级定义
|
|
6532
6543
|
BoundaryLabelsManager.Z_INDEX = {
|
|
@@ -6702,26 +6713,6 @@ class ChargingPileManager {
|
|
|
6702
6713
|
this.container.innerHTML = '';
|
|
6703
6714
|
}
|
|
6704
6715
|
}
|
|
6705
|
-
/**
|
|
6706
|
-
* 设置可见性
|
|
6707
|
-
*/
|
|
6708
|
-
setVisible(visible) {
|
|
6709
|
-
if (this.container) {
|
|
6710
|
-
this.container.style.display = visible ? 'block' : 'none';
|
|
6711
|
-
}
|
|
6712
|
-
}
|
|
6713
|
-
/**
|
|
6714
|
-
* 获取充电桩数量
|
|
6715
|
-
*/
|
|
6716
|
-
getElementCount() {
|
|
6717
|
-
return this.chargingPileElements.length;
|
|
6718
|
-
}
|
|
6719
|
-
/**
|
|
6720
|
-
* 充电桩不需要动态层级调整(为了接口统一而保留)
|
|
6721
|
-
*/
|
|
6722
|
-
resetZIndex() {
|
|
6723
|
-
// 充电桩层级始终保持固定,无需重置
|
|
6724
|
-
}
|
|
6725
6716
|
/**
|
|
6726
6717
|
* 销毁管理器
|
|
6727
6718
|
*/
|
|
@@ -6744,21 +6735,10 @@ class ChargingPileManager {
|
|
|
6744
6735
|
pileElement.style.transform = `translate(-50%, -50%) rotate(${this.originalRotation - this.rotation}deg)`;
|
|
6745
6736
|
});
|
|
6746
6737
|
}
|
|
6747
|
-
/**
|
|
6748
|
-
* 重置充电桩旋转角度
|
|
6749
|
-
*/
|
|
6750
|
-
resetRotation() {
|
|
6751
|
-
this.rotation = 0;
|
|
6752
|
-
const allContainers = this.container.querySelectorAll('.charging-pile');
|
|
6753
|
-
allContainers.forEach((container) => {
|
|
6754
|
-
const pileElement = container;
|
|
6755
|
-
pileElement.style.transform = `translate(-50%, -50%) rotate(${this.originalRotation - this.rotation}deg)`;
|
|
6756
|
-
});
|
|
6757
|
-
}
|
|
6758
6738
|
}
|
|
6759
6739
|
// 简化的层级定义 - 充电桩只需要一个固定层级
|
|
6760
6740
|
ChargingPileManager.Z_INDEX = {
|
|
6761
|
-
CHARGING_PILE:
|
|
6741
|
+
CHARGING_PILE: 750, // 充电桩图标固定层级
|
|
6762
6742
|
};
|
|
6763
6743
|
|
|
6764
6744
|
/**
|
|
@@ -7140,32 +7120,6 @@ class AntennaManager {
|
|
|
7140
7120
|
this.container.innerHTML = '';
|
|
7141
7121
|
}
|
|
7142
7122
|
}
|
|
7143
|
-
/**
|
|
7144
|
-
* 设置可见性
|
|
7145
|
-
*/
|
|
7146
|
-
setVisible(visible) {
|
|
7147
|
-
if (this.container) {
|
|
7148
|
-
this.container.style.display = visible ? 'block' : 'none';
|
|
7149
|
-
}
|
|
7150
|
-
}
|
|
7151
|
-
/**
|
|
7152
|
-
* 获取天线数量
|
|
7153
|
-
*/
|
|
7154
|
-
getElementCount() {
|
|
7155
|
-
return this.antennaElements.length;
|
|
7156
|
-
}
|
|
7157
|
-
/**
|
|
7158
|
-
* 重置天线层级(公共方法)
|
|
7159
|
-
*/
|
|
7160
|
-
resetZIndex() {
|
|
7161
|
-
this.resetAntennaZIndex();
|
|
7162
|
-
}
|
|
7163
|
-
/**
|
|
7164
|
-
* 获取层级常量(静态方法)
|
|
7165
|
-
*/
|
|
7166
|
-
static getZIndexConstants() {
|
|
7167
|
-
return AntennaManager.Z_INDEX;
|
|
7168
|
-
}
|
|
7169
7123
|
/**
|
|
7170
7124
|
* 销毁管理器
|
|
7171
7125
|
*/
|
|
@@ -7193,21 +7147,10 @@ class AntennaManager {
|
|
|
7193
7147
|
antennaContainer.style.transform = `translate(-50%, -50%) rotate(${-this.rotation}deg)`;
|
|
7194
7148
|
});
|
|
7195
7149
|
}
|
|
7196
|
-
/**
|
|
7197
|
-
* 重置天线旋转角度
|
|
7198
|
-
*/
|
|
7199
|
-
resetRotation() {
|
|
7200
|
-
this.rotation = 0;
|
|
7201
|
-
const allContainers = this.container.querySelectorAll('.antenna-container-item');
|
|
7202
|
-
allContainers.forEach((container) => {
|
|
7203
|
-
const antennaContainer = container;
|
|
7204
|
-
antennaContainer.style.transform = `translate(-50%, -50%) rotate(${-this.rotation}deg)`;
|
|
7205
|
-
});
|
|
7206
|
-
}
|
|
7207
7150
|
}
|
|
7208
7151
|
// 简化的层级定义
|
|
7209
7152
|
AntennaManager.Z_INDEX = {
|
|
7210
|
-
DEFAULT:
|
|
7153
|
+
DEFAULT: 800, // 默认层级
|
|
7211
7154
|
ACTIVE: 9999, // 点击激活时的高层级
|
|
7212
7155
|
};
|
|
7213
7156
|
|
|
@@ -7259,7 +7202,7 @@ const EDIT_BEHAVIOR = {
|
|
|
7259
7202
|
};
|
|
7260
7203
|
|
|
7261
7204
|
class MowerPositionManager {
|
|
7262
|
-
constructor(svgView, mowerPositionConfig, overlayDiv, onAnimationComplete, onMowingPositionChange) {
|
|
7205
|
+
constructor(svgView, mowerPositionConfig, modelType, overlayDiv, onAnimationComplete, onMowingPositionChange) {
|
|
7263
7206
|
this.container = null;
|
|
7264
7207
|
this.overlayDiv = null;
|
|
7265
7208
|
this.mowerElement = null;
|
|
@@ -7277,6 +7220,7 @@ class MowerPositionManager {
|
|
|
7277
7220
|
this.onlyUpdateTheta = false;
|
|
7278
7221
|
this.svgView = svgView;
|
|
7279
7222
|
this.mowerPositionConfig = mowerPositionConfig;
|
|
7223
|
+
this.modelType = modelType;
|
|
7280
7224
|
this.overlayDiv = overlayDiv;
|
|
7281
7225
|
this.onAnimationComplete = onAnimationComplete;
|
|
7282
7226
|
this.onMowingPositionChange = onMowingPositionChange;
|
|
@@ -7331,6 +7275,7 @@ class MowerPositionManager {
|
|
|
7331
7275
|
}
|
|
7332
7276
|
this.mowerElement.appendChild(imgElement);
|
|
7333
7277
|
this.container.appendChild(this.mowerElement);
|
|
7278
|
+
this.updatePosition(this.mowerPositionConfig);
|
|
7334
7279
|
}
|
|
7335
7280
|
/**
|
|
7336
7281
|
* 设置叠加层div引用(用于坐标转换)
|
|
@@ -7351,11 +7296,22 @@ class MowerPositionManager {
|
|
|
7351
7296
|
if (!chargingPilesPositionConfig)
|
|
7352
7297
|
return;
|
|
7353
7298
|
this.mowerPositionConfig = chargingPilesPositionConfig;
|
|
7354
|
-
|
|
7299
|
+
const positonOutOfRange = isOutOfRange(chargingPilesPositionConfig);
|
|
7300
|
+
const positionInValid = isInvalidPosition(chargingPilesPositionConfig);
|
|
7301
|
+
let postureX = 0;
|
|
7302
|
+
let postureY = 0;
|
|
7303
|
+
let postureTheta = 0;
|
|
7355
7304
|
const lastPosition = this.lastPosition;
|
|
7356
|
-
|
|
7357
|
-
|
|
7358
|
-
|
|
7305
|
+
if (positonOutOfRange || positionInValid) {
|
|
7306
|
+
postureX = lastPosition?.x || 0;
|
|
7307
|
+
postureY = lastPosition?.y || 0;
|
|
7308
|
+
postureTheta = lastPosition?.rotation || 0;
|
|
7309
|
+
}
|
|
7310
|
+
else {
|
|
7311
|
+
postureX = chargingPilesPositionConfig.postureX || 0;
|
|
7312
|
+
postureY = chargingPilesPositionConfig.postureY || 0;
|
|
7313
|
+
postureTheta = chargingPilesPositionConfig.postureTheta || 0;
|
|
7314
|
+
}
|
|
7359
7315
|
// 检查是否需要更新图片
|
|
7360
7316
|
this.updateMowerImage(chargingPilesPositionConfig);
|
|
7361
7317
|
// 立即更新位置
|
|
@@ -7365,12 +7321,13 @@ class MowerPositionManager {
|
|
|
7365
7321
|
* 更新割草机位置
|
|
7366
7322
|
*/
|
|
7367
7323
|
updatePosition(positionConfig, animationTime = 0) {
|
|
7368
|
-
console.log('manager updatePosition----->', positionConfig);
|
|
7369
7324
|
// 检查是否需要更新图片
|
|
7370
7325
|
this.updateMowerImage(positionConfig);
|
|
7371
|
-
|
|
7372
|
-
|
|
7373
|
-
const
|
|
7326
|
+
// 更新配置
|
|
7327
|
+
this.mowerPositionConfig = positionConfig;
|
|
7328
|
+
const postureX = positionConfig?.postureX || this.lastPosition?.x || 0;
|
|
7329
|
+
const postureY = positionConfig?.postureY || this.lastPosition?.y || 0;
|
|
7330
|
+
const postureTheta = positionConfig?.postureTheta || this.lastPosition?.rotation || 0;
|
|
7374
7331
|
// 停止当前动画(如果有)
|
|
7375
7332
|
this.stopAnimation();
|
|
7376
7333
|
// 第一个点
|
|
@@ -7391,8 +7348,6 @@ class MowerPositionManager {
|
|
|
7391
7348
|
// 立即更新位置
|
|
7392
7349
|
this.setElementPosition(positionConfig.postureX, positionConfig.postureY, positionConfig.postureTheta);
|
|
7393
7350
|
}
|
|
7394
|
-
// 更新配置
|
|
7395
|
-
this.mowerPositionConfig = positionConfig;
|
|
7396
7351
|
}
|
|
7397
7352
|
/**
|
|
7398
7353
|
* 更新割草机图片
|
|
@@ -7403,9 +7358,14 @@ class MowerPositionManager {
|
|
|
7403
7358
|
const imgElement = this.mowerElement.querySelector('img');
|
|
7404
7359
|
if (!imgElement)
|
|
7405
7360
|
return;
|
|
7406
|
-
const imageSrc = getMowerImage(positonConfig);
|
|
7361
|
+
const imageSrc = getMowerImage(positonConfig, this.modelType);
|
|
7407
7362
|
if (imageSrc) {
|
|
7408
7363
|
imgElement.src = imageSrc;
|
|
7364
|
+
imgElement.style.display = 'block';
|
|
7365
|
+
}
|
|
7366
|
+
else {
|
|
7367
|
+
imgElement.style.display = 'none';
|
|
7368
|
+
return;
|
|
7409
7369
|
}
|
|
7410
7370
|
}
|
|
7411
7371
|
/**
|
|
@@ -7415,17 +7375,9 @@ class MowerPositionManager {
|
|
|
7415
7375
|
const { x: pointX, y: pointY } = convertCoordinate(x, y);
|
|
7416
7376
|
const targetPixelPosition = this.convertMapCoordinateToOverlayPixel(pointX, pointY);
|
|
7417
7377
|
const targetRotation = radToDegree(theta);
|
|
7418
|
-
|
|
7419
|
-
|
|
7420
|
-
|
|
7421
|
-
const positionValid = isInvalidPosition({
|
|
7422
|
-
postureX: x,
|
|
7423
|
-
postureY: y,
|
|
7424
|
-
postureTheta: theta,
|
|
7425
|
-
});
|
|
7426
|
-
if (!positonOutOfRange && !positionValid) {
|
|
7427
|
-
this.lastPosition = { x, y, rotation: theta };
|
|
7428
|
-
}
|
|
7378
|
+
this.currentPosition = { x: x, y: y, rotation: theta };
|
|
7379
|
+
this.lastPosition = { x, y, rotation: theta };
|
|
7380
|
+
// console.log('setElementPosition', x, y, theta, targetRotation, positonOutOfRange, positionValid, targetPixelPosition);
|
|
7429
7381
|
if (!this.mowerElement)
|
|
7430
7382
|
return;
|
|
7431
7383
|
this.mowerElement.style.left = `${targetPixelPosition?.x}px`;
|
|
@@ -7451,15 +7403,29 @@ class MowerPositionManager {
|
|
|
7451
7403
|
startAnimationToPosition(positionConfig, duration) {
|
|
7452
7404
|
if (!this.mowerElement || !this.currentPosition)
|
|
7453
7405
|
return;
|
|
7454
|
-
this.startPosition = {
|
|
7455
|
-
...this.currentPosition,
|
|
7456
|
-
rotation: radNormalize(this.currentPosition.rotation),
|
|
7457
|
-
};
|
|
7458
7406
|
this.targetPosition = {
|
|
7459
7407
|
x: positionConfig.postureX,
|
|
7460
7408
|
y: positionConfig.postureY,
|
|
7461
7409
|
rotation: positionConfig.postureTheta,
|
|
7462
7410
|
};
|
|
7411
|
+
const isTargetPositionInvalid = isInvalidPosition({
|
|
7412
|
+
postureX: this.targetPosition.x,
|
|
7413
|
+
postureY: this.targetPosition.y,
|
|
7414
|
+
postureTheta: this.targetPosition.rotation,
|
|
7415
|
+
});
|
|
7416
|
+
const isTargetPositionOutOfRange = isOutOfRange({
|
|
7417
|
+
postureX: this.targetPosition.x,
|
|
7418
|
+
postureY: this.targetPosition.y,
|
|
7419
|
+
postureTheta: this.targetPosition.rotation,
|
|
7420
|
+
});
|
|
7421
|
+
// 如果目标坐标点不合理,则舍弃不使用
|
|
7422
|
+
if (isTargetPositionInvalid || isTargetPositionOutOfRange) {
|
|
7423
|
+
return;
|
|
7424
|
+
}
|
|
7425
|
+
this.startPosition = {
|
|
7426
|
+
...this.currentPosition,
|
|
7427
|
+
rotation: radNormalize(this.currentPosition.rotation),
|
|
7428
|
+
};
|
|
7463
7429
|
this.animationDuration = duration;
|
|
7464
7430
|
this.startTime = window.performance.now();
|
|
7465
7431
|
this.isAnimating = true;
|
|
@@ -7489,7 +7455,7 @@ class MowerPositionManager {
|
|
|
7489
7455
|
* 动画步骤
|
|
7490
7456
|
*/
|
|
7491
7457
|
animateStep() {
|
|
7492
|
-
if (!this.isAnimating || !this.
|
|
7458
|
+
if (!this.isAnimating || !this.targetPosition || !this.startPosition)
|
|
7493
7459
|
return;
|
|
7494
7460
|
const currentTime = window.performance.now();
|
|
7495
7461
|
const elapsed = currentTime - this.startTime;
|
|
@@ -7500,25 +7466,22 @@ class MowerPositionManager {
|
|
|
7500
7466
|
const currentX = this.startPosition.x + this.deltaPosition.x * easedProgress;
|
|
7501
7467
|
const currentY = this.startPosition.y + this.deltaPosition.y * easedProgress;
|
|
7502
7468
|
const currentRotation = this.startPosition.rotation + this.deltaPosition.rotation * easedProgress;
|
|
7503
|
-
this.currentPosition = { x: currentX, y: currentY, rotation: currentRotation };
|
|
7504
7469
|
// 假设在这里进行更新路径数据
|
|
7505
7470
|
if (this.onMowingPositionChange) {
|
|
7506
7471
|
this.onMowingPositionChange({
|
|
7507
7472
|
x: currentX,
|
|
7508
7473
|
y: currentY,
|
|
7509
|
-
vehicleState: this.mowerPositionConfig
|
|
7474
|
+
vehicleState: this.mowerPositionConfig?.vehicleState,
|
|
7510
7475
|
});
|
|
7511
7476
|
}
|
|
7512
|
-
// console.log('animateStep
|
|
7513
|
-
|
|
7477
|
+
// console.log('animateStep-->', this.startPosition, this.deltaPosition, this.targetPosition, easedProgress)
|
|
7478
|
+
this.setElementPosition(currentX, currentY, currentRotation);
|
|
7514
7479
|
// 继续动画或结束
|
|
7515
7480
|
if (progress < 1) {
|
|
7516
7481
|
// 设置当前位置
|
|
7517
|
-
this.setElementPosition(currentX, currentY, currentRotation);
|
|
7518
7482
|
this.animationId = window.requestAnimationFrame(() => this.animateStep());
|
|
7519
7483
|
}
|
|
7520
7484
|
else {
|
|
7521
|
-
this.setElementPosition(currentX, currentY, currentRotation);
|
|
7522
7485
|
// 动画完成
|
|
7523
7486
|
this.stopAnimation();
|
|
7524
7487
|
// 通知动画完成
|
|
@@ -7565,12 +7528,6 @@ class MowerPositionManager {
|
|
|
7565
7528
|
this.container.style.display = visible ? 'block' : 'none';
|
|
7566
7529
|
}
|
|
7567
7530
|
}
|
|
7568
|
-
/**
|
|
7569
|
-
* 检查是否正在动画中
|
|
7570
|
-
*/
|
|
7571
|
-
getIsAnimating() {
|
|
7572
|
-
return this.isAnimating;
|
|
7573
|
-
}
|
|
7574
7531
|
/**
|
|
7575
7532
|
* 销毁管理器
|
|
7576
7533
|
*/
|
|
@@ -7632,10 +7589,34 @@ function throttleAdvanced(func, delay, options = { leading: true, trailing: true
|
|
|
7632
7589
|
}
|
|
7633
7590
|
};
|
|
7634
7591
|
}
|
|
7592
|
+
/**
|
|
7593
|
+
* 检测当前设备是否为移动设备
|
|
7594
|
+
* @returns {boolean} 如果是移动设备返回true,否则返回false
|
|
7595
|
+
*/
|
|
7596
|
+
function isMobileDevice() {
|
|
7597
|
+
// 确保在浏览器环境中运行
|
|
7598
|
+
if (typeof window === 'undefined' || typeof navigator === 'undefined') {
|
|
7599
|
+
return false;
|
|
7600
|
+
}
|
|
7601
|
+
// 检查用户代理字符串
|
|
7602
|
+
const userAgent = navigator.userAgent.toLowerCase();
|
|
7603
|
+
const mobileKeywords = [
|
|
7604
|
+
'android', 'webos', 'iphone', 'ipad', 'ipod',
|
|
7605
|
+
'blackberry', 'windows phone', 'mobile'
|
|
7606
|
+
];
|
|
7607
|
+
const isMobileUserAgent = mobileKeywords.some(keyword => userAgent.includes(keyword));
|
|
7608
|
+
// 检查触摸屏支持
|
|
7609
|
+
const hasTouchScreen = 'ontouchstart' in window ||
|
|
7610
|
+
(navigator.maxTouchPoints && navigator.maxTouchPoints > 0);
|
|
7611
|
+
// 检查屏幕尺寸(移动设备通常屏幕较小)
|
|
7612
|
+
const isSmallScreen = window.innerWidth <= 768;
|
|
7613
|
+
// 综合判断:用户代理包含移动设备关键词,或者有触摸屏且屏幕较小
|
|
7614
|
+
return isMobileUserAgent || (hasTouchScreen && isSmallScreen);
|
|
7615
|
+
}
|
|
7635
7616
|
|
|
7636
7617
|
// Google Maps 叠加层类 - 带编辑功能
|
|
7637
7618
|
class MowerMapOverlay {
|
|
7638
|
-
constructor(bounds, mapData, partitionBoundary, mowerPositionConfig, pathData, isEditMode = false, mapConfig = {}, antennaConfig = {}, mowPartitionData = null, defaultTransform, onMapLoad, onPathLoad, dragCallbacks) {
|
|
7619
|
+
constructor(bounds, mapData, partitionBoundary, mowerPositionConfig, modelType, pathData, isEditMode = false, unitType = UnitsType.Imperial, language = 'en', mapConfig = {}, antennaConfig = {}, mowPartitionData = null, defaultTransform, onMapLoad, onPathLoad, dragCallbacks) {
|
|
7639
7620
|
this.div = null;
|
|
7640
7621
|
this.svgMapView = null;
|
|
7641
7622
|
this.offscreenContainer = null;
|
|
@@ -7683,6 +7664,8 @@ class MowerMapOverlay {
|
|
|
7683
7664
|
this.partitionBoundary = partitionBoundary;
|
|
7684
7665
|
this.pathData = pathData;
|
|
7685
7666
|
this.isEditMode = isEditMode;
|
|
7667
|
+
this.unitType = unitType;
|
|
7668
|
+
this.language = language;
|
|
7686
7669
|
this.mapConfig = mapConfig;
|
|
7687
7670
|
this.antennaConfig = antennaConfig;
|
|
7688
7671
|
this.onMapLoad = onMapLoad;
|
|
@@ -7690,6 +7673,7 @@ class MowerMapOverlay {
|
|
|
7690
7673
|
this.dragCallbacks = dragCallbacks;
|
|
7691
7674
|
this.mowerPositionConfig = mowerPositionConfig;
|
|
7692
7675
|
this.mowPartitionData = mowPartitionData;
|
|
7676
|
+
this.modelType = modelType;
|
|
7693
7677
|
// 设置默认的transform
|
|
7694
7678
|
if (defaultTransform) {
|
|
7695
7679
|
this.defaultTransform = {
|
|
@@ -7722,7 +7706,6 @@ class MowerMapOverlay {
|
|
|
7722
7706
|
this.boundaryData = generateBoundaryData(mapData, pathData);
|
|
7723
7707
|
}
|
|
7724
7708
|
updatePosition(positionConfig, animationTime = 2200) {
|
|
7725
|
-
console.log('updatePosition==', positionConfig, animationTime);
|
|
7726
7709
|
// 保存当前动画时长
|
|
7727
7710
|
this.currentAnimationTime = animationTime;
|
|
7728
7711
|
// 标记是否为用户动画(大于0表示用户主动触发的动画)
|
|
@@ -7735,7 +7718,7 @@ class MowerMapOverlay {
|
|
|
7735
7718
|
}
|
|
7736
7719
|
}
|
|
7737
7720
|
updatePositionByLastPosition(chargingPilesPositionConfig) {
|
|
7738
|
-
|
|
7721
|
+
this.mowerPositionConfig = chargingPilesPositionConfig;
|
|
7739
7722
|
// 更新配置
|
|
7740
7723
|
if (this.mowerPositionManager) {
|
|
7741
7724
|
this.mowerPositionManager.updatePositionByLastPosition(chargingPilesPositionConfig);
|
|
@@ -7756,32 +7739,24 @@ class MowerMapOverlay {
|
|
|
7756
7739
|
return this.overlayView ? this.overlayView.getPanes() : null;
|
|
7757
7740
|
}
|
|
7758
7741
|
resetBorderLayerHighlight() {
|
|
7742
|
+
this.mowPartitionData = null;
|
|
7759
7743
|
const boundaryBorderLayer = this.svgMapView?.getLayer(LAYER_DEFAULT_TYPE.BOUNDARY_BORDER);
|
|
7760
|
-
|
|
7761
|
-
|
|
7762
|
-
|
|
7763
|
-
|
|
7764
|
-
path.setAttribute('stroke', BOUNDARY_STYLES.lineColor);
|
|
7765
|
-
});
|
|
7766
|
-
}
|
|
7767
|
-
});
|
|
7744
|
+
if (!boundaryBorderLayer)
|
|
7745
|
+
return;
|
|
7746
|
+
boundaryBorderLayer.setMowingBoundarys([]);
|
|
7747
|
+
this.svgMapView?.renderLayer(LAYER_DEFAULT_TYPE.BOUNDARY_BORDER);
|
|
7768
7748
|
}
|
|
7769
7749
|
setBorderLayerHighlight(mowPartitionData) {
|
|
7770
7750
|
this.mowPartitionData = mowPartitionData;
|
|
7771
7751
|
const boundaryBorderLayer = this.svgMapView?.getLayer(LAYER_DEFAULT_TYPE.BOUNDARY_BORDER);
|
|
7772
7752
|
const partitionIds = mowPartitionData?.partitionIds || [];
|
|
7773
|
-
|
|
7774
|
-
|
|
7775
|
-
|
|
7776
|
-
|
|
7777
|
-
if (boundaryBorderPaths) {
|
|
7778
|
-
boundaryBorderPaths.forEach((path) => {
|
|
7779
|
-
path.setAttribute('stroke', BOUNDARY_STYLES.mowingLineColor);
|
|
7780
|
-
});
|
|
7781
|
-
}
|
|
7782
|
-
}
|
|
7753
|
+
if (!boundaryBorderLayer)
|
|
7754
|
+
return;
|
|
7755
|
+
boundaryBorderLayer.setMowingBoundarys(partitionIds);
|
|
7756
|
+
this.svgMapView?.renderLayer(LAYER_DEFAULT_TYPE.BOUNDARY_BORDER);
|
|
7783
7757
|
}
|
|
7784
7758
|
onAdd() {
|
|
7759
|
+
console.log('onAdd');
|
|
7785
7760
|
// 创建包含SVG的div
|
|
7786
7761
|
this.div = document.createElement('div');
|
|
7787
7762
|
this.div.style.borderStyle = 'none';
|
|
@@ -7803,6 +7778,7 @@ class MowerMapOverlay {
|
|
|
7803
7778
|
this.createBoundaryLabelsManager();
|
|
7804
7779
|
// 创建割草机位置管理器
|
|
7805
7780
|
this.createMowerPositionManager();
|
|
7781
|
+
this.setManagerRotation(this.defaultTransform.rotation);
|
|
7806
7782
|
// 如果处于编辑模式,创建编辑界面
|
|
7807
7783
|
if (this.isEditMode) {
|
|
7808
7784
|
this.createEditInterface();
|
|
@@ -7841,16 +7817,6 @@ class MowerMapOverlay {
|
|
|
7841
7817
|
const map = this.getMap();
|
|
7842
7818
|
if (!map || !this.svgMapView)
|
|
7843
7819
|
return;
|
|
7844
|
-
// const currentZoom = map.getZoom();
|
|
7845
|
-
// const center = map.getCenter();
|
|
7846
|
-
// 基础公式:像素/米 = 156543.03392 * cos(latitude) / (2 ^ zoom)
|
|
7847
|
-
// const metersPerPixel =
|
|
7848
|
-
// (156543.03392 * Math.cos((center.lat() * Math.PI) / 180)) / Math.pow(2, currentZoom);
|
|
7849
|
-
// 缩放比例 = 1 / 米/像素
|
|
7850
|
-
// const scale = (1 / metersPerPixel) * 50;
|
|
7851
|
-
// 应用缩放到SVG
|
|
7852
|
-
// this.svgMapView.setZoom(scale);
|
|
7853
|
-
// 当缩放变化时,重新绘制以确保位置正确
|
|
7854
7820
|
this.draw();
|
|
7855
7821
|
}
|
|
7856
7822
|
// 创建边界标签管理器
|
|
@@ -7858,7 +7824,10 @@ class MowerMapOverlay {
|
|
|
7858
7824
|
if (!this.div || !this.svgMapView)
|
|
7859
7825
|
return;
|
|
7860
7826
|
// 创建边界标签管理器
|
|
7861
|
-
this.boundaryLabelsManager = new BoundaryLabelsManager(this.svgMapView, this.boundaryData
|
|
7827
|
+
this.boundaryLabelsManager = new BoundaryLabelsManager(this.svgMapView, this.boundaryData, {
|
|
7828
|
+
unitType: this.unitType,
|
|
7829
|
+
language: this.language,
|
|
7830
|
+
});
|
|
7862
7831
|
// 设置叠加层div引用
|
|
7863
7832
|
this.boundaryLabelsManager.setOverlayDiv(this.div);
|
|
7864
7833
|
// 添加所有边界标签
|
|
@@ -7902,9 +7871,7 @@ class MowerMapOverlay {
|
|
|
7902
7871
|
if (!this.div || !this.svgMapView)
|
|
7903
7872
|
return;
|
|
7904
7873
|
// 创建割草机位置管理器,传入动画完成回调
|
|
7905
|
-
this.mowerPositionManager = new MowerPositionManager(this.svgMapView, this.mowerPositionConfig, this.div, () => {
|
|
7906
|
-
console.log('动画完成');
|
|
7907
|
-
}, this.updatePathDataByMowingPositionThrottled.bind(this));
|
|
7874
|
+
this.mowerPositionManager = new MowerPositionManager(this.svgMapView, this.mowerPositionConfig, this.modelType, this.div, () => { }, this.updatePathDataByMowingPositionThrottled.bind(this));
|
|
7908
7875
|
// 设置叠加层div引用
|
|
7909
7876
|
this.mowerPositionManager.setOverlayDiv(this.div);
|
|
7910
7877
|
// 获取容器并添加到主div
|
|
@@ -7935,7 +7902,7 @@ class MowerMapOverlay {
|
|
|
7935
7902
|
this.boundaryLabelsManager.updatePositionsWithPrecomputedData(width, height, viewBoxInfo);
|
|
7936
7903
|
}
|
|
7937
7904
|
// 更新管理器位置
|
|
7938
|
-
updateManagerPositions(
|
|
7905
|
+
updateManagerPositions(_width, _height) {
|
|
7939
7906
|
if (!this.div)
|
|
7940
7907
|
return;
|
|
7941
7908
|
// 更新充电桩位置
|
|
@@ -7986,7 +7953,7 @@ class MowerMapOverlay {
|
|
|
7986
7953
|
this.rotateHandle.style.pointerEvents = 'auto';
|
|
7987
7954
|
this.rotateHandle.innerHTML = DEFAULT_ROTATE_ICON;
|
|
7988
7955
|
this.editContainer.appendChild(this.rotateHandle);
|
|
7989
|
-
//
|
|
7956
|
+
// 创建拖拽手柄(左下角)- 仅在移动设备上显示
|
|
7990
7957
|
this.dragHandle = document.createElement('div');
|
|
7991
7958
|
this.dragHandle.style.position = 'absolute';
|
|
7992
7959
|
this.dragHandle.style.bottom = '-20px';
|
|
@@ -7997,6 +7964,10 @@ class MowerMapOverlay {
|
|
|
7997
7964
|
this.dragHandle.style.zIndex = EDIT_STYLES.Z_INDEX.HANDLE;
|
|
7998
7965
|
this.dragHandle.style.pointerEvents = 'auto';
|
|
7999
7966
|
this.dragHandle.innerHTML = DEFAULT_DRAG_ICON;
|
|
7967
|
+
// 在PC设备上隐藏拖拽手柄
|
|
7968
|
+
if (!isMobileDevice()) {
|
|
7969
|
+
this.dragHandle.style.display = 'none';
|
|
7970
|
+
}
|
|
8000
7971
|
this.editContainer.appendChild(this.dragHandle);
|
|
8001
7972
|
// 将编辑容器添加到主div
|
|
8002
7973
|
this.div.appendChild(this.editContainer);
|
|
@@ -8038,7 +8009,6 @@ class MowerMapOverlay {
|
|
|
8038
8009
|
this.boundaryLabelsManager.collapseAllLabels();
|
|
8039
8010
|
}
|
|
8040
8011
|
this.dragCallbacks?.onDragStart?.(this.getCurrentDragState());
|
|
8041
|
-
console.log('开始旋转操作');
|
|
8042
8012
|
});
|
|
8043
8013
|
// 旋转手柄的触摸事件
|
|
8044
8014
|
this.rotateHandle.addEventListener('touchstart', (e) => {
|
|
@@ -8054,39 +8024,41 @@ class MowerMapOverlay {
|
|
|
8054
8024
|
this.boundaryLabelsManager.collapseAllLabels();
|
|
8055
8025
|
}
|
|
8056
8026
|
this.dragCallbacks?.onDragStart?.(this.getCurrentDragState());
|
|
8057
|
-
console.log('开始旋转操作(触摸)');
|
|
8058
|
-
}, { passive: false });
|
|
8059
|
-
// 拖拽手柄的鼠标事件
|
|
8060
|
-
this.dragHandle.addEventListener('mousedown', (e) => {
|
|
8061
|
-
e.preventDefault();
|
|
8062
|
-
e.stopPropagation();
|
|
8063
|
-
e.stopImmediatePropagation();
|
|
8064
|
-
this.isDragging = true;
|
|
8065
|
-
this.startPos = { x: e.clientX, y: e.clientY };
|
|
8066
|
-
this.dragHandle.style.cursor = 'grabbing';
|
|
8067
|
-
// 开始编辑时关闭所有展开的边界标签
|
|
8068
|
-
if (this.boundaryLabelsManager) {
|
|
8069
|
-
this.boundaryLabelsManager.collapseAllLabels();
|
|
8070
|
-
}
|
|
8071
|
-
this.dragCallbacks?.onDragStart?.(this.getCurrentDragState());
|
|
8072
|
-
console.log('开始拖动操作(通过手柄)');
|
|
8073
|
-
});
|
|
8074
|
-
// 拖拽手柄的触摸事件
|
|
8075
|
-
this.dragHandle.addEventListener('touchstart', (e) => {
|
|
8076
|
-
e.preventDefault();
|
|
8077
|
-
e.stopPropagation();
|
|
8078
|
-
e.stopImmediatePropagation();
|
|
8079
|
-
this.isDragging = true;
|
|
8080
|
-
const touch = e.touches[0];
|
|
8081
|
-
this.startPos = { x: touch.clientX, y: touch.clientY };
|
|
8082
|
-
this.dragHandle.style.cursor = 'grabbing';
|
|
8083
|
-
this.dragCallbacks?.onDragStart?.(this.getCurrentDragState());
|
|
8084
|
-
console.log('开始拖动操作(通过手柄,触摸)');
|
|
8085
8027
|
}, { passive: false });
|
|
8028
|
+
// 拖拽手柄的鼠标事件 - 仅在移动设备上启用
|
|
8029
|
+
if (isMobileDevice()) {
|
|
8030
|
+
this.dragHandle.addEventListener('mousedown', (e) => {
|
|
8031
|
+
e.preventDefault();
|
|
8032
|
+
e.stopPropagation();
|
|
8033
|
+
e.stopImmediatePropagation();
|
|
8034
|
+
this.isDragging = true;
|
|
8035
|
+
this.startPos = { x: e.clientX, y: e.clientY };
|
|
8036
|
+
this.dragHandle.style.cursor = 'grabbing';
|
|
8037
|
+
// 开始编辑时关闭所有展开的边界标签
|
|
8038
|
+
if (this.boundaryLabelsManager) {
|
|
8039
|
+
this.boundaryLabelsManager.collapseAllLabels();
|
|
8040
|
+
}
|
|
8041
|
+
this.dragCallbacks?.onDragStart?.(this.getCurrentDragState());
|
|
8042
|
+
});
|
|
8043
|
+
// 拖拽手柄的触摸事件
|
|
8044
|
+
this.dragHandle.addEventListener('touchstart', (e) => {
|
|
8045
|
+
e.preventDefault();
|
|
8046
|
+
e.stopPropagation();
|
|
8047
|
+
e.stopImmediatePropagation();
|
|
8048
|
+
this.isDragging = true;
|
|
8049
|
+
const touch = e.touches[0];
|
|
8050
|
+
this.startPos = { x: touch.clientX, y: touch.clientY };
|
|
8051
|
+
this.dragHandle.style.cursor = 'grabbing';
|
|
8052
|
+
this.dragCallbacks?.onDragStart?.(this.getCurrentDragState());
|
|
8053
|
+
}, { passive: false });
|
|
8054
|
+
}
|
|
8086
8055
|
// 编辑容器的鼠标事件(整个区域拖拽)
|
|
8087
8056
|
this.editContainer.addEventListener('mousedown', (e) => {
|
|
8088
|
-
|
|
8089
|
-
|
|
8057
|
+
// 在移动设备上,检查是否点击了拖拽手柄或旋转手柄
|
|
8058
|
+
// 在PC设备上,只检查旋转手柄(拖拽手柄已隐藏)
|
|
8059
|
+
const isDragHandleClick = isMobileDevice() && e.target === this.dragHandle;
|
|
8060
|
+
const isRotateHandleClick = e.target === this.rotateHandle;
|
|
8061
|
+
if (isDragHandleClick || isRotateHandleClick) {
|
|
8090
8062
|
return;
|
|
8091
8063
|
}
|
|
8092
8064
|
e.preventDefault();
|
|
@@ -8103,8 +8075,11 @@ class MowerMapOverlay {
|
|
|
8103
8075
|
});
|
|
8104
8076
|
// 编辑容器的触摸事件(整个区域拖拽)
|
|
8105
8077
|
this.editContainer.addEventListener('touchstart', (e) => {
|
|
8106
|
-
|
|
8107
|
-
|
|
8078
|
+
// 在移动设备上,检查是否点击了拖拽手柄或旋转手柄
|
|
8079
|
+
// 在PC设备上,只检查旋转手柄(拖拽手柄已隐藏)
|
|
8080
|
+
const isDragHandleClick = isMobileDevice() && e.target === this.dragHandle;
|
|
8081
|
+
const isRotateHandleClick = e.target === this.rotateHandle;
|
|
8082
|
+
if (isDragHandleClick || isRotateHandleClick) {
|
|
8108
8083
|
return;
|
|
8109
8084
|
}
|
|
8110
8085
|
e.preventDefault();
|
|
@@ -8164,7 +8139,6 @@ class MowerMapOverlay {
|
|
|
8164
8139
|
e.preventDefault();
|
|
8165
8140
|
e.stopPropagation();
|
|
8166
8141
|
e.stopImmediatePropagation();
|
|
8167
|
-
console.log('结束编辑操作');
|
|
8168
8142
|
}
|
|
8169
8143
|
// 如果是拖拽结束,将像素偏移量转换为地理坐标偏移量
|
|
8170
8144
|
if (this.isDragging) {
|
|
@@ -8186,7 +8160,6 @@ class MowerMapOverlay {
|
|
|
8186
8160
|
e.preventDefault();
|
|
8187
8161
|
e.stopPropagation();
|
|
8188
8162
|
e.stopImmediatePropagation();
|
|
8189
|
-
console.log('结束编辑操作(触摸)');
|
|
8190
8163
|
}
|
|
8191
8164
|
// 如果是拖拽结束,将像素偏移量转换为地理坐标偏移量
|
|
8192
8165
|
if (this.isDragging) {
|
|
@@ -8298,7 +8271,6 @@ class MowerMapOverlay {
|
|
|
8298
8271
|
this.div.style.transform = transform;
|
|
8299
8272
|
// 更新鼠标起始位置为当前位置,为下次计算做准备
|
|
8300
8273
|
this.startPos = { x: mouseCurrentX, y: mouseCurrentY };
|
|
8301
|
-
console.log('旋转角度:', this.currentRotation, '角度增量:', angleDifferenceDegrees);
|
|
8302
8274
|
}
|
|
8303
8275
|
// 将像素偏移量转换为地理坐标偏移量
|
|
8304
8276
|
convertPixelOffsetToLatLng() {
|
|
@@ -8328,14 +8300,6 @@ class MowerMapOverlay {
|
|
|
8328
8300
|
// 累积更新地理坐标偏移量(不是直接赋值!)
|
|
8329
8301
|
this.latLngOffset.lat += latOffset;
|
|
8330
8302
|
this.latLngOffset.lng += lngOffset;
|
|
8331
|
-
console.log('精确转换偏移量:', {
|
|
8332
|
-
pixelOffset: this.tempPixelOffset,
|
|
8333
|
-
centerLatLng: { lat: centerLatLng.lat(), lng: centerLatLng.lng() },
|
|
8334
|
-
offsetLatLng: { lat: offsetLatLng.lat(), lng: offsetLatLng.lng() },
|
|
8335
|
-
latOffset,
|
|
8336
|
-
lngOffset,
|
|
8337
|
-
newLatLngOffset: this.latLngOffset,
|
|
8338
|
-
});
|
|
8339
8303
|
// 重置临时像素偏移量
|
|
8340
8304
|
this.tempPixelOffset = { x: 0, y: 0 };
|
|
8341
8305
|
this.draw();
|
|
@@ -8373,8 +8337,6 @@ class MowerMapOverlay {
|
|
|
8373
8337
|
editData: editData,
|
|
8374
8338
|
timestamp: new Date().toISOString(),
|
|
8375
8339
|
};
|
|
8376
|
-
// 在这里可以添加保存逻辑,比如发送到服务器
|
|
8377
|
-
console.log('保存编辑数据:', saveData);
|
|
8378
8340
|
// 显示保存成功提示
|
|
8379
8341
|
this.showSaveSuccess();
|
|
8380
8342
|
return saveData;
|
|
@@ -8467,6 +8429,9 @@ class MowerMapOverlay {
|
|
|
8467
8429
|
y: transform.y,
|
|
8468
8430
|
rotation: transform.rotation,
|
|
8469
8431
|
};
|
|
8432
|
+
// defaultTransform的x对应经度偏移量,y对应纬度偏移量
|
|
8433
|
+
this.latLngOffset.lng = this.defaultTransform.x;
|
|
8434
|
+
this.latLngOffset.lat = this.defaultTransform.y;
|
|
8470
8435
|
this.setManagerRotation(this.currentRotation);
|
|
8471
8436
|
this.draw();
|
|
8472
8437
|
}
|
|
@@ -8500,12 +8465,10 @@ class MowerMapOverlay {
|
|
|
8500
8465
|
try {
|
|
8501
8466
|
// 创建SvgMapView实例
|
|
8502
8467
|
this.svgMapView = new SvgMapView(this.offscreenContainer, 800, 600);
|
|
8503
|
-
window.svgMapView = this.svgMapView;
|
|
8504
8468
|
// 加载地图数据
|
|
8505
8469
|
this.loadMapData();
|
|
8506
8470
|
// 加载路径数据
|
|
8507
8471
|
if (this.pathData && this.svgMapView) {
|
|
8508
|
-
console.log('initializeSvgMapView->', this.pathData, this.mowPartitionData);
|
|
8509
8472
|
this.loadPathData(this.pathData, this.mowPartitionData);
|
|
8510
8473
|
}
|
|
8511
8474
|
// 刷新绘制图层
|
|
@@ -8532,9 +8495,6 @@ class MowerMapOverlay {
|
|
|
8532
8495
|
// 使用现有的MapDataProcessor处理地图数据
|
|
8533
8496
|
const elements = MapDataProcessor.processMapData(this.mapData, this.mapConfig);
|
|
8534
8497
|
// 分离充电桩和天线元素,其他元素添加到SVG图层
|
|
8535
|
-
// const svgElements = elements.filter(element =>
|
|
8536
|
-
// element.type !== 'charging_pile' && element.type !== 'antenna'
|
|
8537
|
-
// );
|
|
8538
8498
|
const svgElements = elements.filter((element) => element.type !== 'charging_pile' && element.type !== 'antenna');
|
|
8539
8499
|
const chargingPileElements = elements.filter((element) => element.type === 'charging_pile');
|
|
8540
8500
|
// 处理SVG图层元素
|
|
@@ -8549,6 +8509,10 @@ class MowerMapOverlay {
|
|
|
8549
8509
|
const layers = drawLayer.getLayers();
|
|
8550
8510
|
this.svgMapView.clear();
|
|
8551
8511
|
this.svgMapView.addLayers(layers);
|
|
8512
|
+
const boundaryBorderLayer = this.svgMapView.getLayer(LAYER_DEFAULT_TYPE.BOUNDARY_BORDER);
|
|
8513
|
+
if (boundaryBorderLayer) {
|
|
8514
|
+
boundaryBorderLayer.setMowingBoundarys(this.mowPartitionData?.partitionIds || []);
|
|
8515
|
+
}
|
|
8552
8516
|
this.createChargingPileManager();
|
|
8553
8517
|
// 使用管理器处理充电桩和天线
|
|
8554
8518
|
if (this.chargingPileManager && chargingPileElements.length > 0) {
|
|
@@ -8578,7 +8542,6 @@ class MowerMapOverlay {
|
|
|
8578
8542
|
try {
|
|
8579
8543
|
// 使用现有的PathDataProcessor处理路径数据
|
|
8580
8544
|
const pathElements = PathDataProcessor.processPathData(pathData, this.mapConfig);
|
|
8581
|
-
console.log('pathdaata->', pathElements, mowPartitionData);
|
|
8582
8545
|
const newPathElements = pathElements.map((pathElement) => {
|
|
8583
8546
|
const { id, elements } = pathElement;
|
|
8584
8547
|
const isMowBoundary = mowPartitionData && mowPartitionData?.partitionIds?.includes(id);
|
|
@@ -8626,7 +8589,6 @@ class MowerMapOverlay {
|
|
|
8626
8589
|
// 找到当前position所在的分区id,将该点更新到pathData中
|
|
8627
8590
|
const currentPartitionId = getPartitionId(this.partitionBoundary, position.x, position.y);
|
|
8628
8591
|
const processStateIsMowing = useProcessMowingState.getState().processStateIsMowing;
|
|
8629
|
-
// console.log('processStateIsMowing==', processStateIsMowing);
|
|
8630
8592
|
if (currentPartitionId && this.pathData?.[currentPartitionId]) {
|
|
8631
8593
|
const currentPathData = this.pathData[currentPartitionId];
|
|
8632
8594
|
this.pathData[currentPartitionId] = {
|
|
@@ -8815,15 +8777,41 @@ class MowerMapOverlay {
|
|
|
8815
8777
|
this.mowerPositionManager.setVisible(visible);
|
|
8816
8778
|
}
|
|
8817
8779
|
}
|
|
8818
|
-
|
|
8819
|
-
|
|
8820
|
-
|
|
8821
|
-
|
|
8822
|
-
|
|
8823
|
-
|
|
8824
|
-
|
|
8825
|
-
|
|
8826
|
-
|
|
8780
|
+
// 获取SvgMapView实例(用于debug)
|
|
8781
|
+
getSvgMapView() {
|
|
8782
|
+
return this.svgMapView;
|
|
8783
|
+
}
|
|
8784
|
+
}
|
|
8785
|
+
|
|
8786
|
+
// 获取车辆状态的中文文案
|
|
8787
|
+
const getVehicleStateText = (vehicleState) => {
|
|
8788
|
+
switch (vehicleState) {
|
|
8789
|
+
case RobotStatus.PARKED:
|
|
8790
|
+
return 'PARKED';
|
|
8791
|
+
case RobotStatus.CHARGING:
|
|
8792
|
+
return 'CHARGING';
|
|
8793
|
+
case RobotStatus.STANDBY:
|
|
8794
|
+
return 'STANDBY';
|
|
8795
|
+
case RobotStatus.MOWING:
|
|
8796
|
+
return 'MOWING';
|
|
8797
|
+
case RobotStatus.WORKING:
|
|
8798
|
+
return 'WORKING';
|
|
8799
|
+
case RobotStatus.MAPPING:
|
|
8800
|
+
return 'MAPPING';
|
|
8801
|
+
case RobotStatus.ERROR:
|
|
8802
|
+
return 'ERROR';
|
|
8803
|
+
case RobotStatus.UPGRADING:
|
|
8804
|
+
return 'UPGRADING';
|
|
8805
|
+
case RobotStatus.DISCONNECTED:
|
|
8806
|
+
return 'DISCONNECTED';
|
|
8807
|
+
case RobotStatus.TASK_DELAY:
|
|
8808
|
+
return 'TASK_DELAY';
|
|
8809
|
+
case RobotStatus.UNKNOWN:
|
|
8810
|
+
return '未知';
|
|
8811
|
+
default:
|
|
8812
|
+
return `未知状态(${vehicleState})`;
|
|
8813
|
+
}
|
|
8814
|
+
};
|
|
8827
8815
|
// 验证GPS坐标是否有效
|
|
8828
8816
|
const isValidGpsCoordinate = (coordinate) => {
|
|
8829
8817
|
if (!coordinate || coordinate.length < 2)
|
|
@@ -8837,35 +8825,76 @@ const isValidGpsCoordinate = (coordinate) => {
|
|
|
8837
8825
|
!(Math.abs(lng) < 0.001 && Math.abs(lat) < 0.001) // 排除接近(0,0)的坐标
|
|
8838
8826
|
);
|
|
8839
8827
|
};
|
|
8828
|
+
// 旋转坐标点
|
|
8829
|
+
const rotateCoordinate = (point, center, angleRadians) => {
|
|
8830
|
+
const [x, y] = point;
|
|
8831
|
+
const [cx, cy] = center;
|
|
8832
|
+
// 将点移动到原点
|
|
8833
|
+
const dx = x - cx;
|
|
8834
|
+
const dy = y - cy;
|
|
8835
|
+
// 应用旋转矩阵
|
|
8836
|
+
const cos = Math.cos(angleRadians);
|
|
8837
|
+
const sin = Math.sin(angleRadians);
|
|
8838
|
+
const rotatedX = dx * cos - dy * sin;
|
|
8839
|
+
const rotatedY = dx * sin + dy * cos;
|
|
8840
|
+
// 移回原位置
|
|
8841
|
+
return [rotatedX + cx, rotatedY + cy];
|
|
8842
|
+
};
|
|
8840
8843
|
// 获取有效的GPS边界
|
|
8841
|
-
const getValidGpsBounds = (mapData) => {
|
|
8844
|
+
const getValidGpsBounds = (mapData, rotation = 0) => {
|
|
8845
|
+
let bounds;
|
|
8842
8846
|
// 首先尝试使用地图数据中的GPS坐标
|
|
8843
8847
|
if (isValidGpsCoordinate(mapData.sw_gps) && isValidGpsCoordinate(mapData.ne_gps)) {
|
|
8844
|
-
|
|
8848
|
+
bounds = {
|
|
8845
8849
|
sw: mapData.sw_gps,
|
|
8846
8850
|
ne: mapData.ne_gps,
|
|
8847
8851
|
};
|
|
8848
8852
|
}
|
|
8849
|
-
|
|
8850
|
-
|
|
8851
|
-
|
|
8852
|
-
|
|
8853
|
-
|
|
8854
|
-
|
|
8855
|
-
|
|
8853
|
+
else {
|
|
8854
|
+
// 如果GPS坐标无效,尝试从地图几何数据估算
|
|
8855
|
+
const { sw, ne } = estimateGpsFromMapBounds(mapData);
|
|
8856
|
+
if (sw && ne) {
|
|
8857
|
+
console.warn('GPS坐标无效,使用地图几何数据估算边界:', sw, ne);
|
|
8858
|
+
bounds = {
|
|
8859
|
+
sw: [sw[0], sw[1]],
|
|
8860
|
+
ne: [ne[0], ne[1]],
|
|
8861
|
+
};
|
|
8862
|
+
}
|
|
8863
|
+
else {
|
|
8864
|
+
// 最后的fallback:使用默认坐标
|
|
8865
|
+
console.warn('无法获取有效的GPS边界,使用默认坐标');
|
|
8866
|
+
bounds = {
|
|
8867
|
+
sw: [-9.1562, -37.7503],
|
|
8868
|
+
ne: [31.247, 5.797],
|
|
8869
|
+
};
|
|
8870
|
+
}
|
|
8871
|
+
}
|
|
8872
|
+
// 如果有旋转角度,计算旋转后的边界
|
|
8873
|
+
if (rotation !== 0) {
|
|
8874
|
+
const angleRadians = (rotation * Math.PI) / 180; // 转换为弧度
|
|
8875
|
+
// 计算边界中心点
|
|
8876
|
+
const centerLng = (bounds.sw[0] + bounds.ne[0]) / 2;
|
|
8877
|
+
const centerLat = (bounds.sw[1] + bounds.ne[1]) / 2;
|
|
8878
|
+
const center = [centerLng, centerLat];
|
|
8879
|
+
// 旋转四个角点
|
|
8880
|
+
const sw = rotateCoordinate(bounds.sw, center, angleRadians);
|
|
8881
|
+
const ne = rotateCoordinate(bounds.ne, center, angleRadians);
|
|
8882
|
+
const se = rotateCoordinate([bounds.ne[0], bounds.sw[1]], center, angleRadians);
|
|
8883
|
+
const nw = rotateCoordinate([bounds.sw[0], bounds.ne[1]], center, angleRadians);
|
|
8884
|
+
// 计算旋转后的边界框(包含所有旋转后的点)
|
|
8885
|
+
const lngs = [sw[0], ne[0], se[0], nw[0]];
|
|
8886
|
+
const lats = [sw[1], ne[1], se[1], nw[1]];
|
|
8887
|
+
bounds = {
|
|
8888
|
+
sw: [Math.min(...lngs), Math.min(...lats)],
|
|
8889
|
+
ne: [Math.max(...lngs), Math.max(...lats)],
|
|
8856
8890
|
};
|
|
8857
8891
|
}
|
|
8858
|
-
|
|
8859
|
-
console.warn('无法获取有效的GPS边界,使用默认坐标');
|
|
8860
|
-
return {
|
|
8861
|
-
sw: [-9.1562, -37.7503],
|
|
8862
|
-
ne: [31.247, 5.797],
|
|
8863
|
-
};
|
|
8892
|
+
return bounds;
|
|
8864
8893
|
};
|
|
8865
8894
|
// 默认配置
|
|
8866
8895
|
const defaultMapConfig = DEFAULT_STYLES;
|
|
8867
8896
|
// 地图渲染器组件
|
|
8868
|
-
const MowerMapRenderer = forwardRef(({ mapConfig, modelType, mapRef, mapJson, pathJson, realTimeData, antennaConfig, onMapLoad, onPathLoad, onError, className, style, googleMapInstance, isEditMode = false, dragCallbacks, defaultTransform, }, ref) => {
|
|
8897
|
+
const MowerMapRenderer = forwardRef(({ unitType = UnitsType.Imperial, language = 'en', mapConfig, modelType, mapRef, mapJson, pathJson, realTimeData, antennaConfig, onMapLoad, onPathLoad, onError, className, style, googleMapInstance, isEditMode = false, dragCallbacks, defaultTransform, debug = false, }, ref) => {
|
|
8869
8898
|
const [elementCount, setElementCount] = useState(0);
|
|
8870
8899
|
const [pathCount, setPathCount] = useState(0);
|
|
8871
8900
|
const [currentError, setCurrentError] = useState(null);
|
|
@@ -8873,10 +8902,12 @@ const MowerMapRenderer = forwardRef(({ mapConfig, modelType, mapRef, mapJson, pa
|
|
|
8873
8902
|
// const mapRef = useMap();
|
|
8874
8903
|
const [isGoogleMapsReady, setIsGoogleMapsReady] = useState(false);
|
|
8875
8904
|
const [hasInitializedBounds, setHasInitializedBounds] = useState(false);
|
|
8876
|
-
const { clearSubBoundaryBorder } = useSubBoundaryBorderStore();
|
|
8905
|
+
const { clearSubBoundaryBorder, clearObstacles } = useSubBoundaryBorderStore();
|
|
8877
8906
|
const currentProcessMowingStatusRef = useRef(false);
|
|
8878
8907
|
const { updateProcessStateIsMowing, processStateIsMowing } = useProcessMowingState();
|
|
8879
8908
|
const [mowPartitionData, setMowPartitionData] = useState(null);
|
|
8909
|
+
// Debug相关状态
|
|
8910
|
+
const [debugInfo, setDebugInfo] = useState({});
|
|
8880
8911
|
// 处理地图分区边界
|
|
8881
8912
|
const partitionBoundary = useMemo(() => {
|
|
8882
8913
|
const allBoundaryElements = [];
|
|
@@ -8901,7 +8932,12 @@ const MowerMapRenderer = forwardRef(({ mapConfig, modelType, mapRef, mapJson, pa
|
|
|
8901
8932
|
const mowerPositionData = useMemo(() => {
|
|
8902
8933
|
// realTimeData 中包含三个种类的数据,之需要实时坐标的数据即可。
|
|
8903
8934
|
if (!realTimeData || realTimeData.length === 0)
|
|
8904
|
-
return
|
|
8935
|
+
return {
|
|
8936
|
+
postureX: 0,
|
|
8937
|
+
postureY: 0,
|
|
8938
|
+
postureTheta: 0,
|
|
8939
|
+
vehicleState: RobotStatus.DISCONNECTED,
|
|
8940
|
+
};
|
|
8905
8941
|
let currentPositionData;
|
|
8906
8942
|
if (realTimeData.length === 1 && realTimeData[0].type === RealTimeDataType.LOCATION) {
|
|
8907
8943
|
currentPositionData = realTimeData[0];
|
|
@@ -8920,13 +8956,15 @@ const MowerMapRenderer = forwardRef(({ mapConfig, modelType, mapRef, mapJson, pa
|
|
|
8920
8956
|
lastPostureTheta: currentPositionData?.lastPostureTheta
|
|
8921
8957
|
? Number(currentPositionData.lastPostureTheta)
|
|
8922
8958
|
: 0,
|
|
8923
|
-
lastPostureX: currentPositionData?.lastPostureX
|
|
8924
|
-
|
|
8925
|
-
|
|
8926
|
-
|
|
8959
|
+
lastPostureX: currentPositionData?.lastPostureX
|
|
8960
|
+
? Number(currentPositionData.lastPostureX)
|
|
8961
|
+
: 0,
|
|
8962
|
+
lastPostureY: currentPositionData?.lastPostureY
|
|
8963
|
+
? Number(currentPositionData.lastPostureY)
|
|
8964
|
+
: 0,
|
|
8965
|
+
vehicleState: currentPositionData?.vehicleState || RobotStatus.DISCONNECTED,
|
|
8927
8966
|
};
|
|
8928
8967
|
}, [realTimeData, modelType]);
|
|
8929
|
-
console.log('mowerPositionData', mowerPositionData);
|
|
8930
8968
|
// 处理错误
|
|
8931
8969
|
const handleError = (error) => {
|
|
8932
8970
|
setCurrentError(error);
|
|
@@ -8942,18 +8980,17 @@ const MowerMapRenderer = forwardRef(({ mapConfig, modelType, mapRef, mapJson, pa
|
|
|
8942
8980
|
return;
|
|
8943
8981
|
}
|
|
8944
8982
|
// 将自定义边界转换为Google Maps LatLngBounds(使用有效的GPS坐标)
|
|
8945
|
-
const validBounds = getValidGpsBounds(mapJson);
|
|
8983
|
+
const validBounds = getValidGpsBounds(mapJson, defaultTransform?.rotation);
|
|
8946
8984
|
// 地图数据中的坐标格式是 [longitude, latitude]
|
|
8947
|
-
const swLat = validBounds.sw[1];
|
|
8948
|
-
const swLng = validBounds.sw[0];
|
|
8949
|
-
const neLat = validBounds.ne[1];
|
|
8950
|
-
const neLng = validBounds.ne[0];
|
|
8985
|
+
const swLat = validBounds.sw[1] + defaultTransform.y;
|
|
8986
|
+
const swLng = validBounds.sw[0] + defaultTransform.x;
|
|
8987
|
+
const neLat = validBounds.ne[1] + defaultTransform.y;
|
|
8988
|
+
const neLng = validBounds.ne[0] + defaultTransform.x;
|
|
8951
8989
|
const googleBounds = new window.google.maps.LatLngBounds(new window.google.maps.LatLng(swLat, swLng), // 西南角
|
|
8952
8990
|
new window.google.maps.LatLng(neLat, neLng) // 东北角
|
|
8953
8991
|
);
|
|
8954
|
-
console.log('fitBounds----->', googleBounds);
|
|
8955
8992
|
mapRef.fitBounds(googleBounds);
|
|
8956
|
-
}, [mapJson, mapRef]);
|
|
8993
|
+
}, [mapJson, mapRef, defaultTransform]);
|
|
8957
8994
|
// 初始化Google Maps叠加层
|
|
8958
8995
|
const initializeGoogleMapsOverlay = async () => {
|
|
8959
8996
|
if (!mapJson)
|
|
@@ -8977,7 +9014,8 @@ const MowerMapRenderer = forwardRef(({ mapConfig, modelType, mapRef, mapJson, pa
|
|
|
8977
9014
|
return;
|
|
8978
9015
|
}
|
|
8979
9016
|
// 将自定义边界转换为Google Maps LatLngBounds(使用有效的GPS坐标)
|
|
8980
|
-
|
|
9017
|
+
// 这里需要使用0度,需要原始的坐标点去计算元素的实际位置,只有在fitbounds的时候才需要使用旋转后的坐标点
|
|
9018
|
+
const validBounds = getValidGpsBounds(mapJson, 0);
|
|
8981
9019
|
// 地图数据中的坐标格式是 [longitude, latitude]
|
|
8982
9020
|
const swLat = validBounds.sw[1];
|
|
8983
9021
|
const swLng = validBounds.sw[0];
|
|
@@ -8992,7 +9030,7 @@ const MowerMapRenderer = forwardRef(({ mapConfig, modelType, mapRef, mapJson, pa
|
|
|
8992
9030
|
overlayRef.current = null;
|
|
8993
9031
|
}
|
|
8994
9032
|
// 创建叠加层
|
|
8995
|
-
const overlay = new MowerMapOverlay(googleBounds, mapJson, partitionBoundary, mowerPositionData, pathJson || {}, isEditMode, mergedMapConfig, mergedAntennaConfig, null, defaultTransform, (count) => {
|
|
9033
|
+
const overlay = new MowerMapOverlay(googleBounds, mapJson, partitionBoundary, mowerPositionData, modelType, pathJson || {}, isEditMode, unitType, language, mergedMapConfig, mergedAntennaConfig, null, defaultTransform, (count) => {
|
|
8996
9034
|
setElementCount(count);
|
|
8997
9035
|
onMapLoad?.(count);
|
|
8998
9036
|
}, (count) => {
|
|
@@ -9013,12 +9051,26 @@ const MowerMapRenderer = forwardRef(({ mapConfig, modelType, mapRef, mapJson, pa
|
|
|
9013
9051
|
handleError(`初始化Google Maps叠加层失败: ${error instanceof Error ? error.message : String(error)}`);
|
|
9014
9052
|
}
|
|
9015
9053
|
};
|
|
9054
|
+
const resetInCharginPie = useCallback(() => {
|
|
9055
|
+
const elements = MapDataProcessor.processMapData(mapJson, mergedMapConfig);
|
|
9056
|
+
const chargingPiles = elements.find((element) => element.type === 'charging_pile');
|
|
9057
|
+
if (!overlayRef.current)
|
|
9058
|
+
return;
|
|
9059
|
+
// 如果在充电桩上,则直接更新位置到充电桩的位置
|
|
9060
|
+
overlayRef.current.updatePosition({
|
|
9061
|
+
...mowerPositionData,
|
|
9062
|
+
postureX: chargingPiles?.originalData.position[0],
|
|
9063
|
+
postureY: chargingPiles?.originalData.position[1],
|
|
9064
|
+
postureTheta: chargingPiles?.originalData.direction - Math.PI || 0,
|
|
9065
|
+
}, 0);
|
|
9066
|
+
}, [mapJson, mowerPositionData]);
|
|
9016
9067
|
// 初始化效果
|
|
9017
9068
|
useEffect(() => {
|
|
9018
9069
|
initializeGoogleMapsOverlay();
|
|
9019
9070
|
// 清理函数
|
|
9020
9071
|
return () => {
|
|
9021
9072
|
clearSubBoundaryBorder();
|
|
9073
|
+
clearObstacles();
|
|
9022
9074
|
updateProcessStateIsMowing(false);
|
|
9023
9075
|
currentProcessMowingStatusRef.current = false;
|
|
9024
9076
|
if (overlayRef.current) {
|
|
@@ -9049,10 +9101,9 @@ const MowerMapRenderer = forwardRef(({ mapConfig, modelType, mapRef, mapJson, pa
|
|
|
9049
9101
|
const inChargingPiles = [RobotStatus.CHARGING, RobotStatus.PARKED];
|
|
9050
9102
|
const isOffLine = mowerPositionData.vehicleState === RobotStatus.DISCONNECTED;
|
|
9051
9103
|
const isInChargingPile = inChargingPiles.includes(mowerPositionData.vehicleState);
|
|
9052
|
-
console.log('isInChargingPile-----------》', isInChargingPile, mowerPositionData);
|
|
9053
9104
|
// 如果在充电桩上,则直接更新位置到充电桩的位置
|
|
9105
|
+
console.log('usefeect mowerPositionData----->', mowerPositionData, isInChargingPile);
|
|
9054
9106
|
if (isInChargingPile) {
|
|
9055
|
-
console.log('isInChargingPile', isInChargingPile, mowerPositionData);
|
|
9056
9107
|
overlayRef.current.updatePosition({
|
|
9057
9108
|
...mowerPositionData,
|
|
9058
9109
|
postureX: chargingPiles?.originalData.position[0],
|
|
@@ -9065,7 +9116,6 @@ const MowerMapRenderer = forwardRef(({ mapConfig, modelType, mapRef, mapJson, pa
|
|
|
9065
9116
|
const positonOutOfRange = isOutOfRange(mowerPositionData);
|
|
9066
9117
|
const positionValid = isInvalidPosition(mowerPositionData);
|
|
9067
9118
|
const isStandby = mowerPositionData.vehicleState === RobotStatus.STANDBY;
|
|
9068
|
-
console.log('positonOutOfRange', positonOutOfRange, positionValid, isOffLine);
|
|
9069
9119
|
if (positonOutOfRange || positionValid || isOffLine) {
|
|
9070
9120
|
// 初始信息是通过后端接口获取的,此时当前位置数据不可用的时候,可以取上一次的位置数据
|
|
9071
9121
|
// mowerPositionData 中可能会包含上一次的位置数据,
|
|
@@ -9085,29 +9135,165 @@ const MowerMapRenderer = forwardRef(({ mapConfig, modelType, mapRef, mapJson, pa
|
|
|
9085
9135
|
}
|
|
9086
9136
|
}
|
|
9087
9137
|
else {
|
|
9088
|
-
console.log('hook updatePosition----->', mowerPositionData);
|
|
9089
9138
|
overlayRef.current.updatePosition(mowerPositionData, isStandby ? 0 : 2000);
|
|
9090
9139
|
}
|
|
9091
9140
|
}
|
|
9092
9141
|
}, [mowerPositionData]);
|
|
9142
|
+
// 更新debug信息
|
|
9143
|
+
useEffect(() => {
|
|
9144
|
+
if (!debug)
|
|
9145
|
+
return;
|
|
9146
|
+
const updateDebugInfo = () => {
|
|
9147
|
+
const newDebugInfo = {};
|
|
9148
|
+
// 获取地图GPS边界
|
|
9149
|
+
if (mapJson) {
|
|
9150
|
+
newDebugInfo.mapBounds = getValidGpsBounds(mapJson, defaultTransform?.rotation);
|
|
9151
|
+
}
|
|
9152
|
+
// 获取SVG viewBox信息
|
|
9153
|
+
if (overlayRef.current) {
|
|
9154
|
+
const overlay = overlayRef.current;
|
|
9155
|
+
const svgMapView = overlay.getSvgMapView?.();
|
|
9156
|
+
if (svgMapView) {
|
|
9157
|
+
const viewBoxInfo = svgMapView.getViewBoxInfo();
|
|
9158
|
+
// 计算实际的米单位数据(除以缩放比例)
|
|
9159
|
+
const SCALE_FACTOR = 50; // 根据项目中的缩放因子
|
|
9160
|
+
newDebugInfo.viewBox = {
|
|
9161
|
+
x: viewBoxInfo.x / SCALE_FACTOR,
|
|
9162
|
+
y: viewBoxInfo.y / SCALE_FACTOR,
|
|
9163
|
+
width: viewBoxInfo.width / SCALE_FACTOR,
|
|
9164
|
+
height: viewBoxInfo.height / SCALE_FACTOR,
|
|
9165
|
+
scale: SCALE_FACTOR,
|
|
9166
|
+
// 计算左下角和右上角坐标
|
|
9167
|
+
sw: {
|
|
9168
|
+
x: viewBoxInfo.x / SCALE_FACTOR,
|
|
9169
|
+
y: viewBoxInfo.y / SCALE_FACTOR,
|
|
9170
|
+
},
|
|
9171
|
+
ne: {
|
|
9172
|
+
x: (viewBoxInfo.x + viewBoxInfo.width) / SCALE_FACTOR,
|
|
9173
|
+
y: (viewBoxInfo.y + viewBoxInfo.height) / SCALE_FACTOR,
|
|
9174
|
+
},
|
|
9175
|
+
};
|
|
9176
|
+
}
|
|
9177
|
+
}
|
|
9178
|
+
// 获取当前割草机位置
|
|
9179
|
+
if (mowerPositionData) {
|
|
9180
|
+
newDebugInfo.mowerPosition = {
|
|
9181
|
+
x: mowerPositionData.postureX || 0,
|
|
9182
|
+
y: mowerPositionData.postureY || 0,
|
|
9183
|
+
theta: mowerPositionData.postureTheta || 0,
|
|
9184
|
+
lastX: mowerPositionData.lastPostureX || 0,
|
|
9185
|
+
lastY: mowerPositionData.lastPostureY || 0,
|
|
9186
|
+
lastTheta: mowerPositionData.lastPostureTheta || 0,
|
|
9187
|
+
vehicleState: mowerPositionData.vehicleState || RobotStatus.UNKNOWN,
|
|
9188
|
+
vehicleStateText: getVehicleStateText(mowerPositionData.vehicleState || RobotStatus.UNKNOWN),
|
|
9189
|
+
};
|
|
9190
|
+
}
|
|
9191
|
+
// 获取当前割草地块数据
|
|
9192
|
+
newDebugInfo.partitionData = mowPartitionData;
|
|
9193
|
+
setDebugInfo(newDebugInfo);
|
|
9194
|
+
};
|
|
9195
|
+
updateDebugInfo();
|
|
9196
|
+
}, [debug, mapJson, mowerPositionData, mowPartitionData, defaultTransform]);
|
|
9197
|
+
// 当关键数据变化时立即更新debug信息
|
|
9198
|
+
useEffect(() => {
|
|
9199
|
+
if (!debug)
|
|
9200
|
+
return;
|
|
9201
|
+
const updateDebugInfo = () => {
|
|
9202
|
+
const newDebugInfo = {};
|
|
9203
|
+
// 获取地图GPS边界
|
|
9204
|
+
if (mapJson) {
|
|
9205
|
+
newDebugInfo.mapBounds = getValidGpsBounds(mapJson, defaultTransform?.rotation);
|
|
9206
|
+
}
|
|
9207
|
+
// 获取SVG viewBox信息
|
|
9208
|
+
if (overlayRef.current) {
|
|
9209
|
+
const overlay = overlayRef.current;
|
|
9210
|
+
const svgMapView = overlay.getSvgMapView?.();
|
|
9211
|
+
if (svgMapView) {
|
|
9212
|
+
const viewBoxInfo = svgMapView.getViewBoxInfo();
|
|
9213
|
+
// 计算实际的米单位数据(除以缩放比例)
|
|
9214
|
+
const SCALE_FACTOR = 50; // 根据项目中的缩放因子
|
|
9215
|
+
newDebugInfo.viewBox = {
|
|
9216
|
+
x: viewBoxInfo.x / SCALE_FACTOR,
|
|
9217
|
+
y: viewBoxInfo.y / SCALE_FACTOR,
|
|
9218
|
+
width: viewBoxInfo.width / SCALE_FACTOR,
|
|
9219
|
+
height: viewBoxInfo.height / SCALE_FACTOR,
|
|
9220
|
+
scale: SCALE_FACTOR,
|
|
9221
|
+
// 计算左下角和右上角坐标
|
|
9222
|
+
sw: {
|
|
9223
|
+
x: viewBoxInfo.x / SCALE_FACTOR,
|
|
9224
|
+
y: viewBoxInfo.y / SCALE_FACTOR,
|
|
9225
|
+
},
|
|
9226
|
+
ne: {
|
|
9227
|
+
x: (viewBoxInfo.x + viewBoxInfo.width) / SCALE_FACTOR,
|
|
9228
|
+
y: (viewBoxInfo.y + viewBoxInfo.height) / SCALE_FACTOR,
|
|
9229
|
+
},
|
|
9230
|
+
};
|
|
9231
|
+
}
|
|
9232
|
+
}
|
|
9233
|
+
// 获取当前割草机位置
|
|
9234
|
+
if (mowerPositionData) {
|
|
9235
|
+
newDebugInfo.mowerPosition = {
|
|
9236
|
+
x: mowerPositionData.postureX || 0,
|
|
9237
|
+
y: mowerPositionData.postureY || 0,
|
|
9238
|
+
theta: mowerPositionData.postureTheta || 0,
|
|
9239
|
+
lastX: mowerPositionData.lastPostureX || 0,
|
|
9240
|
+
lastY: mowerPositionData.lastPostureY || 0,
|
|
9241
|
+
lastTheta: mowerPositionData.lastPostureTheta || 0,
|
|
9242
|
+
vehicleState: mowerPositionData.vehicleState || RobotStatus.UNKNOWN,
|
|
9243
|
+
vehicleStateText: getVehicleStateText(mowerPositionData.vehicleState || RobotStatus.UNKNOWN),
|
|
9244
|
+
};
|
|
9245
|
+
}
|
|
9246
|
+
// 获取当前割草地块数据
|
|
9247
|
+
newDebugInfo.partitionData = mowPartitionData;
|
|
9248
|
+
setDebugInfo(newDebugInfo);
|
|
9249
|
+
};
|
|
9250
|
+
updateDebugInfo();
|
|
9251
|
+
}, [debug, mowerPositionData, mowPartitionData]);
|
|
9093
9252
|
useEffect(() => {
|
|
9253
|
+
if (!realTimeData || realTimeData.length === 0 || !Array.isArray(realTimeData)) {
|
|
9254
|
+
return;
|
|
9255
|
+
}
|
|
9256
|
+
console.log('usefeect realTimeData----->', realTimeData, mapJson, pathJson, overlayRef.current);
|
|
9257
|
+
let curMowPartitionData = mowPartitionData;
|
|
9258
|
+
// realtime中包含当前割草任务的数据,根据数据进行path路径和边界的高亮操作,
|
|
9259
|
+
const mowingPartition = realTimeData.find((item) => item.type === RealTimeDataType.PARTITION);
|
|
9260
|
+
if (mowingPartition) {
|
|
9261
|
+
setMowPartitionData(mowingPartition);
|
|
9262
|
+
curMowPartitionData = mowingPartition;
|
|
9263
|
+
}
|
|
9264
|
+
const positionData = realTimeData?.find(item => item?.type === RealTimeDataType.LOCATION);
|
|
9265
|
+
const statusData = realTimeData?.find(item => item?.type === RealTimeDataType.STATUS);
|
|
9266
|
+
if (statusData || positionData) {
|
|
9267
|
+
const currentStatus = statusData?.vehicleState || positionData?.vehicleState;
|
|
9268
|
+
// 车辆回桩不会回传最后的park的位置,所以根据实时数据的状态数据判断车辆回到桩上
|
|
9269
|
+
if ([RobotStatus.CHARGING, RobotStatus.PARKED].includes(currentStatus || RobotStatus.UNKNOWN)) {
|
|
9270
|
+
resetInCharginPie();
|
|
9271
|
+
}
|
|
9272
|
+
else if (currentStatus === RobotStatus.WORKING) {
|
|
9273
|
+
// 兜底收不到割草地块的实时数据,使用状态来兜底
|
|
9274
|
+
overlayRef.current.resetBorderLayerHighlight();
|
|
9275
|
+
setMowPartitionData(null);
|
|
9276
|
+
curMowPartitionData = null;
|
|
9277
|
+
}
|
|
9278
|
+
else if (currentStatus === RobotStatus.MOWING && (curMowPartitionData && !curMowPartitionData?.partitionIds)) {
|
|
9279
|
+
// 如果当前是割草状态,但是地块数据初始化过且不存在则认为是全局割草,则把所有地块都高亮
|
|
9280
|
+
const allPartitionIds = mapJson?.sub_maps?.map(item => item?.id);
|
|
9281
|
+
setMowPartitionData({
|
|
9282
|
+
partitionIds: allPartitionIds
|
|
9283
|
+
});
|
|
9284
|
+
curMowPartitionData = {
|
|
9285
|
+
partitionIds: allPartitionIds
|
|
9286
|
+
};
|
|
9287
|
+
}
|
|
9288
|
+
}
|
|
9094
9289
|
if (!mapJson ||
|
|
9095
9290
|
!pathJson ||
|
|
9096
|
-
!realTimeData ||
|
|
9097
|
-
realTimeData.length === 0 ||
|
|
9098
|
-
!Array.isArray(realTimeData) ||
|
|
9099
9291
|
!overlayRef.current)
|
|
9100
9292
|
return;
|
|
9101
9293
|
// 根据后端推送的实时数据,进行不同处理
|
|
9102
|
-
// TODO:需要根据返回的数据,处理车辆的移动位置
|
|
9103
|
-
console.log('realTimeData----->', realTimeData);
|
|
9104
|
-
// realtime中包含当前割草任务的数据,根据数据进行path路径和边界的高亮操作
|
|
9105
|
-
const curMowPartitionData = realTimeData.find((item) => item.type === RealTimeDataType.PARTITION) || mowPartitionData;
|
|
9106
9294
|
if (curMowPartitionData) {
|
|
9107
|
-
setMowPartitionData(curMowPartitionData);
|
|
9108
9295
|
const isMowing = curMowPartitionData?.partitionIds && curMowPartitionData.partitionIds.length > 0;
|
|
9109
9296
|
overlayRef.current.updateMowPartitionData(curMowPartitionData);
|
|
9110
|
-
console.log('isMowing', isMowing, curMowPartitionData);
|
|
9111
9297
|
if (!isMowing) {
|
|
9112
9298
|
overlayRef.current.resetBorderLayerHighlight();
|
|
9113
9299
|
}
|
|
@@ -9145,14 +9331,11 @@ const MowerMapRenderer = forwardRef(({ mapConfig, modelType, mapRef, mapJson, pa
|
|
|
9145
9331
|
}
|
|
9146
9332
|
}, [realTimeData, mapJson, pathJson]);
|
|
9147
9333
|
useEffect(() => {
|
|
9148
|
-
console.log('defaultTransform----->', defaultTransform);
|
|
9149
9334
|
if (!overlayRef.current || !defaultTransform)
|
|
9150
9335
|
return;
|
|
9151
|
-
|
|
9152
|
-
return;
|
|
9153
|
-
}
|
|
9336
|
+
console.log('defaultTransform----->', defaultTransform, overlayRef.current, mapJson);
|
|
9154
9337
|
overlayRef.current?.setTransform(defaultTransform);
|
|
9155
|
-
const validBounds = getValidGpsBounds(mapJson);
|
|
9338
|
+
const validBounds = getValidGpsBounds(mapJson, defaultTransform?.rotation);
|
|
9156
9339
|
// 地图数据中的坐标格式是 [longitude, latitude]
|
|
9157
9340
|
const swLat = validBounds.sw[1] + defaultTransform.y;
|
|
9158
9341
|
const swLng = validBounds.sw[0] + defaultTransform.x;
|
|
@@ -9198,12 +9381,32 @@ const MowerMapRenderer = forwardRef(({ mapConfig, modelType, mapRef, mapJson, pa
|
|
|
9198
9381
|
setTransform: (t) => overlayRef.current?.setTransform(t),
|
|
9199
9382
|
resetToDefaultTransform: () => overlayRef.current?.resetToDefaultTransform(),
|
|
9200
9383
|
}));
|
|
9384
|
+
// Debug信息组件
|
|
9385
|
+
const DebugInfo = () => {
|
|
9386
|
+
if (!debug)
|
|
9387
|
+
return null;
|
|
9388
|
+
return (jsxs("div", { style: {
|
|
9389
|
+
position: 'fixed',
|
|
9390
|
+
bottom: '10px',
|
|
9391
|
+
left: '10px',
|
|
9392
|
+
backgroundColor: 'rgba(0, 0, 0, 0.8)',
|
|
9393
|
+
color: 'white',
|
|
9394
|
+
padding: '10px',
|
|
9395
|
+
borderRadius: '5px',
|
|
9396
|
+
fontSize: '12px',
|
|
9397
|
+
fontFamily: 'monospace',
|
|
9398
|
+
zIndex: 10000,
|
|
9399
|
+
maxWidth: '300px',
|
|
9400
|
+
lineHeight: '1.4',
|
|
9401
|
+
}, children: [jsx("div", { style: { fontWeight: 'bold', marginBottom: '8px' }, children: "\uD83D\uDC1B Debug Info" }), debugInfo.mapBounds && (jsxs("div", { style: { marginBottom: '6px' }, children: [jsx("div", { style: { fontWeight: 'bold' }, children: "\uD83D\uDCCD Map GPS Bounds:" }), jsxs("div", { children: ["SW: [", debugInfo.mapBounds.sw[0].toFixed(6), ", ", debugInfo.mapBounds.sw[1].toFixed(6), "]"] }), jsxs("div", { children: ["NE: [", debugInfo.mapBounds.ne[0].toFixed(6), ", ", debugInfo.mapBounds.ne[1].toFixed(6), "]"] })] })), debugInfo.viewBox && (jsxs("div", { style: { marginBottom: '6px' }, children: [jsx("div", { style: { fontWeight: 'bold' }, children: "\uD83D\uDCD0 SVG ViewBox (meters):" }), jsxs("div", { children: ["SW: [", debugInfo.viewBox.sw.x.toFixed(2), ", ", debugInfo.viewBox.sw.y.toFixed(2), "]"] }), jsxs("div", { children: ["NE: [", debugInfo.viewBox.ne.x.toFixed(2), ", ", debugInfo.viewBox.ne.y.toFixed(2), "]"] }), jsxs("div", { children: ["Size: ", debugInfo.viewBox.width.toFixed(2), "m \u00D7 ", debugInfo.viewBox.height.toFixed(2), "m"] }), jsxs("div", { children: ["Scale: 1:", debugInfo.viewBox.scale] })] })), debugInfo.mowerPosition && (jsxs("div", { style: { marginBottom: '6px' }, children: [jsx("div", { style: { fontWeight: 'bold' }, children: "\uD83D\uDE9C Mower Position:" }), jsxs("div", { children: ["Current: X=", debugInfo.mowerPosition.x.toFixed(2), ", Y=", debugInfo.mowerPosition.y.toFixed(2)] }), jsxs("div", { children: ["Theta: ", ((debugInfo.mowerPosition.theta * 180) / Math.PI).toFixed(1), "\u00B0"] }), jsxs("div", { children: ["Last: X=", debugInfo.mowerPosition.lastX.toFixed(2), ", Y=", debugInfo.mowerPosition.lastY.toFixed(2)] }), jsxs("div", { children: ["Last Theta: ", ((debugInfo.mowerPosition.lastTheta * 180) / Math.PI).toFixed(1), "\u00B0"] }), jsxs("div", { children: ["Status: ", debugInfo.mowerPosition.vehicleStateText, " (", debugInfo.mowerPosition.vehicleState, ")"] })] })), debugInfo.partitionData && (jsxs("div", { style: { marginBottom: '6px' }, children: [jsx("div", { style: { fontWeight: 'bold' }, children: "\uD83D\uDD32 Mow Partition Data:" }), jsxs("div", { children: ["Type: ", debugInfo.partitionData.type || 'N/A'] }), debugInfo.partitionData.partitionIds &&
|
|
9402
|
+
debugInfo.partitionData.partitionIds.length > 0 ? (jsxs("div", { children: ["Active IDs: [", debugInfo.partitionData.partitionIds.join(', '), "]"] })) : (jsx("div", { children: "No active partitions" })), debugInfo.partitionData.time && (jsxs("div", { children: ["Updated: ", new Date(debugInfo.partitionData.time).toLocaleTimeString()] }))] })), !debugInfo.partitionData && (jsxs("div", { style: { marginBottom: '6px' }, children: [jsx("div", { style: { fontWeight: 'bold' }, children: "\uD83D\uDD32 Mow Partition Data:" }), jsx("div", { style: { color: '#888' }, children: "No partition data available" })] }))] }));
|
|
9403
|
+
};
|
|
9201
9404
|
// 错误显示
|
|
9202
9405
|
if (currentError) {
|
|
9203
|
-
return (
|
|
9406
|
+
return (jsxs("div", { className: className, style: style, children: [jsxs("div", { style: { color: 'red', padding: '10px' }, children: ["\u9519\u8BEF: ", currentError] }), jsx(DebugInfo, {})] }));
|
|
9204
9407
|
}
|
|
9205
|
-
// 使用goole maps
|
|
9206
|
-
return null;
|
|
9408
|
+
// 使用goole maps自定义叠加层,返回debug信息(如果启用)
|
|
9409
|
+
return debug ? jsx(DebugInfo, {}) : null;
|
|
9207
9410
|
});
|
|
9208
9411
|
MowerMapRenderer.displayName = 'MowerMapRenderer';
|
|
9209
9412
|
|