@fleet-frontend/mower-maps 0.0.9-beta.5 → 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.js CHANGED
@@ -120,7 +120,7 @@ class SvgMapView {
120
120
  * 设置自适应视图变换 - 让SVG刚好包裹住图形
121
121
  */
122
122
  fitToView(bounds) {
123
- const padding = 10; // 添加一些边距以避免内容贴边
123
+ const padding = 20; // 添加一些边距以避免内容贴边
124
124
  const boundWidth = bounds.maxX - bounds.minX;
125
125
  const boundHeight = bounds.maxY - bounds.minY;
126
126
  // 防止宽高为0的情况
@@ -143,9 +143,10 @@ class SvgMapView {
143
143
  this.viewBox = {
144
144
  x: bounds.minX - padding,
145
145
  y: bounds.minY - padding,
146
- width: boundWidth + padding,
147
- height: boundHeight + padding,
146
+ width: boundWidth + padding * 2,
147
+ height: boundHeight + padding * 2,
148
148
  };
149
+ console.log('viewbox->', this.viewBox);
149
150
  // 根据宽高比选择合适的preserveAspectRatio设置
150
151
  if (Math.abs(contentAspectRatio - containerAspectRatio) < 0.01) {
151
152
  // 宽高比接近,使用slice填满容器
@@ -651,8 +652,6 @@ const create = (createState) => createState ? createImpl(createState) : createIm
651
652
 
652
653
  const useSubBoundaryBorderStore = create((set, get) => ({
653
654
  subBoundaryBorder: {},
654
- // 覆盖所有数据
655
- setSubBoundaryBorder: (subBoundaryBorder) => set({ subBoundaryBorder }),
656
655
  // 追加单个数据
657
656
  addSubBoundaryBorder: (key, element) => set((state) => ({
658
657
  subBoundaryBorder: {
@@ -660,17 +659,69 @@ const useSubBoundaryBorderStore = create((set, get) => ({
660
659
  [key]: element,
661
660
  },
662
661
  })),
663
- // 追加多个数据
664
- addMultipleSubBoundaryBorders: (borders) => set((state) => ({
665
- subBoundaryBorder: {
666
- ...state.subBoundaryBorder,
667
- ...borders,
668
- },
669
- })),
670
662
  // 清空所有数据
671
663
  clearSubBoundaryBorder: () => set({ subBoundaryBorder: {} }),
664
+ // 障碍物
665
+ obstacles: {},
666
+ addObstacles: (key, element) => set((state) => ({
667
+ obstacles: {
668
+ ...state.obstacles,
669
+ [key]: element,
670
+ },
671
+ })),
672
+ clearObstacles: () => set({ obstacles: {} }),
673
+ // svg数据
674
+ svgElements: {},
675
+ addSvgElements: (key, element) => set((state) => ({
676
+ svgElements: {
677
+ ...state.svgElements,
678
+ [key]: element,
679
+ },
680
+ })),
681
+ clearSvgElements: () => set({ svgElements: {} }),
672
682
  }));
673
683
 
684
+ /**
685
+ * 常量和枚举类型定义
686
+ */
687
+ /**
688
+ * 机器人状态枚举
689
+ */
690
+ var RobotStatus;
691
+ (function (RobotStatus) {
692
+ RobotStatus[RobotStatus["PARKED"] = 1] = "PARKED";
693
+ RobotStatus[RobotStatus["CHARGING"] = 2] = "CHARGING";
694
+ RobotStatus[RobotStatus["STANDBY"] = 3] = "STANDBY";
695
+ RobotStatus[RobotStatus["MOWING"] = 4] = "MOWING";
696
+ RobotStatus[RobotStatus["WORKING"] = 5] = "WORKING";
697
+ RobotStatus[RobotStatus["MAPPING"] = 6] = "MAPPING";
698
+ RobotStatus[RobotStatus["ERROR"] = 7] = "ERROR";
699
+ RobotStatus[RobotStatus["UPGRADING"] = 8] = "UPGRADING";
700
+ RobotStatus[RobotStatus["DISCONNECTED"] = 9] = "DISCONNECTED";
701
+ RobotStatus[RobotStatus["UNKNOWN"] = -1] = "UNKNOWN";
702
+ RobotStatus[RobotStatus["TASK_DELAY"] = 10] = "TASK_DELAY";
703
+ })(RobotStatus || (RobotStatus = {}));
704
+ /**
705
+ * RTK状态枚举
706
+ */
707
+ var RTK_STATE;
708
+ (function (RTK_STATE) {
709
+ RTK_STATE[RTK_STATE["LOW_RTK"] = 1] = "LOW_RTK";
710
+ RTK_STATE[RTK_STATE["MIDDLE_RTK"] = 2] = "MIDDLE_RTK";
711
+ RTK_STATE[RTK_STATE["HIGH_RTK"] = 3] = "HIGH_RTK";
712
+ RTK_STATE[RTK_STATE["NO_POSTURE"] = 10] = "NO_POSTURE";
713
+ RTK_STATE[RTK_STATE["OUT_OF_RANGE"] = 11] = "OUT_OF_RANGE";
714
+ RTK_STATE[RTK_STATE["OFF_LINE"] = 19] = "OFF_LINE";
715
+ })(RTK_STATE || (RTK_STATE = {}));
716
+ /**
717
+ * 实时数据类型枚举
718
+ */
719
+ var REAL_TIME_DATA_TYPE;
720
+ (function (REAL_TIME_DATA_TYPE) {
721
+ REAL_TIME_DATA_TYPE[REAL_TIME_DATA_TYPE["LOCATION"] = 1] = "LOCATION";
722
+ REAL_TIME_DATA_TYPE[REAL_TIME_DATA_TYPE["PROCESS"] = 2] = "PROCESS";
723
+ })(REAL_TIME_DATA_TYPE || (REAL_TIME_DATA_TYPE = {}));
724
+
674
725
  /**
675
726
  * 地图渲染相关常量配置
676
727
  */
@@ -723,36 +774,6 @@ const LAYER_DEFAULT_TYPE = {
723
774
  VISION_OFF_AREA: 'vision_off_area',
724
775
  ANTENNA: 'antenna',
725
776
  };
726
- var RobotStatus;
727
- (function (RobotStatus) {
728
- RobotStatus[RobotStatus["PARKED"] = 1] = "PARKED";
729
- RobotStatus[RobotStatus["CHARGING"] = 2] = "CHARGING";
730
- RobotStatus[RobotStatus["STANDBY"] = 3] = "STANDBY";
731
- RobotStatus[RobotStatus["MOWING"] = 4] = "MOWING";
732
- RobotStatus[RobotStatus["WORKING"] = 5] = "WORKING";
733
- RobotStatus[RobotStatus["MAPPING"] = 6] = "MAPPING";
734
- RobotStatus[RobotStatus["ERROR"] = 7] = "ERROR";
735
- RobotStatus[RobotStatus["UPGRADING"] = 8] = "UPGRADING";
736
- RobotStatus[RobotStatus["DISCONNECTED"] = 9] = "DISCONNECTED";
737
- RobotStatus[RobotStatus["UNKNOWN"] = -1] = "UNKNOWN";
738
- RobotStatus[RobotStatus["TASK_DELAY"] = 10] = "TASK_DELAY";
739
- // WAITING = 'Waiting',
740
- })(RobotStatus || (RobotStatus = {}));
741
- // RTK状态
742
- var RTK_STATE;
743
- (function (RTK_STATE) {
744
- RTK_STATE[RTK_STATE["LOW_RTK"] = 1] = "LOW_RTK";
745
- RTK_STATE[RTK_STATE["MIDDLE_RTK"] = 2] = "MIDDLE_RTK";
746
- RTK_STATE[RTK_STATE["HIGH_RTK"] = 3] = "HIGH_RTK";
747
- RTK_STATE[RTK_STATE["NO_POSTURE"] = 10] = "NO_POSTURE";
748
- RTK_STATE[RTK_STATE["OUT_OF_RANGE"] = 11] = "OUT_OF_RANGE";
749
- RTK_STATE[RTK_STATE["OFF_LINE"] = 19] = "OFF_LINE";
750
- })(RTK_STATE || (RTK_STATE = {}));
751
- var REAL_TIME_DATA_TYPE;
752
- (function (REAL_TIME_DATA_TYPE) {
753
- REAL_TIME_DATA_TYPE[REAL_TIME_DATA_TYPE["LOCATION"] = 1] = "LOCATION";
754
- REAL_TIME_DATA_TYPE[REAL_TIME_DATA_TYPE["PROCESS"] = 2] = "PROCESS";
755
- })(REAL_TIME_DATA_TYPE || (REAL_TIME_DATA_TYPE = {}));
756
777
  const ISOLATED_BOUNDARY_SVG = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
757
778
  <g opacity="0.6">
758
779
  <rect width="24" height="24" rx="12" fill="#1E1E1F" fill-opacity="0.5"/>
@@ -852,37 +873,66 @@ class ChannelLayer extends BaseLayer {
852
873
  }
853
874
  // 2. 再计算所有通道的边界
854
875
  for (const element of this.elements) {
855
- const tunnelConnection = element.originalData?.connection;
856
- if (tunnelConnection && Array.isArray(tunnelConnection)) {
857
- const clipPathId = `channel-exclude-${element.originalData?.id || Math.random().toString(36).substr(2, 9)}`;
858
- // 检查是否已存在该 clipPath
859
- const existingClipPath = defs.querySelector(`#${clipPathId}`);
860
- if (existingClipPath)
861
- continue;
862
- // 创建 clipPath
863
- const clipPath = document.createElementNS('http://www.w3.org/2000/svg', 'clipPath');
864
- clipPath.setAttribute('id', clipPathId);
865
- clipPath.setAttribute('clipPathUnits', 'userSpaceOnUse');
866
- // === 合成一个 path ===
867
- let d = `M ${minX} ${minY} L ${maxX} ${minY} L ${maxX} ${maxY} L ${minX} ${maxY} Z`;
868
- for (const partitionId of tunnelConnection) {
869
- const boundaryData = subBoundaryBorder[partitionId];
870
- if (boundaryData && boundaryData.coordinates.length >= 3) {
871
- d += ` M ${boundaryData.coordinates[0][0]} ${boundaryData.coordinates[0][1]}`;
872
- for (let i = 1; i < boundaryData.coordinates.length; i++) {
873
- d += ` L ${boundaryData.coordinates[i][0]} ${boundaryData.coordinates[i][1]}`;
874
- }
875
- d += ' Z';
876
+ // const tunnelConnection = element.originalData?.connection;
877
+ // if (tunnelConnection && Array.isArray(tunnelConnection)) {
878
+ // const clipPathId = `channel-exclude-${
879
+ // element.originalData?.id || Math.random().toString(36).substr(2, 9)
880
+ // }`;
881
+ // // 检查是否已存在该 clipPath
882
+ // const existingClipPath = defs.querySelector(`#${clipPathId}`);
883
+ // if (existingClipPath) continue;
884
+ // // 创建 clipPath
885
+ // const clipPath = document.createElementNS('http://www.w3.org/2000/svg', 'clipPath');
886
+ // clipPath.setAttribute('id', clipPathId);
887
+ // clipPath.setAttribute('clipPathUnits', 'userSpaceOnUse');
888
+ // // === 合成一个 path ===
889
+ // let d = `M ${minX} ${minY} L ${maxX} ${minY} L ${maxX} ${maxY} L ${minX} ${maxY} Z`;
890
+ // for (const partitionId of tunnelConnection) {
891
+ // const boundaryData = subBoundaryBorder[partitionId];
892
+ // if (boundaryData && boundaryData.coordinates.length >= 3) {
893
+ // d += ` M ${boundaryData.coordinates[0][0]} ${boundaryData.coordinates[0][1]}`;
894
+ // for (let i = 1; i < boundaryData.coordinates.length; i++) {
895
+ // d += ` L ${boundaryData.coordinates[i][0]} ${boundaryData.coordinates[i][1]}`;
896
+ // }
897
+ // d += ' Z';
898
+ // }
899
+ // }
900
+ // const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
901
+ // path.setAttribute('d', d);
902
+ // path.setAttribute('clip-rule', 'evenodd'); // 关键
903
+ // clipPath.appendChild(path);
904
+ // defs.appendChild(clipPath);
905
+ // clipPathIdsMap[element.originalData?.id.toString()] = clipPathId;
906
+ // } else {
907
+ const clipPathId = `channel-exclude-all-${element.originalData?.id || Math.random().toString(36).substr(2, 9)}`;
908
+ // 检查是否已存在该 clipPath
909
+ const existingClipPath = defs.querySelector(`#${clipPathId}`);
910
+ if (existingClipPath)
911
+ continue;
912
+ // 创建 clipPath
913
+ const clipPath = document.createElementNS('http://www.w3.org/2000/svg', 'clipPath');
914
+ clipPath.setAttribute('id', clipPathId);
915
+ clipPath.setAttribute('clipPathUnits', 'userSpaceOnUse');
916
+ // === 合成一个 path ===
917
+ let d = `M ${minX} ${minY} L ${maxX} ${minY} L ${maxX} ${maxY} L ${minX} ${maxY} Z`;
918
+ for (const partitionId in subBoundaryBorder) {
919
+ const boundaryData = subBoundaryBorder[partitionId];
920
+ if (boundaryData && boundaryData.coordinates.length >= 3) {
921
+ d += ` M ${boundaryData.coordinates[0][0]} ${boundaryData.coordinates[0][1]}`;
922
+ for (let i = 1; i < boundaryData.coordinates.length; i++) {
923
+ d += ` L ${boundaryData.coordinates[i][0]} ${boundaryData.coordinates[i][1]}`;
876
924
  }
925
+ d += ' Z';
877
926
  }
878
- const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
879
- path.setAttribute('d', d);
880
- path.setAttribute('clip-rule', 'evenodd'); // 关键
881
- clipPath.appendChild(path);
882
- defs.appendChild(clipPath);
883
- clipPathIdsMap[element.originalData?.id.toString()] = clipPathId;
884
927
  }
928
+ const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
929
+ path.setAttribute('d', d);
930
+ path.setAttribute('clip-rule', 'evenodd'); // 关键
931
+ clipPath.appendChild(path);
932
+ defs.appendChild(clipPath);
933
+ clipPathIdsMap[element.originalData?.id.toString()] = clipPathId;
885
934
  }
935
+ // }
886
936
  return clipPathIdsMap;
887
937
  }
888
938
  /**
@@ -953,7 +1003,7 @@ class PathLayer extends BaseLayer {
953
1003
  * 创建所有分区并集的 clipPath
954
1004
  */
955
1005
  createUnionClipPath(svgGroup) {
956
- const { subBoundaryBorder } = useSubBoundaryBorderStore.getState();
1006
+ const { subBoundaryBorder, obstacles, svgElements } = useSubBoundaryBorderStore.getState();
957
1007
  // 确保 defs 元素存在
958
1008
  let defs = svgGroup.querySelector('defs');
959
1009
  if (!defs) {
@@ -967,7 +1017,7 @@ class PathLayer extends BaseLayer {
967
1017
  defs.removeChild(existing);
968
1018
  // 合成所有分区的 path
969
1019
  let d = '';
970
- // 合成所有边界
1020
+ // 1. 外圈(主边界,顺时针)
971
1021
  Object.values(subBoundaryBorder).forEach((item) => {
972
1022
  const bCoords = item.coordinates;
973
1023
  if (bCoords.length >= 3) {
@@ -978,6 +1028,27 @@ class PathLayer extends BaseLayer {
978
1028
  d += ' Z ';
979
1029
  }
980
1030
  });
1031
+ // 2. 内圈(禁区,逆时针)
1032
+ Object.values(obstacles).forEach((item) => {
1033
+ const bCoords = item.coordinates;
1034
+ if (bCoords.length >= 3) {
1035
+ d += `M ${bCoords[bCoords.length - 1][0]} ${bCoords[bCoords.length - 1][1]}`;
1036
+ for (let i = bCoords.length - 2; i >= 0; i--) {
1037
+ d += ` L ${bCoords[i][0]} ${bCoords[i][1]}`;
1038
+ }
1039
+ d += ' Z ';
1040
+ }
1041
+ });
1042
+ console.error('svgElements----', svgElements);
1043
+ // 3. svgElements(直接拼接path字符串,建议逆时针)
1044
+ if (Array.isArray(svgElements)) {
1045
+ svgElements.forEach((svgPath) => {
1046
+ const svgPathString = svgPath?.metadata?.svg;
1047
+ if (svgPathString && typeof svgPathString === 'string' && svgPathString.trim()) {
1048
+ d += svgPathString + ' ';
1049
+ }
1050
+ });
1051
+ }
981
1052
  const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
982
1053
  path.setAttribute('d', d);
983
1054
  const clipPath = document.createElementNS('http://www.w3.org/2000/svg', 'clipPath');
@@ -1150,7 +1221,7 @@ class ObstacleLayer extends BaseLayer {
1150
1221
  }
1151
1222
  }
1152
1223
 
1153
- var chargingPileImage = "data:image/png;base64,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";
1224
+ var chargingPileImage = "data:image/png;base64,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";
1154
1225
 
1155
1226
  /**
1156
1227
  * 充电桩图层
@@ -1340,7 +1411,7 @@ class SvgElementLayer extends BaseLayer {
1340
1411
  // 在transformGroup上应用变换:平移到中心,旋转,缩放,然后居中SVG
1341
1412
  const transform = [
1342
1413
  `translate(${center[0]}, ${center[1]})`,
1343
- `rotate(${(direction * 180) / Math.PI})`,
1414
+ `rotate(${-(direction * 180) / Math.PI})`,
1344
1415
  `scale(${userScale})`,
1345
1416
  `translate(${-originalWidth / 2}, ${-originalHeight / 2})`,
1346
1417
  ].join(' ');
@@ -1542,15 +1613,6 @@ function convertCoordinate(x, y) {
1542
1613
  };
1543
1614
  }
1544
1615
 
1545
- /**
1546
- * 路径段类型
1547
- */
1548
- var PathSegmentType;
1549
- (function (PathSegmentType) {
1550
- PathSegmentType["EDGE"] = "edge";
1551
- PathSegmentType["MOWING"] = "mowing";
1552
- PathSegmentType["TRANS"] = "trans";
1553
- })(PathSegmentType || (PathSegmentType = {}));
1554
1616
  /**
1555
1617
  * 按Python逻辑创建路径段:根据连续的两点之间的关系确定线段类型
1556
1618
  */
@@ -1879,6 +1941,14 @@ function generateBoundaryData(mapData, pathData) {
1879
1941
  return boundaryData;
1880
1942
  }
1881
1943
 
1944
+ var RealTimeDataType;
1945
+ (function (RealTimeDataType) {
1946
+ RealTimeDataType[RealTimeDataType["LOCATION"] = 1] = "LOCATION";
1947
+ RealTimeDataType[RealTimeDataType["PROCESS"] = 2] = "PROCESS";
1948
+ RealTimeDataType[RealTimeDataType["PARTITION"] = 3] = "PARTITION";
1949
+ RealTimeDataType[RealTimeDataType["STATUS"] = 4] = "STATUS";
1950
+ })(RealTimeDataType || (RealTimeDataType = {}));
1951
+
1882
1952
  /**
1883
1953
  * 射线法判断点是否在多边形内部
1884
1954
  * @param x 点的x坐标
@@ -2048,7 +2118,7 @@ const getProcessMowingDataFromRealTimeData = ({ realTimeData, isMowing, pathData
2048
2118
  let newMowingStatus = isMowing;
2049
2119
  let newPathData = pathData || {};
2050
2120
  // 找到返回的第一个实时进度的点
2051
- const firstProcessData = realTimeData.find((item) => item.type === REAL_TIME_DATA_TYPE.PROCESS);
2121
+ const firstProcessData = realTimeData.find((item) => item.type === RealTimeDataType.PROCESS);
2052
2122
  if (firstProcessData) {
2053
2123
  // console.log('firstProcessData==', firstProcessData);
2054
2124
  const { action, subAction, currentMowBoundary, currentMowProgress } = firstProcessData;
@@ -4596,6 +4666,36 @@ var merge = createAssigner(function(object, source, srcIndex) {
4596
4666
  */
4597
4667
  var round = createRound('round');
4598
4668
 
4669
+ /**
4670
+ * 工具模块类型定义
4671
+ */
4672
+ /**
4673
+ * 路径段类型枚举
4674
+ */
4675
+ var PathSegmentType;
4676
+ (function (PathSegmentType) {
4677
+ PathSegmentType["EDGE"] = "edge";
4678
+ PathSegmentType["MOWING"] = "mowing";
4679
+ PathSegmentType["TRANS"] = "trans";
4680
+ })(PathSegmentType || (PathSegmentType = {}));
4681
+ /**
4682
+ * 单位类型枚举
4683
+ */
4684
+ var UnitsType;
4685
+ (function (UnitsType) {
4686
+ UnitsType["Metric"] = "metric";
4687
+ UnitsType["Imperial"] = "imperial";
4688
+ })(UnitsType || (UnitsType = {}));
4689
+ /**
4690
+ * 面积单位类型枚举
4691
+ */
4692
+ var UnitsAreaType;
4693
+ (function (UnitsAreaType) {
4694
+ UnitsAreaType["SQUARE_METER"] = "m\u00B2";
4695
+ UnitsAreaType["SQUARE_FOOT"] = "ft\u00B2";
4696
+ UnitsAreaType["ACRE"] = "ac";
4697
+ })(UnitsAreaType || (UnitsAreaType = {}));
4698
+
4599
4699
  /**
4600
4700
  * 默认航向相对于canvas的偏移角度: 航向默认是东
4601
4701
  */
@@ -4669,17 +4769,6 @@ function formatNumberWithMetricPrefix(value, round = true, decimals = 2) {
4669
4769
  return `${mathFn(value / 1000000000, decimals)}B`;
4670
4770
  }
4671
4771
  }
4672
- var UnitsType;
4673
- (function (UnitsType) {
4674
- UnitsType["Metric"] = "metric";
4675
- UnitsType["Imperial"] = "imperial";
4676
- })(UnitsType || (UnitsType = {}));
4677
- var UnitsAreaType;
4678
- (function (UnitsAreaType) {
4679
- UnitsAreaType["SQUARE_METER"] = "m\u00B2";
4680
- UnitsAreaType["SQUARE_FOOT"] = "ft\u00B2";
4681
- UnitsAreaType["ACRE"] = "ac";
4682
- })(UnitsAreaType || (UnitsAreaType = {}));
4683
4772
  /**
4684
4773
  * 转换割草面积的方法
4685
4774
  * @param area 面积数值(单位:m²)
@@ -4875,7 +4964,12 @@ class BoundaryBorderLayer extends BaseLayer {
4875
4964
  * 设置当前割草任务的边界
4876
4965
  */
4877
4966
  setMowingBoundarys(mowingBoundarys) {
4878
- this.mowingBoundarys = mowingBoundarys;
4967
+ if (!mowingBoundarys) {
4968
+ this.mowingBoundarys = this.elements?.map(item => item?.originalData?.id);
4969
+ }
4970
+ else {
4971
+ this.mowingBoundarys = mowingBoundarys;
4972
+ }
4879
4973
  }
4880
4974
  /**
4881
4975
  * SVG渲染方法
@@ -5303,6 +5397,14 @@ class BoundaryDataBuilder {
5303
5397
  * 创建边界元素数据
5304
5398
  */
5305
5399
  static create(type, coordinates, style) {
5400
+ const len = coordinates?.length || 0;
5401
+ const firstPoint = coordinates?.[0];
5402
+ const lastPoint = coordinates?.[len - 1];
5403
+ const isClosed = firstPoint?.[0] === lastPoint?.[0] && firstPoint?.[1] === lastPoint?.[1];
5404
+ // 如果地图没有闭合,则手动新增闭合点,避免border最后一部分没有闭合的情况
5405
+ if (!isClosed) {
5406
+ coordinates.push([firstPoint?.[0], firstPoint?.[1], lastPoint?.[2]]);
5407
+ }
5306
5408
  return {
5307
5409
  type,
5308
5410
  coordinates,
@@ -5705,8 +5807,13 @@ class MapDataProcessor {
5705
5807
  // 为ObstacleData创建兼容的MapElement接口
5706
5808
  const mapElement = element;
5707
5809
  const obstacleElement = ObstacleDataBuilder.fromMapElement(mapElement, this.mapConfig.obstacle);
5708
- if (obstacleElement)
5810
+ if (obstacleElement) {
5709
5811
  result.push(obstacleElement);
5812
+ const { addObstacles } = useSubBoundaryBorderStore.getState();
5813
+ addObstacles(`obstacle-${obstacleElement.originalData.id}`, {
5814
+ ...obstacleElement,
5815
+ });
5816
+ }
5710
5817
  }
5711
5818
  catch (error) {
5712
5819
  console.warn(`Error processing OBSTACLE element:`, element, error);
@@ -5767,8 +5874,13 @@ class MapDataProcessor {
5767
5874
  element.direction !== undefined) {
5768
5875
  const mapElement = element;
5769
5876
  const svgElement = SvgElementDataBuilder.fromMapElement(mapElement, this.mapConfig.doodle);
5770
- if (svgElement)
5877
+ if (svgElement) {
5771
5878
  result.push(svgElement);
5879
+ const { addSvgElements } = useSubBoundaryBorderStore.getState();
5880
+ addSvgElements(`time-limit-obstacle-${svgElement.originalData.id}`, {
5881
+ ...svgElement,
5882
+ });
5883
+ }
5772
5884
  }
5773
5885
  // 如果有points数据,按传统方式绘制
5774
5886
  else if ('points' in element &&
@@ -5777,8 +5889,13 @@ class MapDataProcessor {
5777
5889
  element.points.length >= 3) {
5778
5890
  const mapElement = element;
5779
5891
  const polygonElement = ObstacleDataBuilder.createTimeLimitObstacle(mapElement, this.mapConfig.obstacle);
5780
- if (polygonElement)
5892
+ if (polygonElement) {
5781
5893
  result.push(polygonElement);
5894
+ const { addObstacles } = useSubBoundaryBorderStore.getState();
5895
+ addObstacles(`time-limit-obstacle-${polygonElement.originalData.id}`, {
5896
+ ...polygonElement,
5897
+ });
5898
+ }
5782
5899
  }
5783
5900
  }
5784
5901
  catch (error) {
@@ -6115,7 +6232,6 @@ class BoundaryLabelsManager {
6115
6232
  this.collapseOtherLabels(boundaryId);
6116
6233
  // 展开当前标签
6117
6234
  extendedContent.style.display = 'block';
6118
- labelDiv.style.whiteSpace = 'normal';
6119
6235
  this.currentExpandedBoundaryId = boundaryId;
6120
6236
  }
6121
6237
  /**
@@ -7175,9 +7291,10 @@ class MowerPositionManager {
7175
7291
  return;
7176
7292
  this.mowerPositionConfig = chargingPilesPositionConfig;
7177
7293
  const lastPosition = this.lastPosition;
7178
- const postureX = chargingPilesPositionConfig.postureX ?? chargingPilesPositionConfig.lastPostureX ?? lastPosition?.x ?? 0;
7179
- const postureY = chargingPilesPositionConfig.postureY ?? chargingPilesPositionConfig.lastPostureY ?? lastPosition?.y ?? 0;
7180
- const postureTheta = chargingPilesPositionConfig.postureTheta ?? chargingPilesPositionConfig.lastPostureTheta ?? lastPosition?.rotation ?? 0;
7294
+ const postureX = chargingPilesPositionConfig.postureX || chargingPilesPositionConfig.lastPostureX || lastPosition?.x || 0;
7295
+ const postureY = chargingPilesPositionConfig.postureY || chargingPilesPositionConfig.lastPostureY || lastPosition?.y || 0;
7296
+ const postureTheta = chargingPilesPositionConfig.postureTheta || chargingPilesPositionConfig.lastPostureTheta || lastPosition?.rotation || 0;
7297
+ console.log('updatePositionByLastPosition->', postureX, postureY, postureTheta, chargingPilesPositionConfig);
7181
7298
  // 检查是否需要更新图片
7182
7299
  this.updateMowerImage(chargingPilesPositionConfig);
7183
7300
  // 立即更新位置
@@ -7191,10 +7308,10 @@ class MowerPositionManager {
7191
7308
  this.updateMowerImage(positionConfig);
7192
7309
  // 更新配置
7193
7310
  this.mowerPositionConfig = positionConfig;
7194
- const postureX = positionConfig?.postureX ?? this.lastPosition?.x;
7195
- const postureY = positionConfig?.postureY ?? this.lastPosition?.y;
7196
- const postureTheta = positionConfig?.postureTheta ?? this.lastPosition?.rotation;
7197
- console.log('updatePosition manager', positionConfig, this.lastPosition);
7311
+ const postureX = positionConfig?.postureX || this.lastPosition?.x || 0;
7312
+ const postureY = positionConfig?.postureY || this.lastPosition?.y || 0;
7313
+ const postureTheta = positionConfig?.postureTheta || this.lastPosition?.rotation || 0;
7314
+ console.log('updatePosition manager', JSON.stringify(this.currentPosition), this.currentPosition, !this.currentPosition, positionConfig, this.lastPosition, animationTime);
7198
7315
  // 停止当前动画(如果有)
7199
7316
  this.stopAnimation();
7200
7317
  // 第一个点
@@ -7204,6 +7321,7 @@ class MowerPositionManager {
7204
7321
  y: postureY,
7205
7322
  rotation: postureTheta,
7206
7323
  };
7324
+ console.log('updatePosition first->', this.currentPosition);
7207
7325
  this.setElementPosition(this.currentPosition.x, this.currentPosition.y, this.currentPosition.rotation);
7208
7326
  return;
7209
7327
  }
@@ -7253,7 +7371,7 @@ class MowerPositionManager {
7253
7371
  if (!positonOutOfRange && !positionValid) {
7254
7372
  this.lastPosition = { x, y, rotation: theta };
7255
7373
  }
7256
- // console.log('setElementPosition', x, y, targetRotation, positonOutOfRange, positionValid, targetPixelPosition);
7374
+ // console.log('setElementPosition', x, y, theta, targetRotation, positonOutOfRange, positionValid, targetPixelPosition);
7257
7375
  if (!this.mowerElement)
7258
7376
  return;
7259
7377
  this.mowerElement.style.left = `${targetPixelPosition?.x}px`;
@@ -7307,10 +7425,12 @@ class MowerPositionManager {
7307
7425
  y: this.onlyUpdateTheta ? 0 : this.targetPosition.y - this.startPosition.y,
7308
7426
  rotation: radNormalize(targetTheta - startTheta),
7309
7427
  };
7428
+ console.log('startAnimationToPosition-->', this.deltaPosition, this.onlyUpdateTheta, this.targetPosition, this.startPosition);
7310
7429
  // 开始动画循环
7311
7430
  this.animateStep();
7312
7431
  }
7313
7432
  forceUpdatePosition() {
7433
+ console.log('forceUpdatePosition-->', this.currentPosition, this.targetPosition, this.startPosition);
7314
7434
  this.animateStep();
7315
7435
  }
7316
7436
  /**
@@ -7337,6 +7457,7 @@ class MowerPositionManager {
7337
7457
  vehicleState: this.mowerPositionConfig?.vehicleState,
7338
7458
  });
7339
7459
  }
7460
+ // console.log('animateStep-->', this.startPosition, this.deltaPosition, this.targetPosition, easedProgress)
7340
7461
  // 继续动画或结束
7341
7462
  if (progress < 1) {
7342
7463
  // 设置当前位置
@@ -8623,13 +8744,6 @@ class MowerMapOverlay {
8623
8744
  }
8624
8745
  }
8625
8746
 
8626
- var RealTimeDataType;
8627
- (function (RealTimeDataType) {
8628
- RealTimeDataType[RealTimeDataType["LOCATION"] = 1] = "LOCATION";
8629
- RealTimeDataType[RealTimeDataType["PROCESS"] = 2] = "PROCESS";
8630
- RealTimeDataType[RealTimeDataType["PARTITION"] = 3] = "PARTITION";
8631
- })(RealTimeDataType || (RealTimeDataType = {}));
8632
-
8633
8747
  // 获取车辆状态的中文文案
8634
8748
  const getVehicleStateText = (vehicleState) => {
8635
8749
  switch (vehicleState) {
@@ -8749,7 +8863,7 @@ const MowerMapRenderer = React.forwardRef(({ mapConfig, modelType, mapRef, mapJs
8749
8863
  // const mapRef = useMap();
8750
8864
  const [isGoogleMapsReady, setIsGoogleMapsReady] = React.useState(false);
8751
8865
  const [hasInitializedBounds, setHasInitializedBounds] = React.useState(false);
8752
- const { clearSubBoundaryBorder } = useSubBoundaryBorderStore();
8866
+ const { clearSubBoundaryBorder, clearObstacles } = useSubBoundaryBorderStore();
8753
8867
  const currentProcessMowingStatusRef = React.useRef(false);
8754
8868
  const { updateProcessStateIsMowing, processStateIsMowing } = useProcessMowingState();
8755
8869
  const [mowPartitionData, setMowPartitionData] = React.useState(null);
@@ -8803,8 +8917,12 @@ const MowerMapRenderer = React.forwardRef(({ mapConfig, modelType, mapRef, mapJs
8803
8917
  lastPostureTheta: currentPositionData?.lastPostureTheta
8804
8918
  ? Number(currentPositionData.lastPostureTheta)
8805
8919
  : 0,
8806
- lastPostureX: currentPositionData?.lastPostureX ? Number(currentPositionData.lastPostureX) : 0,
8807
- lastPostureY: currentPositionData?.lastPostureY ? Number(currentPositionData.lastPostureY) : 0,
8920
+ lastPostureX: currentPositionData?.lastPostureX
8921
+ ? Number(currentPositionData.lastPostureX)
8922
+ : 0,
8923
+ lastPostureY: currentPositionData?.lastPostureY
8924
+ ? Number(currentPositionData.lastPostureY)
8925
+ : 0,
8808
8926
  vehicleState: currentPositionData?.vehicleState || RobotStatus.CHARGING,
8809
8927
  };
8810
8928
  }, [realTimeData, modelType]);
@@ -8897,12 +9015,26 @@ const MowerMapRenderer = React.forwardRef(({ mapConfig, modelType, mapRef, mapJs
8897
9015
  handleError(`初始化Google Maps叠加层失败: ${error instanceof Error ? error.message : String(error)}`);
8898
9016
  }
8899
9017
  };
9018
+ const resetInCharginPie = React.useCallback(() => {
9019
+ const elements = MapDataProcessor.processMapData(mapJson, mergedMapConfig);
9020
+ const chargingPiles = elements.find((element) => element.type === 'charging_pile');
9021
+ if (!overlayRef.current)
9022
+ return;
9023
+ // 如果在充电桩上,则直接更新位置到充电桩的位置
9024
+ overlayRef.current.updatePosition({
9025
+ ...mowerPositionData,
9026
+ postureX: chargingPiles?.originalData.position[0],
9027
+ postureY: chargingPiles?.originalData.position[1],
9028
+ postureTheta: chargingPiles?.originalData.direction - Math.PI || 0,
9029
+ }, 0);
9030
+ }, [mapJson]);
8900
9031
  // 初始化效果
8901
9032
  React.useEffect(() => {
8902
9033
  initializeGoogleMapsOverlay();
8903
9034
  // 清理函数
8904
9035
  return () => {
8905
9036
  clearSubBoundaryBorder();
9037
+ clearObstacles();
8906
9038
  updateProcessStateIsMowing(false);
8907
9039
  currentProcessMowingStatusRef.current = false;
8908
9040
  if (overlayRef.current) {
@@ -8999,12 +9131,12 @@ const MowerMapRenderer = React.forwardRef(({ mapConfig, modelType, mapRef, mapJs
8999
9131
  // 计算左下角和右上角坐标
9000
9132
  sw: {
9001
9133
  x: viewBoxInfo.x / SCALE_FACTOR,
9002
- y: viewBoxInfo.y / SCALE_FACTOR
9134
+ y: viewBoxInfo.y / SCALE_FACTOR,
9003
9135
  },
9004
9136
  ne: {
9005
9137
  x: (viewBoxInfo.x + viewBoxInfo.width) / SCALE_FACTOR,
9006
- y: (viewBoxInfo.y + viewBoxInfo.height) / SCALE_FACTOR
9007
- }
9138
+ y: (viewBoxInfo.y + viewBoxInfo.height) / SCALE_FACTOR,
9139
+ },
9008
9140
  };
9009
9141
  }
9010
9142
  }
@@ -9018,7 +9150,7 @@ const MowerMapRenderer = React.forwardRef(({ mapConfig, modelType, mapRef, mapJs
9018
9150
  lastY: mowerPositionData.lastPostureY || 0,
9019
9151
  lastTheta: mowerPositionData.lastPostureTheta || 0,
9020
9152
  vehicleState: mowerPositionData.vehicleState || RobotStatus.UNKNOWN,
9021
- vehicleStateText: getVehicleStateText(mowerPositionData.vehicleState || RobotStatus.UNKNOWN)
9153
+ vehicleStateText: getVehicleStateText(mowerPositionData.vehicleState || RobotStatus.UNKNOWN),
9022
9154
  };
9023
9155
  }
9024
9156
  // 获取当前割草地块数据
@@ -9026,9 +9158,6 @@ const MowerMapRenderer = React.forwardRef(({ mapConfig, modelType, mapRef, mapJs
9026
9158
  setDebugInfo(newDebugInfo);
9027
9159
  };
9028
9160
  updateDebugInfo();
9029
- // 设置定时更新(仅在没有数据变化时使用)
9030
- const interval = setInterval(updateDebugInfo, 1000);
9031
- return () => clearInterval(interval);
9032
9161
  }, [debug, mapJson, mowerPositionData, mowPartitionData, defaultTransform]);
9033
9162
  // 当关键数据变化时立即更新debug信息
9034
9163
  React.useEffect(() => {
@@ -9057,12 +9186,12 @@ const MowerMapRenderer = React.forwardRef(({ mapConfig, modelType, mapRef, mapJs
9057
9186
  // 计算左下角和右上角坐标
9058
9187
  sw: {
9059
9188
  x: viewBoxInfo.x / SCALE_FACTOR,
9060
- y: viewBoxInfo.y / SCALE_FACTOR
9189
+ y: viewBoxInfo.y / SCALE_FACTOR,
9061
9190
  },
9062
9191
  ne: {
9063
9192
  x: (viewBoxInfo.x + viewBoxInfo.width) / SCALE_FACTOR,
9064
- y: (viewBoxInfo.y + viewBoxInfo.height) / SCALE_FACTOR
9065
- }
9193
+ y: (viewBoxInfo.y + viewBoxInfo.height) / SCALE_FACTOR,
9194
+ },
9066
9195
  };
9067
9196
  }
9068
9197
  }
@@ -9076,7 +9205,7 @@ const MowerMapRenderer = React.forwardRef(({ mapConfig, modelType, mapRef, mapJs
9076
9205
  lastY: mowerPositionData.lastPostureY || 0,
9077
9206
  lastTheta: mowerPositionData.lastPostureTheta || 0,
9078
9207
  vehicleState: mowerPositionData.vehicleState || RobotStatus.UNKNOWN,
9079
- vehicleStateText: getVehicleStateText(mowerPositionData.vehicleState || RobotStatus.UNKNOWN)
9208
+ vehicleStateText: getVehicleStateText(mowerPositionData.vehicleState || RobotStatus.UNKNOWN),
9080
9209
  };
9081
9210
  }
9082
9211
  // 获取当前割草地块数据
@@ -9096,6 +9225,24 @@ const MowerMapRenderer = React.forwardRef(({ mapConfig, modelType, mapRef, mapJs
9096
9225
  setMowPartitionData(mowingPartition);
9097
9226
  }
9098
9227
  const curMowPartitionData = mowingPartition || mowPartitionData;
9228
+ const statusData = realTimeData?.find(item => item?.type === RealTimeDataType.STATUS);
9229
+ if (statusData) {
9230
+ // 车辆回桩不会回传最后的park的位置,所以根据实时数据的状态数据判断车辆回到桩上
9231
+ if ([RobotStatus.CHARGING, RobotStatus.PARKED].includes(statusData?.vehicleState || RobotStatus.UNKNOWN)) {
9232
+ resetInCharginPie();
9233
+ }
9234
+ else if (statusData?.vehicleState === RobotStatus.MOWING) {
9235
+ // 兜底收不到割草地块的实时数据,使用状态来兜底
9236
+ const partitionids = curMowPartitionData?.partitionIds;
9237
+ if (!partitionids) {
9238
+ overlayRef.current.setBorderLayerHighlight();
9239
+ }
9240
+ }
9241
+ else if (statusData?.vehicleState === RobotStatus.WORKING) {
9242
+ // 同上
9243
+ overlayRef.current.resetBorderLayerHighlight();
9244
+ }
9245
+ }
9099
9246
  if (!mapJson ||
9100
9247
  !pathJson ||
9101
9248
  !overlayRef.current)
@@ -9211,8 +9358,9 @@ const MowerMapRenderer = React.forwardRef(({ mapConfig, modelType, mapRef, mapJs
9211
9358
  fontFamily: 'monospace',
9212
9359
  zIndex: 10000,
9213
9360
  maxWidth: '300px',
9214
- lineHeight: '1.4'
9215
- }, 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 && 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" })] }))] }));
9361
+ lineHeight: '1.4',
9362
+ }, 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 &&
9363
+ 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" })] }))] }));
9216
9364
  };
9217
9365
  // 错误显示
9218
9366
  if (currentError) {