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