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.
Files changed (70) hide show
  1. package/lib/module/components/MapPlaceholder.js +2 -3
  2. package/lib/module/components/MapPlaceholder.js.map +1 -1
  3. package/lib/module/components/MapView.js +117 -41
  4. package/lib/module/components/MapView.js.map +1 -1
  5. package/lib/module/components/Marker.js +2 -2
  6. package/lib/module/components/Marker.js.map +1 -1
  7. package/lib/module/components/Polygon.js +2 -2
  8. package/lib/module/components/Polygon.js.map +1 -1
  9. package/lib/module/components/Polyline.js +2 -2
  10. package/lib/module/components/Polyline.js.map +1 -1
  11. package/lib/module/components/utils.js +29 -0
  12. package/lib/module/components/utils.js.map +1 -0
  13. package/lib/module/{webContent.js → components/webContent.js} +18 -32
  14. package/lib/module/components/webContent.js.map +1 -0
  15. package/lib/module/components/webFunctions/addMarkerWeb.js +36 -10
  16. package/lib/module/components/webFunctions/addMarkerWeb.js.map +1 -1
  17. package/lib/module/components/webFunctions/addPolylineWeb.js +2 -2
  18. package/lib/module/components/webFunctions/fitBoundsWeb.js +6 -2
  19. package/lib/module/components/webFunctions/fitBoundsWeb.js.map +1 -1
  20. package/lib/module/components/webFunctions/flyToWeb.js +14 -0
  21. package/lib/module/components/webFunctions/flyToWeb.js.map +1 -0
  22. package/lib/module/components/webFunctions/initWeb.js +52 -20
  23. package/lib/module/components/webFunctions/initWeb.js.map +1 -1
  24. package/lib/module/components/webFunctions/updateWeb.js +78 -0
  25. package/lib/module/components/webFunctions/updateWeb.js.map +1 -0
  26. package/lib/typescript/src/components/MapPlaceholder.d.ts.map +1 -1
  27. package/lib/typescript/src/components/MapView.d.ts +8 -1
  28. package/lib/typescript/src/components/MapView.d.ts.map +1 -1
  29. package/lib/typescript/src/components/Marker.d.ts +1 -1
  30. package/lib/typescript/src/components/Marker.d.ts.map +1 -1
  31. package/lib/typescript/src/components/Polygon.d.ts +1 -1
  32. package/lib/typescript/src/components/Polygon.d.ts.map +1 -1
  33. package/lib/typescript/src/components/types.d.ts +4 -0
  34. package/lib/typescript/src/components/types.d.ts.map +1 -1
  35. package/lib/typescript/src/components/utils.d.ts +2 -0
  36. package/lib/typescript/src/components/utils.d.ts.map +1 -0
  37. package/lib/typescript/src/components/webContent.d.ts +3 -0
  38. package/lib/typescript/src/components/webContent.d.ts.map +1 -0
  39. package/lib/typescript/src/components/webFunctions/addMarkerWeb.d.ts +1 -1
  40. package/lib/typescript/src/components/webFunctions/addMarkerWeb.d.ts.map +1 -1
  41. package/lib/typescript/src/components/webFunctions/addPolylineWeb.d.ts +1 -1
  42. package/lib/typescript/src/components/webFunctions/fitBoundsWeb.d.ts +1 -1
  43. package/lib/typescript/src/components/webFunctions/fitBoundsWeb.d.ts.map +1 -1
  44. package/lib/typescript/src/components/webFunctions/flyToWeb.d.ts +2 -0
  45. package/lib/typescript/src/components/webFunctions/flyToWeb.d.ts.map +1 -0
  46. package/lib/typescript/src/components/webFunctions/initWeb.d.ts +1 -1
  47. package/lib/typescript/src/components/webFunctions/initWeb.d.ts.map +1 -1
  48. package/lib/typescript/src/components/webFunctions/updateWeb.d.ts +3 -0
  49. package/lib/typescript/src/components/webFunctions/updateWeb.d.ts.map +1 -0
  50. package/lib/typescript/src/index.d.ts +1 -1
  51. package/lib/typescript/src/index.d.ts.map +1 -1
  52. package/package.json +1 -1
  53. package/src/components/MapPlaceholder.tsx +9 -5
  54. package/src/components/MapView.tsx +163 -57
  55. package/src/components/Marker.tsx +3 -3
  56. package/src/components/Polygon.tsx +3 -3
  57. package/src/components/Polyline.tsx +2 -2
  58. package/src/components/types.ts +4 -0
  59. package/src/components/utils.ts +31 -0
  60. package/src/{webContent.ts → components/webContent.ts} +20 -39
  61. package/src/components/webFunctions/addMarkerWeb.ts +36 -10
  62. package/src/components/webFunctions/addPolylineWeb.ts +2 -2
  63. package/src/components/webFunctions/fitBoundsWeb.ts +6 -2
  64. package/src/components/webFunctions/flyToWeb.ts +11 -0
  65. package/src/components/webFunctions/initWeb.ts +52 -20
  66. package/src/components/webFunctions/updateWeb.ts +75 -0
  67. package/src/index.tsx +1 -1
  68. package/lib/module/webContent.js.map +0 -1
  69. package/lib/typescript/src/webContent.d.ts +0 -3
  70. package/lib/typescript/src/webContent.d.ts.map +0 -1
