@fleet-frontend/mower-maps 0.0.9-beta.4 → 0.0.9-beta.6

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.
Files changed (85) hide show
  1. package/dist/config/constants.d.ts +1 -25
  2. package/dist/config/constants.d.ts.map +1 -1
  3. package/dist/config/styles.d.ts +1 -1
  4. package/dist/config/styles.d.ts.map +1 -1
  5. package/dist/index.d.ts +2 -1
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.esm.js +278 -130
  8. package/dist/index.js +278 -130
  9. package/dist/processor/MapDataProcessor.d.ts +1 -1
  10. package/dist/processor/MapDataProcessor.d.ts.map +1 -1
  11. package/dist/processor/PathDataProcessor.d.ts +2 -21
  12. package/dist/processor/PathDataProcessor.d.ts.map +1 -1
  13. package/dist/processor/builder/AntennaDataBuilder.d.ts +2 -1
  14. package/dist/processor/builder/AntennaDataBuilder.d.ts.map +1 -1
  15. package/dist/processor/builder/BoundaryDataBuilder.d.ts +1 -1
  16. package/dist/processor/builder/BoundaryDataBuilder.d.ts.map +1 -1
  17. package/dist/processor/builder/ChannelDataBuilder.d.ts +1 -1
  18. package/dist/processor/builder/ChannelDataBuilder.d.ts.map +1 -1
  19. package/dist/processor/builder/ChargingPileDataBuilder.d.ts +1 -1
  20. package/dist/processor/builder/ChargingPileDataBuilder.d.ts.map +1 -1
  21. package/dist/processor/builder/ObstacleDataBuilder.d.ts +2 -1
  22. package/dist/processor/builder/ObstacleDataBuilder.d.ts.map +1 -1
  23. package/dist/processor/builder/PathDataBuilder.d.ts +1 -1
  24. package/dist/processor/builder/PathDataBuilder.d.ts.map +1 -1
  25. package/dist/processor/builder/PointDataBuilder.d.ts +2 -1
  26. package/dist/processor/builder/PointDataBuilder.d.ts.map +1 -1
  27. package/dist/processor/builder/SvgElementDataBuilder.d.ts +1 -1
  28. package/dist/processor/builder/SvgElementDataBuilder.d.ts.map +1 -1
  29. package/dist/processor/builder/VisionOffDataBuilder.d.ts +2 -1
  30. package/dist/processor/builder/VisionOffDataBuilder.d.ts.map +1 -1
  31. package/dist/processor/index.d.ts +2 -1
  32. package/dist/processor/index.d.ts.map +1 -1
  33. package/dist/render/BoundaryLabelsManager.d.ts +1 -1
  34. package/dist/render/BoundaryLabelsManager.d.ts.map +1 -1
  35. package/dist/render/MowerMapOverlay.d.ts +2 -2
  36. package/dist/render/MowerMapOverlay.d.ts.map +1 -1
  37. package/dist/render/MowerMapRenderer.d.ts.map +1 -1
  38. package/dist/render/MowerPositionManager.d.ts.map +1 -1
  39. package/dist/render/SvgMapView.d.ts.map +1 -1
  40. package/dist/render/layers/BoundaryBorderLayer.d.ts +2 -2
  41. package/dist/render/layers/BoundaryBorderLayer.d.ts.map +1 -1
  42. package/dist/render/layers/ChannelLayer.d.ts.map +1 -1
  43. package/dist/render/layers/DrawLayer.d.ts +1 -1
  44. package/dist/render/layers/DrawLayer.d.ts.map +1 -1
  45. package/dist/render/layers/PathLayer.d.ts.map +1 -1
  46. package/dist/render/layers/SvgElementLayer.d.ts.map +1 -1
  47. package/dist/render/layers/types.d.ts +1 -38
  48. package/dist/render/layers/types.d.ts.map +1 -1
  49. package/dist/store/processMowingState.d.ts +1 -5
  50. package/dist/store/processMowingState.d.ts.map +1 -1
  51. package/dist/store/useSubBoundaryBorderStore.d.ts +9 -5
  52. package/dist/store/useSubBoundaryBorderStore.d.ts.map +1 -1
  53. package/dist/types/constants.d.ts +38 -0
  54. package/dist/types/constants.d.ts.map +1 -0
  55. package/dist/types/index.d.ts +6 -0
  56. package/dist/types/index.d.ts.map +1 -1
  57. package/dist/types/layers.d.ts +50 -0
  58. package/dist/types/layers.d.ts.map +1 -0
  59. package/dist/types/processor.d.ts +26 -0
  60. package/dist/types/processor.d.ts.map +1 -0
  61. package/dist/types/realTime.d.ts +8 -1
  62. package/dist/types/realTime.d.ts.map +1 -1
  63. package/dist/types/renderer.d.ts +3 -3
  64. package/dist/types/renderer.d.ts.map +1 -1
  65. package/dist/types/store.d.ts +22 -0
  66. package/dist/types/store.d.ts.map +1 -0
  67. package/dist/types/utils.d.ts +102 -0
  68. package/dist/types/utils.d.ts.map +1 -0
  69. package/dist/utils/boundaryUtils.d.ts +1 -29
  70. package/dist/utils/boundaryUtils.d.ts.map +1 -1
  71. package/dist/utils/common.d.ts +1 -5
  72. package/dist/utils/common.d.ts.map +1 -1
  73. package/dist/utils/coordinates.d.ts +1 -7
  74. package/dist/utils/coordinates.d.ts.map +1 -1
  75. package/dist/utils/handleRealTime.d.ts +2 -7
  76. package/dist/utils/handleRealTime.d.ts.map +1 -1
  77. package/dist/utils/mapBounds.d.ts +1 -10
  78. package/dist/utils/mapBounds.d.ts.map +1 -1
  79. package/dist/utils/math.d.ts +2 -9
  80. package/dist/utils/math.d.ts.map +1 -1
  81. package/dist/utils/mower.d.ts +4 -4
  82. package/dist/utils/mower.d.ts.map +1 -1
  83. package/dist/utils/pathSegments.d.ts +1 -23
  84. package/dist/utils/pathSegments.d.ts.map +1 -1
  85. package/package.json +1 -1
