@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.js
CHANGED
|
@@ -3,6 +3,135 @@
|
|
|
3
3
|
var jsxRuntime = require('react/jsx-runtime');
|
|
4
4
|
var React = require('react');
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* 常量和枚举类型定义
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* 机器人状态枚举
|
|
11
|
+
*/
|
|
12
|
+
var RobotStatus;
|
|
13
|
+
(function (RobotStatus) {
|
|
14
|
+
RobotStatus[RobotStatus["PARKED"] = 1] = "PARKED";
|
|
15
|
+
RobotStatus[RobotStatus["CHARGING"] = 2] = "CHARGING";
|
|
16
|
+
RobotStatus[RobotStatus["STANDBY"] = 3] = "STANDBY";
|
|
17
|
+
RobotStatus[RobotStatus["MOWING"] = 4] = "MOWING";
|
|
18
|
+
RobotStatus[RobotStatus["WORKING"] = 5] = "WORKING";
|
|
19
|
+
RobotStatus[RobotStatus["MAPPING"] = 6] = "MAPPING";
|
|
20
|
+
RobotStatus[RobotStatus["ERROR"] = 7] = "ERROR";
|
|
21
|
+
RobotStatus[RobotStatus["UPGRADING"] = 8] = "UPGRADING";
|
|
22
|
+
RobotStatus[RobotStatus["DISCONNECTED"] = 9] = "DISCONNECTED";
|
|
23
|
+
RobotStatus[RobotStatus["UNKNOWN"] = -1] = "UNKNOWN";
|
|
24
|
+
RobotStatus[RobotStatus["TASK_DELAY"] = 10] = "TASK_DELAY";
|
|
25
|
+
})(RobotStatus || (RobotStatus = {}));
|
|
26
|
+
/**
|
|
27
|
+
* RTK状态枚举
|
|
28
|
+
*/
|
|
29
|
+
var RTK_STATE;
|
|
30
|
+
(function (RTK_STATE) {
|
|
31
|
+
RTK_STATE[RTK_STATE["LOW_RTK"] = 1] = "LOW_RTK";
|
|
32
|
+
RTK_STATE[RTK_STATE["MIDDLE_RTK"] = 2] = "MIDDLE_RTK";
|
|
33
|
+
RTK_STATE[RTK_STATE["HIGH_RTK"] = 3] = "HIGH_RTK";
|
|
34
|
+
RTK_STATE[RTK_STATE["NO_POSTURE"] = 10] = "NO_POSTURE";
|
|
35
|
+
RTK_STATE[RTK_STATE["OUT_OF_RANGE"] = 11] = "OUT_OF_RANGE";
|
|
36
|
+
RTK_STATE[RTK_STATE["OFF_LINE"] = 19] = "OFF_LINE";
|
|
37
|
+
})(RTK_STATE || (RTK_STATE = {}));
|
|
38
|
+
/**
|
|
39
|
+
* 实时数据类型枚举
|
|
40
|
+
*/
|
|
41
|
+
var REAL_TIME_DATA_TYPE;
|
|
42
|
+
(function (REAL_TIME_DATA_TYPE) {
|
|
43
|
+
REAL_TIME_DATA_TYPE[REAL_TIME_DATA_TYPE["LOCATION"] = 1] = "LOCATION";
|
|
44
|
+
REAL_TIME_DATA_TYPE[REAL_TIME_DATA_TYPE["PROCESS"] = 2] = "PROCESS";
|
|
45
|
+
})(REAL_TIME_DATA_TYPE || (REAL_TIME_DATA_TYPE = {}));
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* 地图渲染相关常量配置
|
|
49
|
+
*/
|
|
50
|
+
/**
|
|
51
|
+
* 缩放因子 - 将米转换为像素
|
|
52
|
+
* 与Python代码中的SVG比例一致
|
|
53
|
+
*/
|
|
54
|
+
const SCALE_FACTOR = 50; // 50像素/米
|
|
55
|
+
/**
|
|
56
|
+
* 默认线宽设置
|
|
57
|
+
*/
|
|
58
|
+
const DEFAULT_LINE_WIDTHS = {
|
|
59
|
+
OBSTACLE: 2,
|
|
60
|
+
CHARGING_PILE: 2,
|
|
61
|
+
CHANNEL: 2,
|
|
62
|
+
PATH: 20,
|
|
63
|
+
VISION_OFF_AREA: 2,
|
|
64
|
+
TIME_LIMIT_OBSTACLE: 1,
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* 默认透明度设置
|
|
68
|
+
*/
|
|
69
|
+
const DEFAULT_OPACITIES = {
|
|
70
|
+
FULL: 1.0,
|
|
71
|
+
HIGH: 0.7,
|
|
72
|
+
MEDIUM: 0.6};
|
|
73
|
+
/**
|
|
74
|
+
* 默认半径设置
|
|
75
|
+
*/
|
|
76
|
+
const DEFAULT_RADII = {
|
|
77
|
+
CHARGING_PILE: 12};
|
|
78
|
+
/**
|
|
79
|
+
* 图层等级
|
|
80
|
+
*/
|
|
81
|
+
const LAYER_LEVELS = {
|
|
82
|
+
BOUNDARY: 2,
|
|
83
|
+
BOUNDARY_BORDER: 4};
|
|
84
|
+
/**
|
|
85
|
+
* 图层默认id
|
|
86
|
+
*/
|
|
87
|
+
const LAYER_DEFAULT_TYPE = {
|
|
88
|
+
CHANNEL: 'channel',
|
|
89
|
+
BOUNDARY: 'boundary',
|
|
90
|
+
PATH: 'path',
|
|
91
|
+
BOUNDARY_BORDER: 'boundary_border',
|
|
92
|
+
OBSTACLE: 'obstacle',
|
|
93
|
+
CHARGING_PILE: 'charging_pile',
|
|
94
|
+
POINT: 'point',
|
|
95
|
+
SVG: 'svg',
|
|
96
|
+
VISION_OFF_AREA: 'vision_off_area',
|
|
97
|
+
ANTENNA: 'antenna',
|
|
98
|
+
};
|
|
99
|
+
const ISOLATED_BOUNDARY_SVG = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
100
|
+
<g opacity="0.6">
|
|
101
|
+
<rect width="24" height="24" rx="12" fill="#1E1E1F" fill-opacity="0.5"/>
|
|
102
|
+
<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"/>
|
|
103
|
+
<mask id="path-3-outside-1_9822_43516" maskUnits="userSpaceOnUse" x="13.2344" y="7.20545" width="12.0208" height="12.0208" fill="black">
|
|
104
|
+
<rect fill="white" x="13.2344" y="7.20545" width="12.0208" height="12.0208"/>
|
|
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"/>
|
|
106
|
+
</mask>
|
|
107
|
+
<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"/>
|
|
108
|
+
<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)"/>
|
|
109
|
+
<mask id="path-5-outside-2_9822_43516" maskUnits="userSpaceOnUse" x="9.22265" y="10.388" width="12.7279" height="12.7279" fill="black">
|
|
110
|
+
<rect fill="white" x="9.22265" y="10.388" width="12.7279" height="12.7279"/>
|
|
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"/>
|
|
112
|
+
</mask>
|
|
113
|
+
<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"/>
|
|
114
|
+
<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)"/>
|
|
115
|
+
<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"/>
|
|
116
|
+
<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"/>
|
|
117
|
+
<rect width="1.91578" height="4.24403" transform="matrix(-0.707107 -0.707107 -0.707107 0.707107 19.6992 13.8066)" fill="#8E8E8F"/>
|
|
118
|
+
<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"/>
|
|
119
|
+
</g>
|
|
120
|
+
</svg>`;
|
|
121
|
+
/**
|
|
122
|
+
* 遍历割草任务,下述四个字段可以在路径中唯一确定遍历的位置(当前区域、当前块、当前行、在当前行上的路程)
|
|
123
|
+
*/
|
|
124
|
+
const ACTION_BLOCK_COVER = 5;
|
|
125
|
+
/**
|
|
126
|
+
* 遍历割草块转移任务(在同一区域中的一个块转移到下一个块),下述四个字段可以在路径中唯一确定转移的位置(当前区域、前置块、当前转移路径线序号、在当前线上的路程)
|
|
127
|
+
*/
|
|
128
|
+
const ACTION_BLOCK_TRANSFER = 6;
|
|
129
|
+
/**
|
|
130
|
+
* 边界割草任务(割草任务内部的巡边任务)
|
|
131
|
+
*/
|
|
132
|
+
const ACTION_BOUNDARY_TASK = 8;
|
|
133
|
+
const SVG_MAP_VIEW_ID = 'fleet-maps-svg-map-view';
|
|
134
|
+
|
|
6
135
|
/**
|
|
7
136
|
* SVG基础MapView
|
|
8
137
|
* 使用真正的矢量SVG渲染替代Canvas位图渲染
|
|
@@ -16,7 +145,6 @@ class SvgMapView {
|
|
|
16
145
|
this.lineScale = 1; // 线条缩放系数
|
|
17
146
|
// 状态标志
|
|
18
147
|
this.destroyed = false;
|
|
19
|
-
this.showScale = false;
|
|
20
148
|
// 渲染系统 - 移除节流以确保用户操作的实时响应
|
|
21
149
|
// 拖动功能
|
|
22
150
|
this.isDragging = false;
|
|
@@ -59,6 +187,7 @@ class SvgMapView {
|
|
|
59
187
|
this.svg.setAttribute('shape-rendering', 'geometricPrecision');
|
|
60
188
|
this.svg.setAttribute('text-rendering', 'geometricPrecision');
|
|
61
189
|
this.svg.setAttribute('image-rendering', 'optimizeQuality');
|
|
190
|
+
this.svg.setAttribute('id', SVG_MAP_VIEW_ID);
|
|
62
191
|
}
|
|
63
192
|
/**
|
|
64
193
|
* 创建SVG组元素
|
|
@@ -83,7 +212,6 @@ class SvgMapView {
|
|
|
83
212
|
this.layers.sort((a, b) => a.getLevel() - b.getLevel());
|
|
84
213
|
}
|
|
85
214
|
getLayer(type) {
|
|
86
|
-
console.log('getLayer----->', this.layers, type);
|
|
87
215
|
return this.layers.find((layer) => layer.getType() === type) || null;
|
|
88
216
|
}
|
|
89
217
|
/**
|
|
@@ -121,7 +249,7 @@ class SvgMapView {
|
|
|
121
249
|
* 设置自适应视图变换 - 让SVG刚好包裹住图形
|
|
122
250
|
*/
|
|
123
251
|
fitToView(bounds) {
|
|
124
|
-
const padding =
|
|
252
|
+
const padding = 20; // 添加一些边距以避免内容贴边
|
|
125
253
|
const boundWidth = bounds.maxX - bounds.minX;
|
|
126
254
|
const boundHeight = bounds.maxY - bounds.minY;
|
|
127
255
|
// 防止宽高为0的情况
|
|
@@ -144,8 +272,8 @@ class SvgMapView {
|
|
|
144
272
|
this.viewBox = {
|
|
145
273
|
x: bounds.minX - padding,
|
|
146
274
|
y: bounds.minY - padding,
|
|
147
|
-
width: boundWidth + padding,
|
|
148
|
-
height: boundHeight + padding,
|
|
275
|
+
width: boundWidth + padding * 2,
|
|
276
|
+
height: boundHeight + padding * 2,
|
|
149
277
|
};
|
|
150
278
|
// 根据宽高比选择合适的preserveAspectRatio设置
|
|
151
279
|
if (Math.abs(contentAspectRatio - containerAspectRatio) < 0.01) {
|
|
@@ -157,42 +285,6 @@ class SvgMapView {
|
|
|
157
285
|
this.svg.setAttribute('preserveAspectRatio', 'xMidYMid meet');
|
|
158
286
|
}
|
|
159
287
|
this.updateViewBox();
|
|
160
|
-
this.refresh();
|
|
161
|
-
}
|
|
162
|
-
/**
|
|
163
|
-
* 重置变换
|
|
164
|
-
*/
|
|
165
|
-
resetTransform() {
|
|
166
|
-
this.scale = 1;
|
|
167
|
-
// 重置viewBox到默认状态
|
|
168
|
-
const containerRect = this.container.getBoundingClientRect();
|
|
169
|
-
this.viewBox = {
|
|
170
|
-
x: 0,
|
|
171
|
-
y: 0,
|
|
172
|
-
width: containerRect.width,
|
|
173
|
-
height: containerRect.height,
|
|
174
|
-
};
|
|
175
|
-
this.updateViewBox();
|
|
176
|
-
this.refresh();
|
|
177
|
-
}
|
|
178
|
-
/**
|
|
179
|
-
* 设置缩放级别
|
|
180
|
-
*/
|
|
181
|
-
setZoom(zoomLevel) {
|
|
182
|
-
if (zoomLevel <= 0)
|
|
183
|
-
return;
|
|
184
|
-
const oldScale = this.scale;
|
|
185
|
-
this.scale = zoomLevel;
|
|
186
|
-
// 调整viewBox以实现缩放
|
|
187
|
-
const scaleFactor = oldScale / this.scale;
|
|
188
|
-
const centerX = this.viewBox.x + this.viewBox.width / 2;
|
|
189
|
-
const centerY = this.viewBox.y + this.viewBox.height / 2;
|
|
190
|
-
this.viewBox.width *= scaleFactor;
|
|
191
|
-
this.viewBox.height *= scaleFactor;
|
|
192
|
-
this.viewBox.x = centerX - this.viewBox.width / 2;
|
|
193
|
-
this.viewBox.y = centerY - this.viewBox.height / 2;
|
|
194
|
-
this.updateViewBox();
|
|
195
|
-
this.refresh();
|
|
196
288
|
}
|
|
197
289
|
/**
|
|
198
290
|
* 获取当前缩放级别
|
|
@@ -200,15 +292,6 @@ class SvgMapView {
|
|
|
200
292
|
getZoom() {
|
|
201
293
|
return this.scale;
|
|
202
294
|
}
|
|
203
|
-
/**
|
|
204
|
-
* 设置线条缩放系数
|
|
205
|
-
*/
|
|
206
|
-
setLineScale(lineScale) {
|
|
207
|
-
if (lineScale <= 0)
|
|
208
|
-
return;
|
|
209
|
-
this.lineScale = lineScale;
|
|
210
|
-
this.refresh();
|
|
211
|
-
}
|
|
212
295
|
/**
|
|
213
296
|
* 获取当前线条缩放系数
|
|
214
297
|
*/
|
|
@@ -312,7 +395,7 @@ class SvgMapView {
|
|
|
312
395
|
// const layerType = layerIdParts.slice(1, -1).join('-'); // 处理类型名中可能包含连字符的情况
|
|
313
396
|
// const layerLevel = parseInt(layerIdParts[layerIdParts.length - 1]);
|
|
314
397
|
// // 查找对应的图层对象
|
|
315
|
-
// const targetLayer = this.layers.find(layer =>
|
|
398
|
+
// const targetLayer = this.layers.find(layer =>
|
|
316
399
|
// layer.getType() === layerType && layer.getLevel() === layerLevel
|
|
317
400
|
// );
|
|
318
401
|
// if (targetLayer && targetLayer.isVisible()) {
|
|
@@ -349,12 +432,6 @@ class SvgMapView {
|
|
|
349
432
|
return;
|
|
350
433
|
this.render();
|
|
351
434
|
}
|
|
352
|
-
/**
|
|
353
|
-
* 重新初始化SVG(用于容器大小变化)
|
|
354
|
-
*/
|
|
355
|
-
reinitializeSVG() {
|
|
356
|
-
this.refresh();
|
|
357
|
-
}
|
|
358
435
|
// ==================== 拖拽功能 ====================
|
|
359
436
|
/**
|
|
360
437
|
* 设置拖拽事件处理器
|
|
@@ -479,22 +556,6 @@ class SvgMapView {
|
|
|
479
556
|
return null;
|
|
480
557
|
}
|
|
481
558
|
}
|
|
482
|
-
/**
|
|
483
|
-
* 自动适配viewBox到实际内容
|
|
484
|
-
*/
|
|
485
|
-
autoFitToContent() {
|
|
486
|
-
if (this.destroyed || this.layers.length === 0)
|
|
487
|
-
return;
|
|
488
|
-
const bounds = this.getLayersGroupBounds();
|
|
489
|
-
if (bounds) {
|
|
490
|
-
this.fitToView({
|
|
491
|
-
minX: bounds.x,
|
|
492
|
-
minY: bounds.y,
|
|
493
|
-
maxX: bounds.x + bounds.width,
|
|
494
|
-
maxY: bounds.y + bounds.height,
|
|
495
|
-
});
|
|
496
|
-
}
|
|
497
|
-
}
|
|
498
559
|
/**
|
|
499
560
|
* 获取ViewBox信息
|
|
500
561
|
*/
|
|
@@ -515,13 +576,6 @@ class SvgMapView {
|
|
|
515
576
|
* 诊断SVG尺寸信息
|
|
516
577
|
*/
|
|
517
578
|
diagnosticSizeInfo() { }
|
|
518
|
-
/**
|
|
519
|
-
* 设置是否显示比例尺
|
|
520
|
-
*/
|
|
521
|
-
setShowScale(show) {
|
|
522
|
-
this.showScale = show;
|
|
523
|
-
this.refresh();
|
|
524
|
-
}
|
|
525
579
|
/**
|
|
526
580
|
* 获取SVG元素
|
|
527
581
|
*/
|
|
@@ -723,8 +777,6 @@ const create = (createState) => createState ? createImpl(createState) : createIm
|
|
|
723
777
|
|
|
724
778
|
const useSubBoundaryBorderStore = create((set, get) => ({
|
|
725
779
|
subBoundaryBorder: {},
|
|
726
|
-
// 覆盖所有数据
|
|
727
|
-
setSubBoundaryBorder: (subBoundaryBorder) => set({ subBoundaryBorder }),
|
|
728
780
|
// 追加单个数据
|
|
729
781
|
addSubBoundaryBorder: (key, element) => set((state) => ({
|
|
730
782
|
subBoundaryBorder: {
|
|
@@ -732,134 +784,28 @@ const useSubBoundaryBorderStore = create((set, get) => ({
|
|
|
732
784
|
[key]: element,
|
|
733
785
|
},
|
|
734
786
|
})),
|
|
735
|
-
// 追加多个数据
|
|
736
|
-
addMultipleSubBoundaryBorders: (borders) => set((state) => ({
|
|
737
|
-
subBoundaryBorder: {
|
|
738
|
-
...state.subBoundaryBorder,
|
|
739
|
-
...borders,
|
|
740
|
-
},
|
|
741
|
-
})),
|
|
742
787
|
// 清空所有数据
|
|
743
788
|
clearSubBoundaryBorder: () => set({ subBoundaryBorder: {} }),
|
|
789
|
+
// 障碍物
|
|
790
|
+
obstacles: {},
|
|
791
|
+
addObstacles: (key, element) => set((state) => ({
|
|
792
|
+
obstacles: {
|
|
793
|
+
...state.obstacles,
|
|
794
|
+
[key]: element,
|
|
795
|
+
},
|
|
796
|
+
})),
|
|
797
|
+
clearObstacles: () => set({ obstacles: {} }),
|
|
798
|
+
// svg数据
|
|
799
|
+
svgElements: {},
|
|
800
|
+
addSvgElements: (key, element) => set((state) => ({
|
|
801
|
+
svgElements: {
|
|
802
|
+
...state.svgElements,
|
|
803
|
+
[key]: element,
|
|
804
|
+
},
|
|
805
|
+
})),
|
|
806
|
+
clearSvgElements: () => set({ svgElements: {} }),
|
|
744
807
|
}));
|
|
745
808
|
|
|
746
|
-
/**
|
|
747
|
-
* 地图渲染相关常量配置
|
|
748
|
-
*/
|
|
749
|
-
/**
|
|
750
|
-
* 缩放因子 - 将米转换为像素
|
|
751
|
-
* 与Python代码中的SVG比例一致
|
|
752
|
-
*/
|
|
753
|
-
const SCALE_FACTOR = 50; // 50像素/米
|
|
754
|
-
/**
|
|
755
|
-
* 默认线宽设置
|
|
756
|
-
*/
|
|
757
|
-
const DEFAULT_LINE_WIDTHS = {
|
|
758
|
-
OBSTACLE: 2,
|
|
759
|
-
CHARGING_PILE: 2,
|
|
760
|
-
CHANNEL: 2,
|
|
761
|
-
PATH: 20,
|
|
762
|
-
VISION_OFF_AREA: 2,
|
|
763
|
-
TIME_LIMIT_OBSTACLE: 1,
|
|
764
|
-
};
|
|
765
|
-
/**
|
|
766
|
-
* 默认透明度设置
|
|
767
|
-
*/
|
|
768
|
-
const DEFAULT_OPACITIES = {
|
|
769
|
-
FULL: 1.0,
|
|
770
|
-
HIGH: 0.7,
|
|
771
|
-
LOW: 0.4};
|
|
772
|
-
/**
|
|
773
|
-
* 默认半径设置
|
|
774
|
-
*/
|
|
775
|
-
const DEFAULT_RADII = {
|
|
776
|
-
CHARGING_PILE: 12};
|
|
777
|
-
/**
|
|
778
|
-
* 图层等级
|
|
779
|
-
*/
|
|
780
|
-
const LAYER_LEVELS = {
|
|
781
|
-
BOUNDARY: 2,
|
|
782
|
-
BOUNDARY_BORDER: 4};
|
|
783
|
-
/**
|
|
784
|
-
* 图层默认id
|
|
785
|
-
*/
|
|
786
|
-
const LAYER_DEFAULT_TYPE = {
|
|
787
|
-
CHANNEL: 'channel',
|
|
788
|
-
BOUNDARY: 'boundary',
|
|
789
|
-
PATH: 'path',
|
|
790
|
-
BOUNDARY_BORDER: 'boundary_border',
|
|
791
|
-
OBSTACLE: 'obstacle',
|
|
792
|
-
CHARGING_PILE: 'charging_pile',
|
|
793
|
-
POINT: 'point',
|
|
794
|
-
SVG: 'svg',
|
|
795
|
-
VISION_OFF_AREA: 'vision_off_area',
|
|
796
|
-
ANTENNA: 'antenna',
|
|
797
|
-
};
|
|
798
|
-
var RobotStatus;
|
|
799
|
-
(function (RobotStatus) {
|
|
800
|
-
RobotStatus[RobotStatus["PARKED"] = 1] = "PARKED";
|
|
801
|
-
RobotStatus[RobotStatus["CHARGING"] = 2] = "CHARGING";
|
|
802
|
-
RobotStatus[RobotStatus["STANDBY"] = 3] = "STANDBY";
|
|
803
|
-
RobotStatus[RobotStatus["MOWING"] = 4] = "MOWING";
|
|
804
|
-
RobotStatus[RobotStatus["WORKING"] = 5] = "WORKING";
|
|
805
|
-
RobotStatus[RobotStatus["MAPPING"] = 6] = "MAPPING";
|
|
806
|
-
RobotStatus[RobotStatus["ERROR"] = 7] = "ERROR";
|
|
807
|
-
RobotStatus[RobotStatus["UPGRADING"] = 8] = "UPGRADING";
|
|
808
|
-
RobotStatus[RobotStatus["DISCONNECTED"] = 9] = "DISCONNECTED";
|
|
809
|
-
RobotStatus[RobotStatus["UNKNOWN"] = -1] = "UNKNOWN";
|
|
810
|
-
RobotStatus[RobotStatus["TASK_DELAY"] = 10] = "TASK_DELAY";
|
|
811
|
-
// WAITING = 'Waiting',
|
|
812
|
-
})(RobotStatus || (RobotStatus = {}));
|
|
813
|
-
// RTK状态
|
|
814
|
-
var RTK_STATE;
|
|
815
|
-
(function (RTK_STATE) {
|
|
816
|
-
RTK_STATE[RTK_STATE["LOW_RTK"] = 1] = "LOW_RTK";
|
|
817
|
-
RTK_STATE[RTK_STATE["MIDDLE_RTK"] = 2] = "MIDDLE_RTK";
|
|
818
|
-
RTK_STATE[RTK_STATE["HIGH_RTK"] = 3] = "HIGH_RTK";
|
|
819
|
-
RTK_STATE[RTK_STATE["NO_POSTURE"] = 10] = "NO_POSTURE";
|
|
820
|
-
RTK_STATE[RTK_STATE["OUT_OF_RANGE"] = 11] = "OUT_OF_RANGE";
|
|
821
|
-
RTK_STATE[RTK_STATE["OFF_LINE"] = 19] = "OFF_LINE";
|
|
822
|
-
})(RTK_STATE || (RTK_STATE = {}));
|
|
823
|
-
var REAL_TIME_DATA_TYPE;
|
|
824
|
-
(function (REAL_TIME_DATA_TYPE) {
|
|
825
|
-
REAL_TIME_DATA_TYPE[REAL_TIME_DATA_TYPE["LOCATION"] = 1] = "LOCATION";
|
|
826
|
-
REAL_TIME_DATA_TYPE[REAL_TIME_DATA_TYPE["PROCESS"] = 2] = "PROCESS";
|
|
827
|
-
})(REAL_TIME_DATA_TYPE || (REAL_TIME_DATA_TYPE = {}));
|
|
828
|
-
const ISOLATED_BOUNDARY_SVG = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
829
|
-
<g opacity="0.6">
|
|
830
|
-
<rect width="24" height="24" rx="12" fill="#1E1E1F" fill-opacity="0.5"/>
|
|
831
|
-
<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"/>
|
|
832
|
-
<mask id="path-3-outside-1_9822_43516" maskUnits="userSpaceOnUse" x="13.2344" y="7.20545" width="12.0208" height="12.0208" fill="black">
|
|
833
|
-
<rect fill="white" x="13.2344" y="7.20545" width="12.0208" height="12.0208"/>
|
|
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"/>
|
|
835
|
-
</mask>
|
|
836
|
-
<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"/>
|
|
837
|
-
<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)"/>
|
|
838
|
-
<mask id="path-5-outside-2_9822_43516" maskUnits="userSpaceOnUse" x="9.22265" y="10.388" width="12.7279" height="12.7279" fill="black">
|
|
839
|
-
<rect fill="white" x="9.22265" y="10.388" width="12.7279" height="12.7279"/>
|
|
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"/>
|
|
841
|
-
</mask>
|
|
842
|
-
<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"/>
|
|
843
|
-
<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)"/>
|
|
844
|
-
<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"/>
|
|
845
|
-
<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"/>
|
|
846
|
-
<rect width="1.91578" height="4.24403" transform="matrix(-0.707107 -0.707107 -0.707107 0.707107 19.6992 13.8066)" fill="#8E8E8F"/>
|
|
847
|
-
<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"/>
|
|
848
|
-
</g>
|
|
849
|
-
</svg>`;
|
|
850
|
-
/**
|
|
851
|
-
* 遍历割草任务,下述四个字段可以在路径中唯一确定遍历的位置(当前区域、当前块、当前行、在当前行上的路程)
|
|
852
|
-
*/
|
|
853
|
-
const ACTION_BLOCK_COVER = 5;
|
|
854
|
-
/**
|
|
855
|
-
* 遍历割草块转移任务(在同一区域中的一个块转移到下一个块),下述四个字段可以在路径中唯一确定转移的位置(当前区域、前置块、当前转移路径线序号、在当前线上的路程)
|
|
856
|
-
*/
|
|
857
|
-
const ACTION_BLOCK_TRANSFER = 6;
|
|
858
|
-
/**
|
|
859
|
-
* 边界割草任务(割草任务内部的巡边任务)
|
|
860
|
-
*/
|
|
861
|
-
const ACTION_BOUNDARY_TASK = 8;
|
|
862
|
-
|
|
863
809
|
/**
|
|
864
810
|
* 路径图层
|
|
865
811
|
* 专门处理路径元素的渲染
|
|
@@ -910,51 +856,90 @@ class ChannelLayer extends BaseLayer {
|
|
|
910
856
|
}
|
|
911
857
|
// �� 修改:计算包含所有分区和通道的边界框
|
|
912
858
|
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
913
|
-
// 1.
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
859
|
+
// 1. 先计算所有分区的边界,如果能拿到边界的svg的大小,就使用这个如果拿不到,就根据分区去计算
|
|
860
|
+
const svg = document.getElementById(SVG_MAP_VIEW_ID);
|
|
861
|
+
if (svg && svg instanceof SVGSVGElement && svg.viewBox) {
|
|
862
|
+
const viewBox = svg.viewBox.baseVal;
|
|
863
|
+
minX = viewBox.x;
|
|
864
|
+
minY = viewBox.y;
|
|
865
|
+
maxX = viewBox.x + viewBox.width;
|
|
866
|
+
maxY = viewBox.y + viewBox.height;
|
|
867
|
+
}
|
|
868
|
+
else {
|
|
869
|
+
for (const partitionId in subBoundaryBorder) {
|
|
870
|
+
const boundaryData = subBoundaryBorder[partitionId];
|
|
871
|
+
if (boundaryData && boundaryData.coordinates && boundaryData.coordinates.length > 0) {
|
|
872
|
+
for (const coord of boundaryData.coordinates) {
|
|
873
|
+
minX = Math.min(minX, coord[0]);
|
|
874
|
+
minY = Math.min(minY, coord[1]);
|
|
875
|
+
maxX = Math.max(maxX, coord[0]);
|
|
876
|
+
maxY = Math.max(maxY, coord[1]);
|
|
877
|
+
}
|
|
922
878
|
}
|
|
923
879
|
}
|
|
924
880
|
}
|
|
925
881
|
// 2. 再计算所有通道的边界
|
|
926
882
|
for (const element of this.elements) {
|
|
927
|
-
const tunnelConnection = element.originalData?.connection;
|
|
928
|
-
if (tunnelConnection && Array.isArray(tunnelConnection)) {
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
883
|
+
// const tunnelConnection = element.originalData?.connection;
|
|
884
|
+
// if (tunnelConnection && Array.isArray(tunnelConnection)) {
|
|
885
|
+
// const clipPathId = `channel-exclude-${
|
|
886
|
+
// element.originalData?.id || Math.random().toString(36).substr(2, 9)
|
|
887
|
+
// }`;
|
|
888
|
+
// // 检查是否已存在该 clipPath
|
|
889
|
+
// const existingClipPath = defs.querySelector(`#${clipPathId}`);
|
|
890
|
+
// if (existingClipPath) continue;
|
|
891
|
+
// // 创建 clipPath
|
|
892
|
+
// const clipPath = document.createElementNS('http://www.w3.org/2000/svg', 'clipPath');
|
|
893
|
+
// clipPath.setAttribute('id', clipPathId);
|
|
894
|
+
// clipPath.setAttribute('clipPathUnits', 'userSpaceOnUse');
|
|
895
|
+
// // === 合成一个 path ===
|
|
896
|
+
// let d = `M ${minX} ${minY} L ${maxX} ${minY} L ${maxX} ${maxY} L ${minX} ${maxY} Z`;
|
|
897
|
+
// for (const partitionId of tunnelConnection) {
|
|
898
|
+
// const boundaryData = subBoundaryBorder[partitionId];
|
|
899
|
+
// if (boundaryData && boundaryData.coordinates.length >= 3) {
|
|
900
|
+
// d += ` M ${boundaryData.coordinates[0][0]} ${boundaryData.coordinates[0][1]}`;
|
|
901
|
+
// for (let i = 1; i < boundaryData.coordinates.length; i++) {
|
|
902
|
+
// d += ` L ${boundaryData.coordinates[i][0]} ${boundaryData.coordinates[i][1]}`;
|
|
903
|
+
// }
|
|
904
|
+
// d += ' Z';
|
|
905
|
+
// }
|
|
906
|
+
// }
|
|
907
|
+
// const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
|
|
908
|
+
// path.setAttribute('d', d);
|
|
909
|
+
// path.setAttribute('clip-rule', 'evenodd'); // 关键
|
|
910
|
+
// clipPath.appendChild(path);
|
|
911
|
+
// defs.appendChild(clipPath);
|
|
912
|
+
// clipPathIdsMap[element.originalData?.id.toString()] = clipPathId;
|
|
913
|
+
// } else {
|
|
914
|
+
const clipPathId = `channel-exclude-all-${element.originalData?.id || Math.random().toString(36).substr(2, 9)}`;
|
|
915
|
+
// 检查是否已存在该 clipPath
|
|
916
|
+
const existingClipPath = defs.querySelector(`#${clipPathId}`);
|
|
917
|
+
if (existingClipPath)
|
|
918
|
+
continue;
|
|
919
|
+
// 创建 clipPath
|
|
920
|
+
const clipPath = document.createElementNS('http://www.w3.org/2000/svg', 'clipPath');
|
|
921
|
+
clipPath.setAttribute('id', clipPathId);
|
|
922
|
+
clipPath.setAttribute('clipPathUnits', 'userSpaceOnUse');
|
|
923
|
+
// === 合成一个 path ===
|
|
924
|
+
let d = `M ${minX} ${minY} L ${maxX} ${minY} L ${maxX} ${maxY} L ${minX} ${maxY} Z`;
|
|
925
|
+
for (const partitionId in subBoundaryBorder) {
|
|
926
|
+
const boundaryData = subBoundaryBorder[partitionId];
|
|
927
|
+
if (boundaryData && boundaryData.coordinates.length >= 3) {
|
|
928
|
+
d += ` M ${boundaryData.coordinates[0][0]} ${boundaryData.coordinates[0][1]}`;
|
|
929
|
+
for (let i = 1; i < boundaryData.coordinates.length; i++) {
|
|
930
|
+
d += ` L ${boundaryData.coordinates[i][0]} ${boundaryData.coordinates[i][1]}`;
|
|
948
931
|
}
|
|
932
|
+
d += ' Z';
|
|
949
933
|
}
|
|
950
|
-
const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
|
|
951
|
-
path.setAttribute('d', d);
|
|
952
|
-
path.setAttribute('clip-rule', 'evenodd'); // 关键
|
|
953
|
-
clipPath.appendChild(path);
|
|
954
|
-
defs.appendChild(clipPath);
|
|
955
|
-
clipPathIdsMap[element.originalData?.id.toString()] = clipPathId;
|
|
956
934
|
}
|
|
935
|
+
const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
|
|
936
|
+
path.setAttribute('d', d);
|
|
937
|
+
path.setAttribute('clip-rule', 'evenodd'); // 关键
|
|
938
|
+
clipPath.appendChild(path);
|
|
939
|
+
defs.appendChild(clipPath);
|
|
940
|
+
clipPathIdsMap[element.originalData?.id.toString()] = clipPathId;
|
|
957
941
|
}
|
|
942
|
+
// }
|
|
958
943
|
return clipPathIdsMap;
|
|
959
944
|
}
|
|
960
945
|
/**
|
|
@@ -1025,7 +1010,7 @@ class PathLayer extends BaseLayer {
|
|
|
1025
1010
|
* 创建所有分区并集的 clipPath
|
|
1026
1011
|
*/
|
|
1027
1012
|
createUnionClipPath(svgGroup) {
|
|
1028
|
-
const { subBoundaryBorder } = useSubBoundaryBorderStore.getState();
|
|
1013
|
+
const { subBoundaryBorder, obstacles, svgElements } = useSubBoundaryBorderStore.getState();
|
|
1029
1014
|
// 确保 defs 元素存在
|
|
1030
1015
|
let defs = svgGroup.querySelector('defs');
|
|
1031
1016
|
if (!defs) {
|
|
@@ -1039,7 +1024,7 @@ class PathLayer extends BaseLayer {
|
|
|
1039
1024
|
defs.removeChild(existing);
|
|
1040
1025
|
// 合成所有分区的 path
|
|
1041
1026
|
let d = '';
|
|
1042
|
-
//
|
|
1027
|
+
// 1. 外圈(主边界,顺时针)
|
|
1043
1028
|
Object.values(subBoundaryBorder).forEach((item) => {
|
|
1044
1029
|
const bCoords = item.coordinates;
|
|
1045
1030
|
if (bCoords.length >= 3) {
|
|
@@ -1050,6 +1035,26 @@ class PathLayer extends BaseLayer {
|
|
|
1050
1035
|
d += ' Z ';
|
|
1051
1036
|
}
|
|
1052
1037
|
});
|
|
1038
|
+
// 2. 内圈(禁区,逆时针)
|
|
1039
|
+
Object.values(obstacles).forEach((item) => {
|
|
1040
|
+
const bCoords = item.coordinates;
|
|
1041
|
+
if (bCoords.length >= 3) {
|
|
1042
|
+
d += `M ${bCoords[bCoords.length - 1][0]} ${bCoords[bCoords.length - 1][1]}`;
|
|
1043
|
+
for (let i = bCoords.length - 2; i >= 0; i--) {
|
|
1044
|
+
d += ` L ${bCoords[i][0]} ${bCoords[i][1]}`;
|
|
1045
|
+
}
|
|
1046
|
+
d += ' Z ';
|
|
1047
|
+
}
|
|
1048
|
+
});
|
|
1049
|
+
// 3. svgElements(直接拼接path字符串,建议逆时针)
|
|
1050
|
+
if (Array.isArray(svgElements)) {
|
|
1051
|
+
svgElements.forEach((svgPath) => {
|
|
1052
|
+
const svgPathString = svgPath?.metadata?.svg;
|
|
1053
|
+
if (svgPathString && typeof svgPathString === 'string' && svgPathString.trim()) {
|
|
1054
|
+
d += svgPathString + ' ';
|
|
1055
|
+
}
|
|
1056
|
+
});
|
|
1057
|
+
}
|
|
1053
1058
|
const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
|
|
1054
1059
|
path.setAttribute('d', d);
|
|
1055
1060
|
const clipPath = document.createElementNS('http://www.w3.org/2000/svg', 'clipPath');
|
|
@@ -1074,7 +1079,7 @@ class PathLayer extends BaseLayer {
|
|
|
1074
1079
|
// 2. 创建一个组,应用 clipPath
|
|
1075
1080
|
const group = document.createElementNS('http://www.w3.org/2000/svg', 'g');
|
|
1076
1081
|
group.setAttribute('clip-path', `url(#${clipPathId})`);
|
|
1077
|
-
group.setAttribute('opacity', '0.
|
|
1082
|
+
group.setAttribute('opacity', '0.6'); // 统一透明度,防止叠加脏乱
|
|
1078
1083
|
// 3. 渲染所有路径
|
|
1079
1084
|
for (const element of this.elements) {
|
|
1080
1085
|
const { id, elements } = element;
|
|
@@ -1222,7 +1227,7 @@ class ObstacleLayer extends BaseLayer {
|
|
|
1222
1227
|
}
|
|
1223
1228
|
}
|
|
1224
1229
|
|
|
1225
|
-
var chargingPileImage = "data:image/png;base64,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";
|
|
1230
|
+
var chargingPileImage = "data:image/png;base64,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";
|
|
1226
1231
|
|
|
1227
1232
|
/**
|
|
1228
1233
|
* 充电桩图层
|
|
@@ -1412,7 +1417,7 @@ class SvgElementLayer extends BaseLayer {
|
|
|
1412
1417
|
// 在transformGroup上应用变换:平移到中心,旋转,缩放,然后居中SVG
|
|
1413
1418
|
const transform = [
|
|
1414
1419
|
`translate(${center[0]}, ${center[1]})`,
|
|
1415
|
-
`rotate(${(direction * 180) / Math.PI})`,
|
|
1420
|
+
`rotate(${-(direction * 180) / Math.PI})`,
|
|
1416
1421
|
`scale(${userScale})`,
|
|
1417
1422
|
`translate(${-originalWidth / 2}, ${-originalHeight / 2})`,
|
|
1418
1423
|
].join(' ');
|
|
@@ -1510,7 +1515,7 @@ class VisionOffLayer extends BaseLayer {
|
|
|
1510
1515
|
*/
|
|
1511
1516
|
const BOUNDARY_STYLES = {
|
|
1512
1517
|
lineColor: '#ffffff',
|
|
1513
|
-
fillColor: 'rgba(239, 255, 237, 0.
|
|
1518
|
+
fillColor: 'rgba(239, 255, 237, 0.1)', // 更鲜艳的绿色半透明填充,增强可见性
|
|
1514
1519
|
lineWidth: 2,
|
|
1515
1520
|
opacity: DEFAULT_OPACITIES.FULL,
|
|
1516
1521
|
mowingLineColor: 'rgba(99, 216, 174, 1)',
|
|
@@ -1542,10 +1547,10 @@ const DOODLE_STYLES = {
|
|
|
1542
1547
|
};
|
|
1543
1548
|
const PATH_EDGE_STYLES = {
|
|
1544
1549
|
lineWidth: DEFAULT_LINE_WIDTHS.PATH,
|
|
1545
|
-
opacity: DEFAULT_OPACITIES.
|
|
1546
|
-
edgeLineColor: 'rgba(
|
|
1550
|
+
opacity: DEFAULT_OPACITIES.MEDIUM,
|
|
1551
|
+
edgeLineColor: 'rgba(231, 238, 246)',
|
|
1547
1552
|
transLineColor: 'transparent',
|
|
1548
|
-
mowedLineColor: 'rgba(
|
|
1553
|
+
mowedLineColor: 'rgba(231, 238, 246)',
|
|
1549
1554
|
mowingLineColor: 'rgba(123, 200, 187)',
|
|
1550
1555
|
};
|
|
1551
1556
|
const CHANNEL_STYLES = {
|
|
@@ -1614,15 +1619,6 @@ function convertCoordinate(x, y) {
|
|
|
1614
1619
|
};
|
|
1615
1620
|
}
|
|
1616
1621
|
|
|
1617
|
-
/**
|
|
1618
|
-
* 路径段类型
|
|
1619
|
-
*/
|
|
1620
|
-
var PathSegmentType;
|
|
1621
|
-
(function (PathSegmentType) {
|
|
1622
|
-
PathSegmentType["EDGE"] = "edge";
|
|
1623
|
-
PathSegmentType["MOWING"] = "mowing";
|
|
1624
|
-
PathSegmentType["TRANS"] = "trans";
|
|
1625
|
-
})(PathSegmentType || (PathSegmentType = {}));
|
|
1626
1622
|
/**
|
|
1627
1623
|
* 按Python逻辑创建路径段:根据连续的两点之间的关系确定线段类型
|
|
1628
1624
|
*/
|
|
@@ -1897,26 +1893,7 @@ function generateBoundaryData(mapData, pathData) {
|
|
|
1897
1893
|
}
|
|
1898
1894
|
// 第一步:收集所有TUNNEL数据的connection信息
|
|
1899
1895
|
const connectedBoundaryIds = new Set();
|
|
1900
|
-
//
|
|
1901
|
-
for (const subMap of mapData.sub_maps) {
|
|
1902
|
-
if (!subMap.elements)
|
|
1903
|
-
continue;
|
|
1904
|
-
// 找到该子地图中所有 type 为 TUNNEL 的元素
|
|
1905
|
-
const tunnelElements = subMap.elements.filter(element => element.type === 'TUNNEL');
|
|
1906
|
-
for (const tunnelElement of tunnelElements) {
|
|
1907
|
-
const connection = tunnelElement.connection;
|
|
1908
|
-
if (connection) {
|
|
1909
|
-
// connection可能是单个数字或数组
|
|
1910
|
-
if (Array.isArray(connection)) {
|
|
1911
|
-
connection.forEach(id => connectedBoundaryIds.add(id));
|
|
1912
|
-
}
|
|
1913
|
-
else if (typeof connection === 'number') {
|
|
1914
|
-
connectedBoundaryIds.add(connection);
|
|
1915
|
-
}
|
|
1916
|
-
}
|
|
1917
|
-
}
|
|
1918
|
-
}
|
|
1919
|
-
// 1.2 遍历mapData中的tunnels字段
|
|
1896
|
+
// 遍历mapData中的tunnels字段
|
|
1920
1897
|
if (mapData.tunnels && Array.isArray(mapData.tunnels)) {
|
|
1921
1898
|
for (const tunnel of mapData.tunnels) {
|
|
1922
1899
|
const connection = tunnel.connection;
|
|
@@ -1938,6 +1915,8 @@ function generateBoundaryData(mapData, pathData) {
|
|
|
1938
1915
|
continue;
|
|
1939
1916
|
// 每个sub_map的elements是边界坐标,没有sub_map只有一个boundary数据
|
|
1940
1917
|
const boundaryElement = subMap.elements.find(element => element.type === 'BOUNDARY');
|
|
1918
|
+
// 如果当前subMap存在充电桩且充电桩存在tunnel,说明当前subMap中的boundary是初始boundary,这个boundary不为孤立区域
|
|
1919
|
+
const hasTunnelToChargingPile = subMap.elements.some(element => element.type === 'CHARGING_PILE' && element.tunnel);
|
|
1941
1920
|
// 创建基础的 boundary 数据(来自 mapData)
|
|
1942
1921
|
const boundary = {
|
|
1943
1922
|
// 从 BOUNDARY 元素复制属性
|
|
@@ -1947,7 +1926,7 @@ function generateBoundaryData(mapData, pathData) {
|
|
|
1947
1926
|
points: convertPointsFormat(boundaryElement?.points) || [],
|
|
1948
1927
|
type: boundaryElement.type,
|
|
1949
1928
|
// 判断是否为孤立子区域
|
|
1950
|
-
isIsolated: !connectedBoundaryIds.has(boundaryElement.id)
|
|
1929
|
+
isIsolated: hasTunnelToChargingPile ? false : !connectedBoundaryIds.has(boundaryElement.id)
|
|
1951
1930
|
};
|
|
1952
1931
|
// 如果有 pathData,尝试匹配对应的分区数据
|
|
1953
1932
|
if (pathData) {
|
|
@@ -1968,6 +1947,14 @@ function generateBoundaryData(mapData, pathData) {
|
|
|
1968
1947
|
return boundaryData;
|
|
1969
1948
|
}
|
|
1970
1949
|
|
|
1950
|
+
var RealTimeDataType;
|
|
1951
|
+
(function (RealTimeDataType) {
|
|
1952
|
+
RealTimeDataType[RealTimeDataType["LOCATION"] = 1] = "LOCATION";
|
|
1953
|
+
RealTimeDataType[RealTimeDataType["PROCESS"] = 2] = "PROCESS";
|
|
1954
|
+
RealTimeDataType[RealTimeDataType["PARTITION"] = 3] = "PARTITION";
|
|
1955
|
+
RealTimeDataType[RealTimeDataType["STATUS"] = 4] = "STATUS";
|
|
1956
|
+
})(RealTimeDataType || (RealTimeDataType = {}));
|
|
1957
|
+
|
|
1971
1958
|
/**
|
|
1972
1959
|
* 射线法判断点是否在多边形内部
|
|
1973
1960
|
* @param x 点的x坐标
|
|
@@ -2085,7 +2072,6 @@ const handleMultipleRealTimeData = ({ realTimeData, isMowing, pathData, partitio
|
|
|
2085
2072
|
// 割草轨迹
|
|
2086
2073
|
const { postureX, postureY, vehicleState } = item;
|
|
2087
2074
|
const currentPartitionId = getPartitionId(partitionBoundary, Number(postureX), Number(postureY));
|
|
2088
|
-
console.log('currentPartitionId===', currentPartitionId);
|
|
2089
2075
|
if (currentPartitionId && newPathData?.[currentPartitionId]) {
|
|
2090
2076
|
const currentPathData = newPathData[currentPartitionId];
|
|
2091
2077
|
newPathData[currentPartitionId] = {
|
|
@@ -2138,7 +2124,7 @@ const getProcessMowingDataFromRealTimeData = ({ realTimeData, isMowing, pathData
|
|
|
2138
2124
|
let newMowingStatus = isMowing;
|
|
2139
2125
|
let newPathData = pathData || {};
|
|
2140
2126
|
// 找到返回的第一个实时进度的点
|
|
2141
|
-
const firstProcessData = realTimeData.find((item) => item.type ===
|
|
2127
|
+
const firstProcessData = realTimeData.find((item) => item.type === RealTimeDataType.PROCESS);
|
|
2142
2128
|
if (firstProcessData) {
|
|
2143
2129
|
// console.log('firstProcessData==', firstProcessData);
|
|
2144
2130
|
const { action, subAction, currentMowBoundary, currentMowProgress } = firstProcessData;
|
|
@@ -2216,10 +2202,10 @@ function getNoPositionMowerImageByModal(mowerModal) {
|
|
|
2216
2202
|
}
|
|
2217
2203
|
return iNoPosition;
|
|
2218
2204
|
}
|
|
2219
|
-
function getMowerImage(positonConfig) {
|
|
2205
|
+
function getMowerImage(positonConfig, modelType) {
|
|
2220
2206
|
if (!positonConfig)
|
|
2221
2207
|
return '';
|
|
2222
|
-
const model =
|
|
2208
|
+
const model = modelType?.toLowerCase() || 'i';
|
|
2223
2209
|
const state = positonConfig.vehicleState;
|
|
2224
2210
|
const mowerImage = getMowerImageByModal(model);
|
|
2225
2211
|
const disabledImage = getDisabledMowerImageByModal(model);
|
|
@@ -4684,7 +4670,37 @@ var merge = createAssigner(function(object, source, srcIndex) {
|
|
|
4684
4670
|
* _.round(4060, -2);
|
|
4685
4671
|
* // => 4100
|
|
4686
4672
|
*/
|
|
4687
|
-
var round = createRound('round');
|
|
4673
|
+
var round = createRound('round');
|
|
4674
|
+
|
|
4675
|
+
/**
|
|
4676
|
+
* 工具模块类型定义
|
|
4677
|
+
*/
|
|
4678
|
+
/**
|
|
4679
|
+
* 路径段类型枚举
|
|
4680
|
+
*/
|
|
4681
|
+
var PathSegmentType;
|
|
4682
|
+
(function (PathSegmentType) {
|
|
4683
|
+
PathSegmentType["EDGE"] = "edge";
|
|
4684
|
+
PathSegmentType["MOWING"] = "mowing";
|
|
4685
|
+
PathSegmentType["TRANS"] = "trans";
|
|
4686
|
+
})(PathSegmentType || (PathSegmentType = {}));
|
|
4687
|
+
/**
|
|
4688
|
+
* 单位类型枚举
|
|
4689
|
+
*/
|
|
4690
|
+
var UnitsType;
|
|
4691
|
+
(function (UnitsType) {
|
|
4692
|
+
UnitsType["Metric"] = "Metric";
|
|
4693
|
+
UnitsType["Imperial"] = "Imperial";
|
|
4694
|
+
})(UnitsType || (UnitsType = {}));
|
|
4695
|
+
/**
|
|
4696
|
+
* 面积单位类型枚举
|
|
4697
|
+
*/
|
|
4698
|
+
var UnitsAreaType;
|
|
4699
|
+
(function (UnitsAreaType) {
|
|
4700
|
+
UnitsAreaType["SQUARE_METER"] = "m\u00B2";
|
|
4701
|
+
UnitsAreaType["SQUARE_FOOT"] = "ft\u00B2";
|
|
4702
|
+
UnitsAreaType["ACRE"] = "ac";
|
|
4703
|
+
})(UnitsAreaType || (UnitsAreaType = {}));
|
|
4688
4704
|
|
|
4689
4705
|
/**
|
|
4690
4706
|
* 默认航向相对于canvas的偏移角度: 航向默认是东
|
|
@@ -4759,17 +4775,6 @@ function formatNumberWithMetricPrefix(value, round = true, decimals = 2) {
|
|
|
4759
4775
|
return `${mathFn(value / 1000000000, decimals)}B`;
|
|
4760
4776
|
}
|
|
4761
4777
|
}
|
|
4762
|
-
var UnitsType;
|
|
4763
|
-
(function (UnitsType) {
|
|
4764
|
-
UnitsType["Metric"] = "metric";
|
|
4765
|
-
UnitsType["Imperial"] = "imperial";
|
|
4766
|
-
})(UnitsType || (UnitsType = {}));
|
|
4767
|
-
var UnitsAreaType;
|
|
4768
|
-
(function (UnitsAreaType) {
|
|
4769
|
-
UnitsAreaType["SQUARE_METER"] = "m\u00B2";
|
|
4770
|
-
UnitsAreaType["SQUARE_FOOT"] = "ft\u00B2";
|
|
4771
|
-
UnitsAreaType["ACRE"] = "ac";
|
|
4772
|
-
})(UnitsAreaType || (UnitsAreaType = {}));
|
|
4773
4778
|
/**
|
|
4774
4779
|
* 转换割草面积的方法
|
|
4775
4780
|
* @param area 面积数值(单位:m²)
|
|
@@ -4959,6 +4964,18 @@ class BoundaryBorderLayer extends BaseLayer {
|
|
|
4959
4964
|
this.level = LAYER_LEVELS.BOUNDARY_BORDER; // 中等层级
|
|
4960
4965
|
this.type = LAYER_DEFAULT_TYPE.BOUNDARY_BORDER;
|
|
4961
4966
|
this.boudaryBorderPaths = {};
|
|
4967
|
+
this.mowingBoundarys = [];
|
|
4968
|
+
}
|
|
4969
|
+
/**
|
|
4970
|
+
* 设置当前割草任务的边界
|
|
4971
|
+
*/
|
|
4972
|
+
setMowingBoundarys(mowingBoundarys) {
|
|
4973
|
+
if (!mowingBoundarys) {
|
|
4974
|
+
this.mowingBoundarys = this.elements?.map(item => item?.originalData?.id);
|
|
4975
|
+
}
|
|
4976
|
+
else {
|
|
4977
|
+
this.mowingBoundarys = mowingBoundarys;
|
|
4978
|
+
}
|
|
4962
4979
|
}
|
|
4963
4980
|
/**
|
|
4964
4981
|
* SVG渲染方法
|
|
@@ -5004,7 +5021,8 @@ class BoundaryBorderLayer extends BaseLayer {
|
|
|
5004
5021
|
* 创建直接路径(type=2)
|
|
5005
5022
|
*/
|
|
5006
5023
|
createDirectPath(svgGroup, points, style, id) {
|
|
5007
|
-
const
|
|
5024
|
+
const isMowing = this.mowingBoundarys.includes(Number(id));
|
|
5025
|
+
const strokeColor = isMowing ? style.mowingLineColor : style.lineColor;
|
|
5008
5026
|
const lineWidth = dp2px(style.lineWidth || 3);
|
|
5009
5027
|
const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
|
|
5010
5028
|
// 构建路径数据
|
|
@@ -5037,7 +5055,8 @@ class BoundaryBorderLayer extends BaseLayer {
|
|
|
5037
5055
|
* 使用PathMeasure逻辑创建平行路径(type=1)
|
|
5038
5056
|
*/
|
|
5039
5057
|
createParallelPathsWithMeasure(svgGroup, points, style, id) {
|
|
5040
|
-
const
|
|
5058
|
+
const isMowing = this.mowingBoundarys.includes(Number(id));
|
|
5059
|
+
const strokeColor = isMowing ? style.mowingLineColor : style.lineColor;
|
|
5041
5060
|
const lineWidth = dp2px(style.lineWidth || 3);
|
|
5042
5061
|
// 获取当前SVG的缩放级别,计算固定屏幕像素间距
|
|
5043
5062
|
const fixedScreenDistance = lineWidth; // 固定的屏幕像素距离
|
|
@@ -5383,6 +5402,14 @@ class BoundaryDataBuilder {
|
|
|
5383
5402
|
* 创建边界元素数据
|
|
5384
5403
|
*/
|
|
5385
5404
|
static create(type, coordinates, style) {
|
|
5405
|
+
const len = coordinates?.length || 0;
|
|
5406
|
+
const firstPoint = coordinates?.[0];
|
|
5407
|
+
const lastPoint = coordinates?.[len - 1];
|
|
5408
|
+
const isClosed = firstPoint?.[0] === lastPoint?.[0] && firstPoint?.[1] === lastPoint?.[1];
|
|
5409
|
+
// 如果地图没有闭合,则手动新增闭合点,避免border最后一部分没有闭合的情况
|
|
5410
|
+
if (!isClosed) {
|
|
5411
|
+
coordinates.push([firstPoint?.[0], firstPoint?.[1], lastPoint?.[2]]);
|
|
5412
|
+
}
|
|
5386
5413
|
return {
|
|
5387
5414
|
type,
|
|
5388
5415
|
coordinates,
|
|
@@ -5785,8 +5812,13 @@ class MapDataProcessor {
|
|
|
5785
5812
|
// 为ObstacleData创建兼容的MapElement接口
|
|
5786
5813
|
const mapElement = element;
|
|
5787
5814
|
const obstacleElement = ObstacleDataBuilder.fromMapElement(mapElement, this.mapConfig.obstacle);
|
|
5788
|
-
if (obstacleElement)
|
|
5815
|
+
if (obstacleElement) {
|
|
5789
5816
|
result.push(obstacleElement);
|
|
5817
|
+
const { addObstacles } = useSubBoundaryBorderStore.getState();
|
|
5818
|
+
addObstacles(`obstacle-${obstacleElement.originalData.id}`, {
|
|
5819
|
+
...obstacleElement,
|
|
5820
|
+
});
|
|
5821
|
+
}
|
|
5790
5822
|
}
|
|
5791
5823
|
catch (error) {
|
|
5792
5824
|
console.warn(`Error processing OBSTACLE element:`, element, error);
|
|
@@ -5847,8 +5879,13 @@ class MapDataProcessor {
|
|
|
5847
5879
|
element.direction !== undefined) {
|
|
5848
5880
|
const mapElement = element;
|
|
5849
5881
|
const svgElement = SvgElementDataBuilder.fromMapElement(mapElement, this.mapConfig.doodle);
|
|
5850
|
-
if (svgElement)
|
|
5882
|
+
if (svgElement) {
|
|
5851
5883
|
result.push(svgElement);
|
|
5884
|
+
const { addSvgElements } = useSubBoundaryBorderStore.getState();
|
|
5885
|
+
addSvgElements(`time-limit-obstacle-${svgElement.originalData.id}`, {
|
|
5886
|
+
...svgElement,
|
|
5887
|
+
});
|
|
5888
|
+
}
|
|
5852
5889
|
}
|
|
5853
5890
|
// 如果有points数据,按传统方式绘制
|
|
5854
5891
|
else if ('points' in element &&
|
|
@@ -5857,8 +5894,13 @@ class MapDataProcessor {
|
|
|
5857
5894
|
element.points.length >= 3) {
|
|
5858
5895
|
const mapElement = element;
|
|
5859
5896
|
const polygonElement = ObstacleDataBuilder.createTimeLimitObstacle(mapElement, this.mapConfig.obstacle);
|
|
5860
|
-
if (polygonElement)
|
|
5897
|
+
if (polygonElement) {
|
|
5861
5898
|
result.push(polygonElement);
|
|
5899
|
+
const { addObstacles } = useSubBoundaryBorderStore.getState();
|
|
5900
|
+
addObstacles(`time-limit-obstacle-${polygonElement.originalData.id}`, {
|
|
5901
|
+
...polygonElement,
|
|
5902
|
+
});
|
|
5903
|
+
}
|
|
5862
5904
|
}
|
|
5863
5905
|
}
|
|
5864
5906
|
catch (error) {
|
|
@@ -6008,7 +6050,6 @@ class PathDataProcessor {
|
|
|
6008
6050
|
elements,
|
|
6009
6051
|
};
|
|
6010
6052
|
});
|
|
6011
|
-
console.log('result->', result);
|
|
6012
6053
|
return result;
|
|
6013
6054
|
}
|
|
6014
6055
|
}
|
|
@@ -6018,7 +6059,7 @@ class PathDataProcessor {
|
|
|
6018
6059
|
* 专门处理边界标签的创建、定位和管理
|
|
6019
6060
|
*/
|
|
6020
6061
|
class BoundaryLabelsManager {
|
|
6021
|
-
constructor(svgView, boundaryData) {
|
|
6062
|
+
constructor(svgView, boundaryData, { unitType, language }) {
|
|
6022
6063
|
this.container = null;
|
|
6023
6064
|
this.overlayDiv = null;
|
|
6024
6065
|
this.globalClickHandler = null;
|
|
@@ -6029,6 +6070,8 @@ class BoundaryLabelsManager {
|
|
|
6029
6070
|
this.svgView = svgView;
|
|
6030
6071
|
this.boundaryData = boundaryData;
|
|
6031
6072
|
this.initializeContainer();
|
|
6073
|
+
this.unitType = unitType;
|
|
6074
|
+
this.language = language;
|
|
6032
6075
|
}
|
|
6033
6076
|
/**
|
|
6034
6077
|
* 初始化容器
|
|
@@ -6128,9 +6171,10 @@ class BoundaryLabelsManager {
|
|
|
6128
6171
|
this.currentExpandedBoundaryId === boundary.id ? 'block' : 'none';
|
|
6129
6172
|
extendedContent.style.borderTop = '1px solid rgba(255,255,255,0.2)';
|
|
6130
6173
|
extendedContent.style.paddingTop = '6px';
|
|
6174
|
+
console.log('this.unitType->', this.unitType);
|
|
6131
6175
|
// 面积信息
|
|
6132
|
-
const totalArea = convertAreaByUnits(boundary.area || 0,
|
|
6133
|
-
const finishedArea = convertAreaByUnits(boundary.finishedArea || 0,
|
|
6176
|
+
const totalArea = convertAreaByUnits(boundary.area || 0, this.unitType);
|
|
6177
|
+
const finishedArea = convertAreaByUnits(boundary.finishedArea || 0, this.unitType);
|
|
6134
6178
|
const coverageText = `Coverage: ${finishedArea.value}/${totalArea.value}`;
|
|
6135
6179
|
// 日期信息
|
|
6136
6180
|
const dateText = formatBoundaryDateText(boundary.endTime || 0);
|
|
@@ -6196,7 +6240,6 @@ class BoundaryLabelsManager {
|
|
|
6196
6240
|
this.collapseOtherLabels(boundaryId);
|
|
6197
6241
|
// 展开当前标签
|
|
6198
6242
|
extendedContent.style.display = 'block';
|
|
6199
|
-
labelDiv.style.whiteSpace = 'normal';
|
|
6200
6243
|
this.currentExpandedBoundaryId = boundaryId;
|
|
6201
6244
|
}
|
|
6202
6245
|
/**
|
|
@@ -6239,7 +6282,6 @@ class BoundaryLabelsManager {
|
|
|
6239
6282
|
* @param viewBox SVG的viewBox信息
|
|
6240
6283
|
*/
|
|
6241
6284
|
updatePositionsWithPrecomputedData(divWidth, divHeight, viewBox) {
|
|
6242
|
-
console.log('updatePositionsWithPrecomputedData----->', this.rotation);
|
|
6243
6285
|
if (!this.container || !this.svgView)
|
|
6244
6286
|
return;
|
|
6245
6287
|
const dw = parseFloat(this.svgView.getSVG().getAttribute('width')) || divWidth;
|
|
@@ -6433,12 +6475,6 @@ class BoundaryLabelsManager {
|
|
|
6433
6475
|
this.container.style.display = visible ? 'block' : 'none';
|
|
6434
6476
|
}
|
|
6435
6477
|
}
|
|
6436
|
-
/**
|
|
6437
|
-
* 获取边界数据
|
|
6438
|
-
*/
|
|
6439
|
-
getBoundaryData() {
|
|
6440
|
-
return this.boundaryData;
|
|
6441
|
-
}
|
|
6442
6478
|
/**
|
|
6443
6479
|
* 根据ID获取特定边界的标签元素
|
|
6444
6480
|
*/
|
|
@@ -6488,18 +6524,6 @@ class BoundaryLabelsManager {
|
|
|
6488
6524
|
}
|
|
6489
6525
|
});
|
|
6490
6526
|
}
|
|
6491
|
-
/**
|
|
6492
|
-
* 重置标签层级(公共方法)
|
|
6493
|
-
*/
|
|
6494
|
-
resetZIndex() {
|
|
6495
|
-
this.resetLabelZIndex();
|
|
6496
|
-
}
|
|
6497
|
-
/**
|
|
6498
|
-
* 获取层级常量(静态方法)
|
|
6499
|
-
*/
|
|
6500
|
-
static getZIndexConstants() {
|
|
6501
|
-
return BoundaryLabelsManager.Z_INDEX;
|
|
6502
|
-
}
|
|
6503
6527
|
/**
|
|
6504
6528
|
* 设置标签旋转角度,使其与地图旋转相反,保持水平状态
|
|
6505
6529
|
* @param rotation 地图的旋转角度(度)
|
|
@@ -6516,19 +6540,6 @@ class BoundaryLabelsManager {
|
|
|
6516
6540
|
labelElement.style.transform = `translate(-50%, -50%) rotate(${counterRotation}deg)`;
|
|
6517
6541
|
});
|
|
6518
6542
|
}
|
|
6519
|
-
/**
|
|
6520
|
-
* 重置标签旋转角度
|
|
6521
|
-
*/
|
|
6522
|
-
resetLabelsRotation() {
|
|
6523
|
-
if (!this.container)
|
|
6524
|
-
return;
|
|
6525
|
-
const labels = this.container.querySelectorAll('.boundary-label');
|
|
6526
|
-
labels.forEach((label) => {
|
|
6527
|
-
const labelElement = label;
|
|
6528
|
-
// 重置为默认的居中变换
|
|
6529
|
-
labelElement.style.transform = 'translate(-50%, -50%)';
|
|
6530
|
-
});
|
|
6531
|
-
}
|
|
6532
6543
|
}
|
|
6533
6544
|
// 简化的层级定义
|
|
6534
6545
|
BoundaryLabelsManager.Z_INDEX = {
|
|
@@ -6704,26 +6715,6 @@ class ChargingPileManager {
|
|
|
6704
6715
|
this.container.innerHTML = '';
|
|
6705
6716
|
}
|
|
6706
6717
|
}
|
|
6707
|
-
/**
|
|
6708
|
-
* 设置可见性
|
|
6709
|
-
*/
|
|
6710
|
-
setVisible(visible) {
|
|
6711
|
-
if (this.container) {
|
|
6712
|
-
this.container.style.display = visible ? 'block' : 'none';
|
|
6713
|
-
}
|
|
6714
|
-
}
|
|
6715
|
-
/**
|
|
6716
|
-
* 获取充电桩数量
|
|
6717
|
-
*/
|
|
6718
|
-
getElementCount() {
|
|
6719
|
-
return this.chargingPileElements.length;
|
|
6720
|
-
}
|
|
6721
|
-
/**
|
|
6722
|
-
* 充电桩不需要动态层级调整(为了接口统一而保留)
|
|
6723
|
-
*/
|
|
6724
|
-
resetZIndex() {
|
|
6725
|
-
// 充电桩层级始终保持固定,无需重置
|
|
6726
|
-
}
|
|
6727
6718
|
/**
|
|
6728
6719
|
* 销毁管理器
|
|
6729
6720
|
*/
|
|
@@ -6746,21 +6737,10 @@ class ChargingPileManager {
|
|
|
6746
6737
|
pileElement.style.transform = `translate(-50%, -50%) rotate(${this.originalRotation - this.rotation}deg)`;
|
|
6747
6738
|
});
|
|
6748
6739
|
}
|
|
6749
|
-
/**
|
|
6750
|
-
* 重置充电桩旋转角度
|
|
6751
|
-
*/
|
|
6752
|
-
resetRotation() {
|
|
6753
|
-
this.rotation = 0;
|
|
6754
|
-
const allContainers = this.container.querySelectorAll('.charging-pile');
|
|
6755
|
-
allContainers.forEach((container) => {
|
|
6756
|
-
const pileElement = container;
|
|
6757
|
-
pileElement.style.transform = `translate(-50%, -50%) rotate(${this.originalRotation - this.rotation}deg)`;
|
|
6758
|
-
});
|
|
6759
|
-
}
|
|
6760
6740
|
}
|
|
6761
6741
|
// 简化的层级定义 - 充电桩只需要一个固定层级
|
|
6762
6742
|
ChargingPileManager.Z_INDEX = {
|
|
6763
|
-
CHARGING_PILE:
|
|
6743
|
+
CHARGING_PILE: 750, // 充电桩图标固定层级
|
|
6764
6744
|
};
|
|
6765
6745
|
|
|
6766
6746
|
/**
|
|
@@ -7142,32 +7122,6 @@ class AntennaManager {
|
|
|
7142
7122
|
this.container.innerHTML = '';
|
|
7143
7123
|
}
|
|
7144
7124
|
}
|
|
7145
|
-
/**
|
|
7146
|
-
* 设置可见性
|
|
7147
|
-
*/
|
|
7148
|
-
setVisible(visible) {
|
|
7149
|
-
if (this.container) {
|
|
7150
|
-
this.container.style.display = visible ? 'block' : 'none';
|
|
7151
|
-
}
|
|
7152
|
-
}
|
|
7153
|
-
/**
|
|
7154
|
-
* 获取天线数量
|
|
7155
|
-
*/
|
|
7156
|
-
getElementCount() {
|
|
7157
|
-
return this.antennaElements.length;
|
|
7158
|
-
}
|
|
7159
|
-
/**
|
|
7160
|
-
* 重置天线层级(公共方法)
|
|
7161
|
-
*/
|
|
7162
|
-
resetZIndex() {
|
|
7163
|
-
this.resetAntennaZIndex();
|
|
7164
|
-
}
|
|
7165
|
-
/**
|
|
7166
|
-
* 获取层级常量(静态方法)
|
|
7167
|
-
*/
|
|
7168
|
-
static getZIndexConstants() {
|
|
7169
|
-
return AntennaManager.Z_INDEX;
|
|
7170
|
-
}
|
|
7171
7125
|
/**
|
|
7172
7126
|
* 销毁管理器
|
|
7173
7127
|
*/
|
|
@@ -7195,21 +7149,10 @@ class AntennaManager {
|
|
|
7195
7149
|
antennaContainer.style.transform = `translate(-50%, -50%) rotate(${-this.rotation}deg)`;
|
|
7196
7150
|
});
|
|
7197
7151
|
}
|
|
7198
|
-
/**
|
|
7199
|
-
* 重置天线旋转角度
|
|
7200
|
-
*/
|
|
7201
|
-
resetRotation() {
|
|
7202
|
-
this.rotation = 0;
|
|
7203
|
-
const allContainers = this.container.querySelectorAll('.antenna-container-item');
|
|
7204
|
-
allContainers.forEach((container) => {
|
|
7205
|
-
const antennaContainer = container;
|
|
7206
|
-
antennaContainer.style.transform = `translate(-50%, -50%) rotate(${-this.rotation}deg)`;
|
|
7207
|
-
});
|
|
7208
|
-
}
|
|
7209
7152
|
}
|
|
7210
7153
|
// 简化的层级定义
|
|
7211
7154
|
AntennaManager.Z_INDEX = {
|
|
7212
|
-
DEFAULT:
|
|
7155
|
+
DEFAULT: 800, // 默认层级
|
|
7213
7156
|
ACTIVE: 9999, // 点击激活时的高层级
|
|
7214
7157
|
};
|
|
7215
7158
|
|
|
@@ -7261,7 +7204,7 @@ const EDIT_BEHAVIOR = {
|
|
|
7261
7204
|
};
|
|
7262
7205
|
|
|
7263
7206
|
class MowerPositionManager {
|
|
7264
|
-
constructor(svgView, mowerPositionConfig, overlayDiv, onAnimationComplete, onMowingPositionChange) {
|
|
7207
|
+
constructor(svgView, mowerPositionConfig, modelType, overlayDiv, onAnimationComplete, onMowingPositionChange) {
|
|
7265
7208
|
this.container = null;
|
|
7266
7209
|
this.overlayDiv = null;
|
|
7267
7210
|
this.mowerElement = null;
|
|
@@ -7279,6 +7222,7 @@ class MowerPositionManager {
|
|
|
7279
7222
|
this.onlyUpdateTheta = false;
|
|
7280
7223
|
this.svgView = svgView;
|
|
7281
7224
|
this.mowerPositionConfig = mowerPositionConfig;
|
|
7225
|
+
this.modelType = modelType;
|
|
7282
7226
|
this.overlayDiv = overlayDiv;
|
|
7283
7227
|
this.onAnimationComplete = onAnimationComplete;
|
|
7284
7228
|
this.onMowingPositionChange = onMowingPositionChange;
|
|
@@ -7333,6 +7277,7 @@ class MowerPositionManager {
|
|
|
7333
7277
|
}
|
|
7334
7278
|
this.mowerElement.appendChild(imgElement);
|
|
7335
7279
|
this.container.appendChild(this.mowerElement);
|
|
7280
|
+
this.updatePosition(this.mowerPositionConfig);
|
|
7336
7281
|
}
|
|
7337
7282
|
/**
|
|
7338
7283
|
* 设置叠加层div引用(用于坐标转换)
|
|
@@ -7353,11 +7298,22 @@ class MowerPositionManager {
|
|
|
7353
7298
|
if (!chargingPilesPositionConfig)
|
|
7354
7299
|
return;
|
|
7355
7300
|
this.mowerPositionConfig = chargingPilesPositionConfig;
|
|
7356
|
-
|
|
7301
|
+
const positonOutOfRange = isOutOfRange(chargingPilesPositionConfig);
|
|
7302
|
+
const positionInValid = isInvalidPosition(chargingPilesPositionConfig);
|
|
7303
|
+
let postureX = 0;
|
|
7304
|
+
let postureY = 0;
|
|
7305
|
+
let postureTheta = 0;
|
|
7357
7306
|
const lastPosition = this.lastPosition;
|
|
7358
|
-
|
|
7359
|
-
|
|
7360
|
-
|
|
7307
|
+
if (positonOutOfRange || positionInValid) {
|
|
7308
|
+
postureX = lastPosition?.x || 0;
|
|
7309
|
+
postureY = lastPosition?.y || 0;
|
|
7310
|
+
postureTheta = lastPosition?.rotation || 0;
|
|
7311
|
+
}
|
|
7312
|
+
else {
|
|
7313
|
+
postureX = chargingPilesPositionConfig.postureX || 0;
|
|
7314
|
+
postureY = chargingPilesPositionConfig.postureY || 0;
|
|
7315
|
+
postureTheta = chargingPilesPositionConfig.postureTheta || 0;
|
|
7316
|
+
}
|
|
7361
7317
|
// 检查是否需要更新图片
|
|
7362
7318
|
this.updateMowerImage(chargingPilesPositionConfig);
|
|
7363
7319
|
// 立即更新位置
|
|
@@ -7367,12 +7323,13 @@ class MowerPositionManager {
|
|
|
7367
7323
|
* 更新割草机位置
|
|
7368
7324
|
*/
|
|
7369
7325
|
updatePosition(positionConfig, animationTime = 0) {
|
|
7370
|
-
console.log('manager updatePosition----->', positionConfig);
|
|
7371
7326
|
// 检查是否需要更新图片
|
|
7372
7327
|
this.updateMowerImage(positionConfig);
|
|
7373
|
-
|
|
7374
|
-
|
|
7375
|
-
const
|
|
7328
|
+
// 更新配置
|
|
7329
|
+
this.mowerPositionConfig = positionConfig;
|
|
7330
|
+
const postureX = positionConfig?.postureX || this.lastPosition?.x || 0;
|
|
7331
|
+
const postureY = positionConfig?.postureY || this.lastPosition?.y || 0;
|
|
7332
|
+
const postureTheta = positionConfig?.postureTheta || this.lastPosition?.rotation || 0;
|
|
7376
7333
|
// 停止当前动画(如果有)
|
|
7377
7334
|
this.stopAnimation();
|
|
7378
7335
|
// 第一个点
|
|
@@ -7393,8 +7350,6 @@ class MowerPositionManager {
|
|
|
7393
7350
|
// 立即更新位置
|
|
7394
7351
|
this.setElementPosition(positionConfig.postureX, positionConfig.postureY, positionConfig.postureTheta);
|
|
7395
7352
|
}
|
|
7396
|
-
// 更新配置
|
|
7397
|
-
this.mowerPositionConfig = positionConfig;
|
|
7398
7353
|
}
|
|
7399
7354
|
/**
|
|
7400
7355
|
* 更新割草机图片
|
|
@@ -7405,9 +7360,14 @@ class MowerPositionManager {
|
|
|
7405
7360
|
const imgElement = this.mowerElement.querySelector('img');
|
|
7406
7361
|
if (!imgElement)
|
|
7407
7362
|
return;
|
|
7408
|
-
const imageSrc = getMowerImage(positonConfig);
|
|
7363
|
+
const imageSrc = getMowerImage(positonConfig, this.modelType);
|
|
7409
7364
|
if (imageSrc) {
|
|
7410
7365
|
imgElement.src = imageSrc;
|
|
7366
|
+
imgElement.style.display = 'block';
|
|
7367
|
+
}
|
|
7368
|
+
else {
|
|
7369
|
+
imgElement.style.display = 'none';
|
|
7370
|
+
return;
|
|
7411
7371
|
}
|
|
7412
7372
|
}
|
|
7413
7373
|
/**
|
|
@@ -7417,17 +7377,9 @@ class MowerPositionManager {
|
|
|
7417
7377
|
const { x: pointX, y: pointY } = convertCoordinate(x, y);
|
|
7418
7378
|
const targetPixelPosition = this.convertMapCoordinateToOverlayPixel(pointX, pointY);
|
|
7419
7379
|
const targetRotation = radToDegree(theta);
|
|
7420
|
-
|
|
7421
|
-
|
|
7422
|
-
|
|
7423
|
-
const positionValid = isInvalidPosition({
|
|
7424
|
-
postureX: x,
|
|
7425
|
-
postureY: y,
|
|
7426
|
-
postureTheta: theta,
|
|
7427
|
-
});
|
|
7428
|
-
if (!positonOutOfRange && !positionValid) {
|
|
7429
|
-
this.lastPosition = { x, y, rotation: theta };
|
|
7430
|
-
}
|
|
7380
|
+
this.currentPosition = { x: x, y: y, rotation: theta };
|
|
7381
|
+
this.lastPosition = { x, y, rotation: theta };
|
|
7382
|
+
// console.log('setElementPosition', x, y, theta, targetRotation, positonOutOfRange, positionValid, targetPixelPosition);
|
|
7431
7383
|
if (!this.mowerElement)
|
|
7432
7384
|
return;
|
|
7433
7385
|
this.mowerElement.style.left = `${targetPixelPosition?.x}px`;
|
|
@@ -7453,15 +7405,29 @@ class MowerPositionManager {
|
|
|
7453
7405
|
startAnimationToPosition(positionConfig, duration) {
|
|
7454
7406
|
if (!this.mowerElement || !this.currentPosition)
|
|
7455
7407
|
return;
|
|
7456
|
-
this.startPosition = {
|
|
7457
|
-
...this.currentPosition,
|
|
7458
|
-
rotation: radNormalize(this.currentPosition.rotation),
|
|
7459
|
-
};
|
|
7460
7408
|
this.targetPosition = {
|
|
7461
7409
|
x: positionConfig.postureX,
|
|
7462
7410
|
y: positionConfig.postureY,
|
|
7463
7411
|
rotation: positionConfig.postureTheta,
|
|
7464
7412
|
};
|
|
7413
|
+
const isTargetPositionInvalid = isInvalidPosition({
|
|
7414
|
+
postureX: this.targetPosition.x,
|
|
7415
|
+
postureY: this.targetPosition.y,
|
|
7416
|
+
postureTheta: this.targetPosition.rotation,
|
|
7417
|
+
});
|
|
7418
|
+
const isTargetPositionOutOfRange = isOutOfRange({
|
|
7419
|
+
postureX: this.targetPosition.x,
|
|
7420
|
+
postureY: this.targetPosition.y,
|
|
7421
|
+
postureTheta: this.targetPosition.rotation,
|
|
7422
|
+
});
|
|
7423
|
+
// 如果目标坐标点不合理,则舍弃不使用
|
|
7424
|
+
if (isTargetPositionInvalid || isTargetPositionOutOfRange) {
|
|
7425
|
+
return;
|
|
7426
|
+
}
|
|
7427
|
+
this.startPosition = {
|
|
7428
|
+
...this.currentPosition,
|
|
7429
|
+
rotation: radNormalize(this.currentPosition.rotation),
|
|
7430
|
+
};
|
|
7465
7431
|
this.animationDuration = duration;
|
|
7466
7432
|
this.startTime = window.performance.now();
|
|
7467
7433
|
this.isAnimating = true;
|
|
@@ -7491,7 +7457,7 @@ class MowerPositionManager {
|
|
|
7491
7457
|
* 动画步骤
|
|
7492
7458
|
*/
|
|
7493
7459
|
animateStep() {
|
|
7494
|
-
if (!this.isAnimating || !this.
|
|
7460
|
+
if (!this.isAnimating || !this.targetPosition || !this.startPosition)
|
|
7495
7461
|
return;
|
|
7496
7462
|
const currentTime = window.performance.now();
|
|
7497
7463
|
const elapsed = currentTime - this.startTime;
|
|
@@ -7502,25 +7468,22 @@ class MowerPositionManager {
|
|
|
7502
7468
|
const currentX = this.startPosition.x + this.deltaPosition.x * easedProgress;
|
|
7503
7469
|
const currentY = this.startPosition.y + this.deltaPosition.y * easedProgress;
|
|
7504
7470
|
const currentRotation = this.startPosition.rotation + this.deltaPosition.rotation * easedProgress;
|
|
7505
|
-
this.currentPosition = { x: currentX, y: currentY, rotation: currentRotation };
|
|
7506
7471
|
// 假设在这里进行更新路径数据
|
|
7507
7472
|
if (this.onMowingPositionChange) {
|
|
7508
7473
|
this.onMowingPositionChange({
|
|
7509
7474
|
x: currentX,
|
|
7510
7475
|
y: currentY,
|
|
7511
|
-
vehicleState: this.mowerPositionConfig
|
|
7476
|
+
vehicleState: this.mowerPositionConfig?.vehicleState,
|
|
7512
7477
|
});
|
|
7513
7478
|
}
|
|
7514
|
-
// console.log('animateStep
|
|
7515
|
-
|
|
7479
|
+
// console.log('animateStep-->', this.startPosition, this.deltaPosition, this.targetPosition, easedProgress)
|
|
7480
|
+
this.setElementPosition(currentX, currentY, currentRotation);
|
|
7516
7481
|
// 继续动画或结束
|
|
7517
7482
|
if (progress < 1) {
|
|
7518
7483
|
// 设置当前位置
|
|
7519
|
-
this.setElementPosition(currentX, currentY, currentRotation);
|
|
7520
7484
|
this.animationId = window.requestAnimationFrame(() => this.animateStep());
|
|
7521
7485
|
}
|
|
7522
7486
|
else {
|
|
7523
|
-
this.setElementPosition(currentX, currentY, currentRotation);
|
|
7524
7487
|
// 动画完成
|
|
7525
7488
|
this.stopAnimation();
|
|
7526
7489
|
// 通知动画完成
|
|
@@ -7567,12 +7530,6 @@ class MowerPositionManager {
|
|
|
7567
7530
|
this.container.style.display = visible ? 'block' : 'none';
|
|
7568
7531
|
}
|
|
7569
7532
|
}
|
|
7570
|
-
/**
|
|
7571
|
-
* 检查是否正在动画中
|
|
7572
|
-
*/
|
|
7573
|
-
getIsAnimating() {
|
|
7574
|
-
return this.isAnimating;
|
|
7575
|
-
}
|
|
7576
7533
|
/**
|
|
7577
7534
|
* 销毁管理器
|
|
7578
7535
|
*/
|
|
@@ -7634,10 +7591,34 @@ function throttleAdvanced(func, delay, options = { leading: true, trailing: true
|
|
|
7634
7591
|
}
|
|
7635
7592
|
};
|
|
7636
7593
|
}
|
|
7594
|
+
/**
|
|
7595
|
+
* 检测当前设备是否为移动设备
|
|
7596
|
+
* @returns {boolean} 如果是移动设备返回true,否则返回false
|
|
7597
|
+
*/
|
|
7598
|
+
function isMobileDevice() {
|
|
7599
|
+
// 确保在浏览器环境中运行
|
|
7600
|
+
if (typeof window === 'undefined' || typeof navigator === 'undefined') {
|
|
7601
|
+
return false;
|
|
7602
|
+
}
|
|
7603
|
+
// 检查用户代理字符串
|
|
7604
|
+
const userAgent = navigator.userAgent.toLowerCase();
|
|
7605
|
+
const mobileKeywords = [
|
|
7606
|
+
'android', 'webos', 'iphone', 'ipad', 'ipod',
|
|
7607
|
+
'blackberry', 'windows phone', 'mobile'
|
|
7608
|
+
];
|
|
7609
|
+
const isMobileUserAgent = mobileKeywords.some(keyword => userAgent.includes(keyword));
|
|
7610
|
+
// 检查触摸屏支持
|
|
7611
|
+
const hasTouchScreen = 'ontouchstart' in window ||
|
|
7612
|
+
(navigator.maxTouchPoints && navigator.maxTouchPoints > 0);
|
|
7613
|
+
// 检查屏幕尺寸(移动设备通常屏幕较小)
|
|
7614
|
+
const isSmallScreen = window.innerWidth <= 768;
|
|
7615
|
+
// 综合判断:用户代理包含移动设备关键词,或者有触摸屏且屏幕较小
|
|
7616
|
+
return isMobileUserAgent || (hasTouchScreen && isSmallScreen);
|
|
7617
|
+
}
|
|
7637
7618
|
|
|
7638
7619
|
// Google Maps 叠加层类 - 带编辑功能
|
|
7639
7620
|
class MowerMapOverlay {
|
|
7640
|
-
constructor(bounds, mapData, partitionBoundary, mowerPositionConfig, pathData, isEditMode = false, mapConfig = {}, antennaConfig = {}, mowPartitionData = null, defaultTransform, onMapLoad, onPathLoad, dragCallbacks) {
|
|
7621
|
+
constructor(bounds, mapData, partitionBoundary, mowerPositionConfig, modelType, pathData, isEditMode = false, unitType = UnitsType.Imperial, language = 'en', mapConfig = {}, antennaConfig = {}, mowPartitionData = null, defaultTransform, onMapLoad, onPathLoad, dragCallbacks) {
|
|
7641
7622
|
this.div = null;
|
|
7642
7623
|
this.svgMapView = null;
|
|
7643
7624
|
this.offscreenContainer = null;
|
|
@@ -7685,6 +7666,8 @@ class MowerMapOverlay {
|
|
|
7685
7666
|
this.partitionBoundary = partitionBoundary;
|
|
7686
7667
|
this.pathData = pathData;
|
|
7687
7668
|
this.isEditMode = isEditMode;
|
|
7669
|
+
this.unitType = unitType;
|
|
7670
|
+
this.language = language;
|
|
7688
7671
|
this.mapConfig = mapConfig;
|
|
7689
7672
|
this.antennaConfig = antennaConfig;
|
|
7690
7673
|
this.onMapLoad = onMapLoad;
|
|
@@ -7692,6 +7675,7 @@ class MowerMapOverlay {
|
|
|
7692
7675
|
this.dragCallbacks = dragCallbacks;
|
|
7693
7676
|
this.mowerPositionConfig = mowerPositionConfig;
|
|
7694
7677
|
this.mowPartitionData = mowPartitionData;
|
|
7678
|
+
this.modelType = modelType;
|
|
7695
7679
|
// 设置默认的transform
|
|
7696
7680
|
if (defaultTransform) {
|
|
7697
7681
|
this.defaultTransform = {
|
|
@@ -7724,7 +7708,6 @@ class MowerMapOverlay {
|
|
|
7724
7708
|
this.boundaryData = generateBoundaryData(mapData, pathData);
|
|
7725
7709
|
}
|
|
7726
7710
|
updatePosition(positionConfig, animationTime = 2200) {
|
|
7727
|
-
console.log('updatePosition==', positionConfig, animationTime);
|
|
7728
7711
|
// 保存当前动画时长
|
|
7729
7712
|
this.currentAnimationTime = animationTime;
|
|
7730
7713
|
// 标记是否为用户动画(大于0表示用户主动触发的动画)
|
|
@@ -7737,7 +7720,7 @@ class MowerMapOverlay {
|
|
|
7737
7720
|
}
|
|
7738
7721
|
}
|
|
7739
7722
|
updatePositionByLastPosition(chargingPilesPositionConfig) {
|
|
7740
|
-
|
|
7723
|
+
this.mowerPositionConfig = chargingPilesPositionConfig;
|
|
7741
7724
|
// 更新配置
|
|
7742
7725
|
if (this.mowerPositionManager) {
|
|
7743
7726
|
this.mowerPositionManager.updatePositionByLastPosition(chargingPilesPositionConfig);
|
|
@@ -7758,32 +7741,24 @@ class MowerMapOverlay {
|
|
|
7758
7741
|
return this.overlayView ? this.overlayView.getPanes() : null;
|
|
7759
7742
|
}
|
|
7760
7743
|
resetBorderLayerHighlight() {
|
|
7744
|
+
this.mowPartitionData = null;
|
|
7761
7745
|
const boundaryBorderLayer = this.svgMapView?.getLayer(LAYER_DEFAULT_TYPE.BOUNDARY_BORDER);
|
|
7762
|
-
|
|
7763
|
-
|
|
7764
|
-
|
|
7765
|
-
|
|
7766
|
-
path.setAttribute('stroke', BOUNDARY_STYLES.lineColor);
|
|
7767
|
-
});
|
|
7768
|
-
}
|
|
7769
|
-
});
|
|
7746
|
+
if (!boundaryBorderLayer)
|
|
7747
|
+
return;
|
|
7748
|
+
boundaryBorderLayer.setMowingBoundarys([]);
|
|
7749
|
+
this.svgMapView?.renderLayer(LAYER_DEFAULT_TYPE.BOUNDARY_BORDER);
|
|
7770
7750
|
}
|
|
7771
7751
|
setBorderLayerHighlight(mowPartitionData) {
|
|
7772
7752
|
this.mowPartitionData = mowPartitionData;
|
|
7773
7753
|
const boundaryBorderLayer = this.svgMapView?.getLayer(LAYER_DEFAULT_TYPE.BOUNDARY_BORDER);
|
|
7774
7754
|
const partitionIds = mowPartitionData?.partitionIds || [];
|
|
7775
|
-
|
|
7776
|
-
|
|
7777
|
-
|
|
7778
|
-
|
|
7779
|
-
if (boundaryBorderPaths) {
|
|
7780
|
-
boundaryBorderPaths.forEach((path) => {
|
|
7781
|
-
path.setAttribute('stroke', BOUNDARY_STYLES.mowingLineColor);
|
|
7782
|
-
});
|
|
7783
|
-
}
|
|
7784
|
-
}
|
|
7755
|
+
if (!boundaryBorderLayer)
|
|
7756
|
+
return;
|
|
7757
|
+
boundaryBorderLayer.setMowingBoundarys(partitionIds);
|
|
7758
|
+
this.svgMapView?.renderLayer(LAYER_DEFAULT_TYPE.BOUNDARY_BORDER);
|
|
7785
7759
|
}
|
|
7786
7760
|
onAdd() {
|
|
7761
|
+
console.log('onAdd');
|
|
7787
7762
|
// 创建包含SVG的div
|
|
7788
7763
|
this.div = document.createElement('div');
|
|
7789
7764
|
this.div.style.borderStyle = 'none';
|
|
@@ -7805,6 +7780,7 @@ class MowerMapOverlay {
|
|
|
7805
7780
|
this.createBoundaryLabelsManager();
|
|
7806
7781
|
// 创建割草机位置管理器
|
|
7807
7782
|
this.createMowerPositionManager();
|
|
7783
|
+
this.setManagerRotation(this.defaultTransform.rotation);
|
|
7808
7784
|
// 如果处于编辑模式,创建编辑界面
|
|
7809
7785
|
if (this.isEditMode) {
|
|
7810
7786
|
this.createEditInterface();
|
|
@@ -7843,16 +7819,6 @@ class MowerMapOverlay {
|
|
|
7843
7819
|
const map = this.getMap();
|
|
7844
7820
|
if (!map || !this.svgMapView)
|
|
7845
7821
|
return;
|
|
7846
|
-
// const currentZoom = map.getZoom();
|
|
7847
|
-
// const center = map.getCenter();
|
|
7848
|
-
// 基础公式:像素/米 = 156543.03392 * cos(latitude) / (2 ^ zoom)
|
|
7849
|
-
// const metersPerPixel =
|
|
7850
|
-
// (156543.03392 * Math.cos((center.lat() * Math.PI) / 180)) / Math.pow(2, currentZoom);
|
|
7851
|
-
// 缩放比例 = 1 / 米/像素
|
|
7852
|
-
// const scale = (1 / metersPerPixel) * 50;
|
|
7853
|
-
// 应用缩放到SVG
|
|
7854
|
-
// this.svgMapView.setZoom(scale);
|
|
7855
|
-
// 当缩放变化时,重新绘制以确保位置正确
|
|
7856
7822
|
this.draw();
|
|
7857
7823
|
}
|
|
7858
7824
|
// 创建边界标签管理器
|
|
@@ -7860,7 +7826,10 @@ class MowerMapOverlay {
|
|
|
7860
7826
|
if (!this.div || !this.svgMapView)
|
|
7861
7827
|
return;
|
|
7862
7828
|
// 创建边界标签管理器
|
|
7863
|
-
this.boundaryLabelsManager = new BoundaryLabelsManager(this.svgMapView, this.boundaryData
|
|
7829
|
+
this.boundaryLabelsManager = new BoundaryLabelsManager(this.svgMapView, this.boundaryData, {
|
|
7830
|
+
unitType: this.unitType,
|
|
7831
|
+
language: this.language,
|
|
7832
|
+
});
|
|
7864
7833
|
// 设置叠加层div引用
|
|
7865
7834
|
this.boundaryLabelsManager.setOverlayDiv(this.div);
|
|
7866
7835
|
// 添加所有边界标签
|
|
@@ -7904,9 +7873,7 @@ class MowerMapOverlay {
|
|
|
7904
7873
|
if (!this.div || !this.svgMapView)
|
|
7905
7874
|
return;
|
|
7906
7875
|
// 创建割草机位置管理器,传入动画完成回调
|
|
7907
|
-
this.mowerPositionManager = new MowerPositionManager(this.svgMapView, this.mowerPositionConfig, this.div, () => {
|
|
7908
|
-
console.log('动画完成');
|
|
7909
|
-
}, this.updatePathDataByMowingPositionThrottled.bind(this));
|
|
7876
|
+
this.mowerPositionManager = new MowerPositionManager(this.svgMapView, this.mowerPositionConfig, this.modelType, this.div, () => { }, this.updatePathDataByMowingPositionThrottled.bind(this));
|
|
7910
7877
|
// 设置叠加层div引用
|
|
7911
7878
|
this.mowerPositionManager.setOverlayDiv(this.div);
|
|
7912
7879
|
// 获取容器并添加到主div
|
|
@@ -7937,7 +7904,7 @@ class MowerMapOverlay {
|
|
|
7937
7904
|
this.boundaryLabelsManager.updatePositionsWithPrecomputedData(width, height, viewBoxInfo);
|
|
7938
7905
|
}
|
|
7939
7906
|
// 更新管理器位置
|
|
7940
|
-
updateManagerPositions(
|
|
7907
|
+
updateManagerPositions(_width, _height) {
|
|
7941
7908
|
if (!this.div)
|
|
7942
7909
|
return;
|
|
7943
7910
|
// 更新充电桩位置
|
|
@@ -7988,7 +7955,7 @@ class MowerMapOverlay {
|
|
|
7988
7955
|
this.rotateHandle.style.pointerEvents = 'auto';
|
|
7989
7956
|
this.rotateHandle.innerHTML = DEFAULT_ROTATE_ICON;
|
|
7990
7957
|
this.editContainer.appendChild(this.rotateHandle);
|
|
7991
|
-
//
|
|
7958
|
+
// 创建拖拽手柄(左下角)- 仅在移动设备上显示
|
|
7992
7959
|
this.dragHandle = document.createElement('div');
|
|
7993
7960
|
this.dragHandle.style.position = 'absolute';
|
|
7994
7961
|
this.dragHandle.style.bottom = '-20px';
|
|
@@ -7999,6 +7966,10 @@ class MowerMapOverlay {
|
|
|
7999
7966
|
this.dragHandle.style.zIndex = EDIT_STYLES.Z_INDEX.HANDLE;
|
|
8000
7967
|
this.dragHandle.style.pointerEvents = 'auto';
|
|
8001
7968
|
this.dragHandle.innerHTML = DEFAULT_DRAG_ICON;
|
|
7969
|
+
// 在PC设备上隐藏拖拽手柄
|
|
7970
|
+
if (!isMobileDevice()) {
|
|
7971
|
+
this.dragHandle.style.display = 'none';
|
|
7972
|
+
}
|
|
8002
7973
|
this.editContainer.appendChild(this.dragHandle);
|
|
8003
7974
|
// 将编辑容器添加到主div
|
|
8004
7975
|
this.div.appendChild(this.editContainer);
|
|
@@ -8040,7 +8011,6 @@ class MowerMapOverlay {
|
|
|
8040
8011
|
this.boundaryLabelsManager.collapseAllLabels();
|
|
8041
8012
|
}
|
|
8042
8013
|
this.dragCallbacks?.onDragStart?.(this.getCurrentDragState());
|
|
8043
|
-
console.log('开始旋转操作');
|
|
8044
8014
|
});
|
|
8045
8015
|
// 旋转手柄的触摸事件
|
|
8046
8016
|
this.rotateHandle.addEventListener('touchstart', (e) => {
|
|
@@ -8056,39 +8026,41 @@ class MowerMapOverlay {
|
|
|
8056
8026
|
this.boundaryLabelsManager.collapseAllLabels();
|
|
8057
8027
|
}
|
|
8058
8028
|
this.dragCallbacks?.onDragStart?.(this.getCurrentDragState());
|
|
8059
|
-
console.log('开始旋转操作(触摸)');
|
|
8060
|
-
}, { passive: false });
|
|
8061
|
-
// 拖拽手柄的鼠标事件
|
|
8062
|
-
this.dragHandle.addEventListener('mousedown', (e) => {
|
|
8063
|
-
e.preventDefault();
|
|
8064
|
-
e.stopPropagation();
|
|
8065
|
-
e.stopImmediatePropagation();
|
|
8066
|
-
this.isDragging = true;
|
|
8067
|
-
this.startPos = { x: e.clientX, y: e.clientY };
|
|
8068
|
-
this.dragHandle.style.cursor = 'grabbing';
|
|
8069
|
-
// 开始编辑时关闭所有展开的边界标签
|
|
8070
|
-
if (this.boundaryLabelsManager) {
|
|
8071
|
-
this.boundaryLabelsManager.collapseAllLabels();
|
|
8072
|
-
}
|
|
8073
|
-
this.dragCallbacks?.onDragStart?.(this.getCurrentDragState());
|
|
8074
|
-
console.log('开始拖动操作(通过手柄)');
|
|
8075
|
-
});
|
|
8076
|
-
// 拖拽手柄的触摸事件
|
|
8077
|
-
this.dragHandle.addEventListener('touchstart', (e) => {
|
|
8078
|
-
e.preventDefault();
|
|
8079
|
-
e.stopPropagation();
|
|
8080
|
-
e.stopImmediatePropagation();
|
|
8081
|
-
this.isDragging = true;
|
|
8082
|
-
const touch = e.touches[0];
|
|
8083
|
-
this.startPos = { x: touch.clientX, y: touch.clientY };
|
|
8084
|
-
this.dragHandle.style.cursor = 'grabbing';
|
|
8085
|
-
this.dragCallbacks?.onDragStart?.(this.getCurrentDragState());
|
|
8086
|
-
console.log('开始拖动操作(通过手柄,触摸)');
|
|
8087
8029
|
}, { passive: false });
|
|
8030
|
+
// 拖拽手柄的鼠标事件 - 仅在移动设备上启用
|
|
8031
|
+
if (isMobileDevice()) {
|
|
8032
|
+
this.dragHandle.addEventListener('mousedown', (e) => {
|
|
8033
|
+
e.preventDefault();
|
|
8034
|
+
e.stopPropagation();
|
|
8035
|
+
e.stopImmediatePropagation();
|
|
8036
|
+
this.isDragging = true;
|
|
8037
|
+
this.startPos = { x: e.clientX, y: e.clientY };
|
|
8038
|
+
this.dragHandle.style.cursor = 'grabbing';
|
|
8039
|
+
// 开始编辑时关闭所有展开的边界标签
|
|
8040
|
+
if (this.boundaryLabelsManager) {
|
|
8041
|
+
this.boundaryLabelsManager.collapseAllLabels();
|
|
8042
|
+
}
|
|
8043
|
+
this.dragCallbacks?.onDragStart?.(this.getCurrentDragState());
|
|
8044
|
+
});
|
|
8045
|
+
// 拖拽手柄的触摸事件
|
|
8046
|
+
this.dragHandle.addEventListener('touchstart', (e) => {
|
|
8047
|
+
e.preventDefault();
|
|
8048
|
+
e.stopPropagation();
|
|
8049
|
+
e.stopImmediatePropagation();
|
|
8050
|
+
this.isDragging = true;
|
|
8051
|
+
const touch = e.touches[0];
|
|
8052
|
+
this.startPos = { x: touch.clientX, y: touch.clientY };
|
|
8053
|
+
this.dragHandle.style.cursor = 'grabbing';
|
|
8054
|
+
this.dragCallbacks?.onDragStart?.(this.getCurrentDragState());
|
|
8055
|
+
}, { passive: false });
|
|
8056
|
+
}
|
|
8088
8057
|
// 编辑容器的鼠标事件(整个区域拖拽)
|
|
8089
8058
|
this.editContainer.addEventListener('mousedown', (e) => {
|
|
8090
|
-
|
|
8091
|
-
|
|
8059
|
+
// 在移动设备上,检查是否点击了拖拽手柄或旋转手柄
|
|
8060
|
+
// 在PC设备上,只检查旋转手柄(拖拽手柄已隐藏)
|
|
8061
|
+
const isDragHandleClick = isMobileDevice() && e.target === this.dragHandle;
|
|
8062
|
+
const isRotateHandleClick = e.target === this.rotateHandle;
|
|
8063
|
+
if (isDragHandleClick || isRotateHandleClick) {
|
|
8092
8064
|
return;
|
|
8093
8065
|
}
|
|
8094
8066
|
e.preventDefault();
|
|
@@ -8105,8 +8077,11 @@ class MowerMapOverlay {
|
|
|
8105
8077
|
});
|
|
8106
8078
|
// 编辑容器的触摸事件(整个区域拖拽)
|
|
8107
8079
|
this.editContainer.addEventListener('touchstart', (e) => {
|
|
8108
|
-
|
|
8109
|
-
|
|
8080
|
+
// 在移动设备上,检查是否点击了拖拽手柄或旋转手柄
|
|
8081
|
+
// 在PC设备上,只检查旋转手柄(拖拽手柄已隐藏)
|
|
8082
|
+
const isDragHandleClick = isMobileDevice() && e.target === this.dragHandle;
|
|
8083
|
+
const isRotateHandleClick = e.target === this.rotateHandle;
|
|
8084
|
+
if (isDragHandleClick || isRotateHandleClick) {
|
|
8110
8085
|
return;
|
|
8111
8086
|
}
|
|
8112
8087
|
e.preventDefault();
|
|
@@ -8166,7 +8141,6 @@ class MowerMapOverlay {
|
|
|
8166
8141
|
e.preventDefault();
|
|
8167
8142
|
e.stopPropagation();
|
|
8168
8143
|
e.stopImmediatePropagation();
|
|
8169
|
-
console.log('结束编辑操作');
|
|
8170
8144
|
}
|
|
8171
8145
|
// 如果是拖拽结束,将像素偏移量转换为地理坐标偏移量
|
|
8172
8146
|
if (this.isDragging) {
|
|
@@ -8188,7 +8162,6 @@ class MowerMapOverlay {
|
|
|
8188
8162
|
e.preventDefault();
|
|
8189
8163
|
e.stopPropagation();
|
|
8190
8164
|
e.stopImmediatePropagation();
|
|
8191
|
-
console.log('结束编辑操作(触摸)');
|
|
8192
8165
|
}
|
|
8193
8166
|
// 如果是拖拽结束,将像素偏移量转换为地理坐标偏移量
|
|
8194
8167
|
if (this.isDragging) {
|
|
@@ -8300,7 +8273,6 @@ class MowerMapOverlay {
|
|
|
8300
8273
|
this.div.style.transform = transform;
|
|
8301
8274
|
// 更新鼠标起始位置为当前位置,为下次计算做准备
|
|
8302
8275
|
this.startPos = { x: mouseCurrentX, y: mouseCurrentY };
|
|
8303
|
-
console.log('旋转角度:', this.currentRotation, '角度增量:', angleDifferenceDegrees);
|
|
8304
8276
|
}
|
|
8305
8277
|
// 将像素偏移量转换为地理坐标偏移量
|
|
8306
8278
|
convertPixelOffsetToLatLng() {
|
|
@@ -8330,14 +8302,6 @@ class MowerMapOverlay {
|
|
|
8330
8302
|
// 累积更新地理坐标偏移量(不是直接赋值!)
|
|
8331
8303
|
this.latLngOffset.lat += latOffset;
|
|
8332
8304
|
this.latLngOffset.lng += lngOffset;
|
|
8333
|
-
console.log('精确转换偏移量:', {
|
|
8334
|
-
pixelOffset: this.tempPixelOffset,
|
|
8335
|
-
centerLatLng: { lat: centerLatLng.lat(), lng: centerLatLng.lng() },
|
|
8336
|
-
offsetLatLng: { lat: offsetLatLng.lat(), lng: offsetLatLng.lng() },
|
|
8337
|
-
latOffset,
|
|
8338
|
-
lngOffset,
|
|
8339
|
-
newLatLngOffset: this.latLngOffset,
|
|
8340
|
-
});
|
|
8341
8305
|
// 重置临时像素偏移量
|
|
8342
8306
|
this.tempPixelOffset = { x: 0, y: 0 };
|
|
8343
8307
|
this.draw();
|
|
@@ -8375,8 +8339,6 @@ class MowerMapOverlay {
|
|
|
8375
8339
|
editData: editData,
|
|
8376
8340
|
timestamp: new Date().toISOString(),
|
|
8377
8341
|
};
|
|
8378
|
-
// 在这里可以添加保存逻辑,比如发送到服务器
|
|
8379
|
-
console.log('保存编辑数据:', saveData);
|
|
8380
8342
|
// 显示保存成功提示
|
|
8381
8343
|
this.showSaveSuccess();
|
|
8382
8344
|
return saveData;
|
|
@@ -8469,6 +8431,9 @@ class MowerMapOverlay {
|
|
|
8469
8431
|
y: transform.y,
|
|
8470
8432
|
rotation: transform.rotation,
|
|
8471
8433
|
};
|
|
8434
|
+
// defaultTransform的x对应经度偏移量,y对应纬度偏移量
|
|
8435
|
+
this.latLngOffset.lng = this.defaultTransform.x;
|
|
8436
|
+
this.latLngOffset.lat = this.defaultTransform.y;
|
|
8472
8437
|
this.setManagerRotation(this.currentRotation);
|
|
8473
8438
|
this.draw();
|
|
8474
8439
|
}
|
|
@@ -8502,12 +8467,10 @@ class MowerMapOverlay {
|
|
|
8502
8467
|
try {
|
|
8503
8468
|
// 创建SvgMapView实例
|
|
8504
8469
|
this.svgMapView = new SvgMapView(this.offscreenContainer, 800, 600);
|
|
8505
|
-
window.svgMapView = this.svgMapView;
|
|
8506
8470
|
// 加载地图数据
|
|
8507
8471
|
this.loadMapData();
|
|
8508
8472
|
// 加载路径数据
|
|
8509
8473
|
if (this.pathData && this.svgMapView) {
|
|
8510
|
-
console.log('initializeSvgMapView->', this.pathData, this.mowPartitionData);
|
|
8511
8474
|
this.loadPathData(this.pathData, this.mowPartitionData);
|
|
8512
8475
|
}
|
|
8513
8476
|
// 刷新绘制图层
|
|
@@ -8534,9 +8497,6 @@ class MowerMapOverlay {
|
|
|
8534
8497
|
// 使用现有的MapDataProcessor处理地图数据
|
|
8535
8498
|
const elements = MapDataProcessor.processMapData(this.mapData, this.mapConfig);
|
|
8536
8499
|
// 分离充电桩和天线元素,其他元素添加到SVG图层
|
|
8537
|
-
// const svgElements = elements.filter(element =>
|
|
8538
|
-
// element.type !== 'charging_pile' && element.type !== 'antenna'
|
|
8539
|
-
// );
|
|
8540
8500
|
const svgElements = elements.filter((element) => element.type !== 'charging_pile' && element.type !== 'antenna');
|
|
8541
8501
|
const chargingPileElements = elements.filter((element) => element.type === 'charging_pile');
|
|
8542
8502
|
// 处理SVG图层元素
|
|
@@ -8551,6 +8511,10 @@ class MowerMapOverlay {
|
|
|
8551
8511
|
const layers = drawLayer.getLayers();
|
|
8552
8512
|
this.svgMapView.clear();
|
|
8553
8513
|
this.svgMapView.addLayers(layers);
|
|
8514
|
+
const boundaryBorderLayer = this.svgMapView.getLayer(LAYER_DEFAULT_TYPE.BOUNDARY_BORDER);
|
|
8515
|
+
if (boundaryBorderLayer) {
|
|
8516
|
+
boundaryBorderLayer.setMowingBoundarys(this.mowPartitionData?.partitionIds || []);
|
|
8517
|
+
}
|
|
8554
8518
|
this.createChargingPileManager();
|
|
8555
8519
|
// 使用管理器处理充电桩和天线
|
|
8556
8520
|
if (this.chargingPileManager && chargingPileElements.length > 0) {
|
|
@@ -8580,7 +8544,6 @@ class MowerMapOverlay {
|
|
|
8580
8544
|
try {
|
|
8581
8545
|
// 使用现有的PathDataProcessor处理路径数据
|
|
8582
8546
|
const pathElements = PathDataProcessor.processPathData(pathData, this.mapConfig);
|
|
8583
|
-
console.log('pathdaata->', pathElements, mowPartitionData);
|
|
8584
8547
|
const newPathElements = pathElements.map((pathElement) => {
|
|
8585
8548
|
const { id, elements } = pathElement;
|
|
8586
8549
|
const isMowBoundary = mowPartitionData && mowPartitionData?.partitionIds?.includes(id);
|
|
@@ -8628,7 +8591,6 @@ class MowerMapOverlay {
|
|
|
8628
8591
|
// 找到当前position所在的分区id,将该点更新到pathData中
|
|
8629
8592
|
const currentPartitionId = getPartitionId(this.partitionBoundary, position.x, position.y);
|
|
8630
8593
|
const processStateIsMowing = useProcessMowingState.getState().processStateIsMowing;
|
|
8631
|
-
// console.log('processStateIsMowing==', processStateIsMowing);
|
|
8632
8594
|
if (currentPartitionId && this.pathData?.[currentPartitionId]) {
|
|
8633
8595
|
const currentPathData = this.pathData[currentPartitionId];
|
|
8634
8596
|
this.pathData[currentPartitionId] = {
|
|
@@ -8817,15 +8779,41 @@ class MowerMapOverlay {
|
|
|
8817
8779
|
this.mowerPositionManager.setVisible(visible);
|
|
8818
8780
|
}
|
|
8819
8781
|
}
|
|
8820
|
-
|
|
8821
|
-
|
|
8822
|
-
|
|
8823
|
-
|
|
8824
|
-
|
|
8825
|
-
|
|
8826
|
-
|
|
8827
|
-
|
|
8828
|
-
|
|
8782
|
+
// 获取SvgMapView实例(用于debug)
|
|
8783
|
+
getSvgMapView() {
|
|
8784
|
+
return this.svgMapView;
|
|
8785
|
+
}
|
|
8786
|
+
}
|
|
8787
|
+
|
|
8788
|
+
// 获取车辆状态的中文文案
|
|
8789
|
+
const getVehicleStateText = (vehicleState) => {
|
|
8790
|
+
switch (vehicleState) {
|
|
8791
|
+
case RobotStatus.PARKED:
|
|
8792
|
+
return 'PARKED';
|
|
8793
|
+
case RobotStatus.CHARGING:
|
|
8794
|
+
return 'CHARGING';
|
|
8795
|
+
case RobotStatus.STANDBY:
|
|
8796
|
+
return 'STANDBY';
|
|
8797
|
+
case RobotStatus.MOWING:
|
|
8798
|
+
return 'MOWING';
|
|
8799
|
+
case RobotStatus.WORKING:
|
|
8800
|
+
return 'WORKING';
|
|
8801
|
+
case RobotStatus.MAPPING:
|
|
8802
|
+
return 'MAPPING';
|
|
8803
|
+
case RobotStatus.ERROR:
|
|
8804
|
+
return 'ERROR';
|
|
8805
|
+
case RobotStatus.UPGRADING:
|
|
8806
|
+
return 'UPGRADING';
|
|
8807
|
+
case RobotStatus.DISCONNECTED:
|
|
8808
|
+
return 'DISCONNECTED';
|
|
8809
|
+
case RobotStatus.TASK_DELAY:
|
|
8810
|
+
return 'TASK_DELAY';
|
|
8811
|
+
case RobotStatus.UNKNOWN:
|
|
8812
|
+
return '未知';
|
|
8813
|
+
default:
|
|
8814
|
+
return `未知状态(${vehicleState})`;
|
|
8815
|
+
}
|
|
8816
|
+
};
|
|
8829
8817
|
// 验证GPS坐标是否有效
|
|
8830
8818
|
const isValidGpsCoordinate = (coordinate) => {
|
|
8831
8819
|
if (!coordinate || coordinate.length < 2)
|
|
@@ -8839,35 +8827,76 @@ const isValidGpsCoordinate = (coordinate) => {
|
|
|
8839
8827
|
!(Math.abs(lng) < 0.001 && Math.abs(lat) < 0.001) // 排除接近(0,0)的坐标
|
|
8840
8828
|
);
|
|
8841
8829
|
};
|
|
8830
|
+
// 旋转坐标点
|
|
8831
|
+
const rotateCoordinate = (point, center, angleRadians) => {
|
|
8832
|
+
const [x, y] = point;
|
|
8833
|
+
const [cx, cy] = center;
|
|
8834
|
+
// 将点移动到原点
|
|
8835
|
+
const dx = x - cx;
|
|
8836
|
+
const dy = y - cy;
|
|
8837
|
+
// 应用旋转矩阵
|
|
8838
|
+
const cos = Math.cos(angleRadians);
|
|
8839
|
+
const sin = Math.sin(angleRadians);
|
|
8840
|
+
const rotatedX = dx * cos - dy * sin;
|
|
8841
|
+
const rotatedY = dx * sin + dy * cos;
|
|
8842
|
+
// 移回原位置
|
|
8843
|
+
return [rotatedX + cx, rotatedY + cy];
|
|
8844
|
+
};
|
|
8842
8845
|
// 获取有效的GPS边界
|
|
8843
|
-
const getValidGpsBounds = (mapData) => {
|
|
8846
|
+
const getValidGpsBounds = (mapData, rotation = 0) => {
|
|
8847
|
+
let bounds;
|
|
8844
8848
|
// 首先尝试使用地图数据中的GPS坐标
|
|
8845
8849
|
if (isValidGpsCoordinate(mapData.sw_gps) && isValidGpsCoordinate(mapData.ne_gps)) {
|
|
8846
|
-
|
|
8850
|
+
bounds = {
|
|
8847
8851
|
sw: mapData.sw_gps,
|
|
8848
8852
|
ne: mapData.ne_gps,
|
|
8849
8853
|
};
|
|
8850
8854
|
}
|
|
8851
|
-
|
|
8852
|
-
|
|
8853
|
-
|
|
8854
|
-
|
|
8855
|
-
|
|
8856
|
-
|
|
8857
|
-
|
|
8855
|
+
else {
|
|
8856
|
+
// 如果GPS坐标无效,尝试从地图几何数据估算
|
|
8857
|
+
const { sw, ne } = estimateGpsFromMapBounds(mapData);
|
|
8858
|
+
if (sw && ne) {
|
|
8859
|
+
console.warn('GPS坐标无效,使用地图几何数据估算边界:', sw, ne);
|
|
8860
|
+
bounds = {
|
|
8861
|
+
sw: [sw[0], sw[1]],
|
|
8862
|
+
ne: [ne[0], ne[1]],
|
|
8863
|
+
};
|
|
8864
|
+
}
|
|
8865
|
+
else {
|
|
8866
|
+
// 最后的fallback:使用默认坐标
|
|
8867
|
+
console.warn('无法获取有效的GPS边界,使用默认坐标');
|
|
8868
|
+
bounds = {
|
|
8869
|
+
sw: [-9.1562, -37.7503],
|
|
8870
|
+
ne: [31.247, 5.797],
|
|
8871
|
+
};
|
|
8872
|
+
}
|
|
8873
|
+
}
|
|
8874
|
+
// 如果有旋转角度,计算旋转后的边界
|
|
8875
|
+
if (rotation !== 0) {
|
|
8876
|
+
const angleRadians = (rotation * Math.PI) / 180; // 转换为弧度
|
|
8877
|
+
// 计算边界中心点
|
|
8878
|
+
const centerLng = (bounds.sw[0] + bounds.ne[0]) / 2;
|
|
8879
|
+
const centerLat = (bounds.sw[1] + bounds.ne[1]) / 2;
|
|
8880
|
+
const center = [centerLng, centerLat];
|
|
8881
|
+
// 旋转四个角点
|
|
8882
|
+
const sw = rotateCoordinate(bounds.sw, center, angleRadians);
|
|
8883
|
+
const ne = rotateCoordinate(bounds.ne, center, angleRadians);
|
|
8884
|
+
const se = rotateCoordinate([bounds.ne[0], bounds.sw[1]], center, angleRadians);
|
|
8885
|
+
const nw = rotateCoordinate([bounds.sw[0], bounds.ne[1]], center, angleRadians);
|
|
8886
|
+
// 计算旋转后的边界框(包含所有旋转后的点)
|
|
8887
|
+
const lngs = [sw[0], ne[0], se[0], nw[0]];
|
|
8888
|
+
const lats = [sw[1], ne[1], se[1], nw[1]];
|
|
8889
|
+
bounds = {
|
|
8890
|
+
sw: [Math.min(...lngs), Math.min(...lats)],
|
|
8891
|
+
ne: [Math.max(...lngs), Math.max(...lats)],
|
|
8858
8892
|
};
|
|
8859
8893
|
}
|
|
8860
|
-
|
|
8861
|
-
console.warn('无法获取有效的GPS边界,使用默认坐标');
|
|
8862
|
-
return {
|
|
8863
|
-
sw: [-9.1562, -37.7503],
|
|
8864
|
-
ne: [31.247, 5.797],
|
|
8865
|
-
};
|
|
8894
|
+
return bounds;
|
|
8866
8895
|
};
|
|
8867
8896
|
// 默认配置
|
|
8868
8897
|
const defaultMapConfig = DEFAULT_STYLES;
|
|
8869
8898
|
// 地图渲染器组件
|
|
8870
|
-
const MowerMapRenderer = React.forwardRef(({ mapConfig, modelType, mapRef, mapJson, pathJson, realTimeData, antennaConfig, onMapLoad, onPathLoad, onError, className, style, googleMapInstance, isEditMode = false, dragCallbacks, defaultTransform, }, ref) => {
|
|
8899
|
+
const MowerMapRenderer = React.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) => {
|
|
8871
8900
|
const [elementCount, setElementCount] = React.useState(0);
|
|
8872
8901
|
const [pathCount, setPathCount] = React.useState(0);
|
|
8873
8902
|
const [currentError, setCurrentError] = React.useState(null);
|
|
@@ -8875,10 +8904,12 @@ const MowerMapRenderer = React.forwardRef(({ mapConfig, modelType, mapRef, mapJs
|
|
|
8875
8904
|
// const mapRef = useMap();
|
|
8876
8905
|
const [isGoogleMapsReady, setIsGoogleMapsReady] = React.useState(false);
|
|
8877
8906
|
const [hasInitializedBounds, setHasInitializedBounds] = React.useState(false);
|
|
8878
|
-
const { clearSubBoundaryBorder } = useSubBoundaryBorderStore();
|
|
8907
|
+
const { clearSubBoundaryBorder, clearObstacles } = useSubBoundaryBorderStore();
|
|
8879
8908
|
const currentProcessMowingStatusRef = React.useRef(false);
|
|
8880
8909
|
const { updateProcessStateIsMowing, processStateIsMowing } = useProcessMowingState();
|
|
8881
8910
|
const [mowPartitionData, setMowPartitionData] = React.useState(null);
|
|
8911
|
+
// Debug相关状态
|
|
8912
|
+
const [debugInfo, setDebugInfo] = React.useState({});
|
|
8882
8913
|
// 处理地图分区边界
|
|
8883
8914
|
const partitionBoundary = React.useMemo(() => {
|
|
8884
8915
|
const allBoundaryElements = [];
|
|
@@ -8903,7 +8934,12 @@ const MowerMapRenderer = React.forwardRef(({ mapConfig, modelType, mapRef, mapJs
|
|
|
8903
8934
|
const mowerPositionData = React.useMemo(() => {
|
|
8904
8935
|
// realTimeData 中包含三个种类的数据,之需要实时坐标的数据即可。
|
|
8905
8936
|
if (!realTimeData || realTimeData.length === 0)
|
|
8906
|
-
return
|
|
8937
|
+
return {
|
|
8938
|
+
postureX: 0,
|
|
8939
|
+
postureY: 0,
|
|
8940
|
+
postureTheta: 0,
|
|
8941
|
+
vehicleState: RobotStatus.DISCONNECTED,
|
|
8942
|
+
};
|
|
8907
8943
|
let currentPositionData;
|
|
8908
8944
|
if (realTimeData.length === 1 && realTimeData[0].type === RealTimeDataType.LOCATION) {
|
|
8909
8945
|
currentPositionData = realTimeData[0];
|
|
@@ -8922,13 +8958,15 @@ const MowerMapRenderer = React.forwardRef(({ mapConfig, modelType, mapRef, mapJs
|
|
|
8922
8958
|
lastPostureTheta: currentPositionData?.lastPostureTheta
|
|
8923
8959
|
? Number(currentPositionData.lastPostureTheta)
|
|
8924
8960
|
: 0,
|
|
8925
|
-
lastPostureX: currentPositionData?.lastPostureX
|
|
8926
|
-
|
|
8927
|
-
|
|
8928
|
-
|
|
8961
|
+
lastPostureX: currentPositionData?.lastPostureX
|
|
8962
|
+
? Number(currentPositionData.lastPostureX)
|
|
8963
|
+
: 0,
|
|
8964
|
+
lastPostureY: currentPositionData?.lastPostureY
|
|
8965
|
+
? Number(currentPositionData.lastPostureY)
|
|
8966
|
+
: 0,
|
|
8967
|
+
vehicleState: currentPositionData?.vehicleState || RobotStatus.DISCONNECTED,
|
|
8929
8968
|
};
|
|
8930
8969
|
}, [realTimeData, modelType]);
|
|
8931
|
-
console.log('mowerPositionData', mowerPositionData);
|
|
8932
8970
|
// 处理错误
|
|
8933
8971
|
const handleError = (error) => {
|
|
8934
8972
|
setCurrentError(error);
|
|
@@ -8944,18 +8982,17 @@ const MowerMapRenderer = React.forwardRef(({ mapConfig, modelType, mapRef, mapJs
|
|
|
8944
8982
|
return;
|
|
8945
8983
|
}
|
|
8946
8984
|
// 将自定义边界转换为Google Maps LatLngBounds(使用有效的GPS坐标)
|
|
8947
|
-
const validBounds = getValidGpsBounds(mapJson);
|
|
8985
|
+
const validBounds = getValidGpsBounds(mapJson, defaultTransform?.rotation);
|
|
8948
8986
|
// 地图数据中的坐标格式是 [longitude, latitude]
|
|
8949
|
-
const swLat = validBounds.sw[1];
|
|
8950
|
-
const swLng = validBounds.sw[0];
|
|
8951
|
-
const neLat = validBounds.ne[1];
|
|
8952
|
-
const neLng = validBounds.ne[0];
|
|
8987
|
+
const swLat = validBounds.sw[1] + defaultTransform.y;
|
|
8988
|
+
const swLng = validBounds.sw[0] + defaultTransform.x;
|
|
8989
|
+
const neLat = validBounds.ne[1] + defaultTransform.y;
|
|
8990
|
+
const neLng = validBounds.ne[0] + defaultTransform.x;
|
|
8953
8991
|
const googleBounds = new window.google.maps.LatLngBounds(new window.google.maps.LatLng(swLat, swLng), // 西南角
|
|
8954
8992
|
new window.google.maps.LatLng(neLat, neLng) // 东北角
|
|
8955
8993
|
);
|
|
8956
|
-
console.log('fitBounds----->', googleBounds);
|
|
8957
8994
|
mapRef.fitBounds(googleBounds);
|
|
8958
|
-
}, [mapJson, mapRef]);
|
|
8995
|
+
}, [mapJson, mapRef, defaultTransform]);
|
|
8959
8996
|
// 初始化Google Maps叠加层
|
|
8960
8997
|
const initializeGoogleMapsOverlay = async () => {
|
|
8961
8998
|
if (!mapJson)
|
|
@@ -8979,7 +9016,8 @@ const MowerMapRenderer = React.forwardRef(({ mapConfig, modelType, mapRef, mapJs
|
|
|
8979
9016
|
return;
|
|
8980
9017
|
}
|
|
8981
9018
|
// 将自定义边界转换为Google Maps LatLngBounds(使用有效的GPS坐标)
|
|
8982
|
-
|
|
9019
|
+
// 这里需要使用0度,需要原始的坐标点去计算元素的实际位置,只有在fitbounds的时候才需要使用旋转后的坐标点
|
|
9020
|
+
const validBounds = getValidGpsBounds(mapJson, 0);
|
|
8983
9021
|
// 地图数据中的坐标格式是 [longitude, latitude]
|
|
8984
9022
|
const swLat = validBounds.sw[1];
|
|
8985
9023
|
const swLng = validBounds.sw[0];
|
|
@@ -8994,7 +9032,7 @@ const MowerMapRenderer = React.forwardRef(({ mapConfig, modelType, mapRef, mapJs
|
|
|
8994
9032
|
overlayRef.current = null;
|
|
8995
9033
|
}
|
|
8996
9034
|
// 创建叠加层
|
|
8997
|
-
const overlay = new MowerMapOverlay(googleBounds, mapJson, partitionBoundary, mowerPositionData, pathJson || {}, isEditMode, mergedMapConfig, mergedAntennaConfig, null, defaultTransform, (count) => {
|
|
9035
|
+
const overlay = new MowerMapOverlay(googleBounds, mapJson, partitionBoundary, mowerPositionData, modelType, pathJson || {}, isEditMode, unitType, language, mergedMapConfig, mergedAntennaConfig, null, defaultTransform, (count) => {
|
|
8998
9036
|
setElementCount(count);
|
|
8999
9037
|
onMapLoad?.(count);
|
|
9000
9038
|
}, (count) => {
|
|
@@ -9015,12 +9053,26 @@ const MowerMapRenderer = React.forwardRef(({ mapConfig, modelType, mapRef, mapJs
|
|
|
9015
9053
|
handleError(`初始化Google Maps叠加层失败: ${error instanceof Error ? error.message : String(error)}`);
|
|
9016
9054
|
}
|
|
9017
9055
|
};
|
|
9056
|
+
const resetInCharginPie = React.useCallback(() => {
|
|
9057
|
+
const elements = MapDataProcessor.processMapData(mapJson, mergedMapConfig);
|
|
9058
|
+
const chargingPiles = elements.find((element) => element.type === 'charging_pile');
|
|
9059
|
+
if (!overlayRef.current)
|
|
9060
|
+
return;
|
|
9061
|
+
// 如果在充电桩上,则直接更新位置到充电桩的位置
|
|
9062
|
+
overlayRef.current.updatePosition({
|
|
9063
|
+
...mowerPositionData,
|
|
9064
|
+
postureX: chargingPiles?.originalData.position[0],
|
|
9065
|
+
postureY: chargingPiles?.originalData.position[1],
|
|
9066
|
+
postureTheta: chargingPiles?.originalData.direction - Math.PI || 0,
|
|
9067
|
+
}, 0);
|
|
9068
|
+
}, [mapJson, mowerPositionData]);
|
|
9018
9069
|
// 初始化效果
|
|
9019
9070
|
React.useEffect(() => {
|
|
9020
9071
|
initializeGoogleMapsOverlay();
|
|
9021
9072
|
// 清理函数
|
|
9022
9073
|
return () => {
|
|
9023
9074
|
clearSubBoundaryBorder();
|
|
9075
|
+
clearObstacles();
|
|
9024
9076
|
updateProcessStateIsMowing(false);
|
|
9025
9077
|
currentProcessMowingStatusRef.current = false;
|
|
9026
9078
|
if (overlayRef.current) {
|
|
@@ -9051,10 +9103,9 @@ const MowerMapRenderer = React.forwardRef(({ mapConfig, modelType, mapRef, mapJs
|
|
|
9051
9103
|
const inChargingPiles = [RobotStatus.CHARGING, RobotStatus.PARKED];
|
|
9052
9104
|
const isOffLine = mowerPositionData.vehicleState === RobotStatus.DISCONNECTED;
|
|
9053
9105
|
const isInChargingPile = inChargingPiles.includes(mowerPositionData.vehicleState);
|
|
9054
|
-
console.log('isInChargingPile-----------》', isInChargingPile, mowerPositionData);
|
|
9055
9106
|
// 如果在充电桩上,则直接更新位置到充电桩的位置
|
|
9107
|
+
console.log('usefeect mowerPositionData----->', mowerPositionData, isInChargingPile);
|
|
9056
9108
|
if (isInChargingPile) {
|
|
9057
|
-
console.log('isInChargingPile', isInChargingPile, mowerPositionData);
|
|
9058
9109
|
overlayRef.current.updatePosition({
|
|
9059
9110
|
...mowerPositionData,
|
|
9060
9111
|
postureX: chargingPiles?.originalData.position[0],
|
|
@@ -9067,7 +9118,6 @@ const MowerMapRenderer = React.forwardRef(({ mapConfig, modelType, mapRef, mapJs
|
|
|
9067
9118
|
const positonOutOfRange = isOutOfRange(mowerPositionData);
|
|
9068
9119
|
const positionValid = isInvalidPosition(mowerPositionData);
|
|
9069
9120
|
const isStandby = mowerPositionData.vehicleState === RobotStatus.STANDBY;
|
|
9070
|
-
console.log('positonOutOfRange', positonOutOfRange, positionValid, isOffLine);
|
|
9071
9121
|
if (positonOutOfRange || positionValid || isOffLine) {
|
|
9072
9122
|
// 初始信息是通过后端接口获取的,此时当前位置数据不可用的时候,可以取上一次的位置数据
|
|
9073
9123
|
// mowerPositionData 中可能会包含上一次的位置数据,
|
|
@@ -9087,29 +9137,165 @@ const MowerMapRenderer = React.forwardRef(({ mapConfig, modelType, mapRef, mapJs
|
|
|
9087
9137
|
}
|
|
9088
9138
|
}
|
|
9089
9139
|
else {
|
|
9090
|
-
console.log('hook updatePosition----->', mowerPositionData);
|
|
9091
9140
|
overlayRef.current.updatePosition(mowerPositionData, isStandby ? 0 : 2000);
|
|
9092
9141
|
}
|
|
9093
9142
|
}
|
|
9094
9143
|
}, [mowerPositionData]);
|
|
9144
|
+
// 更新debug信息
|
|
9145
|
+
React.useEffect(() => {
|
|
9146
|
+
if (!debug)
|
|
9147
|
+
return;
|
|
9148
|
+
const updateDebugInfo = () => {
|
|
9149
|
+
const newDebugInfo = {};
|
|
9150
|
+
// 获取地图GPS边界
|
|
9151
|
+
if (mapJson) {
|
|
9152
|
+
newDebugInfo.mapBounds = getValidGpsBounds(mapJson, defaultTransform?.rotation);
|
|
9153
|
+
}
|
|
9154
|
+
// 获取SVG viewBox信息
|
|
9155
|
+
if (overlayRef.current) {
|
|
9156
|
+
const overlay = overlayRef.current;
|
|
9157
|
+
const svgMapView = overlay.getSvgMapView?.();
|
|
9158
|
+
if (svgMapView) {
|
|
9159
|
+
const viewBoxInfo = svgMapView.getViewBoxInfo();
|
|
9160
|
+
// 计算实际的米单位数据(除以缩放比例)
|
|
9161
|
+
const SCALE_FACTOR = 50; // 根据项目中的缩放因子
|
|
9162
|
+
newDebugInfo.viewBox = {
|
|
9163
|
+
x: viewBoxInfo.x / SCALE_FACTOR,
|
|
9164
|
+
y: viewBoxInfo.y / SCALE_FACTOR,
|
|
9165
|
+
width: viewBoxInfo.width / SCALE_FACTOR,
|
|
9166
|
+
height: viewBoxInfo.height / SCALE_FACTOR,
|
|
9167
|
+
scale: SCALE_FACTOR,
|
|
9168
|
+
// 计算左下角和右上角坐标
|
|
9169
|
+
sw: {
|
|
9170
|
+
x: viewBoxInfo.x / SCALE_FACTOR,
|
|
9171
|
+
y: viewBoxInfo.y / SCALE_FACTOR,
|
|
9172
|
+
},
|
|
9173
|
+
ne: {
|
|
9174
|
+
x: (viewBoxInfo.x + viewBoxInfo.width) / SCALE_FACTOR,
|
|
9175
|
+
y: (viewBoxInfo.y + viewBoxInfo.height) / SCALE_FACTOR,
|
|
9176
|
+
},
|
|
9177
|
+
};
|
|
9178
|
+
}
|
|
9179
|
+
}
|
|
9180
|
+
// 获取当前割草机位置
|
|
9181
|
+
if (mowerPositionData) {
|
|
9182
|
+
newDebugInfo.mowerPosition = {
|
|
9183
|
+
x: mowerPositionData.postureX || 0,
|
|
9184
|
+
y: mowerPositionData.postureY || 0,
|
|
9185
|
+
theta: mowerPositionData.postureTheta || 0,
|
|
9186
|
+
lastX: mowerPositionData.lastPostureX || 0,
|
|
9187
|
+
lastY: mowerPositionData.lastPostureY || 0,
|
|
9188
|
+
lastTheta: mowerPositionData.lastPostureTheta || 0,
|
|
9189
|
+
vehicleState: mowerPositionData.vehicleState || RobotStatus.UNKNOWN,
|
|
9190
|
+
vehicleStateText: getVehicleStateText(mowerPositionData.vehicleState || RobotStatus.UNKNOWN),
|
|
9191
|
+
};
|
|
9192
|
+
}
|
|
9193
|
+
// 获取当前割草地块数据
|
|
9194
|
+
newDebugInfo.partitionData = mowPartitionData;
|
|
9195
|
+
setDebugInfo(newDebugInfo);
|
|
9196
|
+
};
|
|
9197
|
+
updateDebugInfo();
|
|
9198
|
+
}, [debug, mapJson, mowerPositionData, mowPartitionData, defaultTransform]);
|
|
9199
|
+
// 当关键数据变化时立即更新debug信息
|
|
9200
|
+
React.useEffect(() => {
|
|
9201
|
+
if (!debug)
|
|
9202
|
+
return;
|
|
9203
|
+
const updateDebugInfo = () => {
|
|
9204
|
+
const newDebugInfo = {};
|
|
9205
|
+
// 获取地图GPS边界
|
|
9206
|
+
if (mapJson) {
|
|
9207
|
+
newDebugInfo.mapBounds = getValidGpsBounds(mapJson, defaultTransform?.rotation);
|
|
9208
|
+
}
|
|
9209
|
+
// 获取SVG viewBox信息
|
|
9210
|
+
if (overlayRef.current) {
|
|
9211
|
+
const overlay = overlayRef.current;
|
|
9212
|
+
const svgMapView = overlay.getSvgMapView?.();
|
|
9213
|
+
if (svgMapView) {
|
|
9214
|
+
const viewBoxInfo = svgMapView.getViewBoxInfo();
|
|
9215
|
+
// 计算实际的米单位数据(除以缩放比例)
|
|
9216
|
+
const SCALE_FACTOR = 50; // 根据项目中的缩放因子
|
|
9217
|
+
newDebugInfo.viewBox = {
|
|
9218
|
+
x: viewBoxInfo.x / SCALE_FACTOR,
|
|
9219
|
+
y: viewBoxInfo.y / SCALE_FACTOR,
|
|
9220
|
+
width: viewBoxInfo.width / SCALE_FACTOR,
|
|
9221
|
+
height: viewBoxInfo.height / SCALE_FACTOR,
|
|
9222
|
+
scale: SCALE_FACTOR,
|
|
9223
|
+
// 计算左下角和右上角坐标
|
|
9224
|
+
sw: {
|
|
9225
|
+
x: viewBoxInfo.x / SCALE_FACTOR,
|
|
9226
|
+
y: viewBoxInfo.y / SCALE_FACTOR,
|
|
9227
|
+
},
|
|
9228
|
+
ne: {
|
|
9229
|
+
x: (viewBoxInfo.x + viewBoxInfo.width) / SCALE_FACTOR,
|
|
9230
|
+
y: (viewBoxInfo.y + viewBoxInfo.height) / SCALE_FACTOR,
|
|
9231
|
+
},
|
|
9232
|
+
};
|
|
9233
|
+
}
|
|
9234
|
+
}
|
|
9235
|
+
// 获取当前割草机位置
|
|
9236
|
+
if (mowerPositionData) {
|
|
9237
|
+
newDebugInfo.mowerPosition = {
|
|
9238
|
+
x: mowerPositionData.postureX || 0,
|
|
9239
|
+
y: mowerPositionData.postureY || 0,
|
|
9240
|
+
theta: mowerPositionData.postureTheta || 0,
|
|
9241
|
+
lastX: mowerPositionData.lastPostureX || 0,
|
|
9242
|
+
lastY: mowerPositionData.lastPostureY || 0,
|
|
9243
|
+
lastTheta: mowerPositionData.lastPostureTheta || 0,
|
|
9244
|
+
vehicleState: mowerPositionData.vehicleState || RobotStatus.UNKNOWN,
|
|
9245
|
+
vehicleStateText: getVehicleStateText(mowerPositionData.vehicleState || RobotStatus.UNKNOWN),
|
|
9246
|
+
};
|
|
9247
|
+
}
|
|
9248
|
+
// 获取当前割草地块数据
|
|
9249
|
+
newDebugInfo.partitionData = mowPartitionData;
|
|
9250
|
+
setDebugInfo(newDebugInfo);
|
|
9251
|
+
};
|
|
9252
|
+
updateDebugInfo();
|
|
9253
|
+
}, [debug, mowerPositionData, mowPartitionData]);
|
|
9095
9254
|
React.useEffect(() => {
|
|
9255
|
+
if (!realTimeData || realTimeData.length === 0 || !Array.isArray(realTimeData)) {
|
|
9256
|
+
return;
|
|
9257
|
+
}
|
|
9258
|
+
console.log('usefeect realTimeData----->', realTimeData, mapJson, pathJson, overlayRef.current);
|
|
9259
|
+
let curMowPartitionData = mowPartitionData;
|
|
9260
|
+
// realtime中包含当前割草任务的数据,根据数据进行path路径和边界的高亮操作,
|
|
9261
|
+
const mowingPartition = realTimeData.find((item) => item.type === RealTimeDataType.PARTITION);
|
|
9262
|
+
if (mowingPartition) {
|
|
9263
|
+
setMowPartitionData(mowingPartition);
|
|
9264
|
+
curMowPartitionData = mowingPartition;
|
|
9265
|
+
}
|
|
9266
|
+
const positionData = realTimeData?.find(item => item?.type === RealTimeDataType.LOCATION);
|
|
9267
|
+
const statusData = realTimeData?.find(item => item?.type === RealTimeDataType.STATUS);
|
|
9268
|
+
if (statusData || positionData) {
|
|
9269
|
+
const currentStatus = statusData?.vehicleState || positionData?.vehicleState;
|
|
9270
|
+
// 车辆回桩不会回传最后的park的位置,所以根据实时数据的状态数据判断车辆回到桩上
|
|
9271
|
+
if ([RobotStatus.CHARGING, RobotStatus.PARKED].includes(currentStatus || RobotStatus.UNKNOWN)) {
|
|
9272
|
+
resetInCharginPie();
|
|
9273
|
+
}
|
|
9274
|
+
else if (currentStatus === RobotStatus.WORKING) {
|
|
9275
|
+
// 兜底收不到割草地块的实时数据,使用状态来兜底
|
|
9276
|
+
overlayRef.current.resetBorderLayerHighlight();
|
|
9277
|
+
setMowPartitionData(null);
|
|
9278
|
+
curMowPartitionData = null;
|
|
9279
|
+
}
|
|
9280
|
+
else if (currentStatus === RobotStatus.MOWING && (curMowPartitionData && !curMowPartitionData?.partitionIds)) {
|
|
9281
|
+
// 如果当前是割草状态,但是地块数据初始化过且不存在则认为是全局割草,则把所有地块都高亮
|
|
9282
|
+
const allPartitionIds = mapJson?.sub_maps?.map(item => item?.id);
|
|
9283
|
+
setMowPartitionData({
|
|
9284
|
+
partitionIds: allPartitionIds
|
|
9285
|
+
});
|
|
9286
|
+
curMowPartitionData = {
|
|
9287
|
+
partitionIds: allPartitionIds
|
|
9288
|
+
};
|
|
9289
|
+
}
|
|
9290
|
+
}
|
|
9096
9291
|
if (!mapJson ||
|
|
9097
9292
|
!pathJson ||
|
|
9098
|
-
!realTimeData ||
|
|
9099
|
-
realTimeData.length === 0 ||
|
|
9100
|
-
!Array.isArray(realTimeData) ||
|
|
9101
9293
|
!overlayRef.current)
|
|
9102
9294
|
return;
|
|
9103
9295
|
// 根据后端推送的实时数据,进行不同处理
|
|
9104
|
-
// TODO:需要根据返回的数据,处理车辆的移动位置
|
|
9105
|
-
console.log('realTimeData----->', realTimeData);
|
|
9106
|
-
// realtime中包含当前割草任务的数据,根据数据进行path路径和边界的高亮操作
|
|
9107
|
-
const curMowPartitionData = realTimeData.find((item) => item.type === RealTimeDataType.PARTITION) || mowPartitionData;
|
|
9108
9296
|
if (curMowPartitionData) {
|
|
9109
|
-
setMowPartitionData(curMowPartitionData);
|
|
9110
9297
|
const isMowing = curMowPartitionData?.partitionIds && curMowPartitionData.partitionIds.length > 0;
|
|
9111
9298
|
overlayRef.current.updateMowPartitionData(curMowPartitionData);
|
|
9112
|
-
console.log('isMowing', isMowing, curMowPartitionData);
|
|
9113
9299
|
if (!isMowing) {
|
|
9114
9300
|
overlayRef.current.resetBorderLayerHighlight();
|
|
9115
9301
|
}
|
|
@@ -9147,14 +9333,11 @@ const MowerMapRenderer = React.forwardRef(({ mapConfig, modelType, mapRef, mapJs
|
|
|
9147
9333
|
}
|
|
9148
9334
|
}, [realTimeData, mapJson, pathJson]);
|
|
9149
9335
|
React.useEffect(() => {
|
|
9150
|
-
console.log('defaultTransform----->', defaultTransform);
|
|
9151
9336
|
if (!overlayRef.current || !defaultTransform)
|
|
9152
9337
|
return;
|
|
9153
|
-
|
|
9154
|
-
return;
|
|
9155
|
-
}
|
|
9338
|
+
console.log('defaultTransform----->', defaultTransform, overlayRef.current, mapJson);
|
|
9156
9339
|
overlayRef.current?.setTransform(defaultTransform);
|
|
9157
|
-
const validBounds = getValidGpsBounds(mapJson);
|
|
9340
|
+
const validBounds = getValidGpsBounds(mapJson, defaultTransform?.rotation);
|
|
9158
9341
|
// 地图数据中的坐标格式是 [longitude, latitude]
|
|
9159
9342
|
const swLat = validBounds.sw[1] + defaultTransform.y;
|
|
9160
9343
|
const swLng = validBounds.sw[0] + defaultTransform.x;
|
|
@@ -9200,12 +9383,32 @@ const MowerMapRenderer = React.forwardRef(({ mapConfig, modelType, mapRef, mapJs
|
|
|
9200
9383
|
setTransform: (t) => overlayRef.current?.setTransform(t),
|
|
9201
9384
|
resetToDefaultTransform: () => overlayRef.current?.resetToDefaultTransform(),
|
|
9202
9385
|
}));
|
|
9386
|
+
// Debug信息组件
|
|
9387
|
+
const DebugInfo = () => {
|
|
9388
|
+
if (!debug)
|
|
9389
|
+
return null;
|
|
9390
|
+
return (jsxRuntime.jsxs("div", { style: {
|
|
9391
|
+
position: 'fixed',
|
|
9392
|
+
bottom: '10px',
|
|
9393
|
+
left: '10px',
|
|
9394
|
+
backgroundColor: 'rgba(0, 0, 0, 0.8)',
|
|
9395
|
+
color: 'white',
|
|
9396
|
+
padding: '10px',
|
|
9397
|
+
borderRadius: '5px',
|
|
9398
|
+
fontSize: '12px',
|
|
9399
|
+
fontFamily: 'monospace',
|
|
9400
|
+
zIndex: 10000,
|
|
9401
|
+
maxWidth: '300px',
|
|
9402
|
+
lineHeight: '1.4',
|
|
9403
|
+
}, children: [jsxRuntime.jsx("div", { style: { fontWeight: 'bold', marginBottom: '8px' }, children: "\uD83D\uDC1B Debug Info" }), debugInfo.mapBounds && (jsxRuntime.jsxs("div", { style: { marginBottom: '6px' }, children: [jsxRuntime.jsx("div", { style: { fontWeight: 'bold' }, children: "\uD83D\uDCCD Map GPS Bounds:" }), jsxRuntime.jsxs("div", { children: ["SW: [", debugInfo.mapBounds.sw[0].toFixed(6), ", ", debugInfo.mapBounds.sw[1].toFixed(6), "]"] }), jsxRuntime.jsxs("div", { children: ["NE: [", debugInfo.mapBounds.ne[0].toFixed(6), ", ", debugInfo.mapBounds.ne[1].toFixed(6), "]"] })] })), debugInfo.viewBox && (jsxRuntime.jsxs("div", { style: { marginBottom: '6px' }, children: [jsxRuntime.jsx("div", { style: { fontWeight: 'bold' }, children: "\uD83D\uDCD0 SVG ViewBox (meters):" }), jsxRuntime.jsxs("div", { children: ["SW: [", debugInfo.viewBox.sw.x.toFixed(2), ", ", debugInfo.viewBox.sw.y.toFixed(2), "]"] }), jsxRuntime.jsxs("div", { children: ["NE: [", debugInfo.viewBox.ne.x.toFixed(2), ", ", debugInfo.viewBox.ne.y.toFixed(2), "]"] }), jsxRuntime.jsxs("div", { children: ["Size: ", debugInfo.viewBox.width.toFixed(2), "m \u00D7 ", debugInfo.viewBox.height.toFixed(2), "m"] }), jsxRuntime.jsxs("div", { children: ["Scale: 1:", debugInfo.viewBox.scale] })] })), debugInfo.mowerPosition && (jsxRuntime.jsxs("div", { style: { marginBottom: '6px' }, children: [jsxRuntime.jsx("div", { style: { fontWeight: 'bold' }, children: "\uD83D\uDE9C Mower Position:" }), jsxRuntime.jsxs("div", { children: ["Current: X=", debugInfo.mowerPosition.x.toFixed(2), ", Y=", debugInfo.mowerPosition.y.toFixed(2)] }), jsxRuntime.jsxs("div", { children: ["Theta: ", ((debugInfo.mowerPosition.theta * 180) / Math.PI).toFixed(1), "\u00B0"] }), jsxRuntime.jsxs("div", { children: ["Last: X=", debugInfo.mowerPosition.lastX.toFixed(2), ", Y=", debugInfo.mowerPosition.lastY.toFixed(2)] }), jsxRuntime.jsxs("div", { children: ["Last Theta: ", ((debugInfo.mowerPosition.lastTheta * 180) / Math.PI).toFixed(1), "\u00B0"] }), jsxRuntime.jsxs("div", { children: ["Status: ", debugInfo.mowerPosition.vehicleStateText, " (", debugInfo.mowerPosition.vehicleState, ")"] })] })), debugInfo.partitionData && (jsxRuntime.jsxs("div", { style: { marginBottom: '6px' }, children: [jsxRuntime.jsx("div", { style: { fontWeight: 'bold' }, children: "\uD83D\uDD32 Mow Partition Data:" }), jsxRuntime.jsxs("div", { children: ["Type: ", debugInfo.partitionData.type || 'N/A'] }), debugInfo.partitionData.partitionIds &&
|
|
9404
|
+
debugInfo.partitionData.partitionIds.length > 0 ? (jsxRuntime.jsxs("div", { children: ["Active IDs: [", debugInfo.partitionData.partitionIds.join(', '), "]"] })) : (jsxRuntime.jsx("div", { children: "No active partitions" })), debugInfo.partitionData.time && (jsxRuntime.jsxs("div", { children: ["Updated: ", new Date(debugInfo.partitionData.time).toLocaleTimeString()] }))] })), !debugInfo.partitionData && (jsxRuntime.jsxs("div", { style: { marginBottom: '6px' }, children: [jsxRuntime.jsx("div", { style: { fontWeight: 'bold' }, children: "\uD83D\uDD32 Mow Partition Data:" }), jsxRuntime.jsx("div", { style: { color: '#888' }, children: "No partition data available" })] }))] }));
|
|
9405
|
+
};
|
|
9203
9406
|
// 错误显示
|
|
9204
9407
|
if (currentError) {
|
|
9205
|
-
return (jsxRuntime.
|
|
9408
|
+
return (jsxRuntime.jsxs("div", { className: className, style: style, children: [jsxRuntime.jsxs("div", { style: { color: 'red', padding: '10px' }, children: ["\u9519\u8BEF: ", currentError] }), jsxRuntime.jsx(DebugInfo, {})] }));
|
|
9206
9409
|
}
|
|
9207
|
-
// 使用goole maps
|
|
9208
|
-
return null;
|
|
9410
|
+
// 使用goole maps自定义叠加层,返回debug信息(如果启用)
|
|
9411
|
+
return debug ? jsxRuntime.jsx(DebugInfo, {}) : null;
|
|
9209
9412
|
});
|
|
9210
9413
|
MowerMapRenderer.displayName = 'MowerMapRenderer';
|
|
9211
9414
|
|