@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.js CHANGED
@@ -138,7 +138,7 @@ const SVG_MAP_VIEW_ID = 'fleet-maps-svg-map-view';
138
138
  * 使用真正的矢量SVG渲染替代Canvas位图渲染
139
139
  */
140
140
  class SvgMapView {
141
- constructor(containerElement, width = 800, height = 600) {
141
+ constructor(sn, containerElement, width = 800, height = 600) {
142
142
  // 图层管理
143
143
  this.layers = [];
144
144
  // 简单变换参数
@@ -151,6 +151,7 @@ class SvgMapView {
151
151
  this.isDragging = false;
152
152
  this.lastMouseX = 0;
153
153
  this.lastMouseY = 0;
154
+ this.sn = sn;
154
155
  this.container = containerElement;
155
156
  // 创建SVG元素
156
157
  this.svg = this.createSVGElement();
@@ -188,7 +189,7 @@ class SvgMapView {
188
189
  this.svg.setAttribute('shape-rendering', 'geometricPrecision');
189
190
  this.svg.setAttribute('text-rendering', 'geometricPrecision');
190
191
  this.svg.setAttribute('image-rendering', 'optimizeQuality');
191
- this.svg.setAttribute('id', SVG_MAP_VIEW_ID);
192
+ this.svg.setAttribute('id', `${this.sn}-${SVG_MAP_VIEW_ID}`);
192
193
  }
193
194
  /**
194
195
  * 创建SVG组元素
@@ -643,6 +644,7 @@ class BaseLayer {
643
644
  this.needsRedraw = true;
644
645
  this.mapView = null;
645
646
  this.type = '';
647
+ this.sn = '';
646
648
  this.level = 0; // 中等层级
647
649
  }
648
650
  // ==================== 基础属性方法 ====================
@@ -782,11 +784,17 @@ const usePartitionDataStore = create((set, get) => ({
782
784
  addSubBoundaryBorder: (key, element) => set((state) => ({
783
785
  subBoundaryBorder: {
784
786
  ...state.subBoundaryBorder,
785
- [key]: element,
787
+ [key]: { ...element },
786
788
  },
787
789
  })),
788
790
  // 清空所有数据
789
- clearSubBoundaryBorder: () => set({ subBoundaryBorder: {} }),
791
+ deleteSubBoundaryBorder: (key) => set((state) => {
792
+ const newSubBoundaryBorder = { ...state.subBoundaryBorder };
793
+ delete newSubBoundaryBorder[key];
794
+ return {
795
+ subBoundaryBorder: newSubBoundaryBorder,
796
+ };
797
+ }),
790
798
  // 障碍物
791
799
  obstacles: {},
792
800
  addObstacles: (key, element) => set((state) => ({
@@ -795,7 +803,13 @@ const usePartitionDataStore = create((set, get) => ({
795
803
  [key]: element,
796
804
  },
797
805
  })),
798
- clearObstacles: () => set({ obstacles: {} }),
806
+ deleteObstacles: (key) => set((state) => {
807
+ const newObstacles = { ...state.obstacles };
808
+ delete newObstacles[key];
809
+ return {
810
+ obstacles: newObstacles,
811
+ };
812
+ }),
799
813
  // svg数据
800
814
  svgElements: {},
801
815
  addSvgElements: (key, element) => set((state) => ({
@@ -804,7 +818,13 @@ const usePartitionDataStore = create((set, get) => ({
804
818
  [key]: element,
805
819
  },
806
820
  })),
807
- clearSvgElements: () => set({ svgElements: {} }),
821
+ deleteSvgElements: (key) => set((state) => {
822
+ const newSvgElements = { ...state.svgElements };
823
+ delete newSvgElements[key];
824
+ return {
825
+ svgElements: newSvgElements,
826
+ };
827
+ }),
808
828
  }));
809
829
 
810
830
  /**
@@ -3290,11 +3310,12 @@ var index = {
3290
3310
  * 专门处理路径元素的渲染
3291
3311
  */
3292
3312
  class ChannelLayer extends BaseLayer {
3293
- constructor() {
3313
+ constructor(sn) {
3294
3314
  super();
3295
3315
  this.level = 1;
3296
3316
  this.scale = 1;
3297
3317
  this.type = LAYER_DEFAULT_TYPE.CHANNEL;
3318
+ this.sn = sn;
3298
3319
  }
3299
3320
  /**
3300
3321
  * 获取元素
@@ -3327,7 +3348,10 @@ class ChannelLayer extends BaseLayer {
3327
3348
  createExclusionClipPathDefinitions(svgGroup) {
3328
3349
  // 获取所有分区边界数据
3329
3350
  const subBoundaryBorder = usePartitionDataStore.getState().subBoundaryBorder;
3330
- if (!subBoundaryBorder || Object.keys(subBoundaryBorder).length === 0) {
3351
+ const currentSubBoundaryBorder = subBoundaryBorder[this.sn];
3352
+ console.info('subBoundaryBorder===', subBoundaryBorder);
3353
+ console.info('currentSubBoundaryBorder===', currentSubBoundaryBorder);
3354
+ if (!currentSubBoundaryBorder || Object.keys(currentSubBoundaryBorder).length === 0) {
3331
3355
  return {};
3332
3356
  }
3333
3357
  const clipPathIdsMap = {};
@@ -3340,7 +3364,7 @@ class ChannelLayer extends BaseLayer {
3340
3364
  // 计算包含所有分区和通道的边界框
3341
3365
  let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
3342
3366
  // 1. 先计算所有分区的边界,如果能拿到边界的svg的大小,就使用这个如果拿不到,就根据分区去计算
3343
- const svg = document.getElementById(SVG_MAP_VIEW_ID);
3367
+ const svg = document.getElementById(`${this.sn}-${SVG_MAP_VIEW_ID}`);
3344
3368
  if (svg && svg instanceof SVGSVGElement && svg.viewBox) {
3345
3369
  const viewBox = svg.viewBox.baseVal;
3346
3370
  minX = viewBox.x;
@@ -3349,8 +3373,8 @@ class ChannelLayer extends BaseLayer {
3349
3373
  maxY = viewBox.y + viewBox.height;
3350
3374
  }
3351
3375
  else {
3352
- for (const partitionId in subBoundaryBorder) {
3353
- const boundaryData = subBoundaryBorder[partitionId];
3376
+ for (const partitionId in currentSubBoundaryBorder) {
3377
+ const boundaryData = currentSubBoundaryBorder[partitionId];
3354
3378
  if (boundaryData && boundaryData.coordinates && boundaryData.coordinates.length > 0) {
3355
3379
  for (const coord of boundaryData.coordinates) {
3356
3380
  minX = Math.min(minX, coord[0]);
@@ -3362,7 +3386,7 @@ class ChannelLayer extends BaseLayer {
3362
3386
  }
3363
3387
  }
3364
3388
  // 整理出clipPath路径
3365
- const clipPathId = 'channel-exclude-all';
3389
+ const clipPathId = `${this.sn}-channel-exclude-all`;
3366
3390
  // 创建 clipPath
3367
3391
  const clipPath = document.createElementNS('http://www.w3.org/2000/svg', 'clipPath');
3368
3392
  clipPath.setAttribute('id', clipPathId);
@@ -3371,7 +3395,7 @@ class ChannelLayer extends BaseLayer {
3371
3395
  // 外轮廓(顺时针)
3372
3396
  let d = `M ${minX} ${minY} L ${maxX} ${minY} L ${maxX} ${maxY} L ${minX} ${maxY} Z`;
3373
3397
  // 获取所有需要挖空的分区路径
3374
- const partitionPaths = this.mergeOverlappingPartitions(subBoundaryBorder);
3398
+ const partitionPaths = this.mergeOverlappingPartitions(currentSubBoundaryBorder || {});
3375
3399
  // 将所有分区路径追加到clipPath中(逆时针,形成挖空)
3376
3400
  partitionPaths.forEach((partitionCoords) => {
3377
3401
  if (partitionCoords.length >= 3) {
@@ -3497,12 +3521,12 @@ class ChannelLayer extends BaseLayer {
3497
3521
  /**
3498
3522
  * 智能合并重叠的分区,返回所有需要挖空的路径
3499
3523
  */
3500
- mergeOverlappingPartitions(subBoundaryBorder) {
3524
+ mergeOverlappingPartitions(currentSubBoundaryBorder) {
3501
3525
  try {
3502
3526
  // 将所有分区转换为polygon-clipping格式
3503
3527
  const polygons = [];
3504
3528
  const partitionIds = [];
3505
- Object.entries(subBoundaryBorder).forEach(([partitionId, boundaryData]) => {
3529
+ Object.entries(currentSubBoundaryBorder || {}).forEach(([partitionId, boundaryData]) => {
3506
3530
  if (boundaryData?.coordinates && boundaryData.coordinates.length >= 3) {
3507
3531
  // 确保坐标格式正确(去掉第三个z坐标)
3508
3532
  const coords = boundaryData.coordinates.map((coord) => [coord[0], coord[1]]);
@@ -3587,7 +3611,7 @@ class ChannelLayer extends BaseLayer {
3587
3611
  catch (error) {
3588
3612
  console.error('polygon-clipping union failed:', error);
3589
3613
  // 如果合并失败,返回原始分区
3590
- return Object.values(subBoundaryBorder)
3614
+ return Object.values(currentSubBoundaryBorder)
3591
3615
  .filter((boundaryData) => boundaryData?.coordinates && boundaryData.coordinates.length >= 3)
3592
3616
  .map((boundaryData) => boundaryData.coordinates.map((coord) => [coord[0], coord[1]]));
3593
3617
  }
@@ -3599,19 +3623,21 @@ class ChannelLayer extends BaseLayer {
3599
3623
  * 专门处理路径元素的渲染
3600
3624
  */
3601
3625
  class PathLayer extends BaseLayer {
3602
- constructor() {
3626
+ constructor(sn) {
3603
3627
  super();
3604
3628
  this.level = 3;
3605
3629
  this.scale = 1;
3606
3630
  this.lineScale = 1;
3607
3631
  this.boundaryPaths = {};
3608
3632
  this.type = LAYER_DEFAULT_TYPE.PATH;
3633
+ this.sn = sn;
3609
3634
  }
3610
3635
  /**
3611
3636
  * 为每个分区创建独立的 clipPath
3612
3637
  */
3613
3638
  createPartitionClipPaths(svgGroup) {
3614
3639
  const { subBoundaryBorder, obstacles, svgElements } = usePartitionDataStore.getState();
3640
+ const currentSubBoundaryBorder = subBoundaryBorder[this.sn];
3615
3641
  // 确保 defs 元素存在
3616
3642
  let defs = svgGroup.querySelector('defs');
3617
3643
  if (!defs) {
@@ -3620,9 +3646,9 @@ class PathLayer extends BaseLayer {
3620
3646
  }
3621
3647
  const clipPathIds = {};
3622
3648
  // 为每个分区创建独立的 clipPath
3623
- Object.keys(subBoundaryBorder).forEach((partitionId) => {
3624
- const partitionData = subBoundaryBorder[partitionId];
3625
- const clipPathId = `clip-partition-${partitionId}`;
3649
+ Object.keys(currentSubBoundaryBorder || {}).forEach((partitionId) => {
3650
+ const partitionData = currentSubBoundaryBorder[partitionId];
3651
+ const clipPathId = `clip-partition-${this.sn}-${partitionId}`;
3626
3652
  // 如果已存在,先移除
3627
3653
  const existing = defs.querySelector(`#${clipPathId}`);
3628
3654
  if (existing)
@@ -3639,7 +3665,8 @@ class PathLayer extends BaseLayer {
3639
3665
  d += ' Z ';
3640
3666
  }
3641
3667
  // 2. 所有禁区(逆时针)- 禁区影响所有分区
3642
- Object.values(obstacles).forEach((item) => {
3668
+ const currentObstacles = obstacles[this.sn];
3669
+ Object.values(currentObstacles || {}).forEach((item) => {
3643
3670
  const obstacleCoords = item.coordinates;
3644
3671
  if (obstacleCoords.length >= 3) {
3645
3672
  d += `M ${obstacleCoords[obstacleCoords.length - 1][0]} ${obstacleCoords[obstacleCoords.length - 1][1]}`;
@@ -3650,7 +3677,8 @@ class PathLayer extends BaseLayer {
3650
3677
  }
3651
3678
  });
3652
3679
  // 3. 所有 svgElements(逆时针)- SVG元素影响所有分区
3653
- Object.values(svgElements).forEach((svgPath) => {
3680
+ const currentSvgElements = svgElements[this.sn];
3681
+ Object.values(currentSvgElements || {}).forEach((svgPath) => {
3654
3682
  const svgPathString = svgPath?.metadata?.svg;
3655
3683
  if (svgPathString && typeof svgPathString === 'string' && svgPathString.trim()) {
3656
3684
  // 处理转义字符
@@ -3745,7 +3773,7 @@ class PathLayer extends BaseLayer {
3745
3773
  lineColor = style.lineColor || '#000000';
3746
3774
  }
3747
3775
  // 按分区+类型+样式分组存储
3748
- const groupKey = `${id}-${lineColor}-${style.lineWidth || 1}`;
3776
+ const groupKey = `${id}-${lineColor}-${style.lineWidth || 1}-${this.sn}`;
3749
3777
  if (!partitionTypeGroups.has(groupKey)) {
3750
3778
  partitionTypeGroups.set(groupKey, {
3751
3779
  pathData: [],
@@ -3897,9 +3925,7 @@ class BoundaryLayer extends BaseLayer {
3897
3925
  createBoundaryFill(svgGroup, coordinates, style) {
3898
3926
  const polygon = document.createElementNS('http://www.w3.org/2000/svg', 'polygon');
3899
3927
  // 构建点集合,使用整数坐标(只取x,y坐标)
3900
- const points = coordinates
3901
- .map((coord) => `${coord[0]},${coord[1]}`)
3902
- .join(' ');
3928
+ const points = coordinates.map((coord) => `${coord[0]},${coord[1]}`).join(' ');
3903
3929
  const fillColor = style.fillColor;
3904
3930
  polygon.setAttribute('points', points);
3905
3931
  polygon.setAttribute('fill', fillColor);
@@ -3943,9 +3969,7 @@ class ObstacleLayer extends BaseLayer {
3943
3969
  return;
3944
3970
  const polygon = document.createElementNS('http://www.w3.org/2000/svg', 'polygon');
3945
3971
  // 构建点集合,使用整数坐标
3946
- const points = coordinates
3947
- .map((coord) => `${coord[0]},${coord[1]}`)
3948
- .join(' ');
3972
+ const points = coordinates.map((coord) => `${coord[0]},${coord[1]}`).join(' ');
3949
3973
  polygon.setAttribute('points', points);
3950
3974
  polygon.setAttribute('fill', style.fillColor || 'rgba(220, 53, 69, 0.2)');
3951
3975
  polygon.setAttribute('stroke', style.lineColor || '#dc3545');
@@ -4225,9 +4249,7 @@ class VisionOffLayer extends BaseLayer {
4225
4249
  return;
4226
4250
  const polygon = document.createElementNS('http://www.w3.org/2000/svg', 'polygon');
4227
4251
  // 构建点集合,使用整数坐标
4228
- const points = coordinates
4229
- .map((coord) => `${coord[0]},${coord[1]}`)
4230
- .join(' ');
4252
+ const points = coordinates.map((coord) => `${coord[0]},${coord[1]}`).join(' ');
4231
4253
  const fillColor = style.fillColor || 'rgba(0, 255, 0, 0.4)';
4232
4254
  polygon.setAttribute('points', points);
4233
4255
  polygon.setAttribute('fill', fillColor);
@@ -7925,7 +7947,7 @@ class BoundaryBorderLayer extends BaseLayer {
7925
7947
  */
7926
7948
  setMowingBoundarys(mowingBoundarys) {
7927
7949
  if (!mowingBoundarys) {
7928
- this.mowingBoundarys = this.elements?.map(item => item?.originalData?.id);
7950
+ this.mowingBoundarys = this.elements?.map((item) => item?.originalData?.id);
7929
7951
  }
7930
7952
  else {
7931
7953
  this.mowingBoundarys = mowingBoundarys;
@@ -8245,14 +8267,15 @@ class AntennaLayer extends BaseLayer {
8245
8267
  * 使用具体的图层类来处理不同类型的渲染
8246
8268
  */
8247
8269
  class DrawLayer extends BaseLayer {
8248
- constructor() {
8270
+ constructor(sn) {
8249
8271
  super();
8272
+ this.sn = sn;
8250
8273
  // 初始化各种具体图层
8251
8274
  this.antennaLayer = new AntennaLayer();
8252
8275
  // 通道图层
8253
- this.channelLayer = new ChannelLayer();
8276
+ this.channelLayer = new ChannelLayer(sn);
8254
8277
  // 路径图层
8255
- this.pathLayer = new PathLayer();
8278
+ this.pathLayer = new PathLayer(sn);
8256
8279
  // 边界图层
8257
8280
  this.boundaryLayer = new BoundaryLayer();
8258
8281
  // 边界边框图层
@@ -8675,8 +8698,9 @@ class MapDataProcessor {
8675
8698
  /**
8676
8699
  * 处理地图数据,返回绘制图层
8677
8700
  */
8678
- static processMapData(mapData, mapConfig) {
8701
+ static processMapData(sn, mapData, mapConfig) {
8679
8702
  this.mapConfig = mapConfig;
8703
+ this.sn = sn;
8680
8704
  // 收集所有地图元素
8681
8705
  const allElements = [];
8682
8706
  // 处理子地图中的元素
@@ -8756,6 +8780,9 @@ class MapDataProcessor {
8756
8780
  */
8757
8781
  static processMapElements(elements) {
8758
8782
  const result = [];
8783
+ let subBoundaryBorderObj = {};
8784
+ let obstaclesObj = {};
8785
+ let svgElementsObj = {};
8759
8786
  for (const element of elements) {
8760
8787
  try {
8761
8788
  // 检查必要的基础字段
@@ -8774,10 +8801,18 @@ class MapDataProcessor {
8774
8801
  result.push(boundaryBorderElement);
8775
8802
  // 将边界边框存储到 store 中,以分区ID为key
8776
8803
  if (element.id) {
8804
+ subBoundaryBorderObj = {
8805
+ ...subBoundaryBorderObj,
8806
+ [`${element.id.toString()}`]: {
8807
+ ...boundaryBorderElement,
8808
+ },
8809
+ };
8777
8810
  const { addSubBoundaryBorder } = usePartitionDataStore.getState();
8778
- addSubBoundaryBorder(element.id.toString(), {
8779
- ...boundaryBorderElement,
8780
- });
8811
+ addSubBoundaryBorder(`${this.sn}`, subBoundaryBorderObj);
8812
+ // const { addSubBoundaryBorder } = usePartitionDataStore.getState();
8813
+ // addSubBoundaryBorder(`${element.id.toString()}`, {
8814
+ // ...boundaryBorderElement,
8815
+ // });
8781
8816
  }
8782
8817
  }
8783
8818
  }
@@ -8793,10 +8828,15 @@ class MapDataProcessor {
8793
8828
  const obstacleElement = ObstacleDataBuilder.fromMapElement(mapElement, this.mapConfig.obstacle);
8794
8829
  if (obstacleElement) {
8795
8830
  result.push(obstacleElement);
8796
- const { addObstacles } = usePartitionDataStore.getState();
8797
- addObstacles(`obstacle-${obstacleElement.originalData.id}`, {
8831
+ obstaclesObj[`obstacle-${obstacleElement.originalData.id}`] = {
8798
8832
  ...obstacleElement,
8799
- });
8833
+ };
8834
+ const { addObstacles } = usePartitionDataStore.getState();
8835
+ addObstacles(`${this.sn}`, obstaclesObj);
8836
+ // const { addObstacles } = usePartitionDataStore.getState();
8837
+ // addObstacles(`obstacle-${obstacleElement.originalData.id}`, {
8838
+ // ...obstacleElement,
8839
+ // });
8800
8840
  }
8801
8841
  }
8802
8842
  catch (error) {
@@ -8860,10 +8900,15 @@ class MapDataProcessor {
8860
8900
  const svgElement = SvgElementDataBuilder.fromMapElement(mapElement, this.mapConfig.doodle);
8861
8901
  if (svgElement) {
8862
8902
  result.push(svgElement);
8863
- const { addSvgElements } = usePartitionDataStore.getState();
8864
- addSvgElements(`time-limit-obstacle-${svgElement.originalData.id}`, {
8903
+ svgElementsObj[`time-limit-obstacle-${svgElement.originalData.id}`] = {
8865
8904
  ...svgElement,
8866
- });
8905
+ };
8906
+ const { addSvgElements } = usePartitionDataStore.getState();
8907
+ addSvgElements(`${this.sn}`, svgElementsObj);
8908
+ // const { addSvgElements } = usePartitionDataStore.getState();
8909
+ // addSvgElements(`time-limit-obstacle-${svgElement.originalData.id}`, {
8910
+ // ...svgElement,
8911
+ // });
8867
8912
  }
8868
8913
  }
8869
8914
  // 如果有points数据,按传统方式绘制
@@ -8875,10 +8920,15 @@ class MapDataProcessor {
8875
8920
  const polygonElement = ObstacleDataBuilder.createTimeLimitObstacle(mapElement, this.mapConfig.obstacle);
8876
8921
  if (polygonElement) {
8877
8922
  result.push(polygonElement);
8878
- const { addObstacles } = usePartitionDataStore.getState();
8879
- addObstacles(`time-limit-obstacle-${polygonElement.originalData.id}`, {
8923
+ svgElementsObj[`time-limit-obstacle-${polygonElement.originalData.id}`] = {
8880
8924
  ...polygonElement,
8881
- });
8925
+ };
8926
+ const { addSvgElements } = usePartitionDataStore.getState();
8927
+ addSvgElements(`${this.sn}`, svgElementsObj);
8928
+ // const { addObstacles } = usePartitionDataStore.getState();
8929
+ // addObstacles(`time-limit-obstacle-${polygonElement.originalData.id}`, {
8930
+ // ...polygonElement,
8931
+ // });
8882
8932
  }
8883
8933
  }
8884
8934
  }
@@ -10595,24 +10645,29 @@ function isMobileDevice() {
10595
10645
  // 记录割草状态,状态变更的时候,变量不触发重新渲染
10596
10646
  const useCurrentMowingDataStore = create((set) => ({
10597
10647
  // 当前进度数据返回的割草状态是否为在割草
10598
- processStateIsMowing: false,
10599
- updateProcessStateIsMowing: (isMowing) => set({ processStateIsMowing: isMowing }),
10600
- resetProcessStateIsMowing: () => set({ processStateIsMowing: false }),
10648
+ processStateIsMowing: {},
10649
+ updateProcessStateIsMowing: (sn, isMowing) => set((state) => ({ processStateIsMowing: { ...state.processStateIsMowing, [sn]: isMowing } })),
10650
+ resetProcessStateIsMowing: (key) => set((state) => ({ processStateIsMowing: { ...state.processStateIsMowing, [key]: false } })),
10601
10651
  // 当前割草的分区id
10602
- currentMowingPartitionId: '',
10603
- updateCurrentMowingPartitionId: (partitionId) => set({ currentMowingPartitionId: partitionId }),
10604
- resetCurrentMowingPartitionId: () => set({ currentMowingPartitionId: '' }),
10652
+ currentMowingPartitionId: {},
10653
+ updateCurrentMowingPartitionId: (sn, partitionId) => set((state) => ({
10654
+ currentMowingPartitionId: { ...state.currentMowingPartitionId, [sn]: partitionId },
10655
+ })),
10656
+ resetCurrentMowingPartitionId: (key) => set((state) => ({
10657
+ currentMowingPartitionId: { ...state.currentMowingPartitionId, [key]: '' },
10658
+ })),
10605
10659
  }));
10606
10660
 
10607
10661
  // Google Maps 叠加层类 - 带编辑功能
10608
10662
  class MowerMapOverlay {
10609
- constructor(bounds, mapData, partitionBoundary, mowerPositionConfig, modelType, pathData, isEditMode = false, unitType = UnitsType.Imperial, language = 'en', mapConfig = {}, antennaConfig = {}, mowPartitionData = null, defaultTransform, onMapLoad, onPathLoad, dragCallbacks) {
10663
+ constructor(sn, bounds, mapData, partitionBoundary, mowerPositionConfig, modelType, pathData, isEditMode = false, unitType = UnitsType.Imperial, language = 'en', mapConfig = {}, antennaConfig = {}, mowPartitionData = null, defaultTransform, onMapLoad, onPathLoad, dragCallbacks) {
10610
10664
  this.div = null;
10611
10665
  this.svgMapView = null;
10612
10666
  this.offscreenContainer = null;
10613
10667
  this.overlayView = null;
10614
10668
  this.defaultTransform = { x: 0, y: 0, rotation: 0 };
10615
10669
  this.hasEdger = false;
10670
+ this.sn = '';
10616
10671
  // boundary数据
10617
10672
  this.boundaryData = [];
10618
10673
  // 边界标签管理器
@@ -10650,6 +10705,7 @@ class MowerMapOverlay {
10650
10705
  leading: true,
10651
10706
  trailing: false,
10652
10707
  });
10708
+ this.sn = sn;
10653
10709
  this.bounds = bounds;
10654
10710
  this.mapData = mapData;
10655
10711
  this.partitionBoundary = partitionBoundary;
@@ -11461,7 +11517,7 @@ class MowerMapOverlay {
11461
11517
  return;
11462
11518
  try {
11463
11519
  // 创建SvgMapView实例
11464
- this.svgMapView = new SvgMapView(this.offscreenContainer, 800, 600);
11520
+ this.svgMapView = new SvgMapView(this.sn, this.offscreenContainer, 800, 600);
11465
11521
  // 加载地图数据
11466
11522
  this.loadMapData();
11467
11523
  // 加载路径数据
@@ -11490,12 +11546,12 @@ class MowerMapOverlay {
11490
11546
  return;
11491
11547
  try {
11492
11548
  // 使用现有的MapDataProcessor处理地图数据
11493
- const elements = MapDataProcessor.processMapData(this.mapData, this.mapConfig);
11549
+ const elements = MapDataProcessor.processMapData(this.sn, this.mapData, this.mapConfig);
11494
11550
  // 分离充电桩和天线元素,其他元素添加到SVG图层
11495
11551
  const svgElements = elements.filter((element) => element.type !== 'charging_pile' && element.type !== 'antenna');
11496
11552
  const chargingPileElements = elements.filter((element) => element.type === 'charging_pile');
11497
11553
  // 处理SVG图层元素
11498
- const drawLayer = new DrawLayer();
11554
+ const drawLayer = new DrawLayer(this.sn);
11499
11555
  drawLayer.addElements(svgElements);
11500
11556
  // 处理天线数据
11501
11557
  let antennaElements = [];
@@ -11564,9 +11620,9 @@ class MowerMapOverlay {
11564
11620
  return pathElement;
11565
11621
  }
11566
11622
  });
11567
- const pathLayer = new PathLayer();
11623
+ const pathLayer = new PathLayer(this.sn);
11568
11624
  pathLayer.addElements(newPathElements);
11569
- // 添加图层到SvgMapView
11625
+ // // 添加图层到SvgMapView
11570
11626
  this.svgMapView.removeLayerByType(LAYER_DEFAULT_TYPE.PATH);
11571
11627
  this.svgMapView.addLayer(pathLayer);
11572
11628
  this.svgMapView.renderLayer(LAYER_DEFAULT_TYPE.PATH);
@@ -11585,8 +11641,10 @@ class MowerMapOverlay {
11585
11641
  updatePathDataByMowingPosition(position) {
11586
11642
  // 找到当前position所在的分区id,将该点更新到pathData中
11587
11643
  // 先查找当前的分区id是多少,然后确定当前的点是否在当前分区id中,如果不在,则重新获取分区id并重新设置
11588
- const currentPartitionId = useCurrentMowingDataStore.getState().currentMowingPartitionId;
11589
- const processStateIsMowing = useCurrentMowingDataStore.getState().processStateIsMowing;
11644
+ const partitionIdMap = useCurrentMowingDataStore.getState().currentMowingPartitionId;
11645
+ const processStateIsMowingMap = useCurrentMowingDataStore.getState().processStateIsMowing;
11646
+ const currentPartitionId = partitionIdMap[this.sn];
11647
+ const processStateIsMowing = processStateIsMowingMap[this.sn];
11590
11648
  if (currentPartitionId && this.pathData?.[currentPartitionId]) {
11591
11649
  const currentPathData = this.pathData[currentPartitionId];
11592
11650
  this.pathData[currentPartitionId] = {
@@ -11891,7 +11949,9 @@ const getValidGpsBounds = (mapData, rotation = 0) => {
11891
11949
  // 默认配置
11892
11950
  const defaultMapConfig = DEFAULT_STYLES;
11893
11951
  // 地图渲染器组件
11894
- const MowerMapRenderer = React.forwardRef(({ 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) => {
11952
+ const MowerMapRenderer = React.forwardRef(({
11953
+ // 唯一的可以标识一个割草机的id
11954
+ 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) => {
11895
11955
  const [elementCount, setElementCount] = React.useState(0);
11896
11956
  const [pathCount, setPathCount] = React.useState(0);
11897
11957
  const [currentError, setCurrentError] = React.useState(null);
@@ -11899,10 +11959,9 @@ const MowerMapRenderer = React.forwardRef(({ edger = false, unitType = UnitsType
11899
11959
  // const mapRef = useMap();
11900
11960
  const [isGoogleMapsReady, setIsGoogleMapsReady] = React.useState(false);
11901
11961
  const [hasInitializedBounds, setHasInitializedBounds] = React.useState(false);
11902
- const { clearSubBoundaryBorder, clearObstacles, clearSvgElements } = usePartitionDataStore();
11903
- const { resetCurrentMowingPartitionId } = useCurrentMowingDataStore();
11962
+ const { deleteSubBoundaryBorder, deleteObstacles, deleteSvgElements } = usePartitionDataStore();
11904
11963
  const currentProcessMowingStatusRef = React.useRef(false);
11905
- const { updateProcessStateIsMowing, processStateIsMowing, updateCurrentMowingPartitionId, currentMowingPartitionId, } = useCurrentMowingDataStore();
11964
+ const { updateProcessStateIsMowing, processStateIsMowing, updateCurrentMowingPartitionId, currentMowingPartitionId, resetCurrentMowingPartitionId, } = useCurrentMowingDataStore();
11906
11965
  const [mowPartitionData, setMowPartitionData] = React.useState(null);
11907
11966
  // Debug相关状态
11908
11967
  const [debugInfo, setDebugInfo] = React.useState({});
@@ -12028,7 +12087,7 @@ const MowerMapRenderer = React.forwardRef(({ edger = false, unitType = UnitsType
12028
12087
  overlayRef.current = null;
12029
12088
  }
12030
12089
  // 创建叠加层
12031
- const overlay = new MowerMapOverlay(googleBounds, mapJson, partitionBoundary, mowerPositionData, modelType, pathJson || {}, isEditMode, unitType, language, mergedMapConfig, mergedAntennaConfig, null, defaultTransform, (count) => {
12090
+ const overlay = new MowerMapOverlay(sn, googleBounds, mapJson, partitionBoundary, mowerPositionData, modelType, pathJson || {}, isEditMode, unitType, language, mergedMapConfig, mergedAntennaConfig, null, defaultTransform, (count) => {
12032
12091
  setElementCount(count);
12033
12092
  onMapLoad?.(count);
12034
12093
  }, (count) => {
@@ -12051,7 +12110,7 @@ const MowerMapRenderer = React.forwardRef(({ edger = false, unitType = UnitsType
12051
12110
  }
12052
12111
  };
12053
12112
  const resetInCharginPie = React.useCallback(() => {
12054
- const elements = MapDataProcessor.processMapData(mapJson, mergedMapConfig);
12113
+ const elements = MapDataProcessor.processMapData(sn, mapJson, mergedMapConfig);
12055
12114
  const chargingPiles = elements.find((element) => element.type === 'charging_pile');
12056
12115
  if (!overlayRef.current)
12057
12116
  return;
@@ -12068,18 +12127,22 @@ const MowerMapRenderer = React.forwardRef(({ edger = false, unitType = UnitsType
12068
12127
  initializeGoogleMapsOverlay();
12069
12128
  // 清理函数
12070
12129
  return () => {
12071
- clearSubBoundaryBorder();
12072
- clearObstacles();
12073
- clearSvgElements();
12074
- resetCurrentMowingPartitionId();
12075
- updateProcessStateIsMowing(false);
12076
- currentProcessMowingStatusRef.current = false;
12077
12130
  if (overlayRef.current) {
12078
12131
  overlayRef.current.setMap(null);
12079
12132
  overlayRef.current = null;
12080
12133
  }
12081
12134
  };
12082
- }, [mapJson, pathJson, mergedMapConfig, mergedAntennaConfig]);
12135
+ }, [sn, mapJson, pathJson, mergedMapConfig, mergedAntennaConfig]);
12136
+ React.useEffect(() => {
12137
+ return () => {
12138
+ deleteSubBoundaryBorder(sn);
12139
+ deleteObstacles(sn);
12140
+ deleteSvgElements(sn);
12141
+ resetCurrentMowingPartitionId(sn);
12142
+ updateProcessStateIsMowing(sn, false);
12143
+ currentProcessMowingStatusRef.current = false;
12144
+ };
12145
+ }, []);
12083
12146
  // 监听编辑模式变化
12084
12147
  React.useEffect(() => {
12085
12148
  if (overlayRef.current) {
@@ -12095,7 +12158,7 @@ const MowerMapRenderer = React.forwardRef(({ edger = false, unitType = UnitsType
12095
12158
  React.useEffect(() => {
12096
12159
  if (!mapJson)
12097
12160
  return;
12098
- const elements = MapDataProcessor.processMapData(mapJson, mergedMapConfig);
12161
+ const elements = MapDataProcessor.processMapData(sn, mapJson, mergedMapConfig);
12099
12162
  const chargingPiles = elements.find((element) => element.type === 'charging_pile');
12100
12163
  if (!mowerPositionData || !overlayRef.current)
12101
12164
  return;
@@ -12306,13 +12369,13 @@ const MowerMapRenderer = React.forwardRef(({ edger = false, unitType = UnitsType
12306
12369
  if (realTimeData.length > 1) {
12307
12370
  const { pathData, isMowing, currentMowingPartition } = handleMultipleRealTimeData({
12308
12371
  realTimeData,
12309
- isMowing: processStateIsMowing,
12372
+ isMowing: processStateIsMowing[sn],
12310
12373
  pathData: pathJson,
12311
- currentMowingPartition: currentMowingPartitionId,
12374
+ currentMowingPartition: currentMowingPartitionId[sn],
12312
12375
  });
12313
- updateProcessStateIsMowing(isMowing);
12314
- if (currentMowingPartition !== currentMowingPartitionId) {
12315
- updateCurrentMowingPartitionId(currentMowingPartition);
12376
+ updateProcessStateIsMowing(sn, isMowing);
12377
+ if (currentMowingPartition !== currentMowingPartitionId[sn]) {
12378
+ updateCurrentMowingPartitionId(sn, currentMowingPartition);
12316
12379
  }
12317
12380
  if (pathData) {
12318
12381
  overlayRef.current.updatePathData(pathData, curMowPartitionData);
@@ -12322,13 +12385,13 @@ const MowerMapRenderer = React.forwardRef(({ edger = false, unitType = UnitsType
12322
12385
  else {
12323
12386
  const { isMowing, pathData, currentMowingPartition } = getProcessMowingDataFromRealTimeData({
12324
12387
  realTimeData,
12325
- isMowing: processStateIsMowing,
12388
+ isMowing: processStateIsMowing[sn],
12326
12389
  pathData: pathJson,
12327
- currentMowingPartition: currentMowingPartitionId,
12390
+ currentMowingPartition: currentMowingPartitionId[sn],
12328
12391
  });
12329
- updateProcessStateIsMowing(isMowing);
12330
- if (currentMowingPartition !== currentMowingPartitionId) {
12331
- updateCurrentMowingPartitionId(currentMowingPartition);
12392
+ updateProcessStateIsMowing(sn, isMowing);
12393
+ if (currentMowingPartition !== currentMowingPartitionId[sn]) {
12394
+ updateCurrentMowingPartitionId(sn, currentMowingPartition);
12332
12395
  }
12333
12396
  overlayRef.current.updatePathData(pathData, curMowPartitionData);
12334
12397
  // 更新进度数据
@@ -6,10 +6,11 @@ import { MapData, AntennaData, MapConfig } from '../types';
6
6
  */
7
7
  export declare class MapDataProcessor {
8
8
  private static mapConfig;
9
+ private static sn;
9
10
  /**
10
11
  * 处理地图数据,返回绘制图层
11
12
  */
12
- static processMapData(mapData: MapData, mapConfig: MapConfig): DrawElement[];
13
+ static processMapData(sn: string, mapData: MapData, mapConfig: MapConfig): DrawElement[];
13
14
  /**
14
15
  * 根据元素类型创建分层的地图数据
15
16
  * 图层优先级:TIME_LIMIT_OBSTACLE = VISION_OFF_AREA = CHARGING_PILE = OBSTACLE > BOUNDARY > TUNNEL = TUNNEL_TO_CHARGING_PILE
@@ -1 +1 @@
1
- {"version":3,"file":"MapDataProcessor.d.ts","sourceRoot":"","sources":["../../src/processor/MapDataProcessor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EACL,OAAO,EAOP,WAAW,EAEX,SAAS,EACV,MAAM,UAAU,CAAC;AAkBlB;;;GAGG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,MAAM,CAAC,SAAS,CAAY;IACpC;;OAEG;IACH,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,GAAG,WAAW,EAAE;IAsC5E;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,oBAAoB;IAgDnC;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,kBAAkB;IAmLjC;;OAEG;IACH,MAAM,CAAC,kBAAkB,CACvB,QAAQ,EAAE,WAAW,EAAE,GAAG,SAAS,EACnC,aAAa,EAAE;QACb,IAAI,CAAC,EAAE,OAAO,CAAC;QACf,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,gBAAgB,CAAC,EAAE,OAAO,CAAC;QAC3B,gBAAgB,CAAC,EAAE,OAAO,CAAC;KAC5B,GACA,WAAW,EAAE;CAOjB"}
1
+ {"version":3,"file":"MapDataProcessor.d.ts","sourceRoot":"","sources":["../../src/processor/MapDataProcessor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EACL,OAAO,EAOP,WAAW,EAEX,SAAS,EACV,MAAM,UAAU,CAAC;AAkBlB;;;GAGG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,MAAM,CAAC,SAAS,CAAY;IACpC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAS;IAC1B;;OAEG;IACH,MAAM,CAAC,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,GAAG,WAAW,EAAE;IAuCxF;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,oBAAoB;IAgDnC;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,kBAAkB;IA6MjC;;OAEG;IACH,MAAM,CAAC,kBAAkB,CACvB,QAAQ,EAAE,WAAW,EAAE,GAAG,SAAS,EACnC,aAAa,EAAE;QACb,IAAI,CAAC,EAAE,OAAO,CAAC;QACf,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,gBAAgB,CAAC,EAAE,OAAO,CAAC;QAC3B,gBAAgB,CAAC,EAAE,OAAO,CAAC;KAC5B,GACA,WAAW,EAAE;CAOjB"}
@@ -30,6 +30,7 @@ export declare class MowerMapOverlay {
30
30
  private dragCallbacks?;
31
31
  private defaultTransform;
32
32
  private hasEdger;
33
+ private sn;
33
34
  private boundaryData;
34
35
  private boundaryLabelsManager;
35
36
  private chargingPileManager;
@@ -52,7 +53,7 @@ export declare class MowerMapOverlay {
52
53
  private initialRotation;
53
54
  private cleanupListeners?;
54
55
  private mowPartitionData;
55
- constructor(bounds: any, mapData: any, partitionBoundary: any[], mowerPositionConfig: MowerPositionConfig, modelType?: string, pathData: PathData, isEditMode?: boolean, unitType?: UnitsType, language?: string, mapConfig?: any, antennaConfig?: any, mowPartitionData?: MowerPartitionInfo | null, defaultTransform?: {
56
+ constructor(sn: string, bounds: any, mapData: any, partitionBoundary: any[], mowerPositionConfig: MowerPositionConfig, modelType?: string, pathData: PathData, isEditMode?: boolean, unitType?: UnitsType, language?: string, mapConfig?: any, antennaConfig?: any, mowPartitionData?: MowerPartitionInfo | null, defaultTransform?: {
56
57
  x?: number;
57
58
  y?: number;
58
59
  rotation?: number;