react-native-maplibre-lite 0.1.1 → 0.1.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/lib/module/components/MapPlaceholder.js +2 -3
- package/lib/module/components/MapPlaceholder.js.map +1 -1
- package/lib/module/components/MapView.js +117 -41
- package/lib/module/components/MapView.js.map +1 -1
- package/lib/module/components/Marker.js +2 -2
- package/lib/module/components/Marker.js.map +1 -1
- package/lib/module/components/Polygon.js +2 -2
- package/lib/module/components/Polygon.js.map +1 -1
- package/lib/module/components/Polyline.js +2 -2
- package/lib/module/components/Polyline.js.map +1 -1
- package/lib/module/components/utils.js +29 -0
- package/lib/module/components/utils.js.map +1 -0
- package/lib/module/{webContent.js → components/webContent.js} +18 -32
- package/lib/module/components/webContent.js.map +1 -0
- package/lib/module/components/webFunctions/addMarkerWeb.js +36 -10
- package/lib/module/components/webFunctions/addMarkerWeb.js.map +1 -1
- package/lib/module/components/webFunctions/addPolylineWeb.js +2 -2
- package/lib/module/components/webFunctions/fitBoundsWeb.js +6 -2
- package/lib/module/components/webFunctions/fitBoundsWeb.js.map +1 -1
- package/lib/module/components/webFunctions/flyToWeb.js +14 -0
- package/lib/module/components/webFunctions/flyToWeb.js.map +1 -0
- package/lib/module/components/webFunctions/initWeb.js +52 -20
- package/lib/module/components/webFunctions/initWeb.js.map +1 -1
- package/lib/module/components/webFunctions/updateWeb.js +78 -0
- package/lib/module/components/webFunctions/updateWeb.js.map +1 -0
- package/lib/typescript/src/components/MapPlaceholder.d.ts.map +1 -1
- package/lib/typescript/src/components/MapView.d.ts +8 -1
- package/lib/typescript/src/components/MapView.d.ts.map +1 -1
- package/lib/typescript/src/components/Marker.d.ts +1 -1
- package/lib/typescript/src/components/Marker.d.ts.map +1 -1
- package/lib/typescript/src/components/Polygon.d.ts +1 -1
- package/lib/typescript/src/components/Polygon.d.ts.map +1 -1
- package/lib/typescript/src/components/types.d.ts +4 -0
- package/lib/typescript/src/components/types.d.ts.map +1 -1
- package/lib/typescript/src/components/utils.d.ts +2 -0
- package/lib/typescript/src/components/utils.d.ts.map +1 -0
- package/lib/typescript/src/components/webContent.d.ts +3 -0
- package/lib/typescript/src/components/webContent.d.ts.map +1 -0
- package/lib/typescript/src/components/webFunctions/addMarkerWeb.d.ts +1 -1
- package/lib/typescript/src/components/webFunctions/addMarkerWeb.d.ts.map +1 -1
- package/lib/typescript/src/components/webFunctions/addPolylineWeb.d.ts +1 -1
- package/lib/typescript/src/components/webFunctions/fitBoundsWeb.d.ts +1 -1
- package/lib/typescript/src/components/webFunctions/fitBoundsWeb.d.ts.map +1 -1
- package/lib/typescript/src/components/webFunctions/flyToWeb.d.ts +2 -0
- package/lib/typescript/src/components/webFunctions/flyToWeb.d.ts.map +1 -0
- package/lib/typescript/src/components/webFunctions/initWeb.d.ts +1 -1
- package/lib/typescript/src/components/webFunctions/initWeb.d.ts.map +1 -1
- package/lib/typescript/src/components/webFunctions/updateWeb.d.ts +3 -0
- package/lib/typescript/src/components/webFunctions/updateWeb.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +1 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/MapPlaceholder.tsx +9 -5
- package/src/components/MapView.tsx +163 -57
- package/src/components/Marker.tsx +3 -3
- package/src/components/Polygon.tsx +3 -3
- package/src/components/Polyline.tsx +2 -2
- package/src/components/types.ts +4 -0
- package/src/components/utils.ts +31 -0
- package/src/{webContent.ts → components/webContent.ts} +20 -39
- package/src/components/webFunctions/addMarkerWeb.ts +36 -10
- package/src/components/webFunctions/addPolylineWeb.ts +2 -2
- package/src/components/webFunctions/fitBoundsWeb.ts +6 -2
- package/src/components/webFunctions/flyToWeb.ts +11 -0
- package/src/components/webFunctions/initWeb.ts +52 -20
- package/src/components/webFunctions/updateWeb.ts +75 -0
- package/src/index.tsx +1 -1
- package/lib/module/webContent.js.map +0 -1
- package/lib/typescript/src/webContent.d.ts +0 -3
- package/lib/typescript/src/webContent.d.ts.map +0 -1
|
@@ -1,54 +1,74 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
useState,
|
|
2
|
+
createContext,
|
|
3
|
+
forwardRef,
|
|
4
|
+
useContext,
|
|
5
|
+
useEffect,
|
|
6
|
+
useImperativeHandle,
|
|
7
|
+
useRef,
|
|
8
|
+
useState,
|
|
10
9
|
} from 'react';
|
|
11
10
|
|
|
12
11
|
import {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
type StyleProp,
|
|
13
|
+
Platform,
|
|
14
|
+
View,
|
|
15
|
+
type ViewStyle,
|
|
17
16
|
} from 'react-native';
|
|
18
17
|
import { WebView } from 'react-native-webview';
|
|
19
18
|
|
|
20
|
-
import { maplibreHtmlMap } from '../webContent';
|
|
21
19
|
import MapPlaceholder from './MapPlaceholder';
|
|
22
20
|
import MapSelectPoint, { type MapSelectPointType } from './MapSelectPoint';
|
|
23
21
|
import {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
22
|
+
type EventParams,
|
|
23
|
+
type MarkerProps,
|
|
24
|
+
type PolygonProps,
|
|
25
|
+
type PolylineProps,
|
|
26
|
+
type SourcesProps,
|
|
29
27
|
} from './types';
|
|
28
|
+
import { loadResources } from './utils';
|
|
29
|
+
import { maplibreHtmlMap } from './webContent';
|
|
30
30
|
import addMarkerWeb from './webFunctions/addMarkerWeb';
|
|
31
31
|
import addPolygonWeb from './webFunctions/addPolygonWeb';
|
|
32
32
|
import addPolylineWeb from './webFunctions/addPolylineWeb';
|
|
33
33
|
import fitBoundsWeb from './webFunctions/fitBoundsWeb';
|
|
34
|
+
import { flyToWeb } from './webFunctions/flyToWeb';
|
|
34
35
|
import initWeb from './webFunctions/initWeb';
|
|
35
36
|
import removeMarkerWeb from './webFunctions/removeMarkerWeb';
|
|
36
37
|
import removePolygonWeb from './webFunctions/removePolygonWeb';
|
|
37
38
|
import removePolylineWeb from './webFunctions/removePolylineWeb';
|
|
39
|
+
import updateWeb from './webFunctions/updateWeb';
|
|
40
|
+
|
|
41
|
+
interface UpdateProps {
|
|
42
|
+
center?: [number, number];
|
|
43
|
+
zoom?: number;
|
|
44
|
+
minZoom?: number;
|
|
45
|
+
maxZoom?: number;
|
|
46
|
+
zoomEnabled?: boolean;
|
|
47
|
+
scrollEnabled?: boolean;
|
|
48
|
+
mapStyle?: string;
|
|
49
|
+
}
|
|
38
50
|
|
|
39
51
|
interface MapViewProps {
|
|
40
52
|
children?: React.ReactNode;
|
|
41
53
|
|
|
42
|
-
|
|
54
|
+
|
|
55
|
+
placeholderTheme?: 'light' | 'dark';
|
|
43
56
|
center: [number, number];
|
|
44
57
|
zoom: number;
|
|
45
58
|
|
|
59
|
+
debugMode?: boolean;
|
|
60
|
+
autoFitBounds?: boolean;
|
|
61
|
+
fitBoundsPadding?: number;
|
|
62
|
+
fitBoundsDuration?: number;
|
|
63
|
+
flyToDuration?: number;
|
|
64
|
+
|
|
46
65
|
mapStyle: string;
|
|
47
66
|
style: StyleProp<ViewStyle>;
|
|
48
67
|
minZoom?: number;
|
|
49
68
|
maxZoom?: number;
|
|
50
69
|
zoomEnabled?: boolean;
|
|
51
70
|
scrollEnabled?: boolean;
|
|
71
|
+
onReady?: () => void;
|
|
52
72
|
onMoveStart?: (eventParams: EventParams) => void;
|
|
53
73
|
onMoveEnd?: (eventParams: EventParams) => void;
|
|
54
74
|
onZoomStart?: (eventParams: EventParams) => void;
|
|
@@ -66,6 +86,7 @@ interface MapViewProps {
|
|
|
66
86
|
|
|
67
87
|
export type MapViewRef = {
|
|
68
88
|
fitBounds: () => void;
|
|
89
|
+
flyTo: (center: [number, number], zoom: number) => void;
|
|
69
90
|
};
|
|
70
91
|
|
|
71
92
|
type MapViewRegistry = {
|
|
@@ -94,6 +115,8 @@ const webFunctionsString = [
|
|
|
94
115
|
addPolygonWeb,
|
|
95
116
|
removePolygonWeb,
|
|
96
117
|
fitBoundsWeb,
|
|
118
|
+
flyToWeb,
|
|
119
|
+
updateWeb
|
|
97
120
|
].join('\n');
|
|
98
121
|
|
|
99
122
|
const getBoundsFromCoords = (
|
|
@@ -122,7 +145,7 @@ const getBoundsFromCoords = (
|
|
|
122
145
|
};
|
|
123
146
|
|
|
124
147
|
export const MapView = forwardRef<MapViewRef, MapViewProps>((props, ref) => {
|
|
125
|
-
const webViewRef = useRef<
|
|
148
|
+
const webViewRef = useRef<WebView | null>(null);
|
|
126
149
|
const [inited, setInited] = useState(false);
|
|
127
150
|
const [html, setHtml] = useState('');
|
|
128
151
|
|
|
@@ -135,18 +158,28 @@ export const MapView = forwardRef<MapViewRef, MapViewProps>((props, ref) => {
|
|
|
135
158
|
? 0.85
|
|
136
159
|
: (performanceMode === 'balanced' && Platform.OS === 'android' ? 1 : undefined);
|
|
137
160
|
|
|
138
|
-
const sendToWebView =
|
|
161
|
+
const sendToWebView = (message: { function: string; params: any }) => {
|
|
162
|
+
if (__DEV__) {
|
|
163
|
+
console.log('MapView: sendToWebView', message);
|
|
164
|
+
}
|
|
139
165
|
webViewRef.current?.postMessage(JSON.stringify(message));
|
|
140
|
-
}
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
const initMap = async () => {
|
|
169
|
+
if (__DEV__) {
|
|
170
|
+
console.log('MapView: initMap');
|
|
171
|
+
console.log('MapView: props.mapStyle', props.mapStyle);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const mapStyleText = await loadResources(props.mapStyle);
|
|
175
|
+
const mapStyle = JSON.parse(mapStyleText);
|
|
141
176
|
|
|
142
|
-
const initMap = useCallback(() => {
|
|
143
177
|
sendToWebView({
|
|
144
178
|
function: 'init',
|
|
145
179
|
params: {
|
|
146
|
-
|
|
180
|
+
mapStyle: mapStyle,
|
|
147
181
|
zoomEnabled: props.zoomEnabled ?? false,
|
|
148
182
|
scrollEnabled: props.scrollEnabled ?? false,
|
|
149
|
-
theme: props.theme,
|
|
150
183
|
center: props.center,
|
|
151
184
|
zoom: props.zoom,
|
|
152
185
|
minZoom: props.minZoom,
|
|
@@ -162,73 +195,143 @@ export const MapView = forwardRef<MapViewRef, MapViewProps>((props, ref) => {
|
|
|
162
195
|
turboWhileMoving: props.turboWhileMoving ?? (performanceMode === 'performance'),
|
|
163
196
|
},
|
|
164
197
|
});
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
const addMarker = useCallback((propsMarker: MarkerProps) => {
|
|
168
|
-
if (propsMarker.latitude && propsMarker.longitude) {
|
|
169
|
-
coordsInMapRef.current[propsMarker.uniqueId] = [[propsMarker.longitude, propsMarker.latitude]];
|
|
170
|
-
}
|
|
198
|
+
};
|
|
171
199
|
|
|
200
|
+
const updateMarkerClickHandler = (propsMarker: MarkerProps) => {
|
|
172
201
|
if (propsMarker.onPress) {
|
|
173
202
|
markersClickHandlers.current[propsMarker.uniqueId] = propsMarker.onPress;
|
|
174
203
|
} else {
|
|
175
204
|
delete markersClickHandlers.current[propsMarker.uniqueId];
|
|
176
205
|
}
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
const addMarker = (propsMarker: MarkerProps) => {
|
|
209
|
+
if (propsMarker.latitude != null && propsMarker.longitude != null && !propsMarker.ignoreFitBounds) {
|
|
210
|
+
coordsInMapRef.current[propsMarker.uniqueId] = [[propsMarker.longitude, propsMarker.latitude]];
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
updateMarkerClickHandler(propsMarker);
|
|
177
214
|
|
|
178
215
|
sendToWebView({ function: 'addMarker', params: propsMarker });
|
|
179
|
-
|
|
216
|
+
scheduleAutoFitBounds();
|
|
217
|
+
};
|
|
180
218
|
|
|
181
|
-
const removeMarker =
|
|
219
|
+
const removeMarker = (propsMarker: MarkerProps) => {
|
|
182
220
|
delete coordsInMapRef.current[propsMarker.uniqueId];
|
|
183
221
|
delete markersClickHandlers.current[propsMarker.uniqueId];
|
|
184
222
|
sendToWebView({ function: 'removeMarker', params: propsMarker });
|
|
185
|
-
|
|
223
|
+
scheduleAutoFitBounds();
|
|
224
|
+
};
|
|
186
225
|
|
|
187
|
-
const addPolyline =
|
|
188
|
-
if (propsPolyline.coordinates) {
|
|
226
|
+
const addPolyline = (propsPolyline: PolylineProps) => {
|
|
227
|
+
if (propsPolyline.coordinates && !propsPolyline.ignoreFitBounds) {
|
|
189
228
|
coordsInMapRef.current[propsPolyline.uniqueId] = propsPolyline.coordinates;
|
|
190
229
|
}
|
|
191
230
|
sendToWebView({ function: 'addPolyline', params: propsPolyline });
|
|
192
|
-
|
|
231
|
+
scheduleAutoFitBounds();
|
|
232
|
+
};
|
|
193
233
|
|
|
194
|
-
const removePolyline =
|
|
234
|
+
const removePolyline = (propsPolyline: PolylineProps) => {
|
|
195
235
|
delete coordsInMapRef.current[propsPolyline.uniqueId];
|
|
196
236
|
sendToWebView({ function: 'removePolyline', params: propsPolyline });
|
|
197
|
-
|
|
237
|
+
scheduleAutoFitBounds();
|
|
238
|
+
};
|
|
198
239
|
|
|
199
|
-
const addPolygon =
|
|
200
|
-
if (propsPolygon.coordinates) {
|
|
240
|
+
const addPolygon = (propsPolygon: PolygonProps) => {
|
|
241
|
+
if (propsPolygon.coordinates && !propsPolygon.ignoreFitBounds) {
|
|
201
242
|
coordsInMapRef.current[propsPolygon.uniqueId] = propsPolygon.coordinates;
|
|
202
243
|
}
|
|
203
244
|
sendToWebView({ function: 'addPolygon', params: propsPolygon });
|
|
204
|
-
|
|
245
|
+
scheduleAutoFitBounds();
|
|
246
|
+
};
|
|
205
247
|
|
|
206
|
-
const removePolygon =
|
|
248
|
+
const removePolygon = (propsPolygon: PolygonProps) => {
|
|
207
249
|
delete coordsInMapRef.current[propsPolygon.uniqueId];
|
|
208
250
|
sendToWebView({ function: 'removePolygon', params: propsPolygon });
|
|
209
|
-
|
|
251
|
+
scheduleAutoFitBounds();
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
const autoFitBoundsTimeoutRef = useRef<NodeJS.Timeout | null>(null);
|
|
255
|
+
|
|
256
|
+
const scheduleAutoFitBounds = () => {
|
|
257
|
+
if (!props.autoFitBounds) return;
|
|
258
|
+
if (autoFitBoundsTimeoutRef.current) {
|
|
259
|
+
clearTimeout(autoFitBoundsTimeoutRef.current);
|
|
260
|
+
}
|
|
261
|
+
autoFitBoundsTimeoutRef.current = setTimeout(() => {
|
|
262
|
+
fitBounds();
|
|
263
|
+
}, 1000);
|
|
264
|
+
};
|
|
210
265
|
|
|
211
|
-
|
|
266
|
+
useEffect(() => {
|
|
267
|
+
scheduleAutoFitBounds();
|
|
268
|
+
}, [props.autoFitBounds, props.fitBoundsPadding]);
|
|
269
|
+
|
|
270
|
+
const fitBounds = () => {
|
|
212
271
|
const coords = Object.values(coordsInMapRef.current).flat();
|
|
213
|
-
if (coords.length
|
|
272
|
+
if (coords.length <= 1) return;
|
|
214
273
|
|
|
215
274
|
const bounds = getBoundsFromCoords(coords);
|
|
216
|
-
sendToWebView({ function: 'fitBounds', params: { bounds } });
|
|
217
|
-
}
|
|
275
|
+
sendToWebView({ function: 'fitBounds', params: { bounds, padding: props.fitBoundsPadding ?? 40, duration: props.fitBoundsDuration ?? 500 } });
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
const flyTo = (center: [number, number], zoom: number) => {
|
|
279
|
+
sendToWebView({ function: 'flyTo', params: { center, zoom, duration: props.flyToDuration ?? 500 } });
|
|
280
|
+
};
|
|
218
281
|
|
|
219
282
|
useImperativeHandle(ref, () => ({
|
|
220
283
|
fitBounds,
|
|
284
|
+
flyTo,
|
|
221
285
|
}), [fitBounds]);
|
|
222
286
|
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
const lastPropsRef = useRef<MapViewProps>(props);
|
|
290
|
+
|
|
291
|
+
useEffect(() => {
|
|
292
|
+
const updateProps: UpdateProps = {};
|
|
293
|
+
|
|
294
|
+
if (lastPropsRef.current.minZoom !== props.minZoom) {
|
|
295
|
+
updateProps.minZoom = props.minZoom;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
if (lastPropsRef.current.maxZoom !== props.maxZoom) {
|
|
299
|
+
updateProps.maxZoom = props.maxZoom;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
if (lastPropsRef.current.zoomEnabled !== props.zoomEnabled) {
|
|
303
|
+
updateProps.zoomEnabled = props.zoomEnabled;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
if (lastPropsRef.current.scrollEnabled !== props.scrollEnabled) {
|
|
307
|
+
updateProps.scrollEnabled = props.scrollEnabled;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
if (lastPropsRef.current.mapStyle !== props.mapStyle) {
|
|
311
|
+
updateProps.mapStyle = props.mapStyle;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
lastPropsRef.current = props;
|
|
315
|
+
|
|
316
|
+
if (Object.keys(updateProps).length > 0) {
|
|
317
|
+
sendToWebView({ function: 'update', params: updateProps });
|
|
318
|
+
}
|
|
319
|
+
}, [props.minZoom, props.maxZoom, props.zoomEnabled, props.scrollEnabled, props.mapStyle]);
|
|
320
|
+
|
|
321
|
+
|
|
223
322
|
useEffect(() => {
|
|
224
323
|
if (html) return;
|
|
225
|
-
maplibreHtmlMap(webFunctionsString, props.sources).then(setHtml);
|
|
226
|
-
}, [
|
|
324
|
+
maplibreHtmlMap(webFunctionsString, props.sources, props.debugMode ?? false).then(setHtml);
|
|
325
|
+
}, []);
|
|
227
326
|
|
|
228
|
-
const onReceiveMessageFromWebView =
|
|
327
|
+
const onReceiveMessageFromWebView = (data: string) => {
|
|
229
328
|
try {
|
|
230
329
|
const msg = JSON.parse(data);
|
|
231
330
|
|
|
331
|
+
if (__DEV__) {
|
|
332
|
+
console.log('MapView: event', msg);
|
|
333
|
+
}
|
|
334
|
+
|
|
232
335
|
if (msg.type === 'event') {
|
|
233
336
|
switch (msg.event) {
|
|
234
337
|
case 'movestart':
|
|
@@ -253,6 +356,7 @@ export const MapView = forwardRef<MapViewRef, MapViewProps>((props, ref) => {
|
|
|
253
356
|
}
|
|
254
357
|
|
|
255
358
|
if (msg.type === 'inited') {
|
|
359
|
+
props.onReady?.();
|
|
256
360
|
setInited(true);
|
|
257
361
|
return;
|
|
258
362
|
}
|
|
@@ -274,22 +378,20 @@ export const MapView = forwardRef<MapViewRef, MapViewProps>((props, ref) => {
|
|
|
274
378
|
console.warn('MapView: failed to parse WebView message', e);
|
|
275
379
|
}
|
|
276
380
|
}
|
|
277
|
-
}
|
|
381
|
+
};
|
|
278
382
|
|
|
279
383
|
return (
|
|
280
384
|
<View style={props.style}>
|
|
281
|
-
{!inited && (
|
|
282
|
-
<MapPlaceholder theme={props.theme} />
|
|
283
|
-
)}
|
|
284
385
|
|
|
285
386
|
<MapViewContext.Provider
|
|
286
387
|
value={{
|
|
287
|
-
addPolygon,
|
|
288
|
-
removePolygon,
|
|
289
388
|
addMarker,
|
|
290
389
|
removeMarker,
|
|
390
|
+
|
|
291
391
|
addPolyline,
|
|
292
392
|
removePolyline,
|
|
393
|
+
addPolygon,
|
|
394
|
+
removePolygon,
|
|
293
395
|
}}
|
|
294
396
|
>
|
|
295
397
|
<WebView
|
|
@@ -328,6 +430,10 @@ export const MapView = forwardRef<MapViewRef, MapViewProps>((props, ref) => {
|
|
|
328
430
|
</View>
|
|
329
431
|
)}
|
|
330
432
|
</MapViewContext.Provider>
|
|
433
|
+
{!inited && (
|
|
434
|
+
<MapPlaceholder theme={props.placeholderTheme ?? 'light'} />
|
|
435
|
+
)}
|
|
436
|
+
|
|
331
437
|
</View>
|
|
332
438
|
);
|
|
333
439
|
});
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
} from 'react';
|
|
5
5
|
|
|
6
6
|
import { useMapViewContext } from './MapView';
|
|
7
|
-
import {
|
|
7
|
+
import type { MarkerProps } from './types';
|
|
8
8
|
|
|
9
9
|
export const Marker = (props: MarkerProps) => {
|
|
10
10
|
const { addMarker, removeMarker } = useMapViewContext();
|
|
@@ -19,13 +19,13 @@ export const Marker = (props: MarkerProps) => {
|
|
|
19
19
|
addMarker(props);
|
|
20
20
|
lastRenderProps.current = serialized;
|
|
21
21
|
}
|
|
22
|
-
}, [props
|
|
22
|
+
}, [props]);
|
|
23
23
|
|
|
24
24
|
useEffect(() => {
|
|
25
25
|
return () => {
|
|
26
26
|
removeMarker(propsRef.current);
|
|
27
27
|
};
|
|
28
|
-
}, [
|
|
28
|
+
}, []);
|
|
29
29
|
|
|
30
30
|
return null;
|
|
31
31
|
};
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
} from 'react';
|
|
5
5
|
|
|
6
6
|
import { useMapViewContext } from './MapView';
|
|
7
|
-
import {
|
|
7
|
+
import type { PolygonProps } from './types';
|
|
8
8
|
|
|
9
9
|
export const Polygon = (props: PolygonProps) => {
|
|
10
10
|
const { addPolygon, removePolygon } = useMapViewContext();
|
|
@@ -19,13 +19,13 @@ export const Polygon = (props: PolygonProps) => {
|
|
|
19
19
|
addPolygon(props);
|
|
20
20
|
lastRenderProps.current = serialized;
|
|
21
21
|
}
|
|
22
|
-
}, [props
|
|
22
|
+
}, [props]);
|
|
23
23
|
|
|
24
24
|
useEffect(() => {
|
|
25
25
|
return () => {
|
|
26
26
|
removePolygon(propsRef.current);
|
|
27
27
|
};
|
|
28
|
-
}, [
|
|
28
|
+
}, []);
|
|
29
29
|
|
|
30
30
|
return null;
|
|
31
31
|
};
|
|
@@ -19,13 +19,13 @@ export const Polyline = (props: PolylineProps) => {
|
|
|
19
19
|
addPolyline(props);
|
|
20
20
|
lastRenderProps.current = serialized;
|
|
21
21
|
}
|
|
22
|
-
}, [props
|
|
22
|
+
}, [props]);
|
|
23
23
|
|
|
24
24
|
useEffect(() => {
|
|
25
25
|
return () => {
|
|
26
26
|
removePolyline(propsRef.current);
|
|
27
27
|
};
|
|
28
|
-
}, [
|
|
28
|
+
}, []);
|
|
29
29
|
|
|
30
30
|
return null;
|
|
31
31
|
};
|
package/src/components/types.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
|
|
2
2
|
export type MarkerProps = {
|
|
3
|
+
ignoreFitBounds?: boolean,
|
|
3
4
|
uniqueId: string,
|
|
4
5
|
onPress?: () => void,
|
|
5
6
|
latitude: number,
|
|
@@ -9,6 +10,7 @@ export type MarkerProps = {
|
|
|
9
10
|
iconUrl?: string,
|
|
10
11
|
iconWidth?: number,
|
|
11
12
|
iconHeight?: number,
|
|
13
|
+
html?: string,
|
|
12
14
|
|
|
13
15
|
}
|
|
14
16
|
|
|
@@ -19,6 +21,7 @@ export type SourcesProps = {
|
|
|
19
21
|
}
|
|
20
22
|
|
|
21
23
|
export type PolygonProps = {
|
|
24
|
+
ignoreFitBounds?: boolean,
|
|
22
25
|
uniqueId: string,
|
|
23
26
|
coordinates: [number, number][],
|
|
24
27
|
fillColor?: string,
|
|
@@ -30,6 +33,7 @@ export type PolygonProps = {
|
|
|
30
33
|
}
|
|
31
34
|
|
|
32
35
|
export type PolylineProps = {
|
|
36
|
+
ignoreFitBounds?: boolean,
|
|
33
37
|
uniqueId: string,
|
|
34
38
|
color?: string,
|
|
35
39
|
width?: number,
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
2
|
+
|
|
3
|
+
const CACHE_VERSION = 'v1';
|
|
4
|
+
|
|
5
|
+
export const loadResources = async (url: string) => {
|
|
6
|
+
const cacheKey = `${url}@${CACHE_VERSION}`;
|
|
7
|
+
|
|
8
|
+
try {
|
|
9
|
+
const stored = await AsyncStorage.getItem(cacheKey);
|
|
10
|
+
if (stored) {
|
|
11
|
+
return stored;
|
|
12
|
+
}
|
|
13
|
+
} catch (_) {
|
|
14
|
+
// cache miss — proceed to fetch
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const response = await fetch(url);
|
|
18
|
+
if (!response.ok) {
|
|
19
|
+
throw new Error(`Failed to load resource: ${url} (${response.status})`);
|
|
20
|
+
}
|
|
21
|
+
const text = await response.text();
|
|
22
|
+
|
|
23
|
+
if (text) {
|
|
24
|
+
try {
|
|
25
|
+
await AsyncStorage.setItem(cacheKey, text);
|
|
26
|
+
} catch (_) {
|
|
27
|
+
// storage full or unavailable — non-fatal
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return text;
|
|
31
|
+
}
|
|
@@ -1,38 +1,7 @@
|
|
|
1
|
-
import
|
|
1
|
+
import type {SourcesProps} from './types';
|
|
2
|
+
import {loadResources} from './utils';
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const CACHE_VERSION = 'v1';
|
|
6
|
-
|
|
7
|
-
const loadResources = async (url: string) => {
|
|
8
|
-
const cacheKey = `${url}@${CACHE_VERSION}`;
|
|
9
|
-
|
|
10
|
-
try {
|
|
11
|
-
const stored = await AsyncStorage.getItem(cacheKey);
|
|
12
|
-
if (stored) {
|
|
13
|
-
return stored;
|
|
14
|
-
}
|
|
15
|
-
} catch (_) {
|
|
16
|
-
// cache miss — proceed to fetch
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const response = await fetch(url);
|
|
20
|
-
if (!response.ok) {
|
|
21
|
-
throw new Error(`Failed to load resource: ${url} (${response.status})`);
|
|
22
|
-
}
|
|
23
|
-
const text = await response.text();
|
|
24
|
-
|
|
25
|
-
if (text) {
|
|
26
|
-
try {
|
|
27
|
-
await AsyncStorage.setItem(cacheKey, text);
|
|
28
|
-
} catch (_) {
|
|
29
|
-
// storage full or unavailable — non-fatal
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
return text;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export const maplibreHtmlMap = async (webFunctions: string, sources: SourcesProps) => {
|
|
4
|
+
export const maplibreHtmlMap = async (webFunctions: string, sources: SourcesProps, debugMode: boolean) => {
|
|
36
5
|
//Загружаем скрипты как текст
|
|
37
6
|
|
|
38
7
|
|
|
@@ -40,6 +9,10 @@ export const maplibreHtmlMap = async (webFunctions: string, sources: SourcesProp
|
|
|
40
9
|
let maplibreCSS = await loadResources(sources.maplibreCSS);
|
|
41
10
|
let pmtiles = await loadResources(sources.pmtilesJS);
|
|
42
11
|
|
|
12
|
+
console.log('MapLibre: maplibreJS', !!maplibreJS ? 'true' : 'false');
|
|
13
|
+
console.log('MapLibre: maplibreCSS', !!maplibreCSS ? 'true' : 'false');
|
|
14
|
+
console.log('MapLibre: pmtiles', !!pmtiles ? 'true' : 'false');
|
|
15
|
+
|
|
43
16
|
|
|
44
17
|
|
|
45
18
|
return `<!DOCTYPE html>
|
|
@@ -127,11 +100,9 @@ var layouts = {};
|
|
|
127
100
|
var map = null;
|
|
128
101
|
|
|
129
102
|
try {
|
|
130
|
-
|
|
103
|
+
var protocol = new pmtiles.Protocol();
|
|
131
104
|
maplibregl.addProtocol("pmtiles", protocol.tile);
|
|
132
|
-
|
|
133
|
-
console.error('pmtiles init error:', e.message);
|
|
134
|
-
}
|
|
105
|
+
|
|
135
106
|
window.onload = function () {
|
|
136
107
|
document.addEventListener("message", function (event) {
|
|
137
108
|
receiveMessage(event.data);
|
|
@@ -145,7 +116,7 @@ try {
|
|
|
145
116
|
}
|
|
146
117
|
|
|
147
118
|
|
|
148
|
-
|
|
119
|
+
function receiveMessage(message) {
|
|
149
120
|
|
|
150
121
|
var data = JSON.parse(message);
|
|
151
122
|
|
|
@@ -163,6 +134,9 @@ try {
|
|
|
163
134
|
${webFunctions}
|
|
164
135
|
|
|
165
136
|
} catch (e) {
|
|
137
|
+
if(${debugMode}){
|
|
138
|
+
alert('WebView function error: ' + functionName + ' ' + e.message);
|
|
139
|
+
}
|
|
166
140
|
console.error('WebView function error:', functionName, e.message);
|
|
167
141
|
window.ReactNativeWebView.postMessage(JSON.stringify({
|
|
168
142
|
type: 'error',
|
|
@@ -174,7 +148,14 @@ ${webFunctions}
|
|
|
174
148
|
}
|
|
175
149
|
};
|
|
176
150
|
|
|
151
|
+
} catch (e) {
|
|
152
|
+
|
|
153
|
+
if(${debugMode}){
|
|
154
|
+
alert('pmtiles init error: ' + e.message);
|
|
155
|
+
}
|
|
177
156
|
|
|
157
|
+
|
|
158
|
+
}
|
|
178
159
|
</script>
|
|
179
160
|
|
|
180
161
|
|
|
@@ -2,18 +2,41 @@ export default /*js*/`
|
|
|
2
2
|
|
|
3
3
|
if(functionName === 'addMarker') {
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
|
|
6
6
|
if(markers[params.uniqueId]){
|
|
7
7
|
markers[params.uniqueId].remove();
|
|
8
8
|
delete markers[params.uniqueId];
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
if(params && params.html){
|
|
13
|
+
|
|
14
|
+
var el = document.createElement('div');
|
|
15
|
+
el.className = 'marker';
|
|
16
|
+
el.innerHTML = params.html;
|
|
17
|
+
|
|
18
|
+
el.addEventListener('click', function() {
|
|
19
|
+
window.ReactNativeWebView.postMessage(JSON.stringify({
|
|
20
|
+
type: 'markerClick',
|
|
21
|
+
uniqueId: params.uniqueId
|
|
22
|
+
}));
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
markers[params.uniqueId] = new maplibregl.Marker({element: el})
|
|
27
|
+
.setLngLat([params.longitude, params.latitude])
|
|
28
|
+
.addTo(map);
|
|
29
|
+
|
|
30
|
+
return;
|
|
31
|
+
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
if(!params || !params.iconUrl){
|
|
13
36
|
|
|
14
37
|
|
|
15
38
|
markers[params.uniqueId] = new maplibregl.Marker({
|
|
16
|
-
color: params.color
|
|
39
|
+
color: (params.color != null) ? params.color : undefined,
|
|
17
40
|
}).setLngLat([params.longitude, params.latitude])
|
|
18
41
|
.addTo(map);
|
|
19
42
|
markers[params.uniqueId].getElement().addEventListener('click', function() {
|
|
@@ -28,13 +51,16 @@ export default /*js*/`
|
|
|
28
51
|
}else{
|
|
29
52
|
|
|
30
53
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
54
|
+
var el2 = document.createElement('div');
|
|
55
|
+
el2.className = 'marker';
|
|
56
|
+
el2.style.backgroundImage = 'url(' + params.iconUrl + ')';
|
|
57
|
+
el2.style.backgroundSize = 'cover';
|
|
58
|
+
el2.style.backgroundPosition = 'center';
|
|
59
|
+
el2.style.backgroundRepeat = 'no-repeat';
|
|
60
|
+
el2.style.width = params.iconWidth + 'px';
|
|
61
|
+
el2.style.height = params.iconHeight + 'px';
|
|
36
62
|
|
|
37
|
-
|
|
63
|
+
el2.addEventListener('click', function() {
|
|
38
64
|
window.ReactNativeWebView.postMessage(JSON.stringify({
|
|
39
65
|
type: 'markerClick',
|
|
40
66
|
uniqueId: params.uniqueId
|
|
@@ -42,7 +68,7 @@ export default /*js*/`
|
|
|
42
68
|
});
|
|
43
69
|
|
|
44
70
|
|
|
45
|
-
markers[params.uniqueId] = new maplibregl.Marker({element:
|
|
71
|
+
markers[params.uniqueId] = new maplibregl.Marker({element: el2})
|
|
46
72
|
.setLngLat([params.longitude, params.latitude])
|
|
47
73
|
.addTo(map);
|
|
48
74
|
|
|
@@ -36,8 +36,8 @@ if(functionName === 'addPolyline') {
|
|
|
36
36
|
'line-cap': 'round'
|
|
37
37
|
},
|
|
38
38
|
'paint': {
|
|
39
|
-
'line-color': params.color
|
|
40
|
-
'line-width': params.width
|
|
39
|
+
'line-color': (params.color != null) ? params.color : '#000000',
|
|
40
|
+
'line-width': (params.width != null) ? params.width : 4
|
|
41
41
|
}
|
|
42
42
|
});
|
|
43
43
|
|