package/dist/index.esm.js CHANGED
@@ -118,7 +118,7 @@ class SvgMapView {
118
118
  * 设置自适应视图变换 - 让SVG刚好包裹住图形
119
119
  */
120
120
  fitToView(bounds) {
121
- const padding = 10; // 添加一些边距以避免内容贴边
121
+ const padding = 20; // 添加一些边距以避免内容贴边
122
122
  const boundWidth = bounds.maxX - bounds.minX;
123
123
  const boundHeight = bounds.maxY - bounds.minY;
124
124
  // 防止宽高为0的情况
@@ -141,9 +141,10 @@ class SvgMapView {
141
141
  this.viewBox = {
142
142
  x: bounds.minX - padding,
143
143
  y: bounds.minY - padding,
144
- width: boundWidth + padding,
145
- height: boundHeight + padding,
144
+ width: boundWidth + padding * 2,
145
+ height: boundHeight + padding * 2,
146
146
  };
147
+ console.log('viewbox->', this.viewBox);
147
148
  // 根据宽高比选择合适的preserveAspectRatio设置
148
149
  if (Math.abs(contentAspectRatio - containerAspectRatio) < 0.01) {
149
150
  // 宽高比接近,使用slice填满容器
@@ -649,8 +650,6 @@ const create = (createState) => createState ? createImpl(createState) : createIm
649
650
 
650
651
  const useSubBoundaryBorderStore = create((set, get) => ({
651
652
  subBoundaryBorder: {},
652
- // 覆盖所有数据
653
- setSubBoundaryBorder: (subBoundaryBorder) => set({ subBoundaryBorder }),
654
653
  // 追加单个数据
655
654
  addSubBoundaryBorder: (key, element) => set((state) => ({
656
655
  subBoundaryBorder: {
@@ -658,17 +657,69 @@ const useSubBoundaryBorderStore = create((set, get) => ({
658
657
  [key]: element,
659
658
  },
660
659
  })),
661
- // 追加多个数据
662
- addMultipleSubBoundaryBorders: (borders) => set((state) => ({
663
- subBoundaryBorder: {
664
- ...state.subBoundaryBorder,
665
- ...borders,
666
- },
667
- })),
668
660
  // 清空所有数据
669
661
  clearSubBoundaryBorder: () => set({ subBoundaryBorder: {} }),
662
+ // 障碍物
663
+ obstacles: {},
664
+ addObstacles: (key, element) => set((state) => ({
665
+ obstacles: {
666
+ ...state.obstacles,
667
+ [key]: element,
668
+ },
669
+ })),
670
+ clearObstacles: () => set({ obstacles: {} }),
671
+ // svg数据
672
+ svgElements: {},
673
+ addSvgElements: (key, element) => set((state) => ({
674
+ svgElements: {
675
+ ...state.svgElements,
676
+ [key]: element,
677
+ },
678
+ })),
679
+ clearSvgElements: () => set({ svgElements: {} }),
670
680
  }));
671
681
 
682
+ /**
683
+ * 常量和枚举类型定义
684
+ */
685
+ /**
686
+ * 机器人状态枚举
687
+ */
688
+ var RobotStatus;
689
+ (function (RobotStatus) {
690
+ RobotStatus[RobotStatus["PARKED"] = 1] = "PARKED";
691
+ RobotStatus[RobotStatus["CHARGING"] = 2] = "CHARGING";
692
+ RobotStatus[RobotStatus["STANDBY"] = 3] = "STANDBY";
693
+ RobotStatus[RobotStatus["MOWING"] = 4] = "MOWING";
694
+ RobotStatus[RobotStatus["WORKING"] = 5] = "WORKING";
695
+ RobotStatus[RobotStatus["MAPPING"] = 6] = "MAPPING";
696
+ RobotStatus[RobotStatus["ERROR"] = 7] = "ERROR";
697
+ RobotStatus[RobotStatus["UPGRADING"] = 8] = "UPGRADING";
698
+ RobotStatus[RobotStatus["DISCONNECTED"] = 9] = "DISCONNECTED";
699
+ RobotStatus[RobotStatus["UNKNOWN"] = -1] = "UNKNOWN";
700
+ RobotStatus[RobotStatus["TASK_DELAY"] = 10] = "TASK_DELAY";
701
+ })(RobotStatus || (RobotStatus = {}));
702
+ /**
703
+ * RTK状态枚举
704
+ */
705
+ var RTK_STATE;
706
+ (function (RTK_STATE) {
707
+ RTK_STATE[RTK_STATE["LOW_RTK"] = 1] = "LOW_RTK";
708
+ RTK_STATE[RTK_STATE["MIDDLE_RTK"] = 2] = "MIDDLE_RTK";
709
+ RTK_STATE[RTK_STATE["HIGH_RTK"] = 3] = "HIGH_RTK";
710
+ RTK_STATE[RTK_STATE["NO_POSTURE"] = 10] = "NO_POSTURE";
711
+ RTK_STATE[RTK_STATE["OUT_OF_RANGE"] = 11] = "OUT_OF_RANGE";
712
+ RTK_STATE[RTK_STATE["OFF_LINE"] = 19] = "OFF_LINE";
713
+ })(RTK_STATE || (RTK_STATE = {}));
714
+ /**
715
+ * 实时数据类型枚举
716
+ */
717
+ var REAL_TIME_DATA_TYPE;
718
+ (function (REAL_TIME_DATA_TYPE) {
719
+ REAL_TIME_DATA_TYPE[REAL_TIME_DATA_TYPE["LOCATION"] = 1] = "LOCATION";
720
+ REAL_TIME_DATA_TYPE[REAL_TIME_DATA_TYPE["PROCESS"] = 2] = "PROCESS";
721
+ })(REAL_TIME_DATA_TYPE || (REAL_TIME_DATA_TYPE = {}));
722
+
672
723
  /**
673
724
  * 地图渲染相关常量配置
674
725
  */
@@ -721,36 +772,6 @@ const LAYER_DEFAULT_TYPE = {
721
772
  VISION_OFF_AREA: 'vision_off_area',
722
773
  ANTENNA: 'antenna',
723
774
  };
724
- var RobotStatus;
725
- (function (RobotStatus) {
726
- RobotStatus[RobotStatus["PARKED"] = 1] = "PARKED";
727
- RobotStatus[RobotStatus["CHARGING"] = 2] = "CHARGING";
728
- RobotStatus[RobotStatus["STANDBY"] = 3] = "STANDBY";
729
- RobotStatus[RobotStatus["MOWING"] = 4] = "MOWING";
730
- RobotStatus[RobotStatus["WORKING"] = 5] = "WORKING";
731
- RobotStatus[RobotStatus["MAPPING"] = 6] = "MAPPING";
732
- RobotStatus[RobotStatus["ERROR"] = 7] = "ERROR";
733
- RobotStatus[RobotStatus["UPGRADING"] = 8] = "UPGRADING";
734
- RobotStatus[RobotStatus["DISCONNECTED"] = 9] = "DISCONNECTED";
735
- RobotStatus[RobotStatus["UNKNOWN"] = -1] = "UNKNOWN";
736
- RobotStatus[RobotStatus["TASK_DELAY"] = 10] = "TASK_DELAY";
737
- // WAITING = 'Waiting',
738
- })(RobotStatus || (RobotStatus = {}));
739
- // RTK状态
740
- var RTK_STATE;
741
- (function (RTK_STATE) {
742
- RTK_STATE[RTK_STATE["LOW_RTK"] = 1] = "LOW_RTK";
743
- RTK_STATE[RTK_STATE["MIDDLE_RTK"] = 2] = "MIDDLE_RTK";
744
- RTK_STATE[RTK_STATE["HIGH_RTK"] = 3] = "HIGH_RTK";
745
- RTK_STATE[RTK_STATE["NO_POSTURE"] = 10] = "NO_POSTURE";
746
- RTK_STATE[RTK_STATE["OUT_OF_RANGE"] = 11] = "OUT_OF_RANGE";
747
- RTK_STATE[RTK_STATE["OFF_LINE"] = 19] = "OFF_LINE";
748
- })(RTK_STATE || (RTK_STATE = {}));
749
- var REAL_TIME_DATA_TYPE;
750
- (function (REAL_TIME_DATA_TYPE) {
751
- REAL_TIME_DATA_TYPE[REAL_TIME_DATA_TYPE["LOCATION"] = 1] = "LOCATION";
752
- REAL_TIME_DATA_TYPE[REAL_TIME_DATA_TYPE["PROCESS"] = 2] = "PROCESS";
753
- })(REAL_TIME_DATA_TYPE || (REAL_TIME_DATA_TYPE = {}));
754
775
  const ISOLATED_BOUNDARY_SVG = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
755
776
  <g opacity="0.6">
756
777
  <rect width="24" height="24" rx="12" fill="#1E1E1F" fill-opacity="0.5"/>
@@ -850,37 +871,66 @@ class ChannelLayer extends BaseLayer {
850
871
  }
851
872
  // 2. 再计算所有通道的边界
852
873
  for (const element of this.elements) {
853
- const tunnelConnection = element.originalData?.connection;
854
- if (tunnelConnection && Array.isArray(tunnelConnection)) {
855
- const clipPathId = `channel-exclude-${element.originalData?.id || Math.random().toString(36).substr(2, 9)}`;
856
- // 检查是否已存在该 clipPath
857
- const existingClipPath = defs.querySelector(`#${clipPathId}`);
858
- if (existingClipPath)
859
- continue;
860
- // 创建 clipPath
861
- const clipPath = document.createElementNS('http://www.w3.org/2000/svg', 'clipPath');
862
- clipPath.setAttribute('id', clipPathId);
863
- clipPath.setAttribute('clipPathUnits', 'userSpaceOnUse');
864
- // === 合成一个 path ===
865
- let d = `M ${minX} ${minY} L ${maxX} ${minY} L ${maxX} ${maxY} L ${minX} ${maxY} Z`;
866
- for (const partitionId of tunnelConnection) {
867
- const boundaryData = subBoundaryBorder[partitionId];
868
- if (boundaryData && boundaryData.coordinates.length >= 3) {
869
- d += ` M ${boundaryData.coordinates[0][0]} ${boundaryData.coordinates[0][1]}`;
870
- for (let i = 1; i < boundaryData.coordinates.length; i++) {
871
- d += ` L ${boundaryData.coordinates[i][0]} ${boundaryData.coordinates[i][1]}`;
872
- }
873
- d += ' Z';
874
+ // const tunnelConnection = element.originalData?.connection;
875
+ // if (tunnelConnection && Array.isArray(tunnelConnection)) {
876
+ // const clipPathId = `channel-exclude-${
877
+ // element.originalData?.id || Math.random().toString(36).substr(2, 9)
878
+ // }`;
879
+ // // 检查是否已存在该 clipPath
880
+ // const existingClipPath = defs.querySelector(`#${clipPathId}`);
881
+ // if (existingClipPath) continue;
882
+ // // 创建 clipPath
883
+ // const clipPath = document.createElementNS('http://www.w3.org/2000/svg', 'clipPath');
884
+ // clipPath.setAttribute('id', clipPathId);
885
+ // clipPath.setAttribute('clipPathUnits', 'userSpaceOnUse');
886
+ // // === 合成一个 path ===
887
+ // let d = `M ${minX} ${minY} L ${maxX} ${minY} L ${maxX} ${maxY} L ${minX} ${maxY} Z`;
888
+ // for (const partitionId of tunnelConnection) {
889
+ // const boundaryData = subBoundaryBorder[partitionId];
890
+ // if (boundaryData && boundaryData.coordinates.length >= 3) {
891
+ // d += ` M ${boundaryData.coordinates[0][0]} ${boundaryData.coordinates[0][1]}`;
892
+ // for (let i = 1; i < boundaryData.coordinates.length; i++) {
893
+ // d += ` L ${boundaryData.coordinates[i][0]} ${boundaryData.coordinates[i][1]}`;
894
+ // }
895
+ // d += ' Z';
896
+ // }
897
+ // }
898
+ // const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
899
+ // path.setAttribute('d', d);
900
+ // path.setAttribute('clip-rule', 'evenodd'); // 关键
901
+ // clipPath.appendChild(path);
902
+ // defs.appendChild(clipPath);
903
+ // clipPathIdsMap[element.originalData?.id.toString()] = clipPathId;
904
+ // } else {
905
+ const clipPathId = `channel-exclude-all-${element.originalData?.id || Math.random().toString(36).substr(2, 9)}`;
906
+ // 检查是否已存在该 clipPath
907
+ const existingClipPath = defs.querySelector(`#${clipPathId}`);
908
+ if (existingClipPath)
909
+ continue;
910
+ // 创建 clipPath
911
+ const clipPath = document.createElementNS('http://www.w3.org/2000/svg', 'clipPath');
912
+ clipPath.setAttribute('id', clipPathId);
913
+ clipPath.setAttribute('clipPathUnits', 'userSpaceOnUse');
914
+ // === 合成一个 path ===
915
+ let d = `M ${minX} ${minY} L ${maxX} ${minY} L ${maxX} ${maxY} L ${minX} ${maxY} Z`;
916
+ for (const partitionId in subBoundaryBorder) {
917
+ const boundaryData = subBoundaryBorder[partitionId];
918
+ if (boundaryData && boundaryData.coordinates.length >= 3) {
919
+ d += ` M ${boundaryData.coordinates[0][0]} ${boundaryData.coordinates[0][1]}`;
920
+ for (let i = 1; i < boundaryData.coordinates.length; i++) {
921
+ d += ` L ${boundaryData.coordinates[i][0]} ${boundaryData.coordinates[i][1]}`;
874
922
  }
923
+ d += ' Z';
875
924
  }
876
- const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
877
- path.setAttribute('d', d);
878
- path.setAttribute('clip-rule', 'evenodd'); // 关键
879
- clipPath.appendChild(path);
880
- defs.appendChild(clipPath);
881
- clipPathIdsMap[element.originalData?.id.toString()] = clipPathId;
882
925
  }
926
+ const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
927
+ path.setAttribute('d', d);
928
+ path.setAttribute('clip-rule', 'evenodd'); // 关键
929
+ clipPath.appendChild(path);
930
+ defs.appendChild(clipPath);
931
+ clipPathIdsMap[element.originalData?.id.toString()] = clipPathId;
883
932
  }
933
+ // }
884
934
  return clipPathIdsMap;
885
935
  }
886
936
  /**
@@ -951,7 +1001,7 @@ class PathLayer extends BaseLayer {
951
1001
  * 创建所有分区并集的 clipPath
952
1002
  */
953
1003
  createUnionClipPath(svgGroup) {
954
- const { subBoundaryBorder } = useSubBoundaryBorderStore.getState();
1004
+ const { subBoundaryBorder, obstacles, svgElements } = useSubBoundaryBorderStore.getState();
955
1005
  // 确保 defs 元素存在
956
1006
  let defs = svgGroup.querySelector('defs');
957
1007
  if (!defs) {
@@ -965,7 +1015,7 @@ class PathLayer extends BaseLayer {
965
1015
  defs.removeChild(existing);
966
1016
  // 合成所有分区的 path
967
1017
  let d = '';
968
- // 合成所有边界
1018
+ // 1. 外圈(主边界,顺时针)
969
1019
  Object.values(subBoundaryBorder).forEach((item) => {
970
1020
  const bCoords = item.coordinates;
971
1021
  if (bCoords.length >= 3) {
@@ -976,6 +1026,27 @@ class PathLayer extends BaseLayer {
976
1026
  d += ' Z ';
977
1027
  }
978
1028
  });
1029
+ // 2. 内圈(禁区,逆时针)
1030
+ Object.values(obstacles).forEach((item) => {
1031
+ const bCoords = item.coordinates;
1032
+ if (bCoords.length >= 3) {
1033
+ d += `M ${bCoords[bCoords.length - 1][0]} ${bCoords[bCoords.length - 1][1]}`;
1034
+ for (let i = bCoords.length - 2; i >= 0; i--) {
1035
+ d += ` L ${bCoords[i][0]} ${bCoords[i][1]}`;
1036
+ }
1037
+ d += ' Z ';
1038
+ }
1039
+ });
1040
+ console.error('svgElements----', svgElements);
1041
+ // 3. svgElements(直接拼接path字符串,建议逆时针)
1042
+ if (Array.isArray(svgElements)) {
1043
+ svgElements.forEach((svgPath) => {
1044
+ const svgPathString = svgPath?.metadata?.svg;
1045
+ if (svgPathString && typeof svgPathString === 'string' && svgPathString.trim()) {
1046
+ d += svgPathString + ' ';
1047
+ }
1048
+ });
1049
+ }
979
1050
  const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
980
1051
  path.setAttribute('d', d);
981
1052
  const clipPath = document.createElementNS('http://www.w3.org/2000/svg', 'clipPath');
@@ -1148,7 +1219,7 @@ class ObstacleLayer extends BaseLayer {
1148
1219
  }
1149
1220
  }
1150
1221
 
1151
- var chargingPileImage = "data:image/png;base64,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";
1222
+ var chargingPileImage = "data:image/png;base64,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";
1152
1223
 
1153
1224
  /**
1154
1225
  * 充电桩图层
@@ -1338,7 +1409,7 @@ class SvgElementLayer extends BaseLayer {
1338
1409
  // 在transformGroup上应用变换:平移到中心,旋转,缩放,然后居中SVG
1339
1410
  const transform = [
1340
1411
  `translate(${center[0]}, ${center[1]})`,
1341
- `rotate(${(direction * 180) / Math.PI})`,
1412
+ `rotate(${-(direction * 180) / Math.PI})`,
1342
1413
  `scale(${userScale})`,
1343
1414
  `translate(${-originalWidth / 2}, ${-originalHeight / 2})`,
1344
1415
  ].join(' ');
@@ -1540,15 +1611,6 @@ function convertCoordinate(x, y) {
1540
1611
  };
1541
1612
  }
1542
1613
 
1543
- /**
1544
- * 路径段类型
1545
- */
1546
- var PathSegmentType;
1547
- (function (PathSegmentType) {
1548
- PathSegmentType["EDGE"] = "edge";
1549
- PathSegmentType["MOWING"] = "mowing";
1550
- PathSegmentType["TRANS"] = "trans";
1551
- })(PathSegmentType || (PathSegmentType = {}));
1552
1614
  /**
1553
1615
  * 按Python逻辑创建路径段:根据连续的两点之间的关系确定线段类型
1554
1616
  */
@@ -1877,6 +1939,14 @@ function generateBoundaryData(mapData, pathData) {
1877
1939
  return boundaryData;
1878
1940
  }
1879
1941
 
1942
+ var RealTimeDataType;
1943
+ (function (RealTimeDataType) {
1944
+ RealTimeDataType[RealTimeDataType["LOCATION"] = 1] = "LOCATION";
1945
+ RealTimeDataType[RealTimeDataType["PROCESS"] = 2] = "PROCESS";
1946
+ RealTimeDataType[RealTimeDataType["PARTITION"] = 3] = "PARTITION";
1947
+ RealTimeDataType[RealTimeDataType["STATUS"] = 4] = "STATUS";
1948
+ })(RealTimeDataType || (RealTimeDataType = {}));
1949
+
1880
1950
  /**
1881
1951
  * 射线法判断点是否在多边形内部
1882
1952
  * @param x 点的x坐标
@@ -2046,7 +2116,7 @@ const getProcessMowingDataFromRealTimeData = ({ realTimeData, isMowing, pathData
2046
2116
  let newMowingStatus = isMowing;
2047
2117
  let newPathData = pathData || {};
2048
2118
  // 找到返回的第一个实时进度的点
2049
- const firstProcessData = realTimeData.find((item) => item.type === REAL_TIME_DATA_TYPE.PROCESS);
2119
+ const firstProcessData = realTimeData.find((item) => item.type === RealTimeDataType.PROCESS);
2050
2120
  if (firstProcessData) {
2051
2121
  // console.log('firstProcessData==', firstProcessData);
2052
2122
  const { action, subAction, currentMowBoundary, currentMowProgress } = firstProcessData;
@@ -4594,6 +4664,36 @@ var merge = createAssigner(function(object, source, srcIndex) {
4594
4664
  */
4595
4665
  var round = createRound('round');
4596
4666
 
4667
+ /**
4668
+ * 工具模块类型定义
4669
+ */
4670
+ /**
4671
+ * 路径段类型枚举
4672
+ */
4673
+ var PathSegmentType;
4674
+ (function (PathSegmentType) {
4675
+ PathSegmentType["EDGE"] = "edge";
4676
+ PathSegmentType["MOWING"] = "mowing";
4677
+ PathSegmentType["TRANS"] = "trans";
4678
+ })(PathSegmentType || (PathSegmentType = {}));
4679
+ /**
4680
+ * 单位类型枚举
4681
+ */
4682
+ var UnitsType;
4683
+ (function (UnitsType) {
4684
+ UnitsType["Metric"] = "metric";
4685
+ UnitsType["Imperial"] = "imperial";
4686
+ })(UnitsType || (UnitsType = {}));
4687
+ /**
4688
+ * 面积单位类型枚举
4689
+ */
4690
+ var UnitsAreaType;
4691
+ (function (UnitsAreaType) {
4692
+ UnitsAreaType["SQUARE_METER"] = "m\u00B2";
4693
+ UnitsAreaType["SQUARE_FOOT"] = "ft\u00B2";
4694
+ UnitsAreaType["ACRE"] = "ac";
4695
+ })(UnitsAreaType || (UnitsAreaType = {}));
4696
+
4597
4697
  /**
4598
4698
  * 默认航向相对于canvas的偏移角度: 航向默认是东
4599
4699
  */
@@ -4667,17 +4767,6 @@ function formatNumberWithMetricPrefix(value, round = true, decimals = 2) {
4667
4767
  return `${mathFn(value / 1000000000, decimals)}B`;
4668
4768
  }
4669
4769
  }
4670
- var UnitsType;
4671
- (function (UnitsType) {
4672
- UnitsType["Metric"] = "metric";
4673
- UnitsType["Imperial"] = "imperial";
4674
- })(UnitsType || (UnitsType = {}));
4675
- var UnitsAreaType;
4676
- (function (UnitsAreaType) {
4677
- UnitsAreaType["SQUARE_METER"] = "m\u00B2";
4678
- UnitsAreaType["SQUARE_FOOT"] = "ft\u00B2";
4679
- UnitsAreaType["ACRE"] = "ac";
4680
- })(UnitsAreaType || (UnitsAreaType = {}));
4681
4770
  /**
4682
4771
  * 转换割草面积的方法
4683
4772
  * @param area 面积数值(单位:m²)
@@ -4873,7 +4962,12 @@ class BoundaryBorderLayer extends BaseLayer {
4873
4962
  * 设置当前割草任务的边界
4874
4963
  */
4875
4964
  setMowingBoundarys(mowingBoundarys) {
4876
- this.mowingBoundarys = mowingBoundarys;
4965
+ if (!mowingBoundarys) {
4966
+ this.mowingBoundarys = this.elements?.map(item => item?.originalData?.id);
4967
+ }
4968
+ else {
4969
+ this.mowingBoundarys = mowingBoundarys;
4970
+ }
4877
4971
  }
4878
4972
  /**
4879
4973
  * SVG渲染方法
@@ -5301,6 +5395,14 @@ class BoundaryDataBuilder {
5301
5395
  * 创建边界元素数据
5302
5396
  */
5303
5397
  static create(type, coordinates, style) {
5398
+ const len = coordinates?.length || 0;
5399
+ const firstPoint = coordinates?.[0];
5400
+ const lastPoint = coordinates?.[len - 1];
5401
+ const isClosed = firstPoint?.[0] === lastPoint?.[0] && firstPoint?.[1] === lastPoint?.[1];
5402
+ // 如果地图没有闭合,则手动新增闭合点,避免border最后一部分没有闭合的情况
5403
+ if (!isClosed) {
5404
+ coordinates.push([firstPoint?.[0], firstPoint?.[1], lastPoint?.[2]]);
5405
+ }
5304
5406
  return {
5305
5407
  type,
5306
5408
  coordinates,
@@ -5703,8 +5805,13 @@ class MapDataProcessor {
5703
5805
  // 为ObstacleData创建兼容的MapElement接口
5704
5806
  const mapElement = element;
5705
5807
  const obstacleElement = ObstacleDataBuilder.fromMapElement(mapElement, this.mapConfig.obstacle);
5706
- if (obstacleElement)
5808
+ if (obstacleElement) {
5707
5809
  result.push(obstacleElement);
5810
+ const { addObstacles } = useSubBoundaryBorderStore.getState();
5811
+ addObstacles(`obstacle-${obstacleElement.originalData.id}`, {
5812
+ ...obstacleElement,
5813
+ });
5814
+ }
5708
5815
  }
5709
5816
  catch (error) {
5710
5817
  console.warn(`Error processing OBSTACLE element:`, element, error);
@@ -5765,8 +5872,13 @@ class MapDataProcessor {
5765
5872
  element.direction !== undefined) {
5766
5873
  const mapElement = element;
5767
5874
  const svgElement = SvgElementDataBuilder.fromMapElement(mapElement, this.mapConfig.doodle);
5768
- if (svgElement)
5875
+ if (svgElement) {
5769
5876
  result.push(svgElement);
5877
+ const { addSvgElements } = useSubBoundaryBorderStore.getState();
5878
+ addSvgElements(`time-limit-obstacle-${svgElement.originalData.id}`, {
5879
+ ...svgElement,
5880
+ });
5881
+ }
5770
5882
  }
5771
5883
  // 如果有points数据,按传统方式绘制
5772
5884
  else if ('points' in element &&
@@ -5775,8 +5887,13 @@ class MapDataProcessor {
5775
5887
  element.points.length >= 3) {
5776
5888
  const mapElement = element;
5777
5889
  const polygonElement = ObstacleDataBuilder.createTimeLimitObstacle(mapElement, this.mapConfig.obstacle);
5778
- if (polygonElement)
5890
+ if (polygonElement) {
5779
5891
  result.push(polygonElement);
5892
+ const { addObstacles } = useSubBoundaryBorderStore.getState();
5893
+ addObstacles(`time-limit-obstacle-${polygonElement.originalData.id}`, {
5894
+ ...polygonElement,
5895
+ });
5896
+ }
5780
5897
  }
5781
5898
  }
5782
5899
  catch (error) {
@@ -6113,7 +6230,6 @@ class BoundaryLabelsManager {
6113
6230
  this.collapseOtherLabels(boundaryId);
6114
6231
  // 展开当前标签
6115
6232
  extendedContent.style.display = 'block';
6116
- labelDiv.style.whiteSpace = 'normal';
6117
6233
  this.currentExpandedBoundaryId = boundaryId;
6118
6234
  }
6119
6235
  /**
@@ -7173,9 +7289,10 @@ class MowerPositionManager {
7173
7289
  return;
7174
7290
  this.mowerPositionConfig = chargingPilesPositionConfig;
7175
7291
  const lastPosition = this.lastPosition;
7176
- const postureX = chargingPilesPositionConfig.postureX ?? chargingPilesPositionConfig.lastPostureX ?? lastPosition?.x ?? 0;
7177
- const postureY = chargingPilesPositionConfig.postureY ?? chargingPilesPositionConfig.lastPostureY ?? lastPosition?.y ?? 0;
7178
- const postureTheta = chargingPilesPositionConfig.postureTheta ?? chargingPilesPositionConfig.lastPostureTheta ?? lastPosition?.rotation ?? 0;
7292
+ const postureX = chargingPilesPositionConfig.postureX || chargingPilesPositionConfig.lastPostureX || lastPosition?.x || 0;
7293
+ const postureY = chargingPilesPositionConfig.postureY || chargingPilesPositionConfig.lastPostureY || lastPosition?.y || 0;
7294
+ const postureTheta = chargingPilesPositionConfig.postureTheta || chargingPilesPositionConfig.lastPostureTheta || lastPosition?.rotation || 0;
7295
+ console.log('updatePositionByLastPosition->', postureX, postureY, postureTheta, chargingPilesPositionConfig);
7179
7296
  // 检查是否需要更新图片
7180
7297
  this.updateMowerImage(chargingPilesPositionConfig);
7181
7298
  // 立即更新位置
@@ -7189,10 +7306,10 @@ class MowerPositionManager {
7189
7306
  this.updateMowerImage(positionConfig);
7190
7307
  // 更新配置
7191
7308
  this.mowerPositionConfig = positionConfig;
7192
- const postureX = positionConfig?.postureX ?? this.lastPosition?.x;
7193
- const postureY = positionConfig?.postureY ?? this.lastPosition?.y;
7194
- const postureTheta = positionConfig?.postureTheta ?? this.lastPosition?.rotation;
7195
- console.log('updatePosition manager', positionConfig, this.lastPosition);
7309
+ const postureX = positionConfig?.postureX || this.lastPosition?.x || 0;
7310
+ const postureY = positionConfig?.postureY || this.lastPosition?.y || 0;
7311
+ const postureTheta = positionConfig?.postureTheta || this.lastPosition?.rotation || 0;
7312
+ console.log('updatePosition manager', JSON.stringify(this.currentPosition), this.currentPosition, !this.currentPosition, positionConfig, this.lastPosition, animationTime);
7196
7313
  // 停止当前动画(如果有)
7197
7314
  this.stopAnimation();
7198
7315
  // 第一个点
@@ -7202,6 +7319,7 @@ class MowerPositionManager {
7202
7319
  y: postureY,
7203
7320
  rotation: postureTheta,
7204
7321
  };
7322
+ console.log('updatePosition first->', this.currentPosition);
7205
7323
  this.setElementPosition(this.currentPosition.x, this.currentPosition.y, this.currentPosition.rotation);
7206
7324
  return;
7207
7325
  }
@@ -7251,7 +7369,7 @@ class MowerPositionManager {
7251
7369
  if (!positonOutOfRange && !positionValid) {
7252
7370
  this.lastPosition = { x, y, rotation: theta };
7253
7371
  }
7254
- // console.log('setElementPosition', x, y, targetRotation, positonOutOfRange, positionValid, targetPixelPosition);
7372
+ // console.log('setElementPosition', x, y, theta, targetRotation, positonOutOfRange, positionValid, targetPixelPosition);
7255
7373
  if (!this.mowerElement)
7256
7374
  return;
7257
7375
  this.mowerElement.style.left = `${targetPixelPosition?.x}px`;
@@ -7305,10 +7423,12 @@ class MowerPositionManager {
7305
7423
  y: this.onlyUpdateTheta ? 0 : this.targetPosition.y - this.startPosition.y,
7306
7424
  rotation: radNormalize(targetTheta - startTheta),
7307
7425
  };
7426
+ console.log('startAnimationToPosition-->', this.deltaPosition, this.onlyUpdateTheta, this.targetPosition, this.startPosition);
7308
7427
  // 开始动画循环
7309
7428
  this.animateStep();
7310
7429
  }
7311
7430
  forceUpdatePosition() {
7431
+ console.log('forceUpdatePosition-->', this.currentPosition, this.targetPosition, this.startPosition);
7312
7432
  this.animateStep();
7313
7433
  }
7314
7434
  /**
@@ -7335,6 +7455,7 @@ class MowerPositionManager {
7335
7455
  vehicleState: this.mowerPositionConfig?.vehicleState,
7336
7456
  });
7337
7457
  }
7458
+ // console.log('animateStep-->', this.startPosition, this.deltaPosition, this.targetPosition, easedProgress)
7338
7459
  // 继续动画或结束
7339
7460
  if (progress < 1) {
7340
7461
  // 设置当前位置
@@ -8621,13 +8742,6 @@ class MowerMapOverlay {
8621
8742
  }
8622
8743
  }
8623
8744
 
8624
- var RealTimeDataType;
8625
- (function (RealTimeDataType) {
8626
- RealTimeDataType[RealTimeDataType["LOCATION"] = 1] = "LOCATION";
8627
- RealTimeDataType[RealTimeDataType["PROCESS"] = 2] = "PROCESS";
8628
- RealTimeDataType[RealTimeDataType["PARTITION"] = 3] = "PARTITION";
8629
- })(RealTimeDataType || (RealTimeDataType = {}));
8630
-
8631
8745
  // 获取车辆状态的中文文案
8632
8746
  const getVehicleStateText = (vehicleState) => {
8633
8747
  switch (vehicleState) {
@@ -8747,7 +8861,7 @@ const MowerMapRenderer = forwardRef(({ mapConfig, modelType, mapRef, mapJson, pa
8747
8861
  // const mapRef = useMap();
8748
8862
  const [isGoogleMapsReady, setIsGoogleMapsReady] = useState(false);
8749
8863
  const [hasInitializedBounds, setHasInitializedBounds] = useState(false);
8750
- const { clearSubBoundaryBorder } = useSubBoundaryBorderStore();
8864
+ const { clearSubBoundaryBorder, clearObstacles } = useSubBoundaryBorderStore();
8751
8865
  const currentProcessMowingStatusRef = useRef(false);
8752
8866
  const { updateProcessStateIsMowing, processStateIsMowing } = useProcessMowingState();
8753
8867
  const [mowPartitionData, setMowPartitionData] = useState(null);
@@ -8801,8 +8915,12 @@ const MowerMapRenderer = forwardRef(({ mapConfig, modelType, mapRef, mapJson, pa
8801
8915
  lastPostureTheta: currentPositionData?.lastPostureTheta
8802
8916
  ? Number(currentPositionData.lastPostureTheta)
8803
8917
  : 0,
8804
- lastPostureX: currentPositionData?.lastPostureX ? Number(currentPositionData.lastPostureX) : 0,
8805
- lastPostureY: currentPositionData?.lastPostureY ? Number(currentPositionData.lastPostureY) : 0,
8918
+ lastPostureX: currentPositionData?.lastPostureX
8919
+ ? Number(currentPositionData.lastPostureX)
8920
+ : 0,
8921
+ lastPostureY: currentPositionData?.lastPostureY
8922
+ ? Number(currentPositionData.lastPostureY)
8923
+ : 0,
8806
8924
  vehicleState: currentPositionData?.vehicleState || RobotStatus.CHARGING,
8807
8925
  };
8808
8926
  }, [realTimeData, modelType]);
@@ -8895,12 +9013,26 @@ const MowerMapRenderer = forwardRef(({ mapConfig, modelType, mapRef, mapJson, pa
8895
9013
  handleError(`初始化Google Maps叠加层失败: ${error instanceof Error ? error.message : String(error)}`);
8896
9014
  }
8897
9015
  };
9016
+ const resetInCharginPie = useCallback(() => {
9017
+ const elements = MapDataProcessor.processMapData(mapJson, mergedMapConfig);
9018
+ const chargingPiles = elements.find((element) => element.type === 'charging_pile');
9019
+ if (!overlayRef.current)
9020
+ return;
9021
+ // 如果在充电桩上,则直接更新位置到充电桩的位置
9022
+ overlayRef.current.updatePosition({
9023
+ ...mowerPositionData,
9024
+ postureX: chargingPiles?.originalData.position[0],
9025
+ postureY: chargingPiles?.originalData.position[1],
9026
+ postureTheta: chargingPiles?.originalData.direction - Math.PI || 0,
9027
+ }, 0);
9028
+ }, [mapJson]);
8898
9029
  // 初始化效果
8899
9030
  useEffect(() => {
8900
9031
  initializeGoogleMapsOverlay();
8901
9032
  // 清理函数
8902
9033
  return () => {
8903
9034
  clearSubBoundaryBorder();
9035
+ clearObstacles();
8904
9036
  updateProcessStateIsMowing(false);
8905
9037
  currentProcessMowingStatusRef.current = false;
8906
9038
  if (overlayRef.current) {
@@ -8997,12 +9129,12 @@ const MowerMapRenderer = forwardRef(({ mapConfig, modelType, mapRef, mapJson, pa
8997
9129
  // 计算左下角和右上角坐标
8998
9130
  sw: {
8999
9131
  x: viewBoxInfo.x / SCALE_FACTOR,
9000
- y: viewBoxInfo.y / SCALE_FACTOR
9132
+ y: viewBoxInfo.y / SCALE_FACTOR,
9001
9133
  },
9002
9134
  ne: {
9003
9135
  x: (viewBoxInfo.x + viewBoxInfo.width) / SCALE_FACTOR,
9004
- y: (viewBoxInfo.y + viewBoxInfo.height) / SCALE_FACTOR
9005
- }
9136
+ y: (viewBoxInfo.y + viewBoxInfo.height) / SCALE_FACTOR,
9137
+ },
9006
9138
  };
9007
9139
  }
9008
9140
  }
@@ -9016,7 +9148,7 @@ const MowerMapRenderer = forwardRef(({ mapConfig, modelType, mapRef, mapJson, pa
9016
9148
  lastY: mowerPositionData.lastPostureY || 0,
9017
9149
  lastTheta: mowerPositionData.lastPostureTheta || 0,
9018
9150
  vehicleState: mowerPositionData.vehicleState || RobotStatus.UNKNOWN,
9019
- vehicleStateText: getVehicleStateText(mowerPositionData.vehicleState || RobotStatus.UNKNOWN)
9151
+ vehicleStateText: getVehicleStateText(mowerPositionData.vehicleState || RobotStatus.UNKNOWN),
9020
9152
  };
9021
9153
  }
9022
9154
  // 获取当前割草地块数据
@@ -9024,9 +9156,6 @@ const MowerMapRenderer = forwardRef(({ mapConfig, modelType, mapRef, mapJson, pa
9024
9156
  setDebugInfo(newDebugInfo);
9025
9157
  };
9026
9158
  updateDebugInfo();
9027
- // 设置定时更新(仅在没有数据变化时使用)
9028
- const interval = setInterval(updateDebugInfo, 1000);
9029
- return () => clearInterval(interval);
9030
9159
  }, [debug, mapJson, mowerPositionData, mowPartitionData, defaultTransform]);
9031
9160
  // 当关键数据变化时立即更新debug信息
9032
9161
  useEffect(() => {
@@ -9055,12 +9184,12 @@ const MowerMapRenderer = forwardRef(({ mapConfig, modelType, mapRef, mapJson, pa
9055
9184
  // 计算左下角和右上角坐标
9056
9185
  sw: {
9057
9186
  x: viewBoxInfo.x / SCALE_FACTOR,
9058
- y: viewBoxInfo.y / SCALE_FACTOR
9187
+ y: viewBoxInfo.y / SCALE_FACTOR,
9059
9188
  },
9060
9189
  ne: {
9061
9190
  x: (viewBoxInfo.x + viewBoxInfo.width) / SCALE_FACTOR,
9062
- y: (viewBoxInfo.y + viewBoxInfo.height) / SCALE_FACTOR
9063
- }
9191
+ y: (viewBoxInfo.y + viewBoxInfo.height) / SCALE_FACTOR,
9192
+ },
9064
9193
  };
9065
9194
  }
9066
9195
  }
@@ -9074,7 +9203,7 @@ const MowerMapRenderer = forwardRef(({ mapConfig, modelType, mapRef, mapJson, pa
9074
9203
  lastY: mowerPositionData.lastPostureY || 0,
9075
9204
  lastTheta: mowerPositionData.lastPostureTheta || 0,
9076
9205
  vehicleState: mowerPositionData.vehicleState || RobotStatus.UNKNOWN,
9077
- vehicleStateText: getVehicleStateText(mowerPositionData.vehicleState || RobotStatus.UNKNOWN)
9206
+ vehicleStateText: getVehicleStateText(mowerPositionData.vehicleState || RobotStatus.UNKNOWN),
9078
9207
  };
9079
9208
  }
9080
9209
  // 获取当前割草地块数据
@@ -9094,6 +9223,24 @@ const MowerMapRenderer = forwardRef(({ mapConfig, modelType, mapRef, mapJson, pa
9094
9223
  setMowPartitionData(mowingPartition);
9095
9224
  }
9096
9225
  const curMowPartitionData = mowingPartition || mowPartitionData;
9226
+ const statusData = realTimeData?.find(item => item?.type === RealTimeDataType.STATUS);
9227
+ if (statusData) {
9228
+ // 车辆回桩不会回传最后的park的位置,所以根据实时数据的状态数据判断车辆回到桩上
9229
+ if ([RobotStatus.CHARGING, RobotStatus.PARKED].includes(statusData?.vehicleState || RobotStatus.UNKNOWN)) {
9230
+ resetInCharginPie();
9231
+ }
9232
+ else if (statusData?.vehicleState === RobotStatus.MOWING) {
9233
+ // 兜底收不到割草地块的实时数据,使用状态来兜底
9234
+ const partitionids = curMowPartitionData?.partitionIds;
9235
+ if (!partitionids) {
9236
+ overlayRef.current.setBorderLayerHighlight();
9237
+ }
9238
+ }
9239
+ else if (statusData?.vehicleState === RobotStatus.WORKING) {
9240
+ // 同上
9241
+ overlayRef.current.resetBorderLayerHighlight();
9242
+ }
9243
+ }
9097
9244
  if (!mapJson ||
9098
9245
  !pathJson ||
9099
9246
  !overlayRef.current)
@@ -9209,8 +9356,9 @@ const MowerMapRenderer = forwardRef(({ mapConfig, modelType, mapRef, mapJson, pa
9209
9356
  fontFamily: 'monospace',
9210
9357
  zIndex: 10000,
9211
9358
  maxWidth: '300px',
9212
- lineHeight: '1.4'
9213
- }, children: [jsx("div", { style: { fontWeight: 'bold', marginBottom: '8px' }, children: "\uD83D\uDC1B Debug Info" }), debugInfo.mapBounds && (jsxs("div", { style: { marginBottom: '6px' }, children: [jsx("div", { style: { fontWeight: 'bold' }, children: "\uD83D\uDCCD Map GPS Bounds:" }), jsxs("div", { children: ["SW: [", debugInfo.mapBounds.sw[0].toFixed(6), ", ", debugInfo.mapBounds.sw[1].toFixed(6), "]"] }), jsxs("div", { children: ["NE: [", debugInfo.mapBounds.ne[0].toFixed(6), ", ", debugInfo.mapBounds.ne[1].toFixed(6), "]"] })] })), debugInfo.viewBox && (jsxs("div", { style: { marginBottom: '6px' }, children: [jsx("div", { style: { fontWeight: 'bold' }, children: "\uD83D\uDCD0 SVG ViewBox (meters):" }), jsxs("div", { children: ["SW: [", debugInfo.viewBox.sw.x.toFixed(2), ", ", debugInfo.viewBox.sw.y.toFixed(2), "]"] }), jsxs("div", { children: ["NE: [", debugInfo.viewBox.ne.x.toFixed(2), ", ", debugInfo.viewBox.ne.y.toFixed(2), "]"] }), jsxs("div", { children: ["Size: ", debugInfo.viewBox.width.toFixed(2), "m \u00D7 ", debugInfo.viewBox.height.toFixed(2), "m"] }), jsxs("div", { children: ["Scale: 1:", debugInfo.viewBox.scale] })] })), debugInfo.mowerPosition && (jsxs("div", { style: { marginBottom: '6px' }, children: [jsx("div", { style: { fontWeight: 'bold' }, children: "\uD83D\uDE9C Mower Position:" }), jsxs("div", { children: ["Current: X=", debugInfo.mowerPosition.x.toFixed(2), ", Y=", debugInfo.mowerPosition.y.toFixed(2)] }), jsxs("div", { children: ["Theta: ", (debugInfo.mowerPosition.theta * 180 / Math.PI).toFixed(1), "\u00B0"] }), jsxs("div", { children: ["Last: X=", debugInfo.mowerPosition.lastX.toFixed(2), ", Y=", debugInfo.mowerPosition.lastY.toFixed(2)] }), jsxs("div", { children: ["Last Theta: ", (debugInfo.mowerPosition.lastTheta * 180 / Math.PI).toFixed(1), "\u00B0"] }), jsxs("div", { children: ["Status: ", debugInfo.mowerPosition.vehicleStateText, " (", debugInfo.mowerPosition.vehicleState, ")"] })] })), debugInfo.partitionData && (jsxs("div", { style: { marginBottom: '6px' }, children: [jsx("div", { style: { fontWeight: 'bold' }, children: "\uD83D\uDD32 Mow Partition Data:" }), jsxs("div", { children: ["Type: ", debugInfo.partitionData.type || 'N/A'] }), debugInfo.partitionData.partitionIds && debugInfo.partitionData.partitionIds.length > 0 ? (jsxs("div", { children: ["Active IDs: [", debugInfo.partitionData.partitionIds.join(', '), "]"] })) : (jsx("div", { children: "No active partitions" })), debugInfo.partitionData.time && (jsxs("div", { children: ["Updated: ", new Date(debugInfo.partitionData.time).toLocaleTimeString()] }))] })), !debugInfo.partitionData && (jsxs("div", { style: { marginBottom: '6px' }, children: [jsx("div", { style: { fontWeight: 'bold' }, children: "\uD83D\uDD32 Mow Partition Data:" }), jsx("div", { style: { color: '#888' }, children: "No partition data available" })] }))] }));
9359
+ lineHeight: '1.4',
9360
+ }, children: [jsx("div", { style: { fontWeight: 'bold', marginBottom: '8px' }, children: "\uD83D\uDC1B Debug Info" }), debugInfo.mapBounds && (jsxs("div", { style: { marginBottom: '6px' }, children: [jsx("div", { style: { fontWeight: 'bold' }, children: "\uD83D\uDCCD Map GPS Bounds:" }), jsxs("div", { children: ["SW: [", debugInfo.mapBounds.sw[0].toFixed(6), ", ", debugInfo.mapBounds.sw[1].toFixed(6), "]"] }), jsxs("div", { children: ["NE: [", debugInfo.mapBounds.ne[0].toFixed(6), ", ", debugInfo.mapBounds.ne[1].toFixed(6), "]"] })] })), debugInfo.viewBox && (jsxs("div", { style: { marginBottom: '6px' }, children: [jsx("div", { style: { fontWeight: 'bold' }, children: "\uD83D\uDCD0 SVG ViewBox (meters):" }), jsxs("div", { children: ["SW: [", debugInfo.viewBox.sw.x.toFixed(2), ", ", debugInfo.viewBox.sw.y.toFixed(2), "]"] }), jsxs("div", { children: ["NE: [", debugInfo.viewBox.ne.x.toFixed(2), ", ", debugInfo.viewBox.ne.y.toFixed(2), "]"] }), jsxs("div", { children: ["Size: ", debugInfo.viewBox.width.toFixed(2), "m \u00D7 ", debugInfo.viewBox.height.toFixed(2), "m"] }), jsxs("div", { children: ["Scale: 1:", debugInfo.viewBox.scale] })] })), debugInfo.mowerPosition && (jsxs("div", { style: { marginBottom: '6px' }, children: [jsx("div", { style: { fontWeight: 'bold' }, children: "\uD83D\uDE9C Mower Position:" }), jsxs("div", { children: ["Current: X=", debugInfo.mowerPosition.x.toFixed(2), ", Y=", debugInfo.mowerPosition.y.toFixed(2)] }), jsxs("div", { children: ["Theta: ", ((debugInfo.mowerPosition.theta * 180) / Math.PI).toFixed(1), "\u00B0"] }), jsxs("div", { children: ["Last: X=", debugInfo.mowerPosition.lastX.toFixed(2), ", Y=", debugInfo.mowerPosition.lastY.toFixed(2)] }), jsxs("div", { children: ["Last Theta: ", ((debugInfo.mowerPosition.lastTheta * 180) / Math.PI).toFixed(1), "\u00B0"] }), jsxs("div", { children: ["Status: ", debugInfo.mowerPosition.vehicleStateText, " (", debugInfo.mowerPosition.vehicleState, ")"] })] })), debugInfo.partitionData && (jsxs("div", { style: { marginBottom: '6px' }, children: [jsx("div", { style: { fontWeight: 'bold' }, children: "\uD83D\uDD32 Mow Partition Data:" }), jsxs("div", { children: ["Type: ", debugInfo.partitionData.type || 'N/A'] }), debugInfo.partitionData.partitionIds &&
9361
+ debugInfo.partitionData.partitionIds.length > 0 ? (jsxs("div", { children: ["Active IDs: [", debugInfo.partitionData.partitionIds.join(', '), "]"] })) : (jsx("div", { children: "No active partitions" })), debugInfo.partitionData.time && (jsxs("div", { children: ["Updated: ", new Date(debugInfo.partitionData.time).toLocaleTimeString()] }))] })), !debugInfo.partitionData && (jsxs("div", { style: { marginBottom: '6px' }, children: [jsx("div", { style: { fontWeight: 'bold' }, children: "\uD83D\uDD32 Mow Partition Data:" }), jsx("div", { style: { color: '#888' }, children: "No partition data available" })] }))] }));
9214
9362
  };
9215
9363
  // 错误显示
9216
9364
  if (currentError) {