@fleet-frontend/mower-maps 0.0.2 → 0.0.3
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.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.js +140 -490
- package/dist/index.js +139 -488
- package/dist/render/AntennaManager.d.ts.map +1 -1
- package/dist/render/ChargingPileManager.d.ts.map +1 -1
- package/dist/render/MowerMapRenderer.d.ts.map +1 -1
- package/dist/render/SvgMapView.d.ts +0 -4
- package/dist/render/SvgMapView.d.ts.map +1 -1
- package/dist/types/path.d.ts +1 -1
- package/dist/types/path.d.ts.map +1 -1
- package/dist/types/renderer.d.ts +8 -5
- package/dist/types/renderer.d.ts.map +1 -1
- package/dist/utils/handleRealTime.d.ts +1 -1
- package/dist/utils/handleRealTime.d.ts.map +1 -1
- package/dist/utils/mapBounds.d.ts +11 -2
- package/dist/utils/mapBounds.d.ts.map +1 -1
- package/package.json +9 -6
- package/dist/3900c861790f0a9d.png +0 -0
package/dist/index.esm.js
CHANGED
|
@@ -1,350 +1,5 @@
|
|
|
1
1
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
|
-
import React, { forwardRef,
|
|
3
|
-
import { createPortal } from 'react-dom';
|
|
4
|
-
|
|
5
|
-
function _objectWithoutPropertiesLoose(r, e) {
|
|
6
|
-
if (null == r) return {};
|
|
7
|
-
var t = {};
|
|
8
|
-
for (var n in r) if ({}.hasOwnProperty.call(r, n)) {
|
|
9
|
-
if (-1 !== e.indexOf(n)) continue;
|
|
10
|
-
t[n] = r[n];
|
|
11
|
-
}
|
|
12
|
-
return t;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const APILoadingStatus = {
|
|
16
|
-
NOT_LOADED: 'NOT_LOADED',
|
|
17
|
-
LOADED: 'LOADED'};
|
|
18
|
-
const APIProviderContext = React.createContext(null);
|
|
19
|
-
|
|
20
|
-
function useApiLoadingStatus() {
|
|
21
|
-
var _useContext;
|
|
22
|
-
return ((_useContext = useContext(APIProviderContext)) == null ? void 0 : _useContext.status) || APILoadingStatus.NOT_LOADED;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Hook to check if the Maps JavaScript API is loaded
|
|
27
|
-
*/
|
|
28
|
-
function useApiIsLoaded() {
|
|
29
|
-
const status = useApiLoadingStatus();
|
|
30
|
-
return status === APILoadingStatus.LOADED;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const GoogleMapsContext = React.createContext(null);
|
|
34
|
-
|
|
35
|
-
const shownMessages = new Set();
|
|
36
|
-
function logErrorOnce(...args) {
|
|
37
|
-
const key = JSON.stringify(args);
|
|
38
|
-
if (!shownMessages.has(key)) {
|
|
39
|
-
shownMessages.add(key);
|
|
40
|
-
console.error(...args);
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Retrieves a map-instance from the context. This is either an instance
|
|
46
|
-
* identified by id or the parent map instance if no id is specified.
|
|
47
|
-
* Returns null if neither can be found.
|
|
48
|
-
*/
|
|
49
|
-
const useMap = (id = null) => {
|
|
50
|
-
const ctx = useContext(APIProviderContext);
|
|
51
|
-
const {
|
|
52
|
-
map
|
|
53
|
-
} = useContext(GoogleMapsContext) || {};
|
|
54
|
-
if (ctx === null) {
|
|
55
|
-
logErrorOnce('useMap(): failed to retrieve APIProviderContext. ' + 'Make sure that the <APIProvider> component exists and that the ' + 'component you are calling `useMap()` from is a sibling of the ' + '<APIProvider>.');
|
|
56
|
-
return null;
|
|
57
|
-
}
|
|
58
|
-
const {
|
|
59
|
-
mapInstances
|
|
60
|
-
} = ctx;
|
|
61
|
-
// if an id is specified, the corresponding map or null is returned
|
|
62
|
-
if (id !== null) return mapInstances[id] || null;
|
|
63
|
-
// otherwise, return the closest ancestor
|
|
64
|
-
if (map) return map;
|
|
65
|
-
// finally, return the default map instance
|
|
66
|
-
return mapInstances['default'] || null;
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
function useMapsLibrary(name) {
|
|
70
|
-
const apiIsLoaded = useApiIsLoaded();
|
|
71
|
-
const ctx = useContext(APIProviderContext);
|
|
72
|
-
useEffect(() => {
|
|
73
|
-
if (!apiIsLoaded || !ctx) return;
|
|
74
|
-
// Trigger loading the libraries via our proxy-method.
|
|
75
|
-
// The returned promise is ignored, since importLibrary will update loadedLibraries
|
|
76
|
-
// list in the context, triggering a re-render.
|
|
77
|
-
void ctx.importLibrary(name);
|
|
78
|
-
}, [apiIsLoaded, ctx, name]);
|
|
79
|
-
return (ctx == null ? void 0 : ctx.loadedLibraries[name]) || null;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
83
|
-
/**
|
|
84
|
-
* Internally used to bind events to Maps JavaScript API objects.
|
|
85
|
-
* @internal
|
|
86
|
-
*/
|
|
87
|
-
function useMapsEventListener(target, name, callback) {
|
|
88
|
-
useEffect(() => {
|
|
89
|
-
if (!target || !name || !callback) return;
|
|
90
|
-
const listener = google.maps.event.addListener(target, name, callback);
|
|
91
|
-
return () => listener.remove();
|
|
92
|
-
}, [target, name, callback]);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Internally used to copy values from props into API-Objects
|
|
97
|
-
* whenever they change.
|
|
98
|
-
*
|
|
99
|
-
* @example
|
|
100
|
-
* usePropBinding(marker, 'position', position);
|
|
101
|
-
*
|
|
102
|
-
* @internal
|
|
103
|
-
*/
|
|
104
|
-
function usePropBinding(object, prop, value) {
|
|
105
|
-
useEffect(() => {
|
|
106
|
-
if (!object) return;
|
|
107
|
-
object[prop] = value;
|
|
108
|
-
}, [object, prop, value]);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
112
|
-
/**
|
|
113
|
-
* Internally used to bind events to DOM nodes.
|
|
114
|
-
* @internal
|
|
115
|
-
*/
|
|
116
|
-
function useDomEventListener(target, name, callback) {
|
|
117
|
-
useEffect(() => {
|
|
118
|
-
if (!target || !name || !callback) return;
|
|
119
|
-
target.addEventListener(name, callback);
|
|
120
|
-
return () => target.removeEventListener(name, callback);
|
|
121
|
-
}, [target, name, callback]);
|
|
122
|
-
}
|
|
123
|
-
function isElementNode(node) {
|
|
124
|
-
return node.nodeType === Node.ELEMENT_NODE;
|
|
125
|
-
}
|
|
126
|
-
const AdvancedMarkerContext = React.createContext(null);
|
|
127
|
-
// [xPosition, yPosition] when the top left corner is [0, 0]
|
|
128
|
-
const AdvancedMarkerAnchorPoint = {
|
|
129
|
-
BOTTOM: ['50%', '100%']};
|
|
130
|
-
const MarkerContent = ({
|
|
131
|
-
children,
|
|
132
|
-
styles,
|
|
133
|
-
className,
|
|
134
|
-
anchorPoint
|
|
135
|
-
}) => {
|
|
136
|
-
const [xTranslation, yTranslation] = anchorPoint != null ? anchorPoint : AdvancedMarkerAnchorPoint['BOTTOM'];
|
|
137
|
-
let xTranslationFlipped = `-${xTranslation}`;
|
|
138
|
-
let yTranslationFlipped = `-${yTranslation}`;
|
|
139
|
-
if (xTranslation.trimStart().startsWith('-')) {
|
|
140
|
-
xTranslationFlipped = xTranslation.substring(1);
|
|
141
|
-
}
|
|
142
|
-
if (yTranslation.trimStart().startsWith('-')) {
|
|
143
|
-
yTranslationFlipped = yTranslation.substring(1);
|
|
144
|
-
}
|
|
145
|
-
// The "translate(50%, 100%)" is here to counter and reset the default anchoring of the advanced marker element
|
|
146
|
-
// that comes from the api
|
|
147
|
-
const transformStyle = `translate(50%, 100%) translate(${xTranslationFlipped}, ${yTranslationFlipped})`;
|
|
148
|
-
return (
|
|
149
|
-
/*#__PURE__*/
|
|
150
|
-
// anchoring container
|
|
151
|
-
React.createElement("div", {
|
|
152
|
-
style: {
|
|
153
|
-
transform: transformStyle
|
|
154
|
-
}
|
|
155
|
-
}, /*#__PURE__*/React.createElement("div", {
|
|
156
|
-
className: className,
|
|
157
|
-
style: styles
|
|
158
|
-
}, children))
|
|
159
|
-
);
|
|
160
|
-
};
|
|
161
|
-
function useAdvancedMarker(props) {
|
|
162
|
-
const [marker, setMarker] = useState(null);
|
|
163
|
-
const [contentContainer, setContentContainer] = useState(null);
|
|
164
|
-
const map = useMap();
|
|
165
|
-
const markerLibrary = useMapsLibrary('marker');
|
|
166
|
-
const {
|
|
167
|
-
children,
|
|
168
|
-
onClick,
|
|
169
|
-
className,
|
|
170
|
-
onMouseEnter,
|
|
171
|
-
onMouseLeave,
|
|
172
|
-
onDrag,
|
|
173
|
-
onDragStart,
|
|
174
|
-
onDragEnd,
|
|
175
|
-
collisionBehavior,
|
|
176
|
-
clickable,
|
|
177
|
-
draggable,
|
|
178
|
-
position,
|
|
179
|
-
title,
|
|
180
|
-
zIndex
|
|
181
|
-
} = props;
|
|
182
|
-
const numChildren = Children.count(children);
|
|
183
|
-
// create an AdvancedMarkerElement instance and add it to the map once available
|
|
184
|
-
useEffect(() => {
|
|
185
|
-
if (!map || !markerLibrary) return;
|
|
186
|
-
const newMarker = new markerLibrary.AdvancedMarkerElement();
|
|
187
|
-
newMarker.map = map;
|
|
188
|
-
setMarker(newMarker);
|
|
189
|
-
// create the container for marker content if there are children
|
|
190
|
-
let contentElement = null;
|
|
191
|
-
if (numChildren > 0) {
|
|
192
|
-
contentElement = document.createElement('div');
|
|
193
|
-
// We need some kind of flag to identify the custom marker content
|
|
194
|
-
// in the infowindow component. Choosing a custom property instead of a className
|
|
195
|
-
// to not encourage users to style the marker content directly.
|
|
196
|
-
contentElement.isCustomMarker = true;
|
|
197
|
-
newMarker.content = contentElement;
|
|
198
|
-
setContentContainer(contentElement);
|
|
199
|
-
}
|
|
200
|
-
return () => {
|
|
201
|
-
var _contentElement;
|
|
202
|
-
newMarker.map = null;
|
|
203
|
-
(_contentElement = contentElement) == null || _contentElement.remove();
|
|
204
|
-
setMarker(null);
|
|
205
|
-
setContentContainer(null);
|
|
206
|
-
};
|
|
207
|
-
}, [map, markerLibrary, numChildren]);
|
|
208
|
-
// When no children are present we don't have our own wrapper div
|
|
209
|
-
// which usually gets the user provided className. In this case
|
|
210
|
-
// we set the className directly on the marker.content element that comes
|
|
211
|
-
// with the AdvancedMarker.
|
|
212
|
-
useEffect(() => {
|
|
213
|
-
if (!(marker != null && marker.content) || !isElementNode(marker.content) || numChildren > 0) return;
|
|
214
|
-
marker.content.className = className != null ? className : '';
|
|
215
|
-
}, [marker, className, numChildren]);
|
|
216
|
-
// copy other props
|
|
217
|
-
usePropBinding(marker, 'position', position);
|
|
218
|
-
usePropBinding(marker, 'title', title != null ? title : '');
|
|
219
|
-
usePropBinding(marker, 'zIndex', zIndex);
|
|
220
|
-
usePropBinding(marker, 'collisionBehavior', collisionBehavior);
|
|
221
|
-
// set gmpDraggable from props (when unspecified, it's true if any drag-event
|
|
222
|
-
// callbacks are specified)
|
|
223
|
-
useEffect(() => {
|
|
224
|
-
if (!marker) return;
|
|
225
|
-
if (draggable !== undefined) marker.gmpDraggable = draggable;else if (onDrag || onDragStart || onDragEnd) marker.gmpDraggable = true;else marker.gmpDraggable = false;
|
|
226
|
-
}, [marker, draggable, onDrag, onDragEnd, onDragStart]);
|
|
227
|
-
// set gmpClickable from props (when unspecified, it's true if the onClick or one of
|
|
228
|
-
// the hover events callbacks are specified)
|
|
229
|
-
useEffect(() => {
|
|
230
|
-
if (!marker) return;
|
|
231
|
-
const gmpClickable = clickable !== undefined || Boolean(onClick) || Boolean(onMouseEnter) || Boolean(onMouseLeave);
|
|
232
|
-
// gmpClickable is only available in beta version of the
|
|
233
|
-
// maps api (as of 2024-10-10)
|
|
234
|
-
marker.gmpClickable = gmpClickable;
|
|
235
|
-
// enable pointer events for the markers with custom content
|
|
236
|
-
if (gmpClickable && marker != null && marker.content && isElementNode(marker.content)) {
|
|
237
|
-
marker.content.style.pointerEvents = 'none';
|
|
238
|
-
if (marker.content.firstElementChild) {
|
|
239
|
-
marker.content.firstElementChild.style.pointerEvents = 'all';
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
}, [marker, clickable, onClick, onMouseEnter, onMouseLeave]);
|
|
243
|
-
useMapsEventListener(marker, 'click', onClick);
|
|
244
|
-
useMapsEventListener(marker, 'drag', onDrag);
|
|
245
|
-
useMapsEventListener(marker, 'dragstart', onDragStart);
|
|
246
|
-
useMapsEventListener(marker, 'dragend', onDragEnd);
|
|
247
|
-
useDomEventListener(marker == null ? void 0 : marker.element, 'mouseenter', onMouseEnter);
|
|
248
|
-
useDomEventListener(marker == null ? void 0 : marker.element, 'mouseleave', onMouseLeave);
|
|
249
|
-
return [marker, contentContainer];
|
|
250
|
-
}
|
|
251
|
-
forwardRef((props, ref) => {
|
|
252
|
-
const {
|
|
253
|
-
children,
|
|
254
|
-
style,
|
|
255
|
-
className,
|
|
256
|
-
anchorPoint
|
|
257
|
-
} = props;
|
|
258
|
-
const [marker, contentContainer] = useAdvancedMarker(props);
|
|
259
|
-
const advancedMarkerContextValue = useMemo(() => marker ? {
|
|
260
|
-
marker
|
|
261
|
-
} : null, [marker]);
|
|
262
|
-
useImperativeHandle(ref, () => marker, [marker]);
|
|
263
|
-
if (!contentContainer) return null;
|
|
264
|
-
return /*#__PURE__*/React.createElement(AdvancedMarkerContext.Provider, {
|
|
265
|
-
value: advancedMarkerContextValue
|
|
266
|
-
}, createPortal(/*#__PURE__*/React.createElement(MarkerContent, {
|
|
267
|
-
anchorPoint: anchorPoint,
|
|
268
|
-
styles: style,
|
|
269
|
-
className: className
|
|
270
|
-
}, children), contentContainer));
|
|
271
|
-
});
|
|
272
|
-
|
|
273
|
-
const _excluded = ["onClick", "onDrag", "onDragStart", "onDragEnd", "onMouseOver", "onMouseOut"];
|
|
274
|
-
function useMarker(props) {
|
|
275
|
-
const [marker, setMarker] = useState(null);
|
|
276
|
-
const map = useMap();
|
|
277
|
-
const {
|
|
278
|
-
onClick,
|
|
279
|
-
onDrag,
|
|
280
|
-
onDragStart,
|
|
281
|
-
onDragEnd,
|
|
282
|
-
onMouseOver,
|
|
283
|
-
onMouseOut
|
|
284
|
-
} = props,
|
|
285
|
-
markerOptions = _objectWithoutPropertiesLoose(props, _excluded);
|
|
286
|
-
const {
|
|
287
|
-
position,
|
|
288
|
-
draggable
|
|
289
|
-
} = markerOptions;
|
|
290
|
-
// create marker instance and add to the map once the map is available
|
|
291
|
-
useEffect(() => {
|
|
292
|
-
if (!map) {
|
|
293
|
-
if (map === undefined) console.error('<Marker> has to be inside a Map component.');
|
|
294
|
-
return;
|
|
295
|
-
}
|
|
296
|
-
const newMarker = new google.maps.Marker(markerOptions);
|
|
297
|
-
newMarker.setMap(map);
|
|
298
|
-
setMarker(newMarker);
|
|
299
|
-
return () => {
|
|
300
|
-
newMarker.setMap(null);
|
|
301
|
-
setMarker(null);
|
|
302
|
-
};
|
|
303
|
-
// We do not want to re-render the whole marker when the options change.
|
|
304
|
-
// Marker options update is handled in a useEffect below.
|
|
305
|
-
// Excluding markerOptions from dependency array on purpose here.
|
|
306
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
307
|
-
}, [map]);
|
|
308
|
-
// attach and re-attach event-handlers when any of the properties change
|
|
309
|
-
useEffect(() => {
|
|
310
|
-
if (!marker) return;
|
|
311
|
-
const m = marker;
|
|
312
|
-
// Add event listeners
|
|
313
|
-
const gme = google.maps.event;
|
|
314
|
-
if (onClick) gme.addListener(m, 'click', onClick);
|
|
315
|
-
if (onDrag) gme.addListener(m, 'drag', onDrag);
|
|
316
|
-
if (onDragStart) gme.addListener(m, 'dragstart', onDragStart);
|
|
317
|
-
if (onDragEnd) gme.addListener(m, 'dragend', onDragEnd);
|
|
318
|
-
if (onMouseOver) gme.addListener(m, 'mouseover', onMouseOver);
|
|
319
|
-
if (onMouseOut) gme.addListener(m, 'mouseout', onMouseOut);
|
|
320
|
-
marker.setDraggable(Boolean(draggable));
|
|
321
|
-
return () => {
|
|
322
|
-
gme.clearInstanceListeners(m);
|
|
323
|
-
};
|
|
324
|
-
}, [marker, draggable, onClick, onDrag, onDragStart, onDragEnd, onMouseOver, onMouseOut]);
|
|
325
|
-
// update markerOptions (note the dependencies aren't properly checked
|
|
326
|
-
// here, we just assume that setOptions is smart enough to not waste a
|
|
327
|
-
// lot of time updating values that didn't change)
|
|
328
|
-
useEffect(() => {
|
|
329
|
-
if (!marker) return;
|
|
330
|
-
if (markerOptions) marker.setOptions(markerOptions);
|
|
331
|
-
}, [marker, markerOptions]);
|
|
332
|
-
// update position when changed
|
|
333
|
-
useEffect(() => {
|
|
334
|
-
// Should not update position when draggable
|
|
335
|
-
if (draggable || !position || !marker) return;
|
|
336
|
-
marker.setPosition(position);
|
|
337
|
-
}, [draggable, position, marker]);
|
|
338
|
-
return marker;
|
|
339
|
-
}
|
|
340
|
-
/**
|
|
341
|
-
* Component to render a marker on a map
|
|
342
|
-
*/
|
|
343
|
-
forwardRef((props, ref) => {
|
|
344
|
-
const marker = useMarker(props);
|
|
345
|
-
useImperativeHandle(ref, () => marker, [marker]);
|
|
346
|
-
return /*#__PURE__*/React.createElement(React.Fragment, null);
|
|
347
|
-
});
|
|
2
|
+
import React, { forwardRef, useRef, useState, useMemo, useEffect, useImperativeHandle } from 'react';
|
|
348
3
|
|
|
349
4
|
/**
|
|
350
5
|
* SVG基础MapView
|
|
@@ -452,7 +107,7 @@ class SvgMapView {
|
|
|
452
107
|
*/
|
|
453
108
|
fitToView(bounds) {
|
|
454
109
|
console.log('fitToView----->', bounds);
|
|
455
|
-
const padding =
|
|
110
|
+
const padding = 1; // 添加一些边距以避免内容贴边
|
|
456
111
|
const boundWidth = bounds.maxX - bounds.minX;
|
|
457
112
|
const boundHeight = bounds.maxY - bounds.minY;
|
|
458
113
|
// 防止宽高为0的情况
|
|
@@ -475,8 +130,8 @@ class SvgMapView {
|
|
|
475
130
|
this.viewBox = {
|
|
476
131
|
x: bounds.minX - padding,
|
|
477
132
|
y: bounds.minY - padding,
|
|
478
|
-
width: boundWidth + padding
|
|
479
|
-
height: boundHeight + padding
|
|
133
|
+
width: boundWidth + padding,
|
|
134
|
+
height: boundHeight + padding
|
|
480
135
|
};
|
|
481
136
|
// 根据宽高比选择合适的preserveAspectRatio设置
|
|
482
137
|
if (Math.abs(contentAspectRatio - containerAspectRatio) < 0.01) {
|
|
@@ -555,10 +210,6 @@ class SvgMapView {
|
|
|
555
210
|
this.clearLayersGroup();
|
|
556
211
|
// 绘制所有图层
|
|
557
212
|
this.onDrawLayers();
|
|
558
|
-
// 绘制比例尺
|
|
559
|
-
if (this.showScale) {
|
|
560
|
-
this.drawScale();
|
|
561
|
-
}
|
|
562
213
|
}
|
|
563
214
|
/**
|
|
564
215
|
* 清空图层组
|
|
@@ -594,35 +245,6 @@ class SvgMapView {
|
|
|
594
245
|
reinitializeSVG() {
|
|
595
246
|
this.refresh();
|
|
596
247
|
}
|
|
597
|
-
/**
|
|
598
|
-
* 绘制比例尺
|
|
599
|
-
*/
|
|
600
|
-
drawScale() {
|
|
601
|
-
const padding = 10;
|
|
602
|
-
const scaleX = this.viewBox.x + this.viewBox.width - 100 - padding;
|
|
603
|
-
const scaleY = this.viewBox.y + this.viewBox.height - padding;
|
|
604
|
-
// 创建比例尺线段
|
|
605
|
-
const scaleLength = 10 * 50; // 50像素/米的基准比例
|
|
606
|
-
// 线段
|
|
607
|
-
const line = document.createElementNS('http://www.w3.org/2000/svg', 'line');
|
|
608
|
-
line.setAttribute('x1', scaleX.toString());
|
|
609
|
-
line.setAttribute('y1', scaleY.toString());
|
|
610
|
-
line.setAttribute('x2', (scaleX + scaleLength).toString());
|
|
611
|
-
line.setAttribute('y2', scaleY.toString());
|
|
612
|
-
line.setAttribute('stroke', '#333');
|
|
613
|
-
line.setAttribute('stroke-width', (2 / this.getZoom()).toString());
|
|
614
|
-
// 文字标签
|
|
615
|
-
const text = document.createElementNS('http://www.w3.org/2000/svg', 'text');
|
|
616
|
-
text.setAttribute('x', (scaleX + scaleLength / 2).toString());
|
|
617
|
-
text.setAttribute('y', (scaleY - 5 / this.getZoom()).toString()); // 文字位置适应缩放
|
|
618
|
-
text.setAttribute('text-anchor', 'middle');
|
|
619
|
-
text.setAttribute('font-family', 'Arial, sans-serif');
|
|
620
|
-
text.setAttribute('font-size', (12 / this.getZoom()).toString()); // 字体大小适应缩放
|
|
621
|
-
text.setAttribute('fill', '#333');
|
|
622
|
-
text.textContent = '10m';
|
|
623
|
-
this.layersGroup.appendChild(line);
|
|
624
|
-
this.layersGroup.appendChild(text);
|
|
625
|
-
}
|
|
626
248
|
// ==================== 拖拽功能 ====================
|
|
627
249
|
/**
|
|
628
250
|
* 设置拖拽事件处理器
|
|
@@ -1487,7 +1109,7 @@ class ObstacleLayer extends BaseLayer {
|
|
|
1487
1109
|
}
|
|
1488
1110
|
}
|
|
1489
1111
|
|
|
1490
|
-
var chargingPileImage = "3900c861790f0a9d.png";
|
|
1112
|
+
var chargingPileImage = "data:image/png;base64,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";
|
|
1491
1113
|
|
|
1492
1114
|
/**
|
|
1493
1115
|
* 充电桩图层
|
|
@@ -1936,7 +1558,7 @@ function createPathSegmentsByType(list) {
|
|
|
1936
1558
|
/**
|
|
1937
1559
|
* 计算地图边界
|
|
1938
1560
|
*/
|
|
1939
|
-
function calculateMapBounds(mapData
|
|
1561
|
+
function calculateMapBounds(mapData) {
|
|
1940
1562
|
let minX = Infinity;
|
|
1941
1563
|
let minY = Infinity;
|
|
1942
1564
|
let maxX = -Infinity;
|
|
@@ -1981,21 +1603,6 @@ function calculateMapBounds(mapData, pathData) {
|
|
|
1981
1603
|
if (point)
|
|
1982
1604
|
updateBounds([[point.x, point.y]]);
|
|
1983
1605
|
}
|
|
1984
|
-
// 处理SVG元素的边界(TIME_LIMIT_OBSTACLE)- 简化为使用中心点
|
|
1985
|
-
if (element.svg &&
|
|
1986
|
-
element.center &&
|
|
1987
|
-
element.scale !== undefined &&
|
|
1988
|
-
element.direction !== undefined) {
|
|
1989
|
-
const centerPoint = convertPositionFormat(element.center);
|
|
1990
|
-
if (centerPoint) {
|
|
1991
|
-
// 简单估算SVG边界:使用中心点加上缩放后的估算半径
|
|
1992
|
-
const estimatedRadius = 50 * (element.scale || 1); // 估算半径
|
|
1993
|
-
updateBounds([
|
|
1994
|
-
[centerPoint.x - estimatedRadius, centerPoint.y - estimatedRadius],
|
|
1995
|
-
[centerPoint.x + estimatedRadius, centerPoint.y + estimatedRadius],
|
|
1996
|
-
]);
|
|
1997
|
-
}
|
|
1998
|
-
}
|
|
1999
1606
|
}
|
|
2000
1607
|
// 如果没有找到边界,返回默认值
|
|
2001
1608
|
if (minX === Infinity) {
|
|
@@ -2017,37 +1624,97 @@ function isValidGpsCoordinate$1(lat, lng) {
|
|
|
2017
1624
|
);
|
|
2018
1625
|
}
|
|
2019
1626
|
/**
|
|
2020
|
-
* 从地图几何数据估算GPS
|
|
2021
|
-
* 当GPS
|
|
1627
|
+
* 从地图几何数据估算GPS边界坐标
|
|
1628
|
+
* 当GPS坐标无效时,基于地图的几何边界来估算SW和NE的GPS坐标
|
|
1629
|
+
* calculateMapBounds返回的数据除以50后代表准确的物理单位(米)
|
|
2022
1630
|
*/
|
|
2023
1631
|
function estimateGpsFromMapBounds(mapData) {
|
|
2024
1632
|
try {
|
|
2025
1633
|
const bounds = calculateMapBounds(mapData);
|
|
2026
1634
|
if (!bounds || bounds.minX === Infinity) {
|
|
1635
|
+
return {
|
|
1636
|
+
sw: [0, 0],
|
|
1637
|
+
ne: [0, 0]
|
|
1638
|
+
};
|
|
1639
|
+
}
|
|
1640
|
+
// 将边界数据转换为物理单位(米)
|
|
1641
|
+
const minXMeters = bounds.minX / SCALE_FACTOR * 6; // 西边界
|
|
1642
|
+
const minYMeters = bounds.minY / SCALE_FACTOR * 6; // 南边界
|
|
1643
|
+
const maxXMeters = bounds.maxX / SCALE_FACTOR * 6; // 东边界
|
|
1644
|
+
const maxYMeters = bounds.maxY / SCALE_FACTOR * 6; // 北边界
|
|
1645
|
+
const mapWidthMeters = maxXMeters - minXMeters;
|
|
1646
|
+
const mapHeightMeters = maxYMeters - minYMeters;
|
|
1647
|
+
console.log('地图物理尺寸:', {
|
|
1648
|
+
minX: minXMeters,
|
|
1649
|
+
minY: minYMeters,
|
|
1650
|
+
maxX: maxXMeters,
|
|
1651
|
+
maxY: maxYMeters,
|
|
1652
|
+
width: mapWidthMeters,
|
|
1653
|
+
height: mapHeightMeters
|
|
1654
|
+
});
|
|
1655
|
+
// 根据地图大小选择合适的基准GPS坐标
|
|
1656
|
+
let baseLat;
|
|
1657
|
+
let baseLng;
|
|
1658
|
+
if (mapWidthMeters < 1000 && mapHeightMeters < 1000) {
|
|
1659
|
+
// 小型区域 - 使用更精确的基准点
|
|
1660
|
+
baseLat = 39.9042; // 北京天安门
|
|
1661
|
+
baseLng = 116.4074;
|
|
1662
|
+
}
|
|
1663
|
+
else if (mapWidthMeters < 10000 && mapHeightMeters < 10000) {
|
|
1664
|
+
// 中型区域 - 使用城市级别的基准点
|
|
1665
|
+
baseLat = 39.9000;
|
|
1666
|
+
baseLng = 116.4000;
|
|
1667
|
+
}
|
|
1668
|
+
else {
|
|
1669
|
+
// 大型区域 - 使用更大范围的基准点
|
|
1670
|
+
baseLat = 40.0000;
|
|
1671
|
+
baseLng = 116.0000;
|
|
1672
|
+
}
|
|
1673
|
+
// 精确的坐标转换常数
|
|
1674
|
+
// 1度纬度 = 约111,320米(在地球上任何地方都基本相同)
|
|
1675
|
+
// 1度经度 = 约111,320 * cos(纬度) 米(随纬度变化)
|
|
1676
|
+
const METERS_PER_DEGREE_LAT = 111320;
|
|
1677
|
+
const METERS_PER_DEGREE_LNG = 111320 * Math.cos(baseLat * Math.PI / 180);
|
|
1678
|
+
// 计算SW(西南角)GPS坐标
|
|
1679
|
+
const swLat = baseLat + minYMeters / METERS_PER_DEGREE_LAT; // 南边界纬度
|
|
1680
|
+
const swLng = baseLng + minXMeters / METERS_PER_DEGREE_LNG; // 西边界经度
|
|
1681
|
+
// 计算NE(东北角)GPS坐标
|
|
1682
|
+
const neLat = baseLat + maxYMeters / METERS_PER_DEGREE_LAT; // 北边界纬度
|
|
1683
|
+
const neLng = baseLng + maxXMeters / METERS_PER_DEGREE_LNG; // 东边界经度
|
|
1684
|
+
console.log('GPS边界坐标估算:', {
|
|
1685
|
+
sw: { lat: swLat, lng: swLng },
|
|
1686
|
+
ne: { lat: neLat, lng: neLng },
|
|
1687
|
+
offsets: {
|
|
1688
|
+
minYOffset: minYMeters / METERS_PER_DEGREE_LAT,
|
|
1689
|
+
minXOffset: minXMeters / METERS_PER_DEGREE_LNG,
|
|
1690
|
+
maxYOffset: maxYMeters / METERS_PER_DEGREE_LAT,
|
|
1691
|
+
maxXOffset: maxXMeters / METERS_PER_DEGREE_LNG
|
|
1692
|
+
}
|
|
1693
|
+
});
|
|
1694
|
+
// 验证估算的坐标是否在合理范围内
|
|
1695
|
+
if (swLat < -90 || swLat > 90 || swLng < -180 || swLng > 180 ||
|
|
1696
|
+
neLat < -90 || neLat > 90 || neLng < -180 || neLng > 180) {
|
|
1697
|
+
console.warn('估算的GPS坐标超出有效范围:', {
|
|
1698
|
+
sw: [swLng, swLat],
|
|
1699
|
+
ne: [neLng, neLat]
|
|
1700
|
+
});
|
|
1701
|
+
return null;
|
|
1702
|
+
}
|
|
1703
|
+
// 确保SW在NE的西南方
|
|
1704
|
+
if (swLat >= neLat || swLng >= neLng) {
|
|
1705
|
+
console.warn('GPS边界坐标逻辑错误:', {
|
|
1706
|
+
sw: [swLng, swLat],
|
|
1707
|
+
ne: [neLng, neLat]
|
|
1708
|
+
});
|
|
2027
1709
|
return null;
|
|
2028
1710
|
}
|
|
2029
|
-
// 计算地图的几何中心
|
|
2030
|
-
const centerX = (bounds.minX + bounds.maxX) / 2;
|
|
2031
|
-
const centerY = (bounds.minY + bounds.maxY) / 2;
|
|
2032
|
-
const mapWidth = bounds.maxX - bounds.minX;
|
|
2033
|
-
const mapHeight = bounds.maxY - bounds.minY;
|
|
2034
|
-
// 基于地图大小估算GPS坐标
|
|
2035
|
-
// 这里使用一个简化的转换:假设这是一个小型区域地图
|
|
2036
|
-
// 1米大约对应0.000009度纬度,0.000011度经度(在中纬度地区)
|
|
2037
|
-
const metersToLatDegree = 1 / 110540; // 1米 ≈ 0.000009度纬度
|
|
2038
|
-
const metersToLngDegree = 1 / 111320; // 1米 ≈ 0.000009度经度(赤道附近)
|
|
2039
|
-
// 估算的GPS中心点(使用一个合理的默认位置作为基准)
|
|
2040
|
-
const baseLat = 40.0; // 使用北纬40度作为基准(大致位于中国/美国中部)
|
|
2041
|
-
const baseLng = 116.0; // 使用东经116度作为基准
|
|
2042
|
-
const estimatedLat = baseLat + centerY * metersToLatDegree;
|
|
2043
|
-
const estimatedLng = baseLng + centerX * metersToLngDegree;
|
|
2044
1711
|
return {
|
|
2045
|
-
|
|
2046
|
-
|
|
1712
|
+
sw: [swLng, swLat], // [经度, 纬度]
|
|
1713
|
+
ne: [neLng, neLat] // [经度, 纬度]
|
|
2047
1714
|
};
|
|
2048
1715
|
}
|
|
2049
1716
|
catch (error) {
|
|
2050
|
-
console.warn('估算GPS
|
|
1717
|
+
console.warn('估算GPS边界坐标时出错:', error);
|
|
2051
1718
|
return null;
|
|
2052
1719
|
}
|
|
2053
1720
|
}
|
|
@@ -2093,10 +1760,12 @@ function calculateMapGpsCenter(mapData) {
|
|
|
2093
1760
|
}
|
|
2094
1761
|
}
|
|
2095
1762
|
// 尝试从地图几何边界估算GPS坐标
|
|
2096
|
-
const
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
1763
|
+
const estimatedBounds = estimateGpsFromMapBounds(mapData);
|
|
1764
|
+
if (estimatedBounds) {
|
|
1765
|
+
// 从估算的边界计算中心点
|
|
1766
|
+
const centerLat = (estimatedBounds.sw[1] + estimatedBounds.ne[1]) / 2;
|
|
1767
|
+
const centerLng = (estimatedBounds.sw[0] + estimatedBounds.ne[0]) / 2;
|
|
1768
|
+
return { lat: centerLat, lng: centerLng };
|
|
2100
1769
|
}
|
|
2101
1770
|
return {
|
|
2102
1771
|
lat: 39.9042, // 北京纬度
|
|
@@ -2453,7 +2122,7 @@ const parseMapWorkPosition = (mapWorkPosition) => {
|
|
|
2453
2122
|
currentMowProgress,
|
|
2454
2123
|
};
|
|
2455
2124
|
};
|
|
2456
|
-
const handleRealTimeData = ({ realTimeData, isMowing,
|
|
2125
|
+
const handleRealTimeData = ({ realTimeData, isMowing, pathData, partitionId, }) => {
|
|
2457
2126
|
// 先将数据进行倒排,这样好插入数据
|
|
2458
2127
|
if (realTimeData.length > 0) {
|
|
2459
2128
|
realTimeData.reverse();
|
|
@@ -2463,25 +2132,6 @@ const handleRealTimeData = ({ realTimeData, isMowing, mapData, pathData, partiti
|
|
|
2463
2132
|
let mowingStatus = isMowing || false;
|
|
2464
2133
|
let currentPartitionId = partitionId || null;
|
|
2465
2134
|
realTimeData.forEach((item) => {
|
|
2466
|
-
if (currentPartitionId) {
|
|
2467
|
-
// 如果这个分区不在历史轨迹数据里面,需要去地图数据里面看看是否有这个分区,和相关数据
|
|
2468
|
-
if (!newPathData?.[currentPartitionId]) {
|
|
2469
|
-
const findMapData = mapData?.sub_maps?.find((item) => item.id === Number(currentPartitionId));
|
|
2470
|
-
if (findMapData) {
|
|
2471
|
-
newPathData[currentPartitionId] = {
|
|
2472
|
-
area: findMapData?.elements?.[0]?.area || 0,
|
|
2473
|
-
finishedArea: 0,
|
|
2474
|
-
partitionPercentage: 0,
|
|
2475
|
-
partitionId: Number(currentPartitionId),
|
|
2476
|
-
endTimeAlias: -1,
|
|
2477
|
-
startTime: 0,
|
|
2478
|
-
endTime: 0,
|
|
2479
|
-
// name: findMapData?.name || '',
|
|
2480
|
-
list: [],
|
|
2481
|
-
};
|
|
2482
|
-
}
|
|
2483
|
-
}
|
|
2484
|
-
}
|
|
2485
2135
|
// 这里需要区分,是割草进度还是割草轨迹
|
|
2486
2136
|
if (item.type === REAL_TIME_DATA_TYPE.LOCATION) {
|
|
2487
2137
|
// 割草轨迹
|
|
@@ -2491,8 +2141,8 @@ const handleRealTimeData = ({ realTimeData, isMowing, mapData, pathData, partiti
|
|
|
2491
2141
|
const currentPathData = newPathData[currentPartitionId];
|
|
2492
2142
|
newPathData[currentPartitionId] = {
|
|
2493
2143
|
...currentPathData,
|
|
2494
|
-
|
|
2495
|
-
...(currentPathData?.
|
|
2144
|
+
points: [
|
|
2145
|
+
...(currentPathData?.points || []),
|
|
2496
2146
|
{
|
|
2497
2147
|
postureX: Number(postureX),
|
|
2498
2148
|
postureY: Number(postureY),
|
|
@@ -3761,8 +3411,8 @@ class PathDataProcessor {
|
|
|
3761
3411
|
}
|
|
3762
3412
|
// 获取所有分区的路径数据
|
|
3763
3413
|
const allPathItems = Object.values(pathData).reduce((acc, partitionData) => {
|
|
3764
|
-
if (partitionData && partitionData.
|
|
3765
|
-
acc.push(...partitionData.
|
|
3414
|
+
if (partitionData && partitionData.points && partitionData.points.length > 0) {
|
|
3415
|
+
acc.push(...partitionData.points);
|
|
3766
3416
|
}
|
|
3767
3417
|
return acc;
|
|
3768
3418
|
}, []);
|
|
@@ -4479,21 +4129,24 @@ class ChargingPileManager {
|
|
|
4479
4129
|
if (!svg)
|
|
4480
4130
|
return;
|
|
4481
4131
|
const viewBox = svg.viewBox.baseVal;
|
|
4482
|
-
|
|
4132
|
+
({
|
|
4483
4133
|
x: viewBox.x,
|
|
4484
4134
|
y: viewBox.y,
|
|
4485
4135
|
width: viewBox.width,
|
|
4486
4136
|
height: viewBox.height,
|
|
4487
|
-
};
|
|
4488
|
-
|
|
4137
|
+
});
|
|
4138
|
+
const g = svg.querySelector('g');
|
|
4139
|
+
const gBox = g?.getBBox();
|
|
4140
|
+
console.log('g==', g, gBox, viewBox);
|
|
4141
|
+
this.updatePositionsWithPrecomputedData(divWidth, divHeight, gBox);
|
|
4489
4142
|
}
|
|
4490
4143
|
/**
|
|
4491
4144
|
* 使用预计算数据更新位置
|
|
4492
4145
|
*/
|
|
4493
4146
|
updatePositionsWithPrecomputedData(divWidth, divHeight, viewBox) {
|
|
4494
4147
|
this.chargingPileElements.forEach((element, _index) => {
|
|
4495
|
-
console.log('updatePositionsWithPrecomputedData-------->', element);
|
|
4496
4148
|
const center = element.coordinates[0];
|
|
4149
|
+
console.log('updatePositionsWithPrecomputedData-------->', center, divHeight, divWidth, viewBox, element);
|
|
4497
4150
|
const pixelPosition = this.convertMapCoordinateToPixelWithPrecomputedData(center[0], center[1], divWidth, divHeight, viewBox);
|
|
4498
4151
|
if (pixelPosition) {
|
|
4499
4152
|
const pileId = `pile_${center[0]}_${center[1]}`;
|
|
@@ -4646,10 +4299,10 @@ class AntennaManager {
|
|
|
4646
4299
|
*/
|
|
4647
4300
|
createAntennaElement(antennaData) {
|
|
4648
4301
|
const size = 30; // 默认30px大小
|
|
4649
|
-
const isOnline = antennaData
|
|
4302
|
+
const isOnline = antennaData?.status === 1;
|
|
4650
4303
|
// 根据天线ID和在线状态选择图片
|
|
4651
4304
|
let imageSrc;
|
|
4652
|
-
if (antennaData
|
|
4305
|
+
if (antennaData?.type === 1) {
|
|
4653
4306
|
imageSrc = isOnline ? antennaOneOnline : antennaOneOffline;
|
|
4654
4307
|
}
|
|
4655
4308
|
else {
|
|
@@ -4793,6 +4446,8 @@ class AntennaManager {
|
|
|
4793
4446
|
collapseAllTooltips() {
|
|
4794
4447
|
if (!this.container)
|
|
4795
4448
|
return;
|
|
4449
|
+
this.antennaTooltipFlag = false;
|
|
4450
|
+
this.singleAntennaTooltipFlag = false;
|
|
4796
4451
|
const allTooltips = this.container.querySelectorAll('.antenna-tooltip');
|
|
4797
4452
|
allTooltips.forEach((tooltip) => {
|
|
4798
4453
|
const tooltipElement = tooltip;
|
|
@@ -4858,8 +4513,12 @@ class AntennaManager {
|
|
|
4858
4513
|
*/
|
|
4859
4514
|
updateAntennaPosition() {
|
|
4860
4515
|
this.clear();
|
|
4861
|
-
|
|
4862
|
-
|
|
4516
|
+
if (this.mainAntennaData) {
|
|
4517
|
+
this.addMainAntennaElement(this.mainAntennaData?.originalData);
|
|
4518
|
+
}
|
|
4519
|
+
if (this.singleAntennaData) {
|
|
4520
|
+
this.addSingleAntennaElement(this.singleAntennaData?.originalData);
|
|
4521
|
+
}
|
|
4863
4522
|
}
|
|
4864
4523
|
/**
|
|
4865
4524
|
* 获取容器元素
|
|
@@ -5658,15 +5317,15 @@ class MowerMapOverlay {
|
|
|
5658
5317
|
if (!viewBox)
|
|
5659
5318
|
return;
|
|
5660
5319
|
// 构造viewBox信息对象
|
|
5661
|
-
|
|
5320
|
+
({
|
|
5662
5321
|
x: viewBox.x,
|
|
5663
5322
|
y: viewBox.y,
|
|
5664
5323
|
width: viewBox.width,
|
|
5665
5324
|
height: viewBox.height,
|
|
5666
|
-
};
|
|
5325
|
+
});
|
|
5667
5326
|
// 更新充电桩位置
|
|
5668
5327
|
if (this.chargingPileManager) {
|
|
5669
|
-
this.chargingPileManager.
|
|
5328
|
+
this.chargingPileManager.updatePositions();
|
|
5670
5329
|
}
|
|
5671
5330
|
}
|
|
5672
5331
|
// 创建编辑界面
|
|
@@ -6428,25 +6087,6 @@ const isValidGpsCoordinate = (coordinate) => {
|
|
|
6428
6087
|
!(Math.abs(lng) < 0.001 && Math.abs(lat) < 0.001) // 排除接近(0,0)的坐标
|
|
6429
6088
|
);
|
|
6430
6089
|
};
|
|
6431
|
-
// 从地图几何数据估算GPS边界
|
|
6432
|
-
const estimateGpsBoundsFromMapData = (mapData) => {
|
|
6433
|
-
if (!mapData.origin || !mapData.size)
|
|
6434
|
-
return null;
|
|
6435
|
-
// 使用地图的几何尺寸来估算一个合理的GPS边界
|
|
6436
|
-
// 这是一个简化的估算,假设地图大致在某个区域
|
|
6437
|
-
const defaultLat = 39.9042; // 北京纬度作为默认值
|
|
6438
|
-
const defaultLng = 116.4074; // 北京经度作为默认值
|
|
6439
|
-
// 根据地图尺寸估算边界(简化计算)
|
|
6440
|
-
const mapWidth = mapData.size.width || 1000;
|
|
6441
|
-
const mapHeight = mapData.size.height || 1000;
|
|
6442
|
-
// 大致估算:1000像素 ≈ 0.01度
|
|
6443
|
-
const latRange = (mapHeight / 1000) * 0.01;
|
|
6444
|
-
const lngRange = (mapWidth / 1000) * 0.01;
|
|
6445
|
-
return {
|
|
6446
|
-
sw: [defaultLng - lngRange / 2, defaultLat - latRange / 2],
|
|
6447
|
-
ne: [defaultLng + lngRange / 2, defaultLat + latRange / 2],
|
|
6448
|
-
};
|
|
6449
|
-
};
|
|
6450
6090
|
// 获取有效的GPS边界
|
|
6451
6091
|
const getValidGpsBounds = (mapData) => {
|
|
6452
6092
|
// 首先尝试使用地图数据中的GPS坐标
|
|
@@ -6457,23 +6097,27 @@ const getValidGpsBounds = (mapData) => {
|
|
|
6457
6097
|
};
|
|
6458
6098
|
}
|
|
6459
6099
|
// 如果GPS坐标无效,尝试从地图几何数据估算
|
|
6460
|
-
const
|
|
6461
|
-
|
|
6462
|
-
|
|
6463
|
-
|
|
6100
|
+
const { sw, ne } = estimateGpsFromMapBounds(mapData);
|
|
6101
|
+
console.log('sw, ne==', sw, ne);
|
|
6102
|
+
if (sw && ne) {
|
|
6103
|
+
console.warn('GPS坐标无效,使用地图几何数据估算边界:', sw, ne);
|
|
6104
|
+
return {
|
|
6105
|
+
sw: [sw[0], sw[1]],
|
|
6106
|
+
ne: [ne[0], ne[1]],
|
|
6107
|
+
};
|
|
6464
6108
|
}
|
|
6465
6109
|
// 最后的fallback:使用默认坐标
|
|
6466
6110
|
console.warn('无法获取有效的GPS边界,使用默认坐标');
|
|
6467
6111
|
return {
|
|
6468
|
-
sw: [
|
|
6469
|
-
ne: [
|
|
6112
|
+
sw: [-9.1562, -37.7503],
|
|
6113
|
+
ne: [31.247, 5.797],
|
|
6470
6114
|
};
|
|
6471
6115
|
};
|
|
6472
6116
|
// 默认配置
|
|
6473
6117
|
const defaultMapConfig = DEFAULT_MAP_CONFIG;
|
|
6474
6118
|
const defaultPathConfig = DEFAULT_PATH_CONFIG;
|
|
6475
6119
|
// 地图渲染器组件
|
|
6476
|
-
const MowerMapRenderer = forwardRef(({ mapJson, pathJson, mowerPositonConfig, mapConfig, pathConfig, antennaConfig
|
|
6120
|
+
const MowerMapRenderer = forwardRef(({ mapRef, mapJson, pathJson, mowerPositonConfig, mapConfig, pathConfig, antennaConfig, onMapLoad, onPathLoad, onZoomChange, onError, className, style, googleMapInstance, isEditMode = false, dragCallbacks, }, ref) => {
|
|
6477
6121
|
const containerRef = useRef(null);
|
|
6478
6122
|
const svgMapViewRef = useRef(null);
|
|
6479
6123
|
const [elementCount, setElementCount] = useState(0);
|
|
@@ -6481,12 +6125,15 @@ const MowerMapRenderer = forwardRef(({ mapJson, pathJson, mowerPositonConfig, ma
|
|
|
6481
6125
|
const [zoom, setZoom] = useState(1);
|
|
6482
6126
|
const [currentError, setCurrentError] = useState(null);
|
|
6483
6127
|
const overlayRef = useRef(null);
|
|
6484
|
-
const mapRef = useMap();
|
|
6128
|
+
// const mapRef = useMap();
|
|
6485
6129
|
const [isGoogleMapsReady, setIsGoogleMapsReady] = useState(false);
|
|
6486
6130
|
const [hasInitializedBounds, setHasInitializedBounds] = useState(false);
|
|
6487
6131
|
const { subBoundaryBorder } = useSubBoundaryBorderStore();
|
|
6488
6132
|
// 合并配置
|
|
6489
6133
|
const mergedMapConfig = useMemo(() => {
|
|
6134
|
+
// if (!mapConfig) {
|
|
6135
|
+
// return defaultMapConfig;
|
|
6136
|
+
// }
|
|
6490
6137
|
return { ...defaultMapConfig, ...(mapConfig || {}) };
|
|
6491
6138
|
}, [mapConfig]);
|
|
6492
6139
|
const mergedPathConfig = useMemo(() => {
|
|
@@ -6514,6 +6161,7 @@ const MowerMapRenderer = forwardRef(({ mapJson, pathJson, mowerPositonConfig, ma
|
|
|
6514
6161
|
setCurrentError(error);
|
|
6515
6162
|
onError?.(error);
|
|
6516
6163
|
};
|
|
6164
|
+
console.log('react version', React.version);
|
|
6517
6165
|
// 初始化Google Maps叠加层
|
|
6518
6166
|
const initializeGoogleMapsOverlay = async () => {
|
|
6519
6167
|
if (!mapJson || !mergedMapConfig.useGoogleMaps)
|
|
@@ -6533,6 +6181,7 @@ const MowerMapRenderer = forwardRef(({ mapJson, pathJson, mowerPositonConfig, ma
|
|
|
6533
6181
|
}
|
|
6534
6182
|
// 计算边界
|
|
6535
6183
|
const bounds = calculateMapBounds(mapJson);
|
|
6184
|
+
console.log('bounds==', bounds);
|
|
6536
6185
|
if (!bounds) {
|
|
6537
6186
|
handleError('无法计算地图边界');
|
|
6538
6187
|
return;
|
|
@@ -6656,7 +6305,7 @@ const MowerMapRenderer = forwardRef(({ mapJson, pathJson, mowerPositonConfig, ma
|
|
|
6656
6305
|
Object.values(pathJson).forEach((item) => {
|
|
6657
6306
|
const pathDrawLayer = new DrawLayer();
|
|
6658
6307
|
const elements = PathDataProcessor.processPathData({
|
|
6659
|
-
pathData: item.
|
|
6308
|
+
pathData: item.points || [],
|
|
6660
6309
|
pathConfig: mergedPathConfig,
|
|
6661
6310
|
});
|
|
6662
6311
|
if (elements.length === 0) {
|
|
@@ -6694,7 +6343,7 @@ const MowerMapRenderer = forwardRef(({ mapJson, pathJson, mowerPositonConfig, ma
|
|
|
6694
6343
|
svgMapViewRef.current = null;
|
|
6695
6344
|
}
|
|
6696
6345
|
};
|
|
6697
|
-
}, [mapJson, pathJson, mergedMapConfig, mergedPathConfig]);
|
|
6346
|
+
}, [mapJson, pathJson, mergedMapConfig, mergedPathConfig, mergedAntennaConfig]);
|
|
6698
6347
|
// 监听编辑模式变化
|
|
6699
6348
|
useEffect(() => {
|
|
6700
6349
|
if (overlayRef.current) {
|
|
@@ -6795,6 +6444,9 @@ const MowerMapRenderer = forwardRef(({ mapJson, pathJson, mowerPositonConfig, ma
|
|
|
6795
6444
|
overlayRef.current.setEditMode(enabled);
|
|
6796
6445
|
}
|
|
6797
6446
|
},
|
|
6447
|
+
getEditMode: () => {
|
|
6448
|
+
return isEditMode;
|
|
6449
|
+
},
|
|
6798
6450
|
getCurrentDragState: () => {
|
|
6799
6451
|
return overlayRef.current ? overlayRef.current.getCurrentDragState() : null;
|
|
6800
6452
|
},
|
|
@@ -6802,11 +6454,9 @@ const MowerMapRenderer = forwardRef(({ mapJson, pathJson, mowerPositonConfig, ma
|
|
|
6802
6454
|
getPathCount: () => pathCount,
|
|
6803
6455
|
isGoogleMapsReady: () => isGoogleMapsReady,
|
|
6804
6456
|
handleRealTimeData: ({ realTimeData, isMowing, mapData, pathData, partitionId, }) => {
|
|
6805
|
-
console.log('handleRealTimeData----->', realTimeData, isMowing, mapData, pathData, partitionId);
|
|
6806
6457
|
return handleRealTimeData({
|
|
6807
6458
|
realTimeData,
|
|
6808
6459
|
isMowing,
|
|
6809
|
-
mapData,
|
|
6810
6460
|
pathData,
|
|
6811
6461
|
partitionId,
|
|
6812
6462
|
});
|
|
@@ -6834,4 +6484,4 @@ const MowerMapRenderer = forwardRef(({ mapJson, pathJson, mowerPositonConfig, ma
|
|
|
6834
6484
|
});
|
|
6835
6485
|
MowerMapRenderer.displayName = 'MowerMapRenderer';
|
|
6836
6486
|
|
|
6837
|
-
export { MapDataProcessor, MowerMapRenderer, PathDataProcessor, calculateMapGpsCenter };
|
|
6487
|
+
export { MapDataProcessor, MowerMapRenderer, PathDataProcessor, calculateMapGpsCenter, estimateGpsFromMapBounds };
|