@fleet-frontend/mower-maps 0.1.0-beta.4 → 0.1.0-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 +150 -87
- package/dist/index.js +150 -87
- package/dist/processor/MapDataProcessor.d.ts +2 -1
- package/dist/processor/MapDataProcessor.d.ts.map +1 -1
- package/dist/render/MowerMapOverlay.d.ts +2 -1
- package/dist/render/MowerMapOverlay.d.ts.map +1 -1
- package/dist/render/MowerMapRenderer.d.ts.map +1 -1
- package/dist/render/SvgMapView.d.ts +2 -1
- package/dist/render/SvgMapView.d.ts.map +1 -1
- package/dist/render/layers/BaseLayer.d.ts +1 -0
- package/dist/render/layers/BaseLayer.d.ts.map +1 -1
- package/dist/render/layers/BoundaryBorderLayer.d.ts.map +1 -1
- package/dist/render/layers/BoundaryLayer.d.ts.map +1 -1
- package/dist/render/layers/ChannelLayer.d.ts +2 -1
- package/dist/render/layers/ChannelLayer.d.ts.map +1 -1
- package/dist/render/layers/DrawLayer.d.ts +2 -1
- package/dist/render/layers/DrawLayer.d.ts.map +1 -1
- package/dist/render/layers/ObstacleLayer.d.ts.map +1 -1
- package/dist/render/layers/PathLayer.d.ts +2 -1
- package/dist/render/layers/PathLayer.d.ts.map +1 -1
- package/dist/render/layers/VisionOffLayer.d.ts.map +1 -1
- package/dist/store/useCurrentMowingDataStore.d.ts.map +1 -1
- package/dist/store/usePartitionDataStore.d.ts.map +1 -1
- package/dist/types/renderer.d.ts +1 -0
- package/dist/types/renderer.d.ts.map +1 -1
- package/dist/types/store.d.ts +15 -15
- package/dist/types/store.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.esm.js
CHANGED
|
@@ -136,7 +136,7 @@ const SVG_MAP_VIEW_ID = 'fleet-maps-svg-map-view';
|
|
|
136
136
|
* 使用真正的矢量SVG渲染替代Canvas位图渲染
|
|
137
137
|
*/
|
|
138
138
|
class SvgMapView {
|
|
139
|
-
constructor(containerElement, width = 800, height = 600) {
|
|
139
|
+
constructor(sn, containerElement, width = 800, height = 600) {
|
|
140
140
|
// 图层管理
|
|
141
141
|
this.layers = [];
|
|
142
142
|
// 简单变换参数
|
|
@@ -149,6 +149,7 @@ class SvgMapView {
|
|
|
149
149
|
this.isDragging = false;
|
|
150
150
|
this.lastMouseX = 0;
|
|
151
151
|
this.lastMouseY = 0;
|
|
152
|
+
this.sn = sn;
|
|
152
153
|
this.container = containerElement;
|
|
153
154
|
// 创建SVG元素
|
|
154
155
|
this.svg = this.createSVGElement();
|
|
@@ -186,7 +187,7 @@ class SvgMapView {
|
|
|
186
187
|
this.svg.setAttribute('shape-rendering', 'geometricPrecision');
|
|
187
188
|
this.svg.setAttribute('text-rendering', 'geometricPrecision');
|
|
188
189
|
this.svg.setAttribute('image-rendering', 'optimizeQuality');
|
|
189
|
-
this.svg.setAttribute('id', SVG_MAP_VIEW_ID);
|
|
190
|
+
this.svg.setAttribute('id', `${this.sn}-${SVG_MAP_VIEW_ID}`);
|
|
190
191
|
}
|
|
191
192
|
/**
|
|
192
193
|
* 创建SVG组元素
|
|
@@ -641,6 +642,7 @@ class BaseLayer {
|
|
|
641
642
|
this.needsRedraw = true;
|
|
642
643
|
this.mapView = null;
|
|
643
644
|
this.type = '';
|
|
645
|
+
this.sn = '';
|
|
644
646
|
this.level = 0; // 中等层级
|
|
645
647
|
}
|
|
646
648
|
// ==================== 基础属性方法 ====================
|
|
@@ -780,11 +782,17 @@ const usePartitionDataStore = create((set, get) => ({
|
|
|
780
782
|
addSubBoundaryBorder: (key, element) => set((state) => ({
|
|
781
783
|
subBoundaryBorder: {
|
|
782
784
|
...state.subBoundaryBorder,
|
|
783
|
-
[key]: element,
|
|
785
|
+
[key]: { ...element },
|
|
784
786
|
},
|
|
785
787
|
})),
|
|
786
788
|
// 清空所有数据
|
|
787
|
-
|
|
789
|
+
deleteSubBoundaryBorder: (key) => set((state) => {
|
|
790
|
+
const newSubBoundaryBorder = { ...state.subBoundaryBorder };
|
|
791
|
+
delete newSubBoundaryBorder[key];
|
|
792
|
+
return {
|
|
793
|
+
subBoundaryBorder: newSubBoundaryBorder,
|
|
794
|
+
};
|
|
795
|
+
}),
|
|
788
796
|
// 障碍物
|
|
789
797
|
obstacles: {},
|
|
790
798
|
addObstacles: (key, element) => set((state) => ({
|
|
@@ -793,7 +801,13 @@ const usePartitionDataStore = create((set, get) => ({
|
|
|
793
801
|
[key]: element,
|
|
794
802
|
},
|
|
795
803
|
})),
|
|
796
|
-
|
|
804
|
+
deleteObstacles: (key) => set((state) => {
|
|
805
|
+
const newObstacles = { ...state.obstacles };
|
|
806
|
+
delete newObstacles[key];
|
|
807
|
+
return {
|
|
808
|
+
obstacles: newObstacles,
|
|
809
|
+
};
|
|
810
|
+
}),
|
|
797
811
|
// svg数据
|
|
798
812
|
svgElements: {},
|
|
799
813
|
addSvgElements: (key, element) => set((state) => ({
|
|
@@ -802,7 +816,13 @@ const usePartitionDataStore = create((set, get) => ({
|
|
|
802
816
|
[key]: element,
|
|
803
817
|
},
|
|
804
818
|
})),
|
|
805
|
-
|
|
819
|
+
deleteSvgElements: (key) => set((state) => {
|
|
820
|
+
const newSvgElements = { ...state.svgElements };
|
|
821
|
+
delete newSvgElements[key];
|
|
822
|
+
return {
|
|
823
|
+
svgElements: newSvgElements,
|
|
824
|
+
};
|
|
825
|
+
}),
|
|
806
826
|
}));
|
|
807
827
|
|
|
808
828
|
/**
|
|
@@ -3288,11 +3308,12 @@ var index = {
|
|
|
3288
3308
|
* 专门处理路径元素的渲染
|
|
3289
3309
|
*/
|
|
3290
3310
|
class ChannelLayer extends BaseLayer {
|
|
3291
|
-
constructor() {
|
|
3311
|
+
constructor(sn) {
|
|
3292
3312
|
super();
|
|
3293
3313
|
this.level = 1;
|
|
3294
3314
|
this.scale = 1;
|
|
3295
3315
|
this.type = LAYER_DEFAULT_TYPE.CHANNEL;
|
|
3316
|
+
this.sn = sn;
|
|
3296
3317
|
}
|
|
3297
3318
|
/**
|
|
3298
3319
|
* 获取元素
|
|
@@ -3325,7 +3346,10 @@ class ChannelLayer extends BaseLayer {
|
|
|
3325
3346
|
createExclusionClipPathDefinitions(svgGroup) {
|
|
3326
3347
|
// 获取所有分区边界数据
|
|
3327
3348
|
const subBoundaryBorder = usePartitionDataStore.getState().subBoundaryBorder;
|
|
3328
|
-
|
|
3349
|
+
const currentSubBoundaryBorder = subBoundaryBorder[this.sn];
|
|
3350
|
+
console.info('subBoundaryBorder===', subBoundaryBorder);
|
|
3351
|
+
console.info('currentSubBoundaryBorder===', currentSubBoundaryBorder);
|
|
3352
|
+
if (!currentSubBoundaryBorder || Object.keys(currentSubBoundaryBorder).length === 0) {
|
|
3329
3353
|
return {};
|
|
3330
3354
|
}
|
|
3331
3355
|
const clipPathIdsMap = {};
|
|
@@ -3338,7 +3362,7 @@ class ChannelLayer extends BaseLayer {
|
|
|
3338
3362
|
// 计算包含所有分区和通道的边界框
|
|
3339
3363
|
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
3340
3364
|
// 1. 先计算所有分区的边界,如果能拿到边界的svg的大小,就使用这个如果拿不到,就根据分区去计算
|
|
3341
|
-
const svg = document.getElementById(SVG_MAP_VIEW_ID);
|
|
3365
|
+
const svg = document.getElementById(`${this.sn}-${SVG_MAP_VIEW_ID}`);
|
|
3342
3366
|
if (svg && svg instanceof SVGSVGElement && svg.viewBox) {
|
|
3343
3367
|
const viewBox = svg.viewBox.baseVal;
|
|
3344
3368
|
minX = viewBox.x;
|
|
@@ -3347,8 +3371,8 @@ class ChannelLayer extends BaseLayer {
|
|
|
3347
3371
|
maxY = viewBox.y + viewBox.height;
|
|
3348
3372
|
}
|
|
3349
3373
|
else {
|
|
3350
|
-
for (const partitionId in
|
|
3351
|
-
const boundaryData =
|
|
3374
|
+
for (const partitionId in currentSubBoundaryBorder) {
|
|
3375
|
+
const boundaryData = currentSubBoundaryBorder[partitionId];
|
|
3352
3376
|
if (boundaryData && boundaryData.coordinates && boundaryData.coordinates.length > 0) {
|
|
3353
3377
|
for (const coord of boundaryData.coordinates) {
|
|
3354
3378
|
minX = Math.min(minX, coord[0]);
|
|
@@ -3360,7 +3384,7 @@ class ChannelLayer extends BaseLayer {
|
|
|
3360
3384
|
}
|
|
3361
3385
|
}
|
|
3362
3386
|
// 整理出clipPath路径
|
|
3363
|
-
const clipPathId =
|
|
3387
|
+
const clipPathId = `${this.sn}-channel-exclude-all`;
|
|
3364
3388
|
// 创建 clipPath
|
|
3365
3389
|
const clipPath = document.createElementNS('http://www.w3.org/2000/svg', 'clipPath');
|
|
3366
3390
|
clipPath.setAttribute('id', clipPathId);
|
|
@@ -3369,7 +3393,7 @@ class ChannelLayer extends BaseLayer {
|
|
|
3369
3393
|
// 外轮廓(顺时针)
|
|
3370
3394
|
let d = `M ${minX} ${minY} L ${maxX} ${minY} L ${maxX} ${maxY} L ${minX} ${maxY} Z`;
|
|
3371
3395
|
// 获取所有需要挖空的分区路径
|
|
3372
|
-
const partitionPaths = this.mergeOverlappingPartitions(
|
|
3396
|
+
const partitionPaths = this.mergeOverlappingPartitions(currentSubBoundaryBorder || {});
|
|
3373
3397
|
// 将所有分区路径追加到clipPath中(逆时针,形成挖空)
|
|
3374
3398
|
partitionPaths.forEach((partitionCoords) => {
|
|
3375
3399
|
if (partitionCoords.length >= 3) {
|
|
@@ -3495,12 +3519,12 @@ class ChannelLayer extends BaseLayer {
|
|
|
3495
3519
|
/**
|
|
3496
3520
|
* 智能合并重叠的分区,返回所有需要挖空的路径
|
|
3497
3521
|
*/
|
|
3498
|
-
mergeOverlappingPartitions(
|
|
3522
|
+
mergeOverlappingPartitions(currentSubBoundaryBorder) {
|
|
3499
3523
|
try {
|
|
3500
3524
|
// 将所有分区转换为polygon-clipping格式
|
|
3501
3525
|
const polygons = [];
|
|
3502
3526
|
const partitionIds = [];
|
|
3503
|
-
Object.entries(
|
|
3527
|
+
Object.entries(currentSubBoundaryBorder || {}).forEach(([partitionId, boundaryData]) => {
|
|
3504
3528
|
if (boundaryData?.coordinates && boundaryData.coordinates.length >= 3) {
|
|
3505
3529
|
// 确保坐标格式正确(去掉第三个z坐标)
|
|
3506
3530
|
const coords = boundaryData.coordinates.map((coord) => [coord[0], coord[1]]);
|
|
@@ -3585,7 +3609,7 @@ class ChannelLayer extends BaseLayer {
|
|
|
3585
3609
|
catch (error) {
|
|
3586
3610
|
console.error('polygon-clipping union failed:', error);
|
|
3587
3611
|
// 如果合并失败,返回原始分区
|
|
3588
|
-
return Object.values(
|
|
3612
|
+
return Object.values(currentSubBoundaryBorder)
|
|
3589
3613
|
.filter((boundaryData) => boundaryData?.coordinates && boundaryData.coordinates.length >= 3)
|
|
3590
3614
|
.map((boundaryData) => boundaryData.coordinates.map((coord) => [coord[0], coord[1]]));
|
|
3591
3615
|
}
|
|
@@ -3597,19 +3621,21 @@ class ChannelLayer extends BaseLayer {
|
|
|
3597
3621
|
* 专门处理路径元素的渲染
|
|
3598
3622
|
*/
|
|
3599
3623
|
class PathLayer extends BaseLayer {
|
|
3600
|
-
constructor() {
|
|
3624
|
+
constructor(sn) {
|
|
3601
3625
|
super();
|
|
3602
3626
|
this.level = 3;
|
|
3603
3627
|
this.scale = 1;
|
|
3604
3628
|
this.lineScale = 1;
|
|
3605
3629
|
this.boundaryPaths = {};
|
|
3606
3630
|
this.type = LAYER_DEFAULT_TYPE.PATH;
|
|
3631
|
+
this.sn = sn;
|
|
3607
3632
|
}
|
|
3608
3633
|
/**
|
|
3609
3634
|
* 为每个分区创建独立的 clipPath
|
|
3610
3635
|
*/
|
|
3611
3636
|
createPartitionClipPaths(svgGroup) {
|
|
3612
3637
|
const { subBoundaryBorder, obstacles, svgElements } = usePartitionDataStore.getState();
|
|
3638
|
+
const currentSubBoundaryBorder = subBoundaryBorder[this.sn];
|
|
3613
3639
|
// 确保 defs 元素存在
|
|
3614
3640
|
let defs = svgGroup.querySelector('defs');
|
|
3615
3641
|
if (!defs) {
|
|
@@ -3618,9 +3644,9 @@ class PathLayer extends BaseLayer {
|
|
|
3618
3644
|
}
|
|
3619
3645
|
const clipPathIds = {};
|
|
3620
3646
|
// 为每个分区创建独立的 clipPath
|
|
3621
|
-
Object.keys(
|
|
3622
|
-
const partitionData =
|
|
3623
|
-
const clipPathId = `clip-partition-${partitionId}`;
|
|
3647
|
+
Object.keys(currentSubBoundaryBorder || {}).forEach((partitionId) => {
|
|
3648
|
+
const partitionData = currentSubBoundaryBorder[partitionId];
|
|
3649
|
+
const clipPathId = `clip-partition-${this.sn}-${partitionId}`;
|
|
3624
3650
|
// 如果已存在,先移除
|
|
3625
3651
|
const existing = defs.querySelector(`#${clipPathId}`);
|
|
3626
3652
|
if (existing)
|
|
@@ -3637,7 +3663,8 @@ class PathLayer extends BaseLayer {
|
|
|
3637
3663
|
d += ' Z ';
|
|
3638
3664
|
}
|
|
3639
3665
|
// 2. 所有禁区(逆时针)- 禁区影响所有分区
|
|
3640
|
-
|
|
3666
|
+
const currentObstacles = obstacles[this.sn];
|
|
3667
|
+
Object.values(currentObstacles || {}).forEach((item) => {
|
|
3641
3668
|
const obstacleCoords = item.coordinates;
|
|
3642
3669
|
if (obstacleCoords.length >= 3) {
|
|
3643
3670
|
d += `M ${obstacleCoords[obstacleCoords.length - 1][0]} ${obstacleCoords[obstacleCoords.length - 1][1]}`;
|
|
@@ -3648,7 +3675,8 @@ class PathLayer extends BaseLayer {
|
|
|
3648
3675
|
}
|
|
3649
3676
|
});
|
|
3650
3677
|
// 3. 所有 svgElements(逆时针)- SVG元素影响所有分区
|
|
3651
|
-
|
|
3678
|
+
const currentSvgElements = svgElements[this.sn];
|
|
3679
|
+
Object.values(currentSvgElements || {}).forEach((svgPath) => {
|
|
3652
3680
|
const svgPathString = svgPath?.metadata?.svg;
|
|
3653
3681
|
if (svgPathString && typeof svgPathString === 'string' && svgPathString.trim()) {
|
|
3654
3682
|
// 处理转义字符
|
|
@@ -3743,7 +3771,7 @@ class PathLayer extends BaseLayer {
|
|
|
3743
3771
|
lineColor = style.lineColor || '#000000';
|
|
3744
3772
|
}
|
|
3745
3773
|
// 按分区+类型+样式分组存储
|
|
3746
|
-
const groupKey = `${id}-${lineColor}-${style.lineWidth || 1}`;
|
|
3774
|
+
const groupKey = `${id}-${lineColor}-${style.lineWidth || 1}-${this.sn}`;
|
|
3747
3775
|
if (!partitionTypeGroups.has(groupKey)) {
|
|
3748
3776
|
partitionTypeGroups.set(groupKey, {
|
|
3749
3777
|
pathData: [],
|
|
@@ -3895,9 +3923,7 @@ class BoundaryLayer extends BaseLayer {
|
|
|
3895
3923
|
createBoundaryFill(svgGroup, coordinates, style) {
|
|
3896
3924
|
const polygon = document.createElementNS('http://www.w3.org/2000/svg', 'polygon');
|
|
3897
3925
|
// 构建点集合,使用整数坐标(只取x,y坐标)
|
|
3898
|
-
const points = coordinates
|
|
3899
|
-
.map((coord) => `${coord[0]},${coord[1]}`)
|
|
3900
|
-
.join(' ');
|
|
3926
|
+
const points = coordinates.map((coord) => `${coord[0]},${coord[1]}`).join(' ');
|
|
3901
3927
|
const fillColor = style.fillColor;
|
|
3902
3928
|
polygon.setAttribute('points', points);
|
|
3903
3929
|
polygon.setAttribute('fill', fillColor);
|
|
@@ -3941,9 +3967,7 @@ class ObstacleLayer extends BaseLayer {
|
|
|
3941
3967
|
return;
|
|
3942
3968
|
const polygon = document.createElementNS('http://www.w3.org/2000/svg', 'polygon');
|
|
3943
3969
|
// 构建点集合,使用整数坐标
|
|
3944
|
-
const points = coordinates
|
|
3945
|
-
.map((coord) => `${coord[0]},${coord[1]}`)
|
|
3946
|
-
.join(' ');
|
|
3970
|
+
const points = coordinates.map((coord) => `${coord[0]},${coord[1]}`).join(' ');
|
|
3947
3971
|
polygon.setAttribute('points', points);
|
|
3948
3972
|
polygon.setAttribute('fill', style.fillColor || 'rgba(220, 53, 69, 0.2)');
|
|
3949
3973
|
polygon.setAttribute('stroke', style.lineColor || '#dc3545');
|
|
@@ -4223,9 +4247,7 @@ class VisionOffLayer extends BaseLayer {
|
|
|
4223
4247
|
return;
|
|
4224
4248
|
const polygon = document.createElementNS('http://www.w3.org/2000/svg', 'polygon');
|
|
4225
4249
|
// 构建点集合,使用整数坐标
|
|
4226
|
-
const points = coordinates
|
|
4227
|
-
.map((coord) => `${coord[0]},${coord[1]}`)
|
|
4228
|
-
.join(' ');
|
|
4250
|
+
const points = coordinates.map((coord) => `${coord[0]},${coord[1]}`).join(' ');
|
|
4229
4251
|
const fillColor = style.fillColor || 'rgba(0, 255, 0, 0.4)';
|
|
4230
4252
|
polygon.setAttribute('points', points);
|
|
4231
4253
|
polygon.setAttribute('fill', fillColor);
|
|
@@ -7923,7 +7945,7 @@ class BoundaryBorderLayer extends BaseLayer {
|
|
|
7923
7945
|
*/
|
|
7924
7946
|
setMowingBoundarys(mowingBoundarys) {
|
|
7925
7947
|
if (!mowingBoundarys) {
|
|
7926
|
-
this.mowingBoundarys = this.elements?.map(item => item?.originalData?.id);
|
|
7948
|
+
this.mowingBoundarys = this.elements?.map((item) => item?.originalData?.id);
|
|
7927
7949
|
}
|
|
7928
7950
|
else {
|
|
7929
7951
|
this.mowingBoundarys = mowingBoundarys;
|
|
@@ -8243,14 +8265,15 @@ class AntennaLayer extends BaseLayer {
|
|
|
8243
8265
|
* 使用具体的图层类来处理不同类型的渲染
|
|
8244
8266
|
*/
|
|
8245
8267
|
class DrawLayer extends BaseLayer {
|
|
8246
|
-
constructor() {
|
|
8268
|
+
constructor(sn) {
|
|
8247
8269
|
super();
|
|
8270
|
+
this.sn = sn;
|
|
8248
8271
|
// 初始化各种具体图层
|
|
8249
8272
|
this.antennaLayer = new AntennaLayer();
|
|
8250
8273
|
// 通道图层
|
|
8251
|
-
this.channelLayer = new ChannelLayer();
|
|
8274
|
+
this.channelLayer = new ChannelLayer(sn);
|
|
8252
8275
|
// 路径图层
|
|
8253
|
-
this.pathLayer = new PathLayer();
|
|
8276
|
+
this.pathLayer = new PathLayer(sn);
|
|
8254
8277
|
// 边界图层
|
|
8255
8278
|
this.boundaryLayer = new BoundaryLayer();
|
|
8256
8279
|
// 边界边框图层
|
|
@@ -8673,8 +8696,9 @@ class MapDataProcessor {
|
|
|
8673
8696
|
/**
|
|
8674
8697
|
* 处理地图数据,返回绘制图层
|
|
8675
8698
|
*/
|
|
8676
|
-
static processMapData(mapData, mapConfig) {
|
|
8699
|
+
static processMapData(sn, mapData, mapConfig) {
|
|
8677
8700
|
this.mapConfig = mapConfig;
|
|
8701
|
+
this.sn = sn;
|
|
8678
8702
|
// 收集所有地图元素
|
|
8679
8703
|
const allElements = [];
|
|
8680
8704
|
// 处理子地图中的元素
|
|
@@ -8754,6 +8778,9 @@ class MapDataProcessor {
|
|
|
8754
8778
|
*/
|
|
8755
8779
|
static processMapElements(elements) {
|
|
8756
8780
|
const result = [];
|
|
8781
|
+
let subBoundaryBorderObj = {};
|
|
8782
|
+
let obstaclesObj = {};
|
|
8783
|
+
let svgElementsObj = {};
|
|
8757
8784
|
for (const element of elements) {
|
|
8758
8785
|
try {
|
|
8759
8786
|
// 检查必要的基础字段
|
|
@@ -8772,10 +8799,18 @@ class MapDataProcessor {
|
|
|
8772
8799
|
result.push(boundaryBorderElement);
|
|
8773
8800
|
// 将边界边框存储到 store 中,以分区ID为key
|
|
8774
8801
|
if (element.id) {
|
|
8802
|
+
subBoundaryBorderObj = {
|
|
8803
|
+
...subBoundaryBorderObj,
|
|
8804
|
+
[`${element.id.toString()}`]: {
|
|
8805
|
+
...boundaryBorderElement,
|
|
8806
|
+
},
|
|
8807
|
+
};
|
|
8775
8808
|
const { addSubBoundaryBorder } = usePartitionDataStore.getState();
|
|
8776
|
-
addSubBoundaryBorder(
|
|
8777
|
-
|
|
8778
|
-
}
|
|
8809
|
+
addSubBoundaryBorder(`${this.sn}`, subBoundaryBorderObj);
|
|
8810
|
+
// const { addSubBoundaryBorder } = usePartitionDataStore.getState();
|
|
8811
|
+
// addSubBoundaryBorder(`${element.id.toString()}`, {
|
|
8812
|
+
// ...boundaryBorderElement,
|
|
8813
|
+
// });
|
|
8779
8814
|
}
|
|
8780
8815
|
}
|
|
8781
8816
|
}
|
|
@@ -8791,10 +8826,15 @@ class MapDataProcessor {
|
|
|
8791
8826
|
const obstacleElement = ObstacleDataBuilder.fromMapElement(mapElement, this.mapConfig.obstacle);
|
|
8792
8827
|
if (obstacleElement) {
|
|
8793
8828
|
result.push(obstacleElement);
|
|
8794
|
-
|
|
8795
|
-
addObstacles(`obstacle-${obstacleElement.originalData.id}`, {
|
|
8829
|
+
obstaclesObj[`obstacle-${obstacleElement.originalData.id}`] = {
|
|
8796
8830
|
...obstacleElement,
|
|
8797
|
-
}
|
|
8831
|
+
};
|
|
8832
|
+
const { addObstacles } = usePartitionDataStore.getState();
|
|
8833
|
+
addObstacles(`${this.sn}`, obstaclesObj);
|
|
8834
|
+
// const { addObstacles } = usePartitionDataStore.getState();
|
|
8835
|
+
// addObstacles(`obstacle-${obstacleElement.originalData.id}`, {
|
|
8836
|
+
// ...obstacleElement,
|
|
8837
|
+
// });
|
|
8798
8838
|
}
|
|
8799
8839
|
}
|
|
8800
8840
|
catch (error) {
|
|
@@ -8858,10 +8898,15 @@ class MapDataProcessor {
|
|
|
8858
8898
|
const svgElement = SvgElementDataBuilder.fromMapElement(mapElement, this.mapConfig.doodle);
|
|
8859
8899
|
if (svgElement) {
|
|
8860
8900
|
result.push(svgElement);
|
|
8861
|
-
|
|
8862
|
-
addSvgElements(`time-limit-obstacle-${svgElement.originalData.id}`, {
|
|
8901
|
+
svgElementsObj[`time-limit-obstacle-${svgElement.originalData.id}`] = {
|
|
8863
8902
|
...svgElement,
|
|
8864
|
-
}
|
|
8903
|
+
};
|
|
8904
|
+
const { addSvgElements } = usePartitionDataStore.getState();
|
|
8905
|
+
addSvgElements(`${this.sn}`, svgElementsObj);
|
|
8906
|
+
// const { addSvgElements } = usePartitionDataStore.getState();
|
|
8907
|
+
// addSvgElements(`time-limit-obstacle-${svgElement.originalData.id}`, {
|
|
8908
|
+
// ...svgElement,
|
|
8909
|
+
// });
|
|
8865
8910
|
}
|
|
8866
8911
|
}
|
|
8867
8912
|
// 如果有points数据,按传统方式绘制
|
|
@@ -8873,10 +8918,15 @@ class MapDataProcessor {
|
|
|
8873
8918
|
const polygonElement = ObstacleDataBuilder.createTimeLimitObstacle(mapElement, this.mapConfig.obstacle);
|
|
8874
8919
|
if (polygonElement) {
|
|
8875
8920
|
result.push(polygonElement);
|
|
8876
|
-
|
|
8877
|
-
addObstacles(`time-limit-obstacle-${polygonElement.originalData.id}`, {
|
|
8921
|
+
svgElementsObj[`time-limit-obstacle-${polygonElement.originalData.id}`] = {
|
|
8878
8922
|
...polygonElement,
|
|
8879
|
-
}
|
|
8923
|
+
};
|
|
8924
|
+
const { addSvgElements } = usePartitionDataStore.getState();
|
|
8925
|
+
addSvgElements(`${this.sn}`, svgElementsObj);
|
|
8926
|
+
// const { addObstacles } = usePartitionDataStore.getState();
|
|
8927
|
+
// addObstacles(`time-limit-obstacle-${polygonElement.originalData.id}`, {
|
|
8928
|
+
// ...polygonElement,
|
|
8929
|
+
// });
|
|
8880
8930
|
}
|
|
8881
8931
|
}
|
|
8882
8932
|
}
|
|
@@ -10593,24 +10643,29 @@ function isMobileDevice() {
|
|
|
10593
10643
|
// 记录割草状态,状态变更的时候,变量不触发重新渲染
|
|
10594
10644
|
const useCurrentMowingDataStore = create((set) => ({
|
|
10595
10645
|
// 当前进度数据返回的割草状态是否为在割草
|
|
10596
|
-
processStateIsMowing:
|
|
10597
|
-
updateProcessStateIsMowing: (isMowing) => set({ processStateIsMowing: isMowing }),
|
|
10598
|
-
resetProcessStateIsMowing: () => set({ processStateIsMowing: false }),
|
|
10646
|
+
processStateIsMowing: {},
|
|
10647
|
+
updateProcessStateIsMowing: (sn, isMowing) => set((state) => ({ processStateIsMowing: { ...state.processStateIsMowing, [sn]: isMowing } })),
|
|
10648
|
+
resetProcessStateIsMowing: (key) => set((state) => ({ processStateIsMowing: { ...state.processStateIsMowing, [key]: false } })),
|
|
10599
10649
|
// 当前割草的分区id
|
|
10600
|
-
currentMowingPartitionId:
|
|
10601
|
-
updateCurrentMowingPartitionId: (partitionId) => set(
|
|
10602
|
-
|
|
10650
|
+
currentMowingPartitionId: {},
|
|
10651
|
+
updateCurrentMowingPartitionId: (sn, partitionId) => set((state) => ({
|
|
10652
|
+
currentMowingPartitionId: { ...state.currentMowingPartitionId, [sn]: partitionId },
|
|
10653
|
+
})),
|
|
10654
|
+
resetCurrentMowingPartitionId: (key) => set((state) => ({
|
|
10655
|
+
currentMowingPartitionId: { ...state.currentMowingPartitionId, [key]: '' },
|
|
10656
|
+
})),
|
|
10603
10657
|
}));
|
|
10604
10658
|
|
|
10605
10659
|
// Google Maps 叠加层类 - 带编辑功能
|
|
10606
10660
|
class MowerMapOverlay {
|
|
10607
|
-
constructor(bounds, mapData, partitionBoundary, mowerPositionConfig, modelType, pathData, isEditMode = false, unitType = UnitsType.Imperial, language = 'en', mapConfig = {}, antennaConfig = {}, mowPartitionData = null, defaultTransform, onMapLoad, onPathLoad, dragCallbacks) {
|
|
10661
|
+
constructor(sn, bounds, mapData, partitionBoundary, mowerPositionConfig, modelType, pathData, isEditMode = false, unitType = UnitsType.Imperial, language = 'en', mapConfig = {}, antennaConfig = {}, mowPartitionData = null, defaultTransform, onMapLoad, onPathLoad, dragCallbacks) {
|
|
10608
10662
|
this.div = null;
|
|
10609
10663
|
this.svgMapView = null;
|
|
10610
10664
|
this.offscreenContainer = null;
|
|
10611
10665
|
this.overlayView = null;
|
|
10612
10666
|
this.defaultTransform = { x: 0, y: 0, rotation: 0 };
|
|
10613
10667
|
this.hasEdger = false;
|
|
10668
|
+
this.sn = '';
|
|
10614
10669
|
// boundary数据
|
|
10615
10670
|
this.boundaryData = [];
|
|
10616
10671
|
// 边界标签管理器
|
|
@@ -10648,6 +10703,7 @@ class MowerMapOverlay {
|
|
|
10648
10703
|
leading: true,
|
|
10649
10704
|
trailing: false,
|
|
10650
10705
|
});
|
|
10706
|
+
this.sn = sn;
|
|
10651
10707
|
this.bounds = bounds;
|
|
10652
10708
|
this.mapData = mapData;
|
|
10653
10709
|
this.partitionBoundary = partitionBoundary;
|
|
@@ -11459,7 +11515,7 @@ class MowerMapOverlay {
|
|
|
11459
11515
|
return;
|
|
11460
11516
|
try {
|
|
11461
11517
|
// 创建SvgMapView实例
|
|
11462
|
-
this.svgMapView = new SvgMapView(this.offscreenContainer, 800, 600);
|
|
11518
|
+
this.svgMapView = new SvgMapView(this.sn, this.offscreenContainer, 800, 600);
|
|
11463
11519
|
// 加载地图数据
|
|
11464
11520
|
this.loadMapData();
|
|
11465
11521
|
// 加载路径数据
|
|
@@ -11488,12 +11544,12 @@ class MowerMapOverlay {
|
|
|
11488
11544
|
return;
|
|
11489
11545
|
try {
|
|
11490
11546
|
// 使用现有的MapDataProcessor处理地图数据
|
|
11491
|
-
const elements = MapDataProcessor.processMapData(this.mapData, this.mapConfig);
|
|
11547
|
+
const elements = MapDataProcessor.processMapData(this.sn, this.mapData, this.mapConfig);
|
|
11492
11548
|
// 分离充电桩和天线元素,其他元素添加到SVG图层
|
|
11493
11549
|
const svgElements = elements.filter((element) => element.type !== 'charging_pile' && element.type !== 'antenna');
|
|
11494
11550
|
const chargingPileElements = elements.filter((element) => element.type === 'charging_pile');
|
|
11495
11551
|
// 处理SVG图层元素
|
|
11496
|
-
const drawLayer = new DrawLayer();
|
|
11552
|
+
const drawLayer = new DrawLayer(this.sn);
|
|
11497
11553
|
drawLayer.addElements(svgElements);
|
|
11498
11554
|
// 处理天线数据
|
|
11499
11555
|
let antennaElements = [];
|
|
@@ -11562,9 +11618,9 @@ class MowerMapOverlay {
|
|
|
11562
11618
|
return pathElement;
|
|
11563
11619
|
}
|
|
11564
11620
|
});
|
|
11565
|
-
const pathLayer = new PathLayer();
|
|
11621
|
+
const pathLayer = new PathLayer(this.sn);
|
|
11566
11622
|
pathLayer.addElements(newPathElements);
|
|
11567
|
-
// 添加图层到SvgMapView
|
|
11623
|
+
// // 添加图层到SvgMapView
|
|
11568
11624
|
this.svgMapView.removeLayerByType(LAYER_DEFAULT_TYPE.PATH);
|
|
11569
11625
|
this.svgMapView.addLayer(pathLayer);
|
|
11570
11626
|
this.svgMapView.renderLayer(LAYER_DEFAULT_TYPE.PATH);
|
|
@@ -11583,8 +11639,10 @@ class MowerMapOverlay {
|
|
|
11583
11639
|
updatePathDataByMowingPosition(position) {
|
|
11584
11640
|
// 找到当前position所在的分区id,将该点更新到pathData中
|
|
11585
11641
|
// 先查找当前的分区id是多少,然后确定当前的点是否在当前分区id中,如果不在,则重新获取分区id并重新设置
|
|
11586
|
-
const
|
|
11587
|
-
const
|
|
11642
|
+
const partitionIdMap = useCurrentMowingDataStore.getState().currentMowingPartitionId;
|
|
11643
|
+
const processStateIsMowingMap = useCurrentMowingDataStore.getState().processStateIsMowing;
|
|
11644
|
+
const currentPartitionId = partitionIdMap[this.sn];
|
|
11645
|
+
const processStateIsMowing = processStateIsMowingMap[this.sn];
|
|
11588
11646
|
if (currentPartitionId && this.pathData?.[currentPartitionId]) {
|
|
11589
11647
|
const currentPathData = this.pathData[currentPartitionId];
|
|
11590
11648
|
this.pathData[currentPartitionId] = {
|
|
@@ -11889,7 +11947,9 @@ const getValidGpsBounds = (mapData, rotation = 0) => {
|
|
|
11889
11947
|
// 默认配置
|
|
11890
11948
|
const defaultMapConfig = DEFAULT_STYLES;
|
|
11891
11949
|
// 地图渲染器组件
|
|
11892
|
-
const MowerMapRenderer = forwardRef(({
|
|
11950
|
+
const MowerMapRenderer = forwardRef(({
|
|
11951
|
+
// 唯一的可以标识一个割草机的id
|
|
11952
|
+
sn, edger = false, unitType = UnitsType.Imperial, language = 'en', mapConfig, modelType, mapRef, mapJson, pathJson, realTimeData, antennaConfig, onMapLoad, onPathLoad, onError, className, style, googleMapInstance, isEditMode = false, dragCallbacks, defaultTransform, debug = false, }, ref) => {
|
|
11893
11953
|
const [elementCount, setElementCount] = useState(0);
|
|
11894
11954
|
const [pathCount, setPathCount] = useState(0);
|
|
11895
11955
|
const [currentError, setCurrentError] = useState(null);
|
|
@@ -11897,10 +11957,9 @@ const MowerMapRenderer = forwardRef(({ edger = false, unitType = UnitsType.Imper
|
|
|
11897
11957
|
// const mapRef = useMap();
|
|
11898
11958
|
const [isGoogleMapsReady, setIsGoogleMapsReady] = useState(false);
|
|
11899
11959
|
const [hasInitializedBounds, setHasInitializedBounds] = useState(false);
|
|
11900
|
-
const {
|
|
11901
|
-
const { resetCurrentMowingPartitionId } = useCurrentMowingDataStore();
|
|
11960
|
+
const { deleteSubBoundaryBorder, deleteObstacles, deleteSvgElements } = usePartitionDataStore();
|
|
11902
11961
|
const currentProcessMowingStatusRef = useRef(false);
|
|
11903
|
-
const { updateProcessStateIsMowing, processStateIsMowing, updateCurrentMowingPartitionId, currentMowingPartitionId, } = useCurrentMowingDataStore();
|
|
11962
|
+
const { updateProcessStateIsMowing, processStateIsMowing, updateCurrentMowingPartitionId, currentMowingPartitionId, resetCurrentMowingPartitionId, } = useCurrentMowingDataStore();
|
|
11904
11963
|
const [mowPartitionData, setMowPartitionData] = useState(null);
|
|
11905
11964
|
// Debug相关状态
|
|
11906
11965
|
const [debugInfo, setDebugInfo] = useState({});
|
|
@@ -12026,7 +12085,7 @@ const MowerMapRenderer = forwardRef(({ edger = false, unitType = UnitsType.Imper
|
|
|
12026
12085
|
overlayRef.current = null;
|
|
12027
12086
|
}
|
|
12028
12087
|
// 创建叠加层
|
|
12029
|
-
const overlay = new MowerMapOverlay(googleBounds, mapJson, partitionBoundary, mowerPositionData, modelType, pathJson || {}, isEditMode, unitType, language, mergedMapConfig, mergedAntennaConfig, null, defaultTransform, (count) => {
|
|
12088
|
+
const overlay = new MowerMapOverlay(sn, googleBounds, mapJson, partitionBoundary, mowerPositionData, modelType, pathJson || {}, isEditMode, unitType, language, mergedMapConfig, mergedAntennaConfig, null, defaultTransform, (count) => {
|
|
12030
12089
|
setElementCount(count);
|
|
12031
12090
|
onMapLoad?.(count);
|
|
12032
12091
|
}, (count) => {
|
|
@@ -12049,7 +12108,7 @@ const MowerMapRenderer = forwardRef(({ edger = false, unitType = UnitsType.Imper
|
|
|
12049
12108
|
}
|
|
12050
12109
|
};
|
|
12051
12110
|
const resetInCharginPie = useCallback(() => {
|
|
12052
|
-
const elements = MapDataProcessor.processMapData(mapJson, mergedMapConfig);
|
|
12111
|
+
const elements = MapDataProcessor.processMapData(sn, mapJson, mergedMapConfig);
|
|
12053
12112
|
const chargingPiles = elements.find((element) => element.type === 'charging_pile');
|
|
12054
12113
|
if (!overlayRef.current)
|
|
12055
12114
|
return;
|
|
@@ -12066,18 +12125,22 @@ const MowerMapRenderer = forwardRef(({ edger = false, unitType = UnitsType.Imper
|
|
|
12066
12125
|
initializeGoogleMapsOverlay();
|
|
12067
12126
|
// 清理函数
|
|
12068
12127
|
return () => {
|
|
12069
|
-
clearSubBoundaryBorder();
|
|
12070
|
-
clearObstacles();
|
|
12071
|
-
clearSvgElements();
|
|
12072
|
-
resetCurrentMowingPartitionId();
|
|
12073
|
-
updateProcessStateIsMowing(false);
|
|
12074
|
-
currentProcessMowingStatusRef.current = false;
|
|
12075
12128
|
if (overlayRef.current) {
|
|
12076
12129
|
overlayRef.current.setMap(null);
|
|
12077
12130
|
overlayRef.current = null;
|
|
12078
12131
|
}
|
|
12079
12132
|
};
|
|
12080
|
-
}, [mapJson, pathJson, mergedMapConfig, mergedAntennaConfig]);
|
|
12133
|
+
}, [sn, mapJson, pathJson, mergedMapConfig, mergedAntennaConfig]);
|
|
12134
|
+
useEffect(() => {
|
|
12135
|
+
return () => {
|
|
12136
|
+
deleteSubBoundaryBorder(sn);
|
|
12137
|
+
deleteObstacles(sn);
|
|
12138
|
+
deleteSvgElements(sn);
|
|
12139
|
+
resetCurrentMowingPartitionId(sn);
|
|
12140
|
+
updateProcessStateIsMowing(sn, false);
|
|
12141
|
+
currentProcessMowingStatusRef.current = false;
|
|
12142
|
+
};
|
|
12143
|
+
}, []);
|
|
12081
12144
|
// 监听编辑模式变化
|
|
12082
12145
|
useEffect(() => {
|
|
12083
12146
|
if (overlayRef.current) {
|
|
@@ -12093,7 +12156,7 @@ const MowerMapRenderer = forwardRef(({ edger = false, unitType = UnitsType.Imper
|
|
|
12093
12156
|
useEffect(() => {
|
|
12094
12157
|
if (!mapJson)
|
|
12095
12158
|
return;
|
|
12096
|
-
const elements = MapDataProcessor.processMapData(mapJson, mergedMapConfig);
|
|
12159
|
+
const elements = MapDataProcessor.processMapData(sn, mapJson, mergedMapConfig);
|
|
12097
12160
|
const chargingPiles = elements.find((element) => element.type === 'charging_pile');
|
|
12098
12161
|
if (!mowerPositionData || !overlayRef.current)
|
|
12099
12162
|
return;
|
|
@@ -12304,13 +12367,13 @@ const MowerMapRenderer = forwardRef(({ edger = false, unitType = UnitsType.Imper
|
|
|
12304
12367
|
if (realTimeData.length > 1) {
|
|
12305
12368
|
const { pathData, isMowing, currentMowingPartition } = handleMultipleRealTimeData({
|
|
12306
12369
|
realTimeData,
|
|
12307
|
-
isMowing: processStateIsMowing,
|
|
12370
|
+
isMowing: processStateIsMowing[sn],
|
|
12308
12371
|
pathData: pathJson,
|
|
12309
|
-
currentMowingPartition: currentMowingPartitionId,
|
|
12372
|
+
currentMowingPartition: currentMowingPartitionId[sn],
|
|
12310
12373
|
});
|
|
12311
|
-
updateProcessStateIsMowing(isMowing);
|
|
12312
|
-
if (currentMowingPartition !== currentMowingPartitionId) {
|
|
12313
|
-
updateCurrentMowingPartitionId(currentMowingPartition);
|
|
12374
|
+
updateProcessStateIsMowing(sn, isMowing);
|
|
12375
|
+
if (currentMowingPartition !== currentMowingPartitionId[sn]) {
|
|
12376
|
+
updateCurrentMowingPartitionId(sn, currentMowingPartition);
|
|
12314
12377
|
}
|
|
12315
12378
|
if (pathData) {
|
|
12316
12379
|
overlayRef.current.updatePathData(pathData, curMowPartitionData);
|
|
@@ -12320,13 +12383,13 @@ const MowerMapRenderer = forwardRef(({ edger = false, unitType = UnitsType.Imper
|
|
|
12320
12383
|
else {
|
|
12321
12384
|
const { isMowing, pathData, currentMowingPartition } = getProcessMowingDataFromRealTimeData({
|
|
12322
12385
|
realTimeData,
|
|
12323
|
-
isMowing: processStateIsMowing,
|
|
12386
|
+
isMowing: processStateIsMowing[sn],
|
|
12324
12387
|
pathData: pathJson,
|
|
12325
|
-
currentMowingPartition: currentMowingPartitionId,
|
|
12388
|
+
currentMowingPartition: currentMowingPartitionId[sn],
|
|
12326
12389
|
});
|
|
12327
|
-
updateProcessStateIsMowing(isMowing);
|
|
12328
|
-
if (currentMowingPartition !== currentMowingPartitionId) {
|
|
12329
|
-
updateCurrentMowingPartitionId(currentMowingPartition);
|
|
12390
|
+
updateProcessStateIsMowing(sn, isMowing);
|
|
12391
|
+
if (currentMowingPartition !== currentMowingPartitionId[sn]) {
|
|
12392
|
+
updateCurrentMowingPartitionId(sn, currentMowingPartition);
|
|
12330
12393
|
}
|
|
12331
12394
|
overlayRef.current.updatePathData(pathData, curMowPartitionData);
|
|
12332
12395
|
// 更新进度数据
|