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