@fleet-frontend/mower-maps 0.0.9-beta.3 → 0.0.9-beta.5

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/index.esm.js CHANGED
@@ -1,4 +1,4 @@
1
- import { jsx, jsxs } from 'react/jsx-runtime';
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
2
  import React, { forwardRef, useState, useRef, useMemo, useCallback, useEffect, useImperativeHandle } from 'react';
3
3
 
4
4
  /**
@@ -14,7 +14,6 @@ class SvgMapView {
14
14
  this.lineScale = 1; // 线条缩放系数
15
15
  // 状态标志
16
16
  this.destroyed = false;
17
- this.showScale = false;
18
17
  // 渲染系统 - 移除节流以确保用户操作的实时响应
19
18
  // 拖动功能
20
19
  this.isDragging = false;
@@ -97,6 +96,7 @@ class SvgMapView {
97
96
  */
98
97
  removeLayer(layer) {
99
98
  const index = this.layers.indexOf(layer);
99
+ console.log('removeLayer----->', index);
100
100
  if (index !== -1) {
101
101
  this.layers.splice(index, 1);
102
102
  this.refresh();
@@ -153,43 +153,8 @@ class SvgMapView {
153
153
  // 宽高比差异较大,使用meet确保内容完全可见
154
154
  this.svg.setAttribute('preserveAspectRatio', 'xMidYMid meet');
155
155
  }
156
+ console.log('fitToView');
156
157
  this.updateViewBox();
157
- this.refresh();
158
- }
159
- /**
160
- * 重置变换
161
- */
162
- resetTransform() {
163
- this.scale = 1;
164
- // 重置viewBox到默认状态
165
- const containerRect = this.container.getBoundingClientRect();
166
- this.viewBox = {
167
- x: 0,
168
- y: 0,
169
- width: containerRect.width,
170
- height: containerRect.height,
171
- };
172
- this.updateViewBox();
173
- this.refresh();
174
- }
175
- /**
176
- * 设置缩放级别
177
- */
178
- setZoom(zoomLevel) {
179
- if (zoomLevel <= 0)
180
- return;
181
- const oldScale = this.scale;
182
- this.scale = zoomLevel;
183
- // 调整viewBox以实现缩放
184
- const scaleFactor = oldScale / this.scale;
185
- const centerX = this.viewBox.x + this.viewBox.width / 2;
186
- const centerY = this.viewBox.y + this.viewBox.height / 2;
187
- this.viewBox.width *= scaleFactor;
188
- this.viewBox.height *= scaleFactor;
189
- this.viewBox.x = centerX - this.viewBox.width / 2;
190
- this.viewBox.y = centerY - this.viewBox.height / 2;
191
- this.updateViewBox();
192
- this.refresh();
193
158
  }
194
159
  /**
195
160
  * 获取当前缩放级别
@@ -197,15 +162,6 @@ class SvgMapView {
197
162
  getZoom() {
198
163
  return this.scale;
199
164
  }
200
- /**
201
- * 设置线条缩放系数
202
- */
203
- setLineScale(lineScale) {
204
- if (lineScale <= 0)
205
- return;
206
- this.lineScale = lineScale;
207
- this.refresh();
208
- }
209
165
  /**
210
166
  * 获取当前线条缩放系数
211
167
  */
@@ -268,6 +224,7 @@ class SvgMapView {
268
224
  * 绘制图层,不传参数则默认绘制所有图层
269
225
  */
270
226
  onDrawLayers(type) {
227
+ console.log('onDrawLayers----->', type);
271
228
  if (type) {
272
229
  const layer = this.layers.find((layer) => layer.getType() === type);
273
230
  if (layer) {
@@ -344,14 +301,9 @@ class SvgMapView {
344
301
  refresh() {
345
302
  if (this.destroyed)
346
303
  return;
304
+ console.log('refresh----->');
347
305
  this.render();
348
306
  }
349
- /**
350
- * 重新初始化SVG(用于容器大小变化)
351
- */
352
- reinitializeSVG() {
353
- this.refresh();
354
- }
355
307
  // ==================== 拖拽功能 ====================
356
308
  /**
357
309
  * 设置拖拽事件处理器
@@ -476,22 +428,6 @@ class SvgMapView {
476
428
  return null;
477
429
  }
478
430
  }
479
- /**
480
- * 自动适配viewBox到实际内容
481
- */
482
- autoFitToContent() {
483
- if (this.destroyed || this.layers.length === 0)
484
- return;
485
- const bounds = this.getLayersGroupBounds();
486
- if (bounds) {
487
- this.fitToView({
488
- minX: bounds.x,
489
- minY: bounds.y,
490
- maxX: bounds.x + bounds.width,
491
- maxY: bounds.y + bounds.height,
492
- });
493
- }
494
- }
495
431
  /**
496
432
  * 获取ViewBox信息
497
433
  */
@@ -512,13 +448,6 @@ class SvgMapView {
512
448
  * 诊断SVG尺寸信息
513
449
  */
514
450
  diagnosticSizeInfo() { }
515
- /**
516
- * 设置是否显示比例尺
517
- */
518
- setShowScale(show) {
519
- this.showScale = show;
520
- this.refresh();
521
- }
522
451
  /**
523
452
  * 获取SVG元素
524
453
  */
@@ -1894,26 +1823,7 @@ function generateBoundaryData(mapData, pathData) {
1894
1823
  }
1895
1824
  // 第一步:收集所有TUNNEL数据的connection信息
1896
1825
  const connectedBoundaryIds = new Set();
1897
- // 1.1 遍历子地图中的TUNNEL元素
1898
- for (const subMap of mapData.sub_maps) {
1899
- if (!subMap.elements)
1900
- continue;
1901
- // 找到该子地图中所有 type 为 TUNNEL 的元素
1902
- const tunnelElements = subMap.elements.filter(element => element.type === 'TUNNEL');
1903
- for (const tunnelElement of tunnelElements) {
1904
- const connection = tunnelElement.connection;
1905
- if (connection) {
1906
- // connection可能是单个数字或数组
1907
- if (Array.isArray(connection)) {
1908
- connection.forEach(id => connectedBoundaryIds.add(id));
1909
- }
1910
- else if (typeof connection === 'number') {
1911
- connectedBoundaryIds.add(connection);
1912
- }
1913
- }
1914
- }
1915
- }
1916
- // 1.2 遍历mapData中的tunnels字段
1826
+ // 遍历mapData中的tunnels字段
1917
1827
  if (mapData.tunnels && Array.isArray(mapData.tunnels)) {
1918
1828
  for (const tunnel of mapData.tunnels) {
1919
1829
  const connection = tunnel.connection;
@@ -1935,6 +1845,8 @@ function generateBoundaryData(mapData, pathData) {
1935
1845
  continue;
1936
1846
  // 每个sub_map的elements是边界坐标,没有sub_map只有一个boundary数据
1937
1847
  const boundaryElement = subMap.elements.find(element => element.type === 'BOUNDARY');
1848
+ // 如果当前subMap存在充电桩且充电桩存在tunnel,说明当前subMap中的boundary是初始boundary,这个boundary不为孤立区域
1849
+ const hasTunnelToChargingPile = subMap.elements.some(element => element.type === 'CHARGING_PILE' && element.tunnel);
1938
1850
  // 创建基础的 boundary 数据(来自 mapData)
1939
1851
  const boundary = {
1940
1852
  // 从 BOUNDARY 元素复制属性
@@ -1944,7 +1856,7 @@ function generateBoundaryData(mapData, pathData) {
1944
1856
  points: convertPointsFormat(boundaryElement?.points) || [],
1945
1857
  type: boundaryElement.type,
1946
1858
  // 判断是否为孤立子区域
1947
- isIsolated: !connectedBoundaryIds.has(boundaryElement.id)
1859
+ isIsolated: hasTunnelToChargingPile ? false : !connectedBoundaryIds.has(boundaryElement.id)
1948
1860
  };
1949
1861
  // 如果有 pathData,尝试匹配对应的分区数据
1950
1862
  if (pathData) {
@@ -2212,10 +2124,10 @@ function getNoPositionMowerImageByModal(mowerModal) {
2212
2124
  }
2213
2125
  return iNoPosition;
2214
2126
  }
2215
- function getMowerImage(positonConfig) {
2127
+ function getMowerImage(positonConfig, modelType) {
2216
2128
  if (!positonConfig)
2217
2129
  return '';
2218
- const model = positonConfig.vehicleModel || '';
2130
+ const model = modelType?.toLowerCase() || 'i';
2219
2131
  const state = positonConfig.vehicleState;
2220
2132
  const mowerImage = getMowerImageByModal(model);
2221
2133
  const disabledImage = getDisabledMowerImageByModal(model);
@@ -4955,6 +4867,13 @@ class BoundaryBorderLayer extends BaseLayer {
4955
4867
  this.level = LAYER_LEVELS.BOUNDARY_BORDER; // 中等层级
4956
4868
  this.type = LAYER_DEFAULT_TYPE.BOUNDARY_BORDER;
4957
4869
  this.boudaryBorderPaths = {};
4870
+ this.mowingBoundarys = [];
4871
+ }
4872
+ /**
4873
+ * 设置当前割草任务的边界
4874
+ */
4875
+ setMowingBoundarys(mowingBoundarys) {
4876
+ this.mowingBoundarys = mowingBoundarys;
4958
4877
  }
4959
4878
  /**
4960
4879
  * SVG渲染方法
@@ -4964,6 +4883,7 @@ class BoundaryBorderLayer extends BaseLayer {
4964
4883
  return;
4965
4884
  }
4966
4885
  this.scale = scale;
4886
+ console.log('draw boundary border->', this.elements, this.mowingBoundarys);
4967
4887
  // 只渲染边界边框类型的元素
4968
4888
  for (const element of this.elements) {
4969
4889
  if (element.type === 'boundary_border') {
@@ -5000,7 +4920,8 @@ class BoundaryBorderLayer extends BaseLayer {
5000
4920
  * 创建直接路径(type=2)
5001
4921
  */
5002
4922
  createDirectPath(svgGroup, points, style, id) {
5003
- const strokeColor = style.lineColor;
4923
+ const isMowing = this.mowingBoundarys.includes(Number(id));
4924
+ const strokeColor = isMowing ? style.mowingLineColor : style.lineColor;
5004
4925
  const lineWidth = dp2px(style.lineWidth || 3);
5005
4926
  const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
5006
4927
  // 构建路径数据
@@ -5033,7 +4954,8 @@ class BoundaryBorderLayer extends BaseLayer {
5033
4954
  * 使用PathMeasure逻辑创建平行路径(type=1)
5034
4955
  */
5035
4956
  createParallelPathsWithMeasure(svgGroup, points, style, id) {
5036
- const strokeColor = style.lineColor;
4957
+ const isMowing = this.mowingBoundarys.includes(Number(id));
4958
+ const strokeColor = isMowing ? style.mowingLineColor : style.lineColor;
5037
4959
  const lineWidth = dp2px(style.lineWidth || 3);
5038
4960
  // 获取当前SVG的缩放级别,计算固定屏幕像素间距
5039
4961
  const fixedScreenDistance = lineWidth; // 固定的屏幕像素距离
@@ -6427,12 +6349,6 @@ class BoundaryLabelsManager {
6427
6349
  this.container.style.display = visible ? 'block' : 'none';
6428
6350
  }
6429
6351
  }
6430
- /**
6431
- * 获取边界数据
6432
- */
6433
- getBoundaryData() {
6434
- return this.boundaryData;
6435
- }
6436
6352
  /**
6437
6353
  * 根据ID获取特定边界的标签元素
6438
6354
  */
@@ -6482,18 +6398,6 @@ class BoundaryLabelsManager {
6482
6398
  }
6483
6399
  });
6484
6400
  }
6485
- /**
6486
- * 重置标签层级(公共方法)
6487
- */
6488
- resetZIndex() {
6489
- this.resetLabelZIndex();
6490
- }
6491
- /**
6492
- * 获取层级常量(静态方法)
6493
- */
6494
- static getZIndexConstants() {
6495
- return BoundaryLabelsManager.Z_INDEX;
6496
- }
6497
6401
  /**
6498
6402
  * 设置标签旋转角度,使其与地图旋转相反,保持水平状态
6499
6403
  * @param rotation 地图的旋转角度(度)
@@ -6510,19 +6414,6 @@ class BoundaryLabelsManager {
6510
6414
  labelElement.style.transform = `translate(-50%, -50%) rotate(${counterRotation}deg)`;
6511
6415
  });
6512
6416
  }
6513
- /**
6514
- * 重置标签旋转角度
6515
- */
6516
- resetLabelsRotation() {
6517
- if (!this.container)
6518
- return;
6519
- const labels = this.container.querySelectorAll('.boundary-label');
6520
- labels.forEach((label) => {
6521
- const labelElement = label;
6522
- // 重置为默认的居中变换
6523
- labelElement.style.transform = 'translate(-50%, -50%)';
6524
- });
6525
- }
6526
6417
  }
6527
6418
  // 简化的层级定义
6528
6419
  BoundaryLabelsManager.Z_INDEX = {
@@ -6698,26 +6589,6 @@ class ChargingPileManager {
6698
6589
  this.container.innerHTML = '';
6699
6590
  }
6700
6591
  }
6701
- /**
6702
- * 设置可见性
6703
- */
6704
- setVisible(visible) {
6705
- if (this.container) {
6706
- this.container.style.display = visible ? 'block' : 'none';
6707
- }
6708
- }
6709
- /**
6710
- * 获取充电桩数量
6711
- */
6712
- getElementCount() {
6713
- return this.chargingPileElements.length;
6714
- }
6715
- /**
6716
- * 充电桩不需要动态层级调整(为了接口统一而保留)
6717
- */
6718
- resetZIndex() {
6719
- // 充电桩层级始终保持固定,无需重置
6720
- }
6721
6592
  /**
6722
6593
  * 销毁管理器
6723
6594
  */
@@ -6740,17 +6611,6 @@ class ChargingPileManager {
6740
6611
  pileElement.style.transform = `translate(-50%, -50%) rotate(${this.originalRotation - this.rotation}deg)`;
6741
6612
  });
6742
6613
  }
6743
- /**
6744
- * 重置充电桩旋转角度
6745
- */
6746
- resetRotation() {
6747
- this.rotation = 0;
6748
- const allContainers = this.container.querySelectorAll('.charging-pile');
6749
- allContainers.forEach((container) => {
6750
- const pileElement = container;
6751
- pileElement.style.transform = `translate(-50%, -50%) rotate(${this.originalRotation - this.rotation}deg)`;
6752
- });
6753
- }
6754
6614
  }
6755
6615
  // 简化的层级定义 - 充电桩只需要一个固定层级
6756
6616
  ChargingPileManager.Z_INDEX = {
@@ -7136,32 +6996,6 @@ class AntennaManager {
7136
6996
  this.container.innerHTML = '';
7137
6997
  }
7138
6998
  }
7139
- /**
7140
- * 设置可见性
7141
- */
7142
- setVisible(visible) {
7143
- if (this.container) {
7144
- this.container.style.display = visible ? 'block' : 'none';
7145
- }
7146
- }
7147
- /**
7148
- * 获取天线数量
7149
- */
7150
- getElementCount() {
7151
- return this.antennaElements.length;
7152
- }
7153
- /**
7154
- * 重置天线层级(公共方法)
7155
- */
7156
- resetZIndex() {
7157
- this.resetAntennaZIndex();
7158
- }
7159
- /**
7160
- * 获取层级常量(静态方法)
7161
- */
7162
- static getZIndexConstants() {
7163
- return AntennaManager.Z_INDEX;
7164
- }
7165
6999
  /**
7166
7000
  * 销毁管理器
7167
7001
  */
@@ -7189,17 +7023,6 @@ class AntennaManager {
7189
7023
  antennaContainer.style.transform = `translate(-50%, -50%) rotate(${-this.rotation}deg)`;
7190
7024
  });
7191
7025
  }
7192
- /**
7193
- * 重置天线旋转角度
7194
- */
7195
- resetRotation() {
7196
- this.rotation = 0;
7197
- const allContainers = this.container.querySelectorAll('.antenna-container-item');
7198
- allContainers.forEach((container) => {
7199
- const antennaContainer = container;
7200
- antennaContainer.style.transform = `translate(-50%, -50%) rotate(${-this.rotation}deg)`;
7201
- });
7202
- }
7203
7026
  }
7204
7027
  // 简化的层级定义
7205
7028
  AntennaManager.Z_INDEX = {
@@ -7255,7 +7078,7 @@ const EDIT_BEHAVIOR = {
7255
7078
  };
7256
7079
 
7257
7080
  class MowerPositionManager {
7258
- constructor(svgView, mowerPositionConfig, overlayDiv, onAnimationComplete, onMowingPositionChange) {
7081
+ constructor(svgView, mowerPositionConfig, modelType, overlayDiv, onAnimationComplete, onMowingPositionChange) {
7259
7082
  this.container = null;
7260
7083
  this.overlayDiv = null;
7261
7084
  this.mowerElement = null;
@@ -7273,6 +7096,7 @@ class MowerPositionManager {
7273
7096
  this.onlyUpdateTheta = false;
7274
7097
  this.svgView = svgView;
7275
7098
  this.mowerPositionConfig = mowerPositionConfig;
7099
+ this.modelType = modelType;
7276
7100
  this.overlayDiv = overlayDiv;
7277
7101
  this.onAnimationComplete = onAnimationComplete;
7278
7102
  this.onMowingPositionChange = onMowingPositionChange;
@@ -7327,6 +7151,7 @@ class MowerPositionManager {
7327
7151
  }
7328
7152
  this.mowerElement.appendChild(imgElement);
7329
7153
  this.container.appendChild(this.mowerElement);
7154
+ this.updatePosition(this.mowerPositionConfig);
7330
7155
  }
7331
7156
  /**
7332
7157
  * 设置叠加层div引用(用于坐标转换)
@@ -7348,9 +7173,9 @@ class MowerPositionManager {
7348
7173
  return;
7349
7174
  this.mowerPositionConfig = chargingPilesPositionConfig;
7350
7175
  const lastPosition = this.lastPosition;
7351
- const postureX = chargingPilesPositionConfig.postureX || chargingPilesPositionConfig.lastPostureX || lastPosition?.x;
7352
- const postureY = chargingPilesPositionConfig.postureY || chargingPilesPositionConfig.lastPostureY || lastPosition?.y;
7353
- const postureTheta = chargingPilesPositionConfig.postureTheta || chargingPilesPositionConfig.lastPostureTheta || lastPosition?.rotation;
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;
7354
7179
  // 检查是否需要更新图片
7355
7180
  this.updateMowerImage(chargingPilesPositionConfig);
7356
7181
  // 立即更新位置
@@ -7364,9 +7189,10 @@ class MowerPositionManager {
7364
7189
  this.updateMowerImage(positionConfig);
7365
7190
  // 更新配置
7366
7191
  this.mowerPositionConfig = positionConfig;
7367
- const postureX = positionConfig.postureX || this.lastPosition?.x;
7368
- const postureY = positionConfig.postureY || this.lastPosition?.y;
7369
- const postureTheta = positionConfig.postureTheta || this.lastPosition?.rotation;
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);
7370
7196
  // 停止当前动画(如果有)
7371
7197
  this.stopAnimation();
7372
7198
  // 第一个点
@@ -7397,9 +7223,14 @@ class MowerPositionManager {
7397
7223
  const imgElement = this.mowerElement.querySelector('img');
7398
7224
  if (!imgElement)
7399
7225
  return;
7400
- const imageSrc = getMowerImage(positonConfig);
7226
+ const imageSrc = getMowerImage(positonConfig, this.modelType);
7401
7227
  if (imageSrc) {
7402
7228
  imgElement.src = imageSrc;
7229
+ imgElement.style.display = 'block';
7230
+ }
7231
+ else {
7232
+ imgElement.style.display = 'none';
7233
+ return;
7403
7234
  }
7404
7235
  }
7405
7236
  /**
@@ -7420,6 +7251,7 @@ class MowerPositionManager {
7420
7251
  if (!positonOutOfRange && !positionValid) {
7421
7252
  this.lastPosition = { x, y, rotation: theta };
7422
7253
  }
7254
+ // console.log('setElementPosition', x, y, targetRotation, positonOutOfRange, positionValid, targetPixelPosition);
7423
7255
  if (!this.mowerElement)
7424
7256
  return;
7425
7257
  this.mowerElement.style.left = `${targetPixelPosition?.x}px`;
@@ -7557,12 +7389,6 @@ class MowerPositionManager {
7557
7389
  this.container.style.display = visible ? 'block' : 'none';
7558
7390
  }
7559
7391
  }
7560
- /**
7561
- * 检查是否正在动画中
7562
- */
7563
- getIsAnimating() {
7564
- return this.isAnimating;
7565
- }
7566
7392
  /**
7567
7393
  * 销毁管理器
7568
7394
  */
@@ -7627,7 +7453,7 @@ function throttleAdvanced(func, delay, options = { leading: true, trailing: true
7627
7453
 
7628
7454
  // Google Maps 叠加层类 - 带编辑功能
7629
7455
  class MowerMapOverlay {
7630
- constructor(bounds, mapData, partitionBoundary, mowerPositionConfig, pathData, isEditMode = false, mapConfig = {}, antennaConfig = {}, mowPartitionData = null, defaultTransform, onMapLoad, onPathLoad, dragCallbacks) {
7456
+ constructor(bounds, mapData, partitionBoundary, mowerPositionConfig, modelType, pathData, isEditMode = false, mapConfig = {}, antennaConfig = {}, mowPartitionData = null, defaultTransform, onMapLoad, onPathLoad, dragCallbacks) {
7631
7457
  this.div = null;
7632
7458
  this.svgMapView = null;
7633
7459
  this.offscreenContainer = null;
@@ -7682,6 +7508,7 @@ class MowerMapOverlay {
7682
7508
  this.dragCallbacks = dragCallbacks;
7683
7509
  this.mowerPositionConfig = mowerPositionConfig;
7684
7510
  this.mowPartitionData = mowPartitionData;
7511
+ this.modelType = modelType;
7685
7512
  // 设置默认的transform
7686
7513
  if (defaultTransform) {
7687
7514
  this.defaultTransform = {
@@ -7720,12 +7547,14 @@ class MowerMapOverlay {
7720
7547
  this.isUserAnimation = animationTime > 0;
7721
7548
  // 更新割草机位置配置
7722
7549
  this.mowerPositionConfig = positionConfig;
7550
+ console.log('updatePosition overlay', positionConfig);
7723
7551
  // 更新割草机位置管理器
7724
7552
  if (this.mowerPositionManager) {
7725
7553
  this.mowerPositionManager.updatePosition(positionConfig, animationTime);
7726
7554
  }
7727
7555
  }
7728
7556
  updatePositionByLastPosition(chargingPilesPositionConfig) {
7557
+ this.mowerPositionConfig = chargingPilesPositionConfig;
7729
7558
  // 更新配置
7730
7559
  if (this.mowerPositionManager) {
7731
7560
  this.mowerPositionManager.updatePositionByLastPosition(chargingPilesPositionConfig);
@@ -7746,30 +7575,24 @@ class MowerMapOverlay {
7746
7575
  return this.overlayView ? this.overlayView.getPanes() : null;
7747
7576
  }
7748
7577
  resetBorderLayerHighlight() {
7578
+ this.mowPartitionData = null;
7749
7579
  const boundaryBorderLayer = this.svgMapView?.getLayer(LAYER_DEFAULT_TYPE.BOUNDARY_BORDER);
7750
- Object.keys(boundaryBorderLayer?.boudaryBorderPaths || {}).forEach((key) => {
7751
- const paths = boundaryBorderLayer?.boudaryBorderPaths?.[key];
7752
- if (paths) {
7753
- paths.forEach((path) => {
7754
- path.setAttribute('stroke', BOUNDARY_STYLES.lineColor);
7755
- });
7756
- }
7757
- });
7580
+ if (!boundaryBorderLayer)
7581
+ return;
7582
+ boundaryBorderLayer.setMowingBoundarys([]);
7583
+ this.svgMapView?.renderLayer(LAYER_DEFAULT_TYPE.BOUNDARY_BORDER);
7758
7584
  }
7759
7585
  setBorderLayerHighlight(mowPartitionData) {
7760
7586
  this.mowPartitionData = mowPartitionData;
7761
7587
  const boundaryBorderLayer = this.svgMapView?.getLayer(LAYER_DEFAULT_TYPE.BOUNDARY_BORDER);
7762
7588
  const partitionIds = mowPartitionData?.partitionIds || [];
7763
- for (const partitionId of partitionIds) {
7764
- const boundaryBorderPaths = boundaryBorderLayer?.boudaryBorderPaths?.[partitionId];
7765
- if (boundaryBorderPaths) {
7766
- boundaryBorderPaths.forEach((path) => {
7767
- path.setAttribute('stroke', BOUNDARY_STYLES.mowingLineColor);
7768
- });
7769
- }
7770
- }
7589
+ if (!boundaryBorderLayer)
7590
+ return;
7591
+ boundaryBorderLayer.setMowingBoundarys(partitionIds);
7592
+ this.svgMapView?.renderLayer(LAYER_DEFAULT_TYPE.BOUNDARY_BORDER);
7771
7593
  }
7772
7594
  onAdd() {
7595
+ console.log('onAdd');
7773
7596
  // 创建包含SVG的div
7774
7597
  this.div = document.createElement('div');
7775
7598
  this.div.style.borderStyle = 'none';
@@ -7830,16 +7653,6 @@ class MowerMapOverlay {
7830
7653
  const map = this.getMap();
7831
7654
  if (!map || !this.svgMapView)
7832
7655
  return;
7833
- // const currentZoom = map.getZoom();
7834
- // const center = map.getCenter();
7835
- // 基础公式:像素/米 = 156543.03392 * cos(latitude) / (2 ^ zoom)
7836
- // const metersPerPixel =
7837
- // (156543.03392 * Math.cos((center.lat() * Math.PI) / 180)) / Math.pow(2, currentZoom);
7838
- // 缩放比例 = 1 / 米/像素
7839
- // const scale = (1 / metersPerPixel) * 50;
7840
- // 应用缩放到SVG
7841
- // this.svgMapView.setZoom(scale);
7842
- // 当缩放变化时,重新绘制以确保位置正确
7843
7656
  this.draw();
7844
7657
  }
7845
7658
  // 创建边界标签管理器
@@ -7891,7 +7704,7 @@ class MowerMapOverlay {
7891
7704
  if (!this.div || !this.svgMapView)
7892
7705
  return;
7893
7706
  // 创建割草机位置管理器,传入动画完成回调
7894
- this.mowerPositionManager = new MowerPositionManager(this.svgMapView, this.mowerPositionConfig, this.div, () => {
7707
+ this.mowerPositionManager = new MowerPositionManager(this.svgMapView, this.mowerPositionConfig, this.modelType, this.div, () => {
7895
7708
  console.log('动画完成');
7896
7709
  }, this.updatePathDataByMowingPositionThrottled.bind(this));
7897
7710
  // 设置叠加层div引用
@@ -7924,7 +7737,7 @@ class MowerMapOverlay {
7924
7737
  this.boundaryLabelsManager.updatePositionsWithPrecomputedData(width, height, viewBoxInfo);
7925
7738
  }
7926
7739
  // 更新管理器位置
7927
- updateManagerPositions(width, height) {
7740
+ updateManagerPositions(_width, _height) {
7928
7741
  if (!this.div)
7929
7742
  return;
7930
7743
  // 更新充电桩位置
@@ -8489,13 +8302,13 @@ class MowerMapOverlay {
8489
8302
  try {
8490
8303
  // 创建SvgMapView实例
8491
8304
  this.svgMapView = new SvgMapView(this.offscreenContainer, 800, 600);
8492
- window.svgMapView = this.svgMapView;
8493
8305
  // 加载地图数据
8494
8306
  this.loadMapData();
8495
8307
  // 加载路径数据
8496
8308
  if (this.pathData && this.svgMapView) {
8497
8309
  this.loadPathData(this.pathData, this.mowPartitionData);
8498
8310
  }
8311
+ console.log('initializeSvgMapView');
8499
8312
  // 刷新绘制图层
8500
8313
  this.svgMapView.refresh();
8501
8314
  // 获取生成的SVG并添加到叠加层div中
@@ -8520,9 +8333,6 @@ class MowerMapOverlay {
8520
8333
  // 使用现有的MapDataProcessor处理地图数据
8521
8334
  const elements = MapDataProcessor.processMapData(this.mapData, this.mapConfig);
8522
8335
  // 分离充电桩和天线元素,其他元素添加到SVG图层
8523
- // const svgElements = elements.filter(element =>
8524
- // element.type !== 'charging_pile' && element.type !== 'antenna'
8525
- // );
8526
8336
  const svgElements = elements.filter((element) => element.type !== 'charging_pile' && element.type !== 'antenna');
8527
8337
  const chargingPileElements = elements.filter((element) => element.type === 'charging_pile');
8528
8338
  // 处理SVG图层元素
@@ -8537,6 +8347,10 @@ class MowerMapOverlay {
8537
8347
  const layers = drawLayer.getLayers();
8538
8348
  this.svgMapView.clear();
8539
8349
  this.svgMapView.addLayers(layers);
8350
+ const boundaryBorderLayer = this.svgMapView.getLayer(LAYER_DEFAULT_TYPE.BOUNDARY_BORDER);
8351
+ if (boundaryBorderLayer) {
8352
+ boundaryBorderLayer.setMowingBoundarys(this.mowPartitionData?.partitionIds || []);
8353
+ }
8540
8354
  this.createChargingPileManager();
8541
8355
  // 使用管理器处理充电桩和天线
8542
8356
  if (this.chargingPileManager && chargingPileElements.length > 0) {
@@ -8801,6 +8615,10 @@ class MowerMapOverlay {
8801
8615
  this.mowerPositionManager.setVisible(visible);
8802
8616
  }
8803
8617
  }
8618
+ // 获取SvgMapView实例(用于debug)
8619
+ getSvgMapView() {
8620
+ return this.svgMapView;
8621
+ }
8804
8622
  }
8805
8623
 
8806
8624
  var RealTimeDataType;
@@ -8810,6 +8628,35 @@ var RealTimeDataType;
8810
8628
  RealTimeDataType[RealTimeDataType["PARTITION"] = 3] = "PARTITION";
8811
8629
  })(RealTimeDataType || (RealTimeDataType = {}));
8812
8630
 
8631
+ // 获取车辆状态的中文文案
8632
+ const getVehicleStateText = (vehicleState) => {
8633
+ switch (vehicleState) {
8634
+ case RobotStatus.PARKED:
8635
+ return 'PARKED';
8636
+ case RobotStatus.CHARGING:
8637
+ return 'CHARGING';
8638
+ case RobotStatus.STANDBY:
8639
+ return 'STANDBY';
8640
+ case RobotStatus.MOWING:
8641
+ return 'MOWING';
8642
+ case RobotStatus.WORKING:
8643
+ return 'WORKING';
8644
+ case RobotStatus.MAPPING:
8645
+ return 'MAPPING';
8646
+ case RobotStatus.ERROR:
8647
+ return 'ERROR';
8648
+ case RobotStatus.UPGRADING:
8649
+ return 'UPGRADING';
8650
+ case RobotStatus.DISCONNECTED:
8651
+ return 'DISCONNECTED';
8652
+ case RobotStatus.TASK_DELAY:
8653
+ return 'TASK_DELAY';
8654
+ case RobotStatus.UNKNOWN:
8655
+ return '未知';
8656
+ default:
8657
+ return `未知状态(${vehicleState})`;
8658
+ }
8659
+ };
8813
8660
  // 验证GPS坐标是否有效
8814
8661
  const isValidGpsCoordinate = (coordinate) => {
8815
8662
  if (!coordinate || coordinate.length < 2)
@@ -8892,7 +8739,7 @@ const getValidGpsBounds = (mapData, rotation = 0) => {
8892
8739
  // 默认配置
8893
8740
  const defaultMapConfig = DEFAULT_STYLES;
8894
8741
  // 地图渲染器组件
8895
- const MowerMapRenderer = forwardRef(({ mapConfig, modelType, mapRef, mapJson, pathJson, realTimeData, antennaConfig, onMapLoad, onPathLoad, onError, className, style, googleMapInstance, isEditMode = false, dragCallbacks, defaultTransform, }, ref) => {
8742
+ const MowerMapRenderer = forwardRef(({ mapConfig, modelType, mapRef, mapJson, pathJson, realTimeData, antennaConfig, onMapLoad, onPathLoad, onError, className, style, googleMapInstance, isEditMode = false, dragCallbacks, defaultTransform, debug = false, }, ref) => {
8896
8743
  const [elementCount, setElementCount] = useState(0);
8897
8744
  const [pathCount, setPathCount] = useState(0);
8898
8745
  const [currentError, setCurrentError] = useState(null);
@@ -8904,6 +8751,8 @@ const MowerMapRenderer = forwardRef(({ mapConfig, modelType, mapRef, mapJson, pa
8904
8751
  const currentProcessMowingStatusRef = useRef(false);
8905
8752
  const { updateProcessStateIsMowing, processStateIsMowing } = useProcessMowingState();
8906
8753
  const [mowPartitionData, setMowPartitionData] = useState(null);
8754
+ // Debug相关状态
8755
+ const [debugInfo, setDebugInfo] = useState({});
8907
8756
  // 处理地图分区边界
8908
8757
  const partitionBoundary = useMemo(() => {
8909
8758
  const allBoundaryElements = [];
@@ -8928,7 +8777,12 @@ const MowerMapRenderer = forwardRef(({ mapConfig, modelType, mapRef, mapJson, pa
8928
8777
  const mowerPositionData = useMemo(() => {
8929
8778
  // realTimeData 中包含三个种类的数据,之需要实时坐标的数据即可。
8930
8779
  if (!realTimeData || realTimeData.length === 0)
8931
- return undefined;
8780
+ return {
8781
+ postureX: 0,
8782
+ postureY: 0,
8783
+ postureTheta: 0,
8784
+ vehicleState: RobotStatus.PARKED,
8785
+ };
8932
8786
  let currentPositionData;
8933
8787
  if (realTimeData.length === 1 && realTimeData[0].type === RealTimeDataType.LOCATION) {
8934
8788
  currentPositionData = realTimeData[0];
@@ -8950,7 +8804,6 @@ const MowerMapRenderer = forwardRef(({ mapConfig, modelType, mapRef, mapJson, pa
8950
8804
  lastPostureX: currentPositionData?.lastPostureX ? Number(currentPositionData.lastPostureX) : 0,
8951
8805
  lastPostureY: currentPositionData?.lastPostureY ? Number(currentPositionData.lastPostureY) : 0,
8952
8806
  vehicleState: currentPositionData?.vehicleState || RobotStatus.CHARGING,
8953
- vehicleModel: modelType?.toLowerCase() || '',
8954
8807
  };
8955
8808
  }, [realTimeData, modelType]);
8956
8809
  console.log('mowerPositionData', mowerPositionData);
@@ -9019,8 +8872,9 @@ const MowerMapRenderer = forwardRef(({ mapConfig, modelType, mapRef, mapJson, pa
9019
8872
  overlayRef.current.setMap(null);
9020
8873
  overlayRef.current = null;
9021
8874
  }
8875
+ console.log('initializeGoogleMapsOverlay', mowPartitionData);
9022
8876
  // 创建叠加层
9023
- const overlay = new MowerMapOverlay(googleBounds, mapJson, partitionBoundary, mowerPositionData, pathJson || {}, isEditMode, mergedMapConfig, mergedAntennaConfig, null, defaultTransform, (count) => {
8877
+ const overlay = new MowerMapOverlay(googleBounds, mapJson, partitionBoundary, mowerPositionData, modelType, pathJson || {}, isEditMode, mergedMapConfig, mergedAntennaConfig, null, defaultTransform, (count) => {
9024
8878
  setElementCount(count);
9025
8879
  onMapLoad?.(count);
9026
8880
  }, (count) => {
@@ -9078,6 +8932,7 @@ const MowerMapRenderer = forwardRef(({ mapConfig, modelType, mapRef, mapJson, pa
9078
8932
  const isOffLine = mowerPositionData.vehicleState === RobotStatus.DISCONNECTED;
9079
8933
  const isInChargingPile = inChargingPiles.includes(mowerPositionData.vehicleState);
9080
8934
  // 如果在充电桩上,则直接更新位置到充电桩的位置
8935
+ console.log('usefeect mowerPositionData----->', mowerPositionData);
9081
8936
  if (isInChargingPile) {
9082
8937
  overlayRef.current.updatePosition({
9083
8938
  ...mowerPositionData,
@@ -9115,19 +8970,137 @@ const MowerMapRenderer = forwardRef(({ mapConfig, modelType, mapRef, mapJson, pa
9115
8970
  }
9116
8971
  }
9117
8972
  }, [mowerPositionData]);
8973
+ // 更新debug信息
9118
8974
  useEffect(() => {
8975
+ if (!debug)
8976
+ return;
8977
+ const updateDebugInfo = () => {
8978
+ const newDebugInfo = {};
8979
+ // 获取地图GPS边界
8980
+ if (mapJson) {
8981
+ newDebugInfo.mapBounds = getValidGpsBounds(mapJson, defaultTransform?.rotation);
8982
+ }
8983
+ // 获取SVG viewBox信息
8984
+ if (overlayRef.current) {
8985
+ const overlay = overlayRef.current;
8986
+ const svgMapView = overlay.getSvgMapView?.();
8987
+ if (svgMapView) {
8988
+ const viewBoxInfo = svgMapView.getViewBoxInfo();
8989
+ // 计算实际的米单位数据(除以缩放比例)
8990
+ const SCALE_FACTOR = 50; // 根据项目中的缩放因子
8991
+ newDebugInfo.viewBox = {
8992
+ x: viewBoxInfo.x / SCALE_FACTOR,
8993
+ y: viewBoxInfo.y / SCALE_FACTOR,
8994
+ width: viewBoxInfo.width / SCALE_FACTOR,
8995
+ height: viewBoxInfo.height / SCALE_FACTOR,
8996
+ scale: SCALE_FACTOR,
8997
+ // 计算左下角和右上角坐标
8998
+ sw: {
8999
+ x: viewBoxInfo.x / SCALE_FACTOR,
9000
+ y: viewBoxInfo.y / SCALE_FACTOR
9001
+ },
9002
+ ne: {
9003
+ x: (viewBoxInfo.x + viewBoxInfo.width) / SCALE_FACTOR,
9004
+ y: (viewBoxInfo.y + viewBoxInfo.height) / SCALE_FACTOR
9005
+ }
9006
+ };
9007
+ }
9008
+ }
9009
+ // 获取当前割草机位置
9010
+ if (mowerPositionData) {
9011
+ newDebugInfo.mowerPosition = {
9012
+ x: mowerPositionData.postureX || 0,
9013
+ y: mowerPositionData.postureY || 0,
9014
+ theta: mowerPositionData.postureTheta || 0,
9015
+ lastX: mowerPositionData.lastPostureX || 0,
9016
+ lastY: mowerPositionData.lastPostureY || 0,
9017
+ lastTheta: mowerPositionData.lastPostureTheta || 0,
9018
+ vehicleState: mowerPositionData.vehicleState || RobotStatus.UNKNOWN,
9019
+ vehicleStateText: getVehicleStateText(mowerPositionData.vehicleState || RobotStatus.UNKNOWN)
9020
+ };
9021
+ }
9022
+ // 获取当前割草地块数据
9023
+ newDebugInfo.partitionData = mowPartitionData;
9024
+ setDebugInfo(newDebugInfo);
9025
+ };
9026
+ updateDebugInfo();
9027
+ // 设置定时更新(仅在没有数据变化时使用)
9028
+ const interval = setInterval(updateDebugInfo, 1000);
9029
+ return () => clearInterval(interval);
9030
+ }, [debug, mapJson, mowerPositionData, mowPartitionData, defaultTransform]);
9031
+ // 当关键数据变化时立即更新debug信息
9032
+ useEffect(() => {
9033
+ if (!debug)
9034
+ return;
9035
+ const updateDebugInfo = () => {
9036
+ const newDebugInfo = {};
9037
+ // 获取地图GPS边界
9038
+ if (mapJson) {
9039
+ newDebugInfo.mapBounds = getValidGpsBounds(mapJson, defaultTransform?.rotation);
9040
+ }
9041
+ // 获取SVG viewBox信息
9042
+ if (overlayRef.current) {
9043
+ const overlay = overlayRef.current;
9044
+ const svgMapView = overlay.getSvgMapView?.();
9045
+ if (svgMapView) {
9046
+ const viewBoxInfo = svgMapView.getViewBoxInfo();
9047
+ // 计算实际的米单位数据(除以缩放比例)
9048
+ const SCALE_FACTOR = 50; // 根据项目中的缩放因子
9049
+ newDebugInfo.viewBox = {
9050
+ x: viewBoxInfo.x / SCALE_FACTOR,
9051
+ y: viewBoxInfo.y / SCALE_FACTOR,
9052
+ width: viewBoxInfo.width / SCALE_FACTOR,
9053
+ height: viewBoxInfo.height / SCALE_FACTOR,
9054
+ scale: SCALE_FACTOR,
9055
+ // 计算左下角和右上角坐标
9056
+ sw: {
9057
+ x: viewBoxInfo.x / SCALE_FACTOR,
9058
+ y: viewBoxInfo.y / SCALE_FACTOR
9059
+ },
9060
+ ne: {
9061
+ x: (viewBoxInfo.x + viewBoxInfo.width) / SCALE_FACTOR,
9062
+ y: (viewBoxInfo.y + viewBoxInfo.height) / SCALE_FACTOR
9063
+ }
9064
+ };
9065
+ }
9066
+ }
9067
+ // 获取当前割草机位置
9068
+ if (mowerPositionData) {
9069
+ newDebugInfo.mowerPosition = {
9070
+ x: mowerPositionData.postureX || 0,
9071
+ y: mowerPositionData.postureY || 0,
9072
+ theta: mowerPositionData.postureTheta || 0,
9073
+ lastX: mowerPositionData.lastPostureX || 0,
9074
+ lastY: mowerPositionData.lastPostureY || 0,
9075
+ lastTheta: mowerPositionData.lastPostureTheta || 0,
9076
+ vehicleState: mowerPositionData.vehicleState || RobotStatus.UNKNOWN,
9077
+ vehicleStateText: getVehicleStateText(mowerPositionData.vehicleState || RobotStatus.UNKNOWN)
9078
+ };
9079
+ }
9080
+ // 获取当前割草地块数据
9081
+ newDebugInfo.partitionData = mowPartitionData;
9082
+ setDebugInfo(newDebugInfo);
9083
+ };
9084
+ updateDebugInfo();
9085
+ }, [debug, mowerPositionData, mowPartitionData]);
9086
+ useEffect(() => {
9087
+ if (!realTimeData || realTimeData.length === 0 || !Array.isArray(realTimeData)) {
9088
+ return;
9089
+ }
9090
+ console.log('usefeect realTimeData----->', realTimeData, mapJson, pathJson, overlayRef.current);
9091
+ // realtime中包含当前割草任务的数据,根据数据进行path路径和边界的高亮操作,
9092
+ const mowingPartition = realTimeData.find((item) => item.type === RealTimeDataType.PARTITION);
9093
+ if (mowingPartition) {
9094
+ setMowPartitionData(mowingPartition);
9095
+ }
9096
+ const curMowPartitionData = mowingPartition || mowPartitionData;
9119
9097
  if (!mapJson ||
9120
9098
  !pathJson ||
9121
- !realTimeData ||
9122
- realTimeData.length === 0 ||
9123
- !Array.isArray(realTimeData) ||
9124
9099
  !overlayRef.current)
9125
9100
  return;
9126
9101
  // 根据后端推送的实时数据,进行不同处理
9127
9102
  // TODO:需要根据返回的数据,处理车辆的移动位置
9128
- console.log('realTimeData----->', realTimeData);
9129
- // realtime中包含当前割草任务的数据,根据数据进行path路径和边界的高亮操作
9130
- const curMowPartitionData = realTimeData.find((item) => item.type === RealTimeDataType.PARTITION) || mowPartitionData;
9103
+ console.log('realTimeData----->', realTimeData, curMowPartitionData);
9131
9104
  if (curMowPartitionData) {
9132
9105
  setMowPartitionData(curMowPartitionData);
9133
9106
  const isMowing = curMowPartitionData?.partitionIds && curMowPartitionData.partitionIds.length > 0;
@@ -9170,12 +9143,9 @@ const MowerMapRenderer = forwardRef(({ mapConfig, modelType, mapRef, mapJson, pa
9170
9143
  }
9171
9144
  }, [realTimeData, mapJson, pathJson]);
9172
9145
  useEffect(() => {
9173
- console.log('defaultTransform----->', defaultTransform, overlayRef.current);
9146
+ console.log('defaultTransform----->', defaultTransform, overlayRef.current, mapJson);
9174
9147
  if (!overlayRef.current || !defaultTransform)
9175
9148
  return;
9176
- if (defaultTransform.x === 0 && defaultTransform.y === 0 && defaultTransform.rotation === 0) {
9177
- return;
9178
- }
9179
9149
  overlayRef.current?.setTransform(defaultTransform);
9180
9150
  const validBounds = getValidGpsBounds(mapJson, defaultTransform?.rotation);
9181
9151
  // 地图数据中的坐标格式是 [longitude, latitude]
@@ -9223,12 +9193,31 @@ const MowerMapRenderer = forwardRef(({ mapConfig, modelType, mapRef, mapJson, pa
9223
9193
  setTransform: (t) => overlayRef.current?.setTransform(t),
9224
9194
  resetToDefaultTransform: () => overlayRef.current?.resetToDefaultTransform(),
9225
9195
  }));
9196
+ // Debug信息组件
9197
+ const DebugInfo = () => {
9198
+ if (!debug)
9199
+ return null;
9200
+ return (jsxs("div", { style: {
9201
+ position: 'fixed',
9202
+ bottom: '10px',
9203
+ left: '10px',
9204
+ backgroundColor: 'rgba(0, 0, 0, 0.8)',
9205
+ color: 'white',
9206
+ padding: '10px',
9207
+ borderRadius: '5px',
9208
+ fontSize: '12px',
9209
+ fontFamily: 'monospace',
9210
+ zIndex: 10000,
9211
+ 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" })] }))] }));
9214
+ };
9226
9215
  // 错误显示
9227
9216
  if (currentError) {
9228
- return (jsx("div", { className: className, style: style, children: jsxs("div", { style: { color: 'red', padding: '10px' }, children: ["\u9519\u8BEF: ", currentError] }) }));
9217
+ return (jsxs("div", { className: className, style: style, children: [jsxs("div", { style: { color: 'red', padding: '10px' }, children: ["\u9519\u8BEF: ", currentError] }), jsx(DebugInfo, {})] }));
9229
9218
  }
9230
- // 使用goole maps自定义叠加层,不需要实际返回组件内容
9231
- return null;
9219
+ // 使用goole maps自定义叠加层,返回debug信息(如果启用)
9220
+ return debug ? jsx(DebugInfo, {}) : null;
9232
9221
  });
9233
9222
  MowerMapRenderer.displayName = 'MowerMapRenderer';
9234
9223