@@ -1,54 +1,74 @@
1
1
  import {
2
- createContext,
3
- forwardRef,
4
- useCallback,
5
- useContext,
6
- useEffect,
7
- useImperativeHandle,
8
- useRef,
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
- type StyleProp,
14
- Platform,
15
- View,
16
- type ViewStyle,
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
- type EventParams,
25
- type MarkerProps,
26
- type PolygonProps,
27
- type PolylineProps,
28
- type SourcesProps,
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
- theme: 'light' | 'dark';
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<any>(null);
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 = useCallback((message: { function: string; params: any }) => {
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
- style: props.mapStyle,
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
- }, [sendToWebView, props.zoomEnabled, props.scrollEnabled, props.theme, props.center, props.zoom, props.minZoom, props.maxZoom, props.mapStyle, performanceMode, props.pixelRatio, fallbackPixelRatio, props.turboWhileMoving]);
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
- }, [sendToWebView]);
216
+ scheduleAutoFitBounds();
217
+ };
180
218
 
181
- const removeMarker = useCallback((propsMarker: MarkerProps) => {
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
- }, [sendToWebView]);
223
+ scheduleAutoFitBounds();
224
+ };
186
225
 
187
- const addPolyline = useCallback((propsPolyline: PolylineProps) => {
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
- }, [sendToWebView]);
231
+ scheduleAutoFitBounds();
232
+ };
193
233
 
194
- const removePolyline = useCallback((propsPolyline: PolylineProps) => {
234
+ const removePolyline = (propsPolyline: PolylineProps) => {
195
235
  delete coordsInMapRef.current[propsPolyline.uniqueId];
196
236
  sendToWebView({ function: 'removePolyline', params: propsPolyline });
197
- }, [sendToWebView]);
237
+ scheduleAutoFitBounds();
238
+ };
198
239
 
199
- const addPolygon = useCallback((propsPolygon: PolygonProps) => {
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
- }, [sendToWebView]);
245
+ scheduleAutoFitBounds();
246
+ };
205
247
 
206
- const removePolygon = useCallback((propsPolygon: PolygonProps) => {
248
+ const removePolygon = (propsPolygon: PolygonProps) => {
207
249
  delete coordsInMapRef.current[propsPolygon.uniqueId];
208
250
  sendToWebView({ function: 'removePolygon', params: propsPolygon });
209
- }, [sendToWebView]);
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
- const fitBounds = useCallback(() => {
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 === 0) return;
272
+ if (coords.length <= 1) return;
214
273
 
215
274
  const bounds = getBoundsFromCoords(coords);
216
- sendToWebView({ function: 'fitBounds', params: { bounds } });
217
- }, [sendToWebView]);
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
- }, [html, props.sources]);
324
+ maplibreHtmlMap(webFunctionsString, props.sources, props.debugMode ?? false).then(setHtml);
325
+ }, []);
227
326
 
228
- const onReceiveMessageFromWebView = useCallback((data: string) => {
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
- }, [props.onMoveStart, props.onMoveEnd, props.onZoomStart, props.onZoomEnd, props.onIdle, initMap]);
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 { type MarkerProps } from './types';
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, addMarker]);
22
+ }, [props]);
23
23
 
24
24
  useEffect(() => {
25
25
  return () => {
26
26
  removeMarker(propsRef.current);
27
27
  };
28
- }, [removeMarker]);
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 { type PolygonProps } from './types';
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, addPolygon]);
22
+ }, [props]);
23
23
 
24
24
  useEffect(() => {
25
25
  return () => {
26
26
  removePolygon(propsRef.current);
27
27
  };
28
- }, [removePolygon]);
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, addPolyline]);
22
+ }, [props]);
23
23
 
24
24
  useEffect(() => {
25
25
  return () => {
26
26
  removePolyline(propsRef.current);
27
27
  };
28
- }, [removePolyline]);
28
+ }, []);
29
29
 
30
30
  return null;
31
31
  };
@@ -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 AsyncStorage from '@react-native-async-storage/async-storage';
1
+ import type {SourcesProps} from './types';
2
+ import {loadResources} from './utils';
2
3
 
3
- import type { SourcesProps } from './components/types';
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
- let protocol = new pmtiles.Protocol();
103
+ var protocol = new pmtiles.Protocol();
131
104
  maplibregl.addProtocol("pmtiles", protocol.tile);
132
- } catch (e) {
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
- const receiveMessage = (message) => {
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
- if(!params?.iconUrl){
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 ?? undefined,
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
- const el = document.createElement('div');
32
- el.className = 'marker';
33
- el.style.backgroundImage = 'url(' + params.iconUrl + ')';
34
- el.style.width = params.iconWidth + 'px';
35
- el.style.height = params.iconHeight + 'px';
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
- el.addEventListener('click', () => {
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: el})
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 ?? '#000000',
40
- 'line-width': params.width ?? 4
39
+ 'line-color': (params.color != null) ? params.color : '#000000',
40
+ 'line-width': (params.width != null) ? params.width : 4
41
41
  }
42
42
  });
43
43