@nativescript-community/ui-mapbox 6.2.31 → 7.0.0

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 (42) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/common.d.ts +56 -26
  3. package/common.js +44 -28
  4. package/expression/expression-parser.android.d.ts +2 -2
  5. package/expression/expression-parser.android.js +4 -3
  6. package/expression/expression-parser.ios.d.ts +2 -2
  7. package/expression/expression-parser.ios.js +28 -13
  8. package/index.android.d.ts +59 -66
  9. package/index.android.js +1388 -1244
  10. package/index.d.ts +36 -5
  11. package/index.ios.d.ts +72 -243
  12. package/index.ios.js +1161 -1999
  13. package/layers/layer-factory.android.d.ts +7 -5
  14. package/layers/layer-factory.android.js +71 -41
  15. package/layers/layer-factory.d.ts +2 -1
  16. package/layers/layer-factory.ios.d.ts +8 -8
  17. package/layers/layer-factory.ios.js +46 -100
  18. package/layers/parser/property-parser.android.d.ts +3 -1
  19. package/layers/parser/property-parser.android.js +25 -24
  20. package/layers/parser/property-parser.d.ts +1 -1
  21. package/layers/parser/property-parser.ios.d.ts +0 -2
  22. package/layers/parser/property-parser.ios.js +0 -149
  23. package/markers/Marker.android.d.ts +28 -0
  24. package/markers/Marker.android.js +54 -0
  25. package/markers/Marker.common.d.ts +2 -0
  26. package/markers/Marker.common.js +31 -0
  27. package/markers/MarkerManager.android.d.ts +35 -0
  28. package/markers/MarkerManager.android.js +220 -0
  29. package/package.json +7 -6
  30. package/platforms/android/include.gradle +31 -27
  31. package/platforms/android/ui_mapbox.aar +0 -0
  32. package/platforms/ios/Podfile +3 -1
  33. package/platforms/ios/Resources/default_pin.png +0 -0
  34. package/platforms/ios/src/MapboxBridge.swift +1479 -0
  35. package/platforms/ios/src/NativeExpressionParser.swift +33 -0
  36. package/platforms/ios/src/NativeLayerFactory.swift +108 -0
  37. package/tsconfig.tsbuildinfo +1 -0
  38. package/typings/Mapbox.ios.d.ts +2 -3242
  39. package/typings/geojson.android.d.ts +689 -0
  40. package/typings/index.android.d.ts +46 -0
  41. package/typings/mapbox.android.d.ts +39968 -12560
  42. package/typings/mapbox.bridge.ios.d.ts +129 -0
package/index.ios.js CHANGED
@@ -1,527 +1,114 @@
1
- import { Color, File, Http, ImageSource, Trace, Utils, knownFolders, path } from '@nativescript/core';
2
- import { CLog, CLogTypes, ControlPosition, MapStyle, MapboxCommon, MapboxViewBase, telemetryProperty } from './common';
3
- import { Layer, LayerFactory } from './layers/layer-factory';
4
- import { ExpressionParser } from './expression/expression-parser';
5
- var MGLMapViewDelegateImpl = /** @class */ (function (_super) {
6
- __extends(MGLMapViewDelegateImpl, _super);
7
- function MGLMapViewDelegateImpl() {
8
- return _super !== null && _super.apply(this, arguments) || this;
9
- }
10
- MGLMapViewDelegateImpl.new = function () {
11
- return _super.new.call(this);
12
- };
13
- /**
14
- * initialize with the mapReady callback
15
- */
16
- MGLMapViewDelegateImpl.prototype.initWithCallback = function (mapLoadedCallback) {
17
- if (Trace.isEnabled()) {
18
- CLog(CLogTypes.info, 'MGLMapViewDelegateImpl::initWithCallback()');
19
- }
20
- this.mapLoadedCallback = mapLoadedCallback;
21
- return this;
22
- };
23
- /**
24
- * set a reference to the mapboxAPI instance
25
- */
26
- MGLMapViewDelegateImpl.prototype.setMapboxApi = function (api) {
27
- this.mapboxApi = api;
28
- };
29
- /**
30
- * set the user location click listener callback
31
- */
32
- MGLMapViewDelegateImpl.prototype.setUserLocationClickListener = function (callback) {
33
- this.userLocationClickListener = callback;
34
- };
35
- /**
36
- * set the user location click listener callback
37
- */
38
- MGLMapViewDelegateImpl.prototype.setUserLocationChangedistener = function (callback) {
39
- this.userLocationChangedListener = callback;
40
- };
41
- /**
42
- * set user location marker modes
43
- */
44
- MGLMapViewDelegateImpl.prototype.changeUserLocationRenderMode = function (userLocationRenderMode) {
45
- // nothing to do here
46
- };
47
- /**
48
- * set the camera changd listener callback
49
- */
50
- MGLMapViewDelegateImpl.prototype.setCameraChangedListener = function (callback) {
51
- this.cameraChangedListener = callback;
52
- };
53
- /**
54
- * set the camera idled listener callback
55
- */
56
- MGLMapViewDelegateImpl.prototype.setCameraIdledListener = function (callback) {
57
- this.cameraIdledListener = callback;
58
- };
59
- /**
60
- * set style loaded callback.
61
- *
62
- * set an optional callback to be invoked when a style set with
63
- * setMapStyle() is finished loading
64
- *
65
- * @param {function} callback function with loaded style as parameter.
66
- *
67
- * @see Mapbox:setMapStyle()
68
- */
69
- MGLMapViewDelegateImpl.prototype.setStyleLoadedCallback = function (callback) {
70
- this.styleLoadedCallback = callback;
71
- };
72
- /**
73
- * map ready callback
74
- */
75
- MGLMapViewDelegateImpl.prototype.mapViewDidFinishLoadingMap = function (mapView) {
76
- if (Trace.isEnabled()) {
77
- CLog(CLogTypes.info, 'MGLMapViewDelegateImpl:mapViewDidFinishLoadingMap(): top');
78
- }
79
- if (this.mapLoadedCallback !== undefined) {
80
- this.mapLoadedCallback(mapView);
81
- // this should be fired only once, but it's also fired when the style changes, so just remove the callback
82
- this.mapLoadedCallback = undefined;
83
- }
84
- };
85
- MGLMapViewDelegateImpl.prototype.mapViewDidFinishRenderingMapFullyRendered = function (mapView, fullyRendered) {
86
- if (Trace.isEnabled()) {
87
- CLog(CLogTypes.info, 'MGLMapViewDelegateImpl:mapViewDidFinishRenderingMapFullyRendered(): rendered is:', fullyRendered);
88
- }
89
- };
90
- /**
91
- * Callback when the style has been loaded.
92
- *
93
- * Based on my testing, it looks like this callback is invoked multiple times.
94
- *
95
- * @see Mapbox:setMapStyle()
96
- *
97
- * @link https://mapbox.github.io/mapbox-gl-native/macos/0.3.0/Protocols/MGLMapViewDelegate.html#/c:objc(pl)MGLMapViewDelegate(im)mapView:didFinishLoadingStyle:
98
- */
99
- MGLMapViewDelegateImpl.prototype.mapViewDidFinishLoadingStyle = function (mapView, style) {
100
- if (Trace.isEnabled()) {
101
- CLog(CLogTypes.info, 'MGLMapViewDelegateImpl:mapViewDidFinishLoadingStyle(): callback called.');
102
- }
103
- if (this.styleLoadedCallback !== undefined) {
104
- this.styleLoadedCallback(mapView, style);
105
- // to avoid multiple calls. This is only invoked from setMapStyle().
106
- this.styleLoadedCallback = undefined;
107
- }
108
- };
109
- /**
110
- * disable the default user location callout
111
- *
112
- * This took forever to find. The default iOS click handler for the user location
113
- * marker is about useless. It just displays "You Are Here". The examples do not
114
- * show how to disable it.
115
- */
116
- MGLMapViewDelegateImpl.prototype.mapViewAnnotationCanShowCallout = function (mapView, annotation) {
117
- if (annotation.isKindOfClass(MGLUserLocation.class())) {
118
- return false;
119
- }
120
- else {
121
- return true;
122
- }
123
- };
124
- MGLMapViewDelegateImpl.prototype.mapViewDidFailLoadingMapWithError = function (mapView, error) {
125
- if (Trace.isEnabled()) {
126
- CLog(CLogTypes.info, 'mapViewDidFailLoadingMapWithError: ' + error);
127
- }
128
- };
129
- MGLMapViewDelegateImpl.prototype.mapViewDidChangeUserTrackingModeAnimated = function (mapView, mode, animated) {
130
- if (Trace.isEnabled()) {
131
- CLog(CLogTypes.info, 'mapViewDidChangeUserTrackingModeAnimated: ' + mode);
132
- }
133
- };
134
- /**
135
- * fired when the marker icon is about to be rendered - return null for the default icon
136
- */
137
- MGLMapViewDelegateImpl.prototype.mapViewImageForAnnotation = function (mapView, annotation) {
138
- var cachedMarker = this.getTappedMarkerDetails(annotation);
139
- if (cachedMarker) {
140
- if (cachedMarker.reuseIdentifier) {
141
- var reusedImage = mapView.dequeueReusableAnnotationImageWithIdentifier(cachedMarker.reuseIdentifier);
142
- if (reusedImage) {
143
- return reusedImage;
144
- }
145
- }
146
- // TODO try adding .rotatesToMatchCamera = true;
147
- // .. for instance in the mapViewDidDeselectAnnotationView / mapViewDidSelectAnnotationView / mapViewViewForAnnotation delegate
148
- if (cachedMarker.icon) {
149
- if (cachedMarker.icon.startsWith('res://')) {
150
- var resourceName = cachedMarker.icon.substring('res://'.length);
151
- var imageSource = ImageSource.fromResourceSync(resourceName);
152
- if (imageSource === null) {
153
- console.log("Unable to locate ".concat(resourceName));
154
- }
155
- else {
156
- cachedMarker.reuseIdentifier = cachedMarker.icon;
157
- return MGLAnnotationImage.annotationImageWithImageReuseIdentifier(imageSource.ios, cachedMarker.reuseIdentifier);
158
- }
159
- }
160
- else if (cachedMarker.icon.startsWith('http')) {
161
- if (cachedMarker.iconDownloaded !== null) {
162
- cachedMarker.reuseIdentifier = cachedMarker.icon;
163
- return MGLAnnotationImage.annotationImageWithImageReuseIdentifier(cachedMarker.iconDownloaded, cachedMarker.reuseIdentifier);
164
- }
165
- }
166
- else {
167
- if (Trace.isEnabled()) {
168
- CLog(CLogTypes.info, 'Please use res://resourceName, http(s)://imageUrl or iconPath to use a local path');
169
- }
170
- }
171
- }
172
- else if (cachedMarker.iconPath) {
173
- var appPath = knownFolders.currentApp().path;
174
- var iconFullPath = appPath + '/' + cachedMarker.iconPath.replace('~/', '');
175
- if (File.exists(iconFullPath)) {
176
- var image = ImageSource.fromFileSync(iconFullPath).ios;
177
- // perhaps add resize options for nice retina rendering (although you can now use the 'icon' param instead)
178
- cachedMarker.reuseIdentifier = cachedMarker.iconPath;
179
- return MGLAnnotationImage.annotationImageWithImageReuseIdentifier(image, cachedMarker.reuseIdentifier);
180
- }
181
- }
182
- }
183
- return null;
184
- };
185
- /**
186
- * fired when one of the callout's accessoryviews is tapped (not currently used)
187
- */
188
- MGLMapViewDelegateImpl.prototype.mapViewAnnotationCalloutAccessoryControlTapped = function (mapView, annotation, control) { };
189
- /**
190
- * fired when a marker is tapped
191
- */
192
- MGLMapViewDelegateImpl.prototype.mapViewDidSelectAnnotation = function (mapView, annotation) {
193
- if (Trace.isEnabled()) {
194
- CLog(CLogTypes.info, 'MGLMapViewDelegateImpl::mapViewDidSelectAnntation()');
195
- }
196
- if (annotation.isKindOfClass(MGLUserLocation.class())) {
197
- if (Trace.isEnabled()) {
198
- CLog(CLogTypes.info, 'MGLMapViewDelegateImpl::mapViewDidSelectAnnotation(): tapped the user location button');
199
- }
200
- if (typeof this.userLocationClickListener != 'undefined') {
201
- this.userLocationClickListener(annotation);
202
- return;
203
- }
204
- mapView.deselectAnnotationAnimated(annotation, false);
205
- }
206
- var cachedMarker = this.getTappedMarkerDetails(annotation);
207
- if (cachedMarker && cachedMarker.onTap) {
208
- cachedMarker.onTap(cachedMarker);
209
- }
210
- };
211
- /**
212
- * fired when a callout is tapped
213
- */
214
- MGLMapViewDelegateImpl.prototype.mapViewTapOnCalloutForAnnotation = function (mapView, annotation) {
215
- var cachedMarker = this.getTappedMarkerDetails(annotation);
216
- if (cachedMarker && cachedMarker.onCalloutTap) {
217
- cachedMarker.onCalloutTap(cachedMarker);
218
- }
219
- };
220
- MGLMapViewDelegateImpl.prototype.getTappedMarkerDetails = function (tapped) {
221
- for (var m in _markers) {
222
- var cached = _markers[m];
223
- // don't compare lat/lng types as they're not the same (same for (sub)title, they may be null vs undefined)
224
- if (
225
- // eslint-disable-next-line eqeqeq
226
- cached.lat == tapped.coordinate.latitude &&
227
- // eslint-disable-next-line eqeqeq
228
- cached.lng == tapped.coordinate.longitude &&
229
- // eslint-disable-next-line eqeqeq
230
- cached.title == tapped.title &&
231
- // eslint-disable-next-line eqeqeq
232
- cached.subtitle == tapped.subtitle) {
233
- return cached;
234
- }
235
- }
236
- };
237
- MGLMapViewDelegateImpl.prototype.mapViewRegionIsChangingWithReason = function (mapView, reason) {
238
- if (Trace.isEnabled()) {
239
- CLog(CLogTypes.info, 'MGLMapViewDelegateImpl::mapViewRegionIsChanging()');
240
- }
241
- if (this.cameraChangedListener) {
242
- this.cameraChangedListener(reason);
243
- }
244
- };
245
- MGLMapViewDelegateImpl.prototype.mapViewRegionDidChangeWithReasonAnimated = function (mapView, reason, animated) {
246
- if (Trace.isEnabled()) {
247
- CLog(CLogTypes.info, 'MGLMapViewDelegateImpl::mapViewRegionDidChangeAnimated()');
248
- }
249
- if (this.cameraChangedListener) {
250
- this.cameraChangedListener(reason, animated);
251
- }
252
- if (this.cameraIdledListener) {
253
- this.cameraIdledListener();
254
- }
255
- };
256
- MGLMapViewDelegateImpl.prototype.mapViewDidUpdateUserLocation = function (mapView, userLocation) {
257
- if (Trace.isEnabled()) {
258
- CLog(CLogTypes.info, 'MGLMapViewDelegateImpl::mapViewDidUpdateUserLocation()');
259
- }
260
- if (this.userLocationChangedListener) {
261
- this.userLocationChangedListener(_getLocation(userLocation));
262
- }
263
- };
264
- MGLMapViewDelegateImpl.ObjCProtocols = [MGLMapViewDelegate];
265
- return MGLMapViewDelegateImpl;
266
- }(NSObject));
267
- var MapTapHandlerImpl = /** @class */ (function (_super) {
268
- __extends(MapTapHandlerImpl, _super);
269
- function MapTapHandlerImpl() {
270
- return _super !== null && _super.apply(this, arguments) || this;
271
- }
272
- MapTapHandlerImpl.initWithOwnerAndListenerForMap = function (owner, listener, mapView) {
273
- var handler = MapTapHandlerImpl.new();
274
- handler._owner = owner;
275
- handler._listener = listener;
276
- handler._mapView = mapView;
277
- return handler;
278
- };
279
- MapTapHandlerImpl.prototype.tap = function (recognizer) {
280
- var tapPoint = recognizer.locationInView(this._mapView);
281
- var tapCoordinate = this._mapView.convertPointToCoordinateFromView(tapPoint, this._mapView);
282
- this._listener({
283
- lat: tapCoordinate.latitude,
284
- lng: tapCoordinate.longitude
285
- });
286
- };
287
- MapTapHandlerImpl.ObjCExposedMethods = {
288
- tap: { returns: interop.types.void, params: [interop.types.id] }
289
- };
290
- return MapTapHandlerImpl;
291
- }(NSObject));
292
- var MapLongPressHandlerImpl = /** @class */ (function (_super) {
293
- __extends(MapLongPressHandlerImpl, _super);
294
- function MapLongPressHandlerImpl() {
295
- return _super !== null && _super.apply(this, arguments) || this;
296
- }
297
- MapLongPressHandlerImpl.initWithOwnerAndListenerForMap = function (owner, listener, mapView) {
298
- var handler = MapLongPressHandlerImpl.new();
299
- handler._owner = owner;
300
- handler._listener = listener;
301
- handler._mapView = mapView;
302
- return handler;
303
- };
304
- MapLongPressHandlerImpl.prototype.longPress = function (recognizer) {
305
- var longPressPoint = recognizer.locationInView(this._mapView);
306
- var longPressCoordinate = this._mapView.convertPointToCoordinateFromView(longPressPoint, this._mapView);
307
- this._listener({
308
- lat: longPressCoordinate.latitude,
309
- lng: longPressCoordinate.longitude
310
- });
311
- };
312
- MapLongPressHandlerImpl.ObjCExposedMethods = {
313
- longPress: { returns: interop.types.void, params: [interop.types.id] }
314
- };
315
- return MapLongPressHandlerImpl;
316
- }(NSObject));
317
- var MapPanHandlerImpl = /** @class */ (function (_super) {
318
- __extends(MapPanHandlerImpl, _super);
319
- function MapPanHandlerImpl() {
1
+ // src/ui-mapbox/index.ios.ts
2
+ // Full iOS TypeScript bridge for MapboxBridge (MapboxMaps + TileStore).
3
+ // - Adds addGeoJsonClustered and addExtrusion (ported behavior).
4
+ // - querySourceFeatures now passes filter JSON to native bridge so the native SDK can apply filtering.
5
+ // - Uses LayerFactory and ExpressionParser TS shims (delegate to native helpers when available).
6
+ //
7
+ // Replace your existing file with this full implementation.
8
+ import { Application, Color, Http, ImageSource, Screen, Trace, Utils, View } from '@nativescript/core';
9
+ import { CLog, CLogTypes, MapboxCommon, MapboxViewBase, telemetryProperty } from './common';
10
+ import { Layer, LayerFactory } from './layers//layer-factory.ios';
11
+ import { createInfoWindowView } from './markers/Marker.common';
12
+ export * from './common';
13
+ // Notification names (must match Swift constants)
14
+ const MAPBOX_BRIDGE_MAP_LOADED = 'MapboxBridgeMapLoaded';
15
+ const MAPBOX_BRIDGE_STYLE_LOADED = 'MapboxBridgeStyleLoaded';
16
+ const MAPBOX_BRIDGE_MAP_CLICK = 'MapboxBridgeMapClick';
17
+ const MAPBOX_BRIDGE_MAP_LONGPRESS = 'MapboxBridgeMapLongPress';
18
+ const MAPBOX_BRIDGE_ANNOTATION_TAP = 'MapboxBridgeAnnotationTap';
19
+ const MAPBOX_BRIDGE_CAMERA_CHANGED = 'MapboxBridgeCameraChanged';
20
+ const MAPBOX_BRIDGE_CAMERA_IDLE = 'MapboxBridgeCameraIdle';
21
+ const MAPBOX_BRIDGE_MAP_SCROLL = 'MapboxBridgeMapScroll';
22
+ const MAPBOX_BRIDGE_MAP_MOVE_BEGIN = 'MapboxBridgeMapMoveBegin';
23
+ const MAPBOX_BRIDGE_MAP_MOVE_END = 'MapboxBridgeMapMoveEnd';
24
+ const MAPBOX_BRIDGE_MAP_FLING = 'MapboxBridgeMapFling';
25
+ const MAPBOX_BRIDGE_CAMERA_MOVE_CANCEL = 'MapboxBridgeCameraMoveCancel';
26
+ const MAPBOX_BRIDGE_OFFLINE_PROGRESS = 'MapboxBridgeOfflineProgress';
27
+ const MAPBOX_BRIDGE_OFFLINE_COMPLETE = 'MapboxBridgeOfflineComplete';
28
+ var UIViewAutoSizeUIViewAutoSize = /** @class */ (function (_super) {
29
+ __extends(UIViewAutoSizeUIViewAutoSize, _super);
30
+ function UIViewAutoSizeUIViewAutoSize() {
320
31
  return _super !== null && _super.apply(this, arguments) || this;
321
32
  }
322
- MapPanHandlerImpl.initWithOwnerAndListenerForMap = function (owner, listener, panState, mapView) {
323
- var handler = MapPanHandlerImpl.new();
324
- handler._owner = owner;
325
- handler._listener = new Map([[panState, listener]]);
326
- handler._mapView = mapView;
327
- return handler;
328
- };
329
- MapPanHandlerImpl.prototype.addListener = function (panState, listener) {
330
- this._listener.set(panState, listener);
331
- };
332
- MapPanHandlerImpl.prototype.pan = function (recognizer) {
333
- var panCoordinate = this.getCoordinates(recognizer);
334
- if (Trace.isEnabled()) {
335
- CLog(CLogTypes.info, 'MapPanHandlerImpl::pan(): top with state:', recognizer.state);
336
- }
337
- if (recognizer.state === UIGestureRecognizerState.Changed) {
338
- this.notifyListener(recognizer.state, panCoordinate.latitude, panCoordinate.longitude);
339
- }
340
- };
341
- MapPanHandlerImpl.prototype.panEnd = function (recognizer) {
342
- var panCoordinate = this.getCoordinates(recognizer);
343
- if (Trace.isEnabled()) {
344
- CLog(CLogTypes.info, 'MapPanHandlerImpl::panEnd(): top with state:', recognizer.state);
345
- }
346
- if (recognizer.state === UIGestureRecognizerState.Ended) {
347
- this.notifyListener(recognizer.state, panCoordinate.latitude, panCoordinate.longitude);
348
- }
349
- };
350
- MapPanHandlerImpl.prototype.panBegin = function (recognizer) {
351
- var panCoordinate = this.getCoordinates(recognizer);
352
- if (Trace.isEnabled()) {
353
- CLog(CLogTypes.info, 'MapPanHandlerImpl::panBegin(): top with state:', recognizer.state);
354
- }
355
- if (recognizer.state === UIGestureRecognizerState.Began) {
356
- this.notifyListener(recognizer.state, panCoordinate.latitude, panCoordinate.longitude);
357
- }
33
+ UIViewAutoSizeUIViewAutoSize.prototype.systemLayoutSizeFittingSize = function (boundsSize) {
34
+ var _a;
35
+ var view = (_a = this._view) === null || _a === void 0 ? void 0 : _a.get();
36
+ if (!view) {
37
+ return CGSizeZero;
38
+ }
39
+ var widthSpec = Utils.layout.makeMeasureSpec(Math.max(Screen.mainScreen.widthPixels, Utils.layout.toDevicePixels(boundsSize.width)), Utils.layout.AT_MOST);
40
+ var heighthSpec = Utils.layout.makeMeasureSpec(Math.max(Screen.mainScreen.widthPixels, Utils.layout.toDevicePixels(boundsSize.height)), Utils.layout.AT_MOST);
41
+ var measuredSize = View.measureChild(null, view, widthSpec, heighthSpec);
42
+ view.setMeasuredDimension(measuredSize.measuredWidth, measuredSize.measuredHeight);
43
+ var size = CGSizeMake(Utils.layout.toDeviceIndependentPixels(measuredSize.measuredWidth), Utils.layout.toDeviceIndependentPixels(measuredSize.measuredHeight));
44
+ return size;
358
45
  };
359
- MapPanHandlerImpl.prototype.getCoordinates = function (recognizer) {
360
- var panPoint = recognizer.locationInView(this._mapView);
361
- return this._mapView.convertPointToCoordinateFromView(panPoint, this._mapView);
362
- };
363
- MapPanHandlerImpl.prototype.notifyListener = function (panState, latitude, longitude) {
364
- if (this._listener.has(panState)) {
365
- this._listener.get(panState)({ lat: latitude, lng: longitude });
46
+ UIViewAutoSizeUIViewAutoSize.prototype.layoutSubviews = function () {
47
+ var _a;
48
+ var view = (_a = this._view) === null || _a === void 0 ? void 0 : _a.get();
49
+ if (!view) {
50
+ return;
366
51
  }
52
+ var frame = this.frame;
53
+ var size = this.frame.size;
54
+ View.layoutChild(null, view, 0, 0, Utils.layout.toDevicePixels(size.width), Utils.layout.toDevicePixels(size.height));
55
+ // this.frame = frame;
367
56
  };
368
- MapPanHandlerImpl.ObjCExposedMethods = {
369
- pan: { returns: interop.types.void, params: [interop.types.id] },
370
- panEnd: { returns: interop.types.void, params: [interop.types.id] },
371
- panBegin: { returns: interop.types.void, params: [interop.types.id] }
372
- };
373
- return MapPanHandlerImpl;
374
- }(NSObject));
375
- var MapSwipeHandlerImpl = /** @class */ (function (_super) {
376
- __extends(MapSwipeHandlerImpl, _super);
377
- function MapSwipeHandlerImpl() {
378
- return _super !== null && _super.apply(this, arguments) || this;
379
- }
380
- MapSwipeHandlerImpl.initWithOwnerAndListenerForMap = function (owner, listener, mapView) {
381
- var handler = MapSwipeHandlerImpl.new();
382
- handler._owner = owner;
383
- handler._listener = listener;
384
- handler._mapView = mapView;
385
- return handler;
386
- };
387
- MapSwipeHandlerImpl.prototype.swipe = function (recognizer) {
388
- var swipePoint = recognizer.locationInView(this._mapView);
389
- var swipeCoordinate = this._mapView.convertPointToCoordinateFromView(swipePoint, this._mapView);
390
- this._listener({
391
- lat: swipeCoordinate.latitude,
392
- lng: swipeCoordinate.longitude
393
- });
394
- };
395
- MapSwipeHandlerImpl.ObjCExposedMethods = {
396
- swipe: { returns: interop.types.void, params: [interop.types.id] }
397
- };
398
- return MapSwipeHandlerImpl;
399
- }(NSObject));
400
- // Export the enums for devs not using TS
401
- export * from './common';
57
+ return UIViewAutoSizeUIViewAutoSize;
58
+ }(UIView));
59
+ function createUIViewAutoSizeUIViewAutoSize(view) {
60
+ const self = UIViewAutoSizeUIViewAutoSize.new();
61
+ view['iosIgnoreSafeArea'] = true;
62
+ view._setupAsRootView({});
63
+ view.parent = Application.getRootView();
64
+ view._isAddedToNativeVisualTree = true;
65
+ view.callLoaded();
66
+ self._view = new WeakRef(view);
67
+ self.addSubview(view.nativeViewProtected);
68
+ view.nativeViewProtected.autoresizingMask = 2 /* UIViewAutoresizing.FlexibleWidth */ | 16 /* UIViewAutoresizing.FlexibleHeight */;
69
+ return self;
70
+ }
71
+ // Local caches and helpers
402
72
  let _markers = [];
403
- const _markerIconDownloadCache = [];
404
- const _setMapboxMapOptions = (mapView, settings) => {
405
- mapView.logoView.hidden = settings.hideLogo;
406
- mapView.logoViewPosition = _mapControlPositionToOrnamentPosition(settings.logoPosition);
407
- mapView.attributionButton.hidden = settings.hideAttribution;
408
- mapView.attributionButtonPosition = _mapControlPositionToOrnamentPosition(settings.attributionPosition);
409
- mapView.compassView.hidden = settings.hideCompass;
410
- mapView.compassViewPosition = _mapControlPositionToOrnamentPosition(settings.compassPosition);
411
- mapView.rotateEnabled = !settings.disableRotation;
412
- mapView.scrollEnabled = !settings.disableScroll;
413
- mapView.zoomEnabled = !settings.disableZoom;
414
- mapView.allowsTilting = !settings.disableTilt;
415
- if (settings.center && settings.center.lat && settings.center.lng) {
416
- const centerCoordinate = CLLocationCoordinate2DMake(settings.center.lat, settings.center.lng);
417
- mapView.setCenterCoordinateZoomLevelAnimated(centerCoordinate, settings.zoomLevel, false);
418
- }
419
- else {
420
- mapView.setZoomLevelAnimated(settings.zoomLevel, false);
421
- }
422
- mapView.showsUserLocation = settings.showUserLocation;
423
- mapView.autoresizingMask = 2 /* UIViewAutoresizing.FlexibleWidth */ | 16 /* UIViewAutoresizing.FlexibleHeight */;
424
- };
425
- const _mapControlPositionToOrnamentPosition = (position) => {
426
- switch (position) {
427
- case ControlPosition.TOP_LEFT:
428
- return 0 /* MGLOrnamentPosition.TopLeft */;
429
- case ControlPosition.TOP_RIGHT:
430
- return 1 /* MGLOrnamentPosition.TopRight */;
431
- case ControlPosition.BOTTOM_LEFT:
432
- return 2 /* MGLOrnamentPosition.BottomLeft */;
433
- case ControlPosition.BOTTOM_RIGHT:
434
- return 3 /* MGLOrnamentPosition.BottomRight */;
435
- }
436
- };
437
- const _getMapStyle = (input) => {
438
- if (input.startsWith('mapbox://styles') || input.startsWith('http://') || input.startsWith('https://')) {
439
- return NSURL.URLWithString(input);
440
- }
441
- else if (input.startsWith('~/')) {
442
- return NSURL.URLWithString('file://' + path.join(knownFolders.currentApp().path, input.replace('~/', '')));
443
- }
444
- else if (input === MapStyle.LIGHT) {
445
- return MGLStyle.lightStyleURL;
446
- }
447
- else if (input === MapStyle.DARK) {
448
- return MGLStyle.darkStyleURL;
449
- }
450
- else if (input === MapStyle.OUTDOORS) {
451
- return MGLStyle.outdoorsStyleURL;
452
- }
453
- else if (input === MapStyle.SATELLITE) {
454
- return MGLStyle.satelliteStyleURL;
455
- }
456
- else if (input === MapStyle.SATELLITE_STREETS) {
457
- return MGLStyle.satelliteStreetsStyleURL;
458
- }
459
- else if (input === MapStyle.TRAFFIC_DAY) {
460
- return NSURL.URLWithString('mapbox://styles/mapbox/traffic-day-v2');
461
- }
462
- else if (input === MapStyle.TRAFFIC_NIGHT) {
463
- return NSURL.URLWithString('mapbox://styles/mapbox/traffic-night-v2');
464
- }
465
- else {
466
- return MGLStyle.streetsStyleURL;
467
- }
468
- };
469
- function _getLocation(loc) {
470
- if (loc === null) {
471
- return null;
73
+ const _markerIconDownloadCache = {};
74
+ function getIosColor(color) {
75
+ const temp = color instanceof Color ? color : new Color(color);
76
+ if (Color.isValid(temp)) {
77
+ return temp.argb;
472
78
  }
473
79
  else {
474
- return {
475
- location: {
476
- lat: loc.coordinate.latitude,
477
- lng: loc.coordinate.longitude
478
- },
479
- speed: loc.location ? loc.location.speed : 0
480
- };
80
+ return new Color('black').argb;
481
81
  }
482
82
  }
483
- export function setLogLevel(level) {
484
- let loggingLevel;
485
- switch (level) {
486
- case 'none':
487
- loggingLevel = 0 /* MGLLoggingLevel.None */;
488
- break;
489
- case 'info':
490
- loggingLevel = 1 /* MGLLoggingLevel.Info */;
491
- break;
492
- case 'verbose':
493
- case 'debug':
494
- loggingLevel = 2 /* MGLLoggingLevel.Debug */;
495
- break;
496
- case 'error':
497
- loggingLevel = 3 /* MGLLoggingLevel.Error */;
498
- break;
499
- case 'fault':
500
- loggingLevel = 4 /* MGLLoggingLevel.Fault */;
501
- break;
502
- }
503
- MGLLoggingConfiguration.sharedConfiguration.loggingLevel = loggingLevel;
83
+ async function fetchImageIOS(imagePath) {
84
+ try {
85
+ if (!imagePath)
86
+ return null;
87
+ if (_markerIconDownloadCache[imagePath])
88
+ return _markerIconDownloadCache[imagePath];
89
+ const img = await Http.getImage(imagePath);
90
+ if (img && img.ios) {
91
+ _markerIconDownloadCache[imagePath] = img.ios;
92
+ return img.ios;
93
+ }
94
+ }
95
+ catch (e) {
96
+ // ignore
97
+ }
98
+ return null;
504
99
  }
505
- /**
506
- * Map View Class instantiated from XML
507
- *
508
- * This class is created by the NativeScript XML view parsing
509
- * code.
510
- */
100
+ function convertToJSON(data) {
101
+ return data ? JSON.parse(data.objectForKey?.('data') ?? data) : {};
102
+ }
103
+ // ---------------------- MapboxView ----------------------
511
104
  export class MapboxView extends MapboxViewBase {
512
105
  constructor() {
513
106
  super(...arguments);
514
107
  this.nativeMapView = null;
515
- this.delegate = null;
516
108
  this.settings = null;
517
109
  this.initialized = false;
518
- // see initMap. Count of how many times we've
519
- // tried to init the map.
520
110
  this.initCountHack = 50;
521
111
  }
522
- /**
523
- * programmatically include settings
524
- */
525
112
  setConfig(settings) {
526
113
  if (Trace.isEnabled()) {
527
114
  CLog(CLogTypes.info, 'setConfig(): settings:', settings);
@@ -535,30 +122,11 @@ export class MapboxView extends MapboxViewBase {
535
122
  if (Trace.isEnabled()) {
536
123
  CLog(CLogTypes.info, 'createNativeView(): top');
537
124
  }
538
- const v = super.createNativeView();
539
- return v;
540
- }
541
- /**
542
- * init the native view.
543
- *
544
- * FIXME: It appears that the order of events is different between iOS and Android.
545
- * In the demo under Android, the main-page event handler is called first then the one
546
- * in the plugin. Under iOS it's the reverse.
547
- *
548
- * The symptom is that any properties that reference a binding aren't available
549
- * at the time this method is called. For example {{access_token}}.
550
- *
551
- * I'm sure there is something I do not understand about how this is supposed to work
552
- * and that the handstands below are not necessary.
553
- */
125
+ return super.createNativeView();
126
+ }
554
127
  onLoaded() {
555
128
  super.onLoaded();
556
- if (Trace.isEnabled()) {
557
- CLog(CLogTypes.info, 'initNativeView(): on - loaded');
558
- }
559
- if (this.telemetry === false) {
560
- NSUserDefaults.standardUserDefaults.setBoolForKey(false, 'MGLMapboxMetricsEnabled');
561
- }
129
+ // if (this.telemetry === false) NSUserDefaults.standardUserDefaults.setBoolForKey(false, 'MGLMapboxMetricsEnabled');
562
130
  if (!this.initialized) {
563
131
  this.initMap();
564
132
  this.initialized = true;
@@ -566,334 +134,279 @@ export class MapboxView extends MapboxViewBase {
566
134
  }
567
135
  initNativeView() {
568
136
  super.initNativeView();
137
+ if (Trace.isEnabled()) {
138
+ CLog(CLogTypes.info, 'initNativeView(): on - loaded');
139
+ }
569
140
  this.nativeView.owner = this;
570
141
  }
571
- /**
572
- * when the view is destroyed.
573
- *
574
- * This is called by the framework when the view is destroyed (made not visible).
575
- *
576
- * However, it does not seem to be called when the page is unloaded.
577
- *
578
- * @link https://docs.nativescript.org/plugins/ui-plugin-custom
579
- */
580
142
  async disposeNativeView() {
581
- if (Trace.isEnabled()) {
582
- CLog(CLogTypes.info, 'disposeNativeView(): top');
583
- }
584
143
  this.nativeView.owner = null;
585
- await this.mapbox.destroy();
586
- if (Trace.isEnabled()) {
587
- CLog(CLogTypes.info, 'disposeNativeView(): after mapbox.destroy()');
588
- }
144
+ if (this.mapbox)
145
+ await this.mapbox.destroy();
589
146
  super.disposeNativeView();
590
- if (Trace.isEnabled()) {
591
- CLog(CLogTypes.info, 'disposeNativeView(): bottom');
592
- }
593
147
  }
594
- /**
595
- * returns a reference to the class Mapbox API shim instance
596
- *
597
- * @see Mapbox
598
- */
599
148
  getMapboxApi() {
600
149
  return this.mapbox;
601
150
  }
602
- /**
603
- * initialize the map
604
- *
605
- * @see MGLMapViewDelegateImpl
606
- *
607
- * @todo FIXME: figure out why the accessToken property (which is using a binding in the demo XML) isn't set before we arrive here.
608
- */
609
151
  initMap() {
610
152
  if (Trace.isEnabled()) {
611
153
  CLog(CLogTypes.info, 'initMap() top with settings:', this.settings);
612
154
  }
613
- // FIXME: HACK: if we are arriving here because of an XML parse the property evaluations may not have
614
- // happened yet. This needs to be redone, but for the moment we'll assume the accessToken is done
615
- // via a property eval (since it really shouldn't be hard coded in XML).
616
- //
617
- // settings will only be set here if we are programmatically showing a map.
618
155
  if (!this.settings && !this.config.accessToken) {
619
- if (Trace.isEnabled()) {
620
- CLog(CLogTypes.info, 'initMap() no access token. Race condition on XML property evaluation?');
621
- }
622
- // If the user didn't specify an accessToken we don't want to loop forever
623
- if (this.initCountHack > 50) {
156
+ if (this.initCountHack > 50)
624
157
  return;
625
- }
626
- // FIXME: super ugly.
627
- setTimeout(() => {
628
- this.initMap();
629
- }, 50);
158
+ setTimeout(() => this.initMap(), 50);
630
159
  this.initCountHack++;
631
160
  return;
632
161
  }
633
- if (!this.settings) {
162
+ if (!this.settings)
634
163
  this.settings = Mapbox.merge(this.config, Mapbox.defaults);
635
- }
636
- else {
164
+ else
637
165
  this.settings = Mapbox.merge(this.settings, Mapbox.defaults);
638
- }
639
166
  if (!this.nativeMapView) {
640
167
  this.mapbox = new Mapbox(this);
641
- if (Trace.isEnabled()) {
642
- CLog(CLogTypes.info, 'initMap(): after new Mapbox()');
643
- }
644
- // called in a setTimeout call at the bottom.
645
- const drawMap = () => {
646
- MGLAccountManager.accessToken = this.settings.accessToken;
647
- this.nativeMapView = MGLMapView.alloc().initWithFrameStyleURL(CGRectMake(0, 0, this.nativeView.frame.size.width, this.nativeView.frame.size.height), _getMapStyle(this.settings.style));
648
- // this delegate class is defined later in this file and is where, in Obj-C land,
649
- // callbacks are delivered and handled.
650
- this.nativeMapView.delegate = this.delegate = MGLMapViewDelegateImpl.new().initWithCallback(() => {
651
- if (Trace.isEnabled()) {
652
- CLog(CLogTypes.info, 'initMap(): MLMapViewDeleteImpl onMapReady callback');
653
- }
654
- // FIXME: on the Android side the view is created in Mapbox::show(). On the iOS side it's created
655
- // here in MapboxView, however the mapbox api still needs a reference to it.
656
- this.mapbox.setMapboxViewInstance(this.nativeMapView);
657
- this.mapbox.initEventHandlerShim(this.settings, this.nativeMapView);
168
+ const options = {
169
+ parentView: this.nativeView,
170
+ onLocationPermissionGranted: (event) => {
658
171
  this.notify({
659
- eventName: MapboxViewBase.mapReadyEvent,
172
+ eventName: MapboxViewBase.locationPermissionGrantedEvent,
660
173
  object: this,
661
174
  map: this,
662
175
  ios: this.nativeMapView
663
176
  });
664
- // no permission required, but to align with Android we fire the event anyway
177
+ },
178
+ onLocationPermissionDenied: (event) => {
665
179
  this.notify({
666
- eventName: MapboxViewBase.locationPermissionGrantedEvent,
180
+ eventName: MapboxViewBase.locationPermissionDeniedEvent,
667
181
  object: this,
668
182
  map: this,
669
183
  ios: this.nativeMapView
670
184
  });
671
- });
672
- // this.delegate.setStyleLoadedCallback((map, style)=>{
673
- // this.delegate.setStyleLoadedCallback(null);
674
- // });
675
- _setMapboxMapOptions(this.nativeMapView, this.settings);
676
- _markers = [];
677
- this.nativeView.addSubview(this.nativeMapView);
678
- // this.notify will notify an event listener specified
679
- // in the XML, in this case (onMoveBegin)="..."
680
- this.mapbox.setOnMoveBeginListener((data) => {
185
+ },
186
+ onMapReady: (view) => {
187
+ this.nativeMapView = view;
188
+ // if (this.telemetry === false) {
189
+ // com.nativescript.mapbox.Telemetry.setUserTelemetryRequestState(this.nativeMapView, false);
190
+ // }
191
+ if (Trace.isEnabled()) {
192
+ CLog(CLogTypes.info, 'initMap(): onMapReady event - calling notify with the MapboxViewBase.mapReadyEvent');
193
+ }
194
+ if (this.hasListeners(MapboxViewBase.mapReadyEvent)) {
195
+ if (Trace.isEnabled()) {
196
+ CLog(CLogTypes.info, 'initMap(): onMapReady has listeners.');
197
+ }
198
+ }
199
+ else {
200
+ if (Trace.isEnabled()) {
201
+ CLog(CLogTypes.info, 'initMap(): onMapReady DOES NOT HAVE listeners.');
202
+ }
203
+ }
204
+ this.notify({
205
+ eventName: MapboxViewBase.mapReadyEvent,
206
+ object: this,
207
+ map: this,
208
+ ios: this.nativeMapView
209
+ });
210
+ },
211
+ onScrollEvent: (event) => {
681
212
  if (Trace.isEnabled()) {
682
- CLog(CLogTypes.info, 'initMap(): onMoveBegin listener');
213
+ CLog(CLogTypes.info, 'initMap(): onScrollEvent event:' + JSON.stringify(event));
683
214
  }
684
215
  this.notify({
685
- eventName: MapboxViewBase.moveBeginEvent,
216
+ eventName: MapboxViewBase.scrollEvent,
686
217
  object: this,
218
+ event,
687
219
  map: this,
688
220
  ios: this.nativeMapView
689
221
  });
690
- }, this.nativeMapView);
691
- this.mapbox.setOnMoveEndListener((data) => {
222
+ },
223
+ onMoveBeginEvent: (event) => {
692
224
  if (Trace.isEnabled()) {
693
- CLog(CLogTypes.info, 'initMap(): onMoveEnd listener');
225
+ CLog(CLogTypes.info, 'initMap(): onMoveBeginEvent event');
694
226
  }
695
227
  this.notify({
696
- eventName: MapboxViewBase.moveEndEvent,
228
+ eventName: MapboxViewBase.moveBeginEvent,
697
229
  object: this,
230
+ event,
698
231
  map: this,
699
232
  ios: this.nativeMapView
700
233
  });
701
- }, this.nativeMapView);
702
- this.mapbox.setOnScrollListener((data) => {
234
+ },
235
+ onMoveEndEvent: (event) => {
703
236
  if (Trace.isEnabled()) {
704
- CLog(CLogTypes.info, 'initMap(): onScroll listener');
237
+ CLog(CLogTypes.info, 'initMap(): onMoveEndEvent event');
705
238
  }
706
239
  this.notify({
707
- eventName: MapboxViewBase.scrollEvent,
240
+ eventName: MapboxViewBase.moveEndEvent,
708
241
  object: this,
242
+ event,
709
243
  map: this,
710
244
  ios: this.nativeMapView
711
245
  });
712
- }, this.nativeMapView);
246
+ }
247
+ };
248
+ this.settings = Mapbox.merge(this.settings, options);
249
+ const drawMap = () => {
250
+ if (Trace.isEnabled()) {
251
+ CLog(CLogTypes.info, 'drawMap()');
252
+ }
253
+ this.mapbox.show(this.settings);
254
+ // _setMapboxMapOptions(this.nativeMapView, this.settings);
255
+ // _markers = [];
256
+ // this.nativeView.addSubview(this.nativeMapView);
257
+ // this.mapbox.setMapboxViewInstance(this.nativeMapView);
713
258
  };
714
- // draw the map after a timeout
715
259
  setTimeout(drawMap, this.settings.delay ? this.settings.delay : 0);
716
260
  }
717
- } // end of initMap()
261
+ }
718
262
  onLayout(left, top, right, bottom) {
719
263
  super.onLayout(left, top, right, bottom);
720
- if (this.nativeMapView) {
264
+ if (this.nativeMapView)
721
265
  this.nativeMapView.layer.frame = this.ios.layer.bounds;
722
- }
723
266
  }
724
267
  [telemetryProperty.setNative](value) {
725
268
  NSUserDefaults.standardUserDefaults.setBoolForKey(false, 'MGLMapboxMetricsEnabled');
726
269
  }
727
270
  }
271
+ // ----------------------- Mapbox TS API -----------------------
728
272
  export class Mapbox extends MapboxCommon {
729
273
  constructor() {
730
- // reference to the native mapbox API
731
274
  super(...arguments);
732
275
  this.eventCallbacks = {};
276
+ this._markers = [];
277
+ this._observerTokens = [];
278
+ this._reusableCalloutView = null;
279
+ this._programmaticMapView = null;
280
+ // ---------------- Events wiring helpers ----------------
281
+ // Event listeners (setOnCameraChangeListener)
282
+ this.pushToken = (t) => this._observerTokens.push(t);
733
283
  }
734
- /**
735
- * set the mapboxViewInstance
736
- *
737
- * @see MapboxView::initMap();
738
- */
739
- setMapboxViewInstance(mapboxViewInstance) {
740
- this._mapboxViewInstance = mapboxViewInstance;
741
- }
742
- /**
743
- * event handler shim
744
- *
745
- * Initialize our event handler shim so that we can intercept events here.
746
- *
747
- * @param { MapboxView } mapboxView
748
- */
749
- initEventHandlerShim(settings, mapboxNativeViewInstance) {
750
- if (Trace.isEnabled()) {
751
- CLog(CLogTypes.info, 'Mapbox:initEventHandlerShim(): top');
752
- }
753
- this.setOnMapClickListener((point) => this.checkForClickEvent(point), mapboxNativeViewInstance);
284
+ setMapboxViewInstance(m) {
285
+ this._mapboxViewInstance = m;
754
286
  }
755
- /**
756
- * register a map event handler
757
- *
758
- * The NativeScript ContentView base class as on() and off() methods.
759
- */
760
287
  onMapEvent(eventName, id, callback, nativeMapView) {
761
- if (typeof this.eventCallbacks[eventName] == 'undefined') {
288
+ if (typeof this.eventCallbacks[eventName] === 'undefined')
762
289
  this.eventCallbacks[eventName] = [];
763
- }
764
- this.eventCallbacks[eventName].push({
765
- id,
766
- callback
767
- });
290
+ this.eventCallbacks[eventName].push({ id, callback });
768
291
  }
769
292
  offMapEvent(eventName, id, nativeMapView) {
770
- if (typeof this.eventCallbacks[eventName] == 'undefined') {
293
+ if (typeof this.eventCallbacks[eventName] === 'undefined')
771
294
  return;
772
- }
773
295
  this.eventCallbacks[eventName] = this.eventCallbacks[eventName].filter((entry) => entry.id !== id);
774
296
  }
775
- /**
776
- * If click events registered and a feature found for the event, then fire listener.
777
- */
778
297
  checkForClickEvent(point, nativeMap) {
779
298
  if (Trace.isEnabled()) {
780
- CLog(CLogTypes.info, 'Mapbox:checkForClickEvent(): got click event with point:', point);
299
+ CLog(CLogTypes.info, 'setOnMapClickListener(): click event at point:', point);
781
300
  }
782
301
  this.eventCallbacks['click'] &&
783
302
  this.eventCallbacks['click'].forEach((eventListener) => {
303
+ if (Trace.isEnabled()) {
304
+ CLog(CLogTypes.info, 'checkForClickEvent():', eventListener.id);
305
+ }
784
306
  this.queryRenderedFeatures({ point, layers: [eventListener.id] }, nativeMap)
785
307
  .then((response) => {
786
- if (response.length > 0) {
787
- eventListener.callback(response);
308
+ if (Trace.isEnabled()) {
309
+ CLog(CLogTypes.info, 'checkForClickEvent: queryRenderedFeatures:', response);
788
310
  }
311
+ if (response.length > 0)
312
+ eventListener.callback(response);
789
313
  })
790
- .catch((err) => {
791
- console.error('click error ', eventListener.id, err);
792
- });
314
+ .catch((err) => console.error('click error ', eventListener.id, err, err.stack));
793
315
  });
794
316
  this.view && this.view.notify({ eventName: 'mapClick', object: this.view, point });
795
317
  return false;
796
318
  }
797
- _addMarkers(markers, nativeMap) {
798
- if (!markers) {
319
+ // ---------------- lifecycle & programmatic ----------------
320
+ initEventHandlerShim(settings, mapboxNativeViewInstance) {
321
+ if (Trace.isEnabled()) {
322
+ CLog(CLogTypes.info, 'initEventHandlerShim(): top');
323
+ }
324
+ this.setOnMapClickListener((point) => {
325
+ if (this.selectedMarker) {
326
+ this.deselectMarker(this.selectedMarker);
327
+ return;
328
+ }
329
+ this.checkForClickEvent(point);
330
+ }, mapboxNativeViewInstance);
331
+ this.addNotificationCenterObserver(MAPBOX_BRIDGE_ANNOTATION_TAP, mapboxNativeViewInstance, (e) => this.onNativeAnnotationTap(e));
332
+ this.setOnMoveBeginListener((point) => {
799
333
  if (Trace.isEnabled()) {
800
- CLog(CLogTypes.info, 'No markers passed');
334
+ CLog(CLogTypes.info, 'initEventHandlerShim(): moveBegin:', point);
801
335
  }
802
- return;
803
- }
804
- if (!Array.isArray(markers)) {
336
+ if (typeof settings.onMoveBeginEvent != 'undefined') {
337
+ settings.onMoveBeginEvent(point);
338
+ }
339
+ }, mapboxNativeViewInstance);
340
+ this.setOnMoveEndListener((point) => {
805
341
  if (Trace.isEnabled()) {
806
- CLog(CLogTypes.info, "markers must be passed as an Array: [{title: 'foo'}]");
342
+ CLog(CLogTypes.info, 'initEventHandlerShim(): moveEnd:', point);
807
343
  }
808
- return;
809
- }
810
- const theMap = nativeMap || this._mapboxViewInstance;
811
- _downloadMarkerImages(markers).then((updatedMarkers) => {
812
- updatedMarkers.forEach((marker) => {
813
- const lat = marker.lat;
814
- const lng = marker.lng;
815
- const point = MGLPointAnnotation.new();
816
- point.coordinate = CLLocationCoordinate2DMake(lat, lng);
817
- point.title = marker.title;
818
- point.subtitle = marker.subtitle;
819
- // needs to be done before adding to the map, otherwise the delegate method 'mapViewImageForAnnotation' can't use it
820
- _markers.push(marker);
821
- theMap.addAnnotation(point);
822
- if (marker.selected) {
823
- theMap.selectAnnotationAnimated(point, false);
824
- }
825
- marker.ios = point;
826
- marker.update = (newSettings) => {
827
- _markers.forEach((_marker) => {
828
- if (marker.id === _marker.id) {
829
- if (newSettings.onTap !== undefined) {
830
- _marker.onTap = newSettings.onTap;
831
- }
832
- if (newSettings.onCalloutTap !== undefined) {
833
- _marker.onCalloutTap = newSettings.onCalloutTap;
834
- }
835
- if (newSettings.title !== undefined) {
836
- _marker.ios.title = _marker.title = newSettings.title;
837
- }
838
- if (newSettings.subtitle !== undefined) {
839
- _marker.ios.subtitle = _marker.subtitle = newSettings.subtitle;
840
- }
841
- if (newSettings.lat && newSettings.lng) {
842
- _marker.lat = newSettings.lat;
843
- _marker.lng = newSettings.lng;
844
- _marker.ios.coordinate = CLLocationCoordinate2DMake(newSettings.lat, newSettings.lng);
845
- }
846
- if (newSettings.selected) {
847
- theMap.selectAnnotationAnimated(_marker.ios, false);
848
- }
849
- }
850
- });
851
- };
852
- });
853
- });
344
+ if (typeof settings.onMoveEndEvent != 'undefined') {
345
+ settings.onMoveEndEvent(point);
346
+ }
347
+ }, mapboxNativeViewInstance);
348
+ this.setOnScrollListener((point) => {
349
+ if (Trace.isEnabled()) {
350
+ CLog(CLogTypes.info, 'initEventHandlerShim(): move:', point);
351
+ }
352
+ if (typeof settings.onScrollEvent != 'undefined') {
353
+ settings.onScrollEvent(point);
354
+ }
355
+ }, mapboxNativeViewInstance);
854
356
  }
855
- /**
856
- * create an display the map
857
- *
858
- * @todo FIXME: This method is not called. See MapboxView::initMap().
859
- */
860
- show(options) {
861
- if (Trace.isEnabled()) {
862
- CLog(CLogTypes.info, 'show(): top with options:', options);
863
- }
357
+ async show(options) {
358
+ // Implementation same as earlier merged file; create programmatic map instance
864
359
  return new Promise((resolve, reject) => {
865
360
  try {
361
+ if (Trace.isEnabled()) {
362
+ CLog(CLogTypes.info, 'show');
363
+ }
866
364
  const settings = Mapbox.merge(options, Mapbox.defaults);
867
- // let directions = MBDirections.alloc().initWithAccessToken(arg.accessToken);
868
- // alert("directions: " + directions);
869
- // if no accessToken was set the app may crash
870
- if (settings.accessToken === undefined) {
365
+ if (!settings.accessToken) {
871
366
  reject("Please set the 'accessToken' parameter");
872
367
  return;
873
368
  }
874
- // if already added, make sure it's removed first
875
- if (this._mapboxViewInstance) {
876
- this._mapboxViewInstance.removeFromSuperview();
877
- }
878
- const view = UIApplication.sharedApplication.keyWindow.rootViewController.view, frameRect = view.frame, mapFrame = CGRectMake(settings.margins.left, settings.margins.top, frameRect.size.width - settings.margins.left - settings.margins.right, frameRect.size.height - settings.margins.top - settings.margins.bottom), styleURL = _getMapStyle(settings.style);
879
- MGLAccountManager.accessToken = settings.accessToken;
880
- this._mapboxViewInstance = MGLMapView.alloc().initWithFrameStyleURL(mapFrame, styleURL);
881
- _setMapboxMapOptions(this._mapboxViewInstance, settings);
882
- this._mapboxViewInstance.delegate = MGLMapViewDelegateImpl.new().initWithCallback((mapView) => {
883
- resolve({
884
- ios: mapView
885
- });
886
- });
369
+ if (this._programmaticMapView) {
370
+ try {
371
+ this._programmaticMapView.removeFromSuperview();
372
+ }
373
+ catch (e) {
374
+ console.error(e, e.stack);
375
+ }
376
+ this._programmaticMapView = null;
377
+ }
378
+ const bridge = (this.bridgeInstance = MapboxBridge.alloc().init());
379
+ const view = options.parentView || UIApplication.sharedApplication.keyWindow.rootViewController.view;
380
+ const frameRect = view.frame;
381
+ const mapFrame = CGRectMake(settings.margins?.left ?? 0, settings.margins?.top ?? 0, frameRect.size.width - (settings.margins?.left ?? 0) - (settings.margins?.right ?? 0), frameRect.size.height - (settings.margins?.top ?? 0) - (settings.margins?.bottom ?? 0));
382
+ const style = typeof settings.style === 'string' ? settings.style : settings.style || 'streets';
383
+ const { center, disableRotation, disableScroll, disableTilt, disableZoom, hideAttribution, hideLogo, showUserLocation, zoomLevel, ...others } = settings;
384
+ const nativeMap = bridge.createMap(mapFrame.origin.x, mapFrame.origin.y, mapFrame.size.width, mapFrame.size.height, settings.accessToken, style, JSON.stringify({
385
+ zoomLevel,
386
+ center,
387
+ hideLogo,
388
+ hideAttribution,
389
+ disableRotation,
390
+ disableScroll,
391
+ disableZoom,
392
+ disableTilt,
393
+ showUserLocation
394
+ }));
395
+ nativeMap.autoresizingMask = 2 /* UIViewAutoresizing.FlexibleWidth */ | 16 /* UIViewAutoresizing.FlexibleHeight */;
887
396
  _markers = [];
888
- this._addMarkers(settings.markers);
889
- // wrapping in a little timeout since the map area tends to flash black a bit initially
890
- setTimeout(() => {
891
- view.addSubview(this._mapboxViewInstance);
892
- }, 500);
397
+ this.addMarkers(settings.markers);
398
+ // setTimeout(() => view.addSubview(nativeMap), 0);
399
+ view.addSubview(nativeMap);
400
+ this.setMapboxViewInstance(nativeMap);
401
+ this.initEventHandlerShim(settings, this._mapboxViewInstance);
402
+ if (settings.onMapReady) {
403
+ settings.onMapReady(this._mapboxViewInstance);
404
+ }
405
+ resolve({ ios: nativeMap });
893
406
  }
894
407
  catch (ex) {
895
408
  if (Trace.isEnabled()) {
896
- CLog(CLogTypes.info, 'Error in mapbox.show: ' + ex);
409
+ CLog(CLogTypes.error, 'show:', ex, ex.stack);
897
410
  }
898
411
  reject(ex);
899
412
  }
@@ -902,15 +415,12 @@ export class Mapbox extends MapboxCommon {
902
415
  hide() {
903
416
  return new Promise((resolve, reject) => {
904
417
  try {
905
- if (this._mapboxViewInstance) {
906
- this._mapboxViewInstance.removeFromSuperview();
418
+ if (this._programmaticMapView) {
419
+ this._programmaticMapView.hidden = true;
907
420
  }
908
421
  resolve();
909
422
  }
910
423
  catch (ex) {
911
- if (Trace.isEnabled()) {
912
- CLog(CLogTypes.info, 'Error in mapbox.hide: ' + ex);
913
- }
914
424
  reject(ex);
915
425
  }
916
426
  });
@@ -918,1640 +428,1292 @@ export class Mapbox extends MapboxCommon {
918
428
  unhide() {
919
429
  return new Promise((resolve, reject) => {
920
430
  try {
921
- if (this._mapboxViewInstance) {
922
- const view = UIApplication.sharedApplication.keyWindow.rootViewController.view;
923
- view.addSubview(this._mapboxViewInstance);
431
+ if (this._programmaticMapView) {
432
+ this._programmaticMapView.hidden = false;
924
433
  resolve();
925
434
  }
926
- else {
435
+ else
927
436
  reject('No map found');
928
- }
929
437
  }
930
438
  catch (ex) {
931
- if (Trace.isEnabled()) {
932
- CLog(CLogTypes.info, 'Error in mapbox.unhide: ' + ex);
933
- }
934
439
  reject(ex);
935
440
  }
936
441
  });
937
442
  }
938
443
  destroy(nativeMap) {
939
- return new Promise((resolve, reject) => {
940
- const theMap = nativeMap || this._mapboxViewInstance;
941
- if (theMap) {
942
- theMap.removeFromSuperview();
943
- theMap.delegate = null;
944
- }
945
- resolve();
946
- });
947
- }
948
- // ----------------------------------------
949
- // Life Cycle Hooks - Required on Android
950
- // ----------------------------------------
951
- onStart(nativeMap) {
952
- return Promise.resolve();
953
- }
954
- onResume(nativeMap) {
955
- return Promise.resolve();
956
- }
957
- onPause(nativeMap) {
958
- return Promise.resolve();
959
- }
960
- onStop(nativeMap) {
961
- return Promise.resolve();
962
- }
963
- onLowMemory(nativeMap) {
964
- return Promise.resolve();
965
- }
966
- onDestroy(nativeMap) {
967
- return Promise.resolve();
968
- }
969
- /**
970
- * explicitly set a map style
971
- */
972
- setMapStyle(style, nativeMap) {
973
444
  return new Promise((resolve, reject) => {
974
445
  try {
975
- const theMap = nativeMap || this._mapboxViewInstance;
976
- // the style takes some time to load so we have to set a callback
977
- // to wait for the style to finish loading
978
- const delegate = theMap.delegate;
979
- delegate.setStyleLoadedCallback((mapView) => {
980
- if (Trace.isEnabled()) {
981
- CLog(CLogTypes.info, 'Mapbox:setMapStyle(): style loaded callback returned.');
446
+ const theMap = nativeMap || this._mapboxViewInstance || this._programmaticMapView;
447
+ if (theMap) {
448
+ try {
449
+ theMap.removeFromSuperview();
450
+ }
451
+ catch (e) {
452
+ console.error(e, e.stack);
982
453
  }
983
- resolve();
984
- });
985
- theMap.styleURL = _getMapStyle(style);
986
- }
987
- catch (ex) {
988
- if (Trace.isEnabled()) {
989
- CLog(CLogTypes.info, 'Error in mapbox.setMapStyle: ' + ex);
990
454
  }
991
- reject(ex);
992
- }
993
- });
994
- }
995
- async getImage(imageId, nativeMap) {
996
- return new Promise((resolve, reject) => {
997
- const theMap = nativeMap || this._mapboxViewInstance;
998
- if (!theMap) {
999
- reject('No map has been loaded');
1000
- return;
1001
- }
1002
- try {
1003
- const nativeImage = theMap.style.imageForName(imageId);
1004
- const img = new ImageSource(nativeImage);
1005
- resolve(img);
455
+ if (this._programmaticMapView) {
456
+ this._programmaticMapView = null;
457
+ }
458
+ const bridge = MapboxBridge.bridgeFor(theMap);
459
+ bridge.destroy();
460
+ if (bridge === this.bridgeInstance) {
461
+ this.bridgeInstance = null;
462
+ }
463
+ try {
464
+ this._observerTokens.forEach((t) => {
465
+ try {
466
+ NSNotificationCenter.defaultCenter.removeObserver(t);
467
+ }
468
+ catch (e) {
469
+ console.error(e, e.stack);
470
+ }
471
+ });
472
+ this._observerTokens = [];
473
+ }
474
+ catch (e) {
475
+ console.error(e, e.stack);
476
+ }
477
+ if (this._reusableCalloutView) {
478
+ this._reusableCalloutView._tearDownUI();
479
+ this._reusableCalloutView = null;
480
+ }
481
+ resolve();
1006
482
  }
1007
483
  catch (ex) {
1008
- reject('Error during getImage: ' + ex);
1009
- if (Trace.isEnabled()) {
1010
- CLog(CLogTypes.info, 'Error in mapbox.getImage: ' + ex);
1011
- }
1012
- throw ex;
484
+ reject(ex);
1013
485
  }
1014
486
  });
1015
487
  }
488
+ // ---------------- Images ----------------
1016
489
  async addImage(imageId, imagePath, nativeMap) {
1017
490
  return new Promise(async (resolve, reject) => {
1018
- const theMap = nativeMap || this._mapboxViewInstance;
1019
- if (!theMap) {
1020
- reject('No map has been loaded');
1021
- return;
1022
- }
1023
491
  try {
1024
- const imageSource = await this.fetchImageSource(imagePath);
1025
- theMap.style.setImageForName(imageSource.ios, imageId);
492
+ const b = nativeMap ? MapboxBridge.bridgeFor(nativeMap) : this.bridgeInstance;
493
+ if (!b) {
494
+ reject('No bridge available');
495
+ return;
496
+ }
497
+ let imageSource = null;
498
+ try {
499
+ imageSource = ImageSource.fromFileOrResourceSync(imagePath);
500
+ }
501
+ catch (e) {
502
+ console.error('error adding image:', e, e.stack);
503
+ imageSource = null;
504
+ }
505
+ if (!imageSource) {
506
+ const httpImg = await Http.getImage(imagePath).catch(() => null);
507
+ if (!httpImg || !httpImg.ios) {
508
+ reject('Unable to fetch image');
509
+ return;
510
+ }
511
+ b.addImage(imageId, httpImg.ios);
512
+ resolve();
513
+ return;
514
+ }
515
+ b.addImage(imageId, imageSource.ios);
1026
516
  resolve();
1027
517
  }
1028
518
  catch (ex) {
1029
- reject('Error during addImage: ' + ex);
1030
- if (Trace.isEnabled()) {
1031
- CLog(CLogTypes.info, 'Error in mapbox.addImage: ' + ex);
1032
- }
1033
- throw ex;
519
+ reject(ex);
1034
520
  }
1035
521
  });
1036
522
  }
1037
523
  async removeImage(imageId, nativeMap) {
1038
524
  return new Promise((resolve, reject) => {
1039
- const theMap = nativeMap || this._mapboxViewInstance;
1040
- if (!theMap) {
1041
- reject('No map has been loaded');
1042
- return;
1043
- }
1044
525
  try {
1045
- theMap.style.removeImageForName(imageId);
526
+ const b = nativeMap ? MapboxBridge.bridgeFor(nativeMap) : this.bridgeInstance;
527
+ if (!b) {
528
+ reject('No bridge available');
529
+ return;
530
+ }
531
+ b.removeImage(imageId);
1046
532
  resolve();
1047
533
  }
1048
534
  catch (ex) {
1049
- reject('Error during removeImage: ' + ex);
1050
- if (Trace.isEnabled()) {
1051
- CLog(CLogTypes.info, 'Error in mapbox.removeImage: ' + ex);
1052
- }
1053
- throw ex;
535
+ reject(ex);
1054
536
  }
1055
537
  });
1056
538
  }
1057
- addMarkers(markers, nativeMap) {
1058
- return new Promise((resolve, reject) => {
539
+ // ---------------- Markers ----------------
540
+ async addMarkers(markers, nativeMap) {
541
+ return new Promise(async (resolve, reject) => {
1059
542
  try {
1060
- const theMap = nativeMap || this._mapboxViewInstance;
1061
- this._addMarkers(markers, theMap);
543
+ const b = nativeMap ? MapboxBridge.bridgeFor(nativeMap) : this.bridgeInstance;
544
+ if (!b) {
545
+ reject('No bridge available');
546
+ return;
547
+ }
548
+ const updated = await Promise.all(markers.map(async (m) => {
549
+ if (m.icon && typeof m.icon === 'string' && m.icon.startsWith('http')) {
550
+ m.iconDownloaded = await fetchImageIOS(m.icon);
551
+ }
552
+ return m;
553
+ }));
554
+ updated.forEach((m) => {
555
+ if (m.icon && typeof m.icon === 'string' && m.iconDownloaded) {
556
+ try {
557
+ b.addImage(m.icon, m.iconDownloaded);
558
+ delete m.iconDownloaded;
559
+ }
560
+ catch (e) {
561
+ console.error(e, e.stack);
562
+ }
563
+ }
564
+ });
565
+ let firstId = Date.now() * 1000;
566
+ let markerToSelect;
567
+ updated.forEach((marker) => {
568
+ marker.id = marker.id ?? firstId++;
569
+ if (marker.id && !this._markers.find((mm) => mm.id === marker.id))
570
+ this._markers.push(marker);
571
+ if (marker.selected) {
572
+ markerToSelect = marker;
573
+ }
574
+ marker.update = (newSettings) => {
575
+ const _marker = this._markers.find((m) => m.id === marker.id);
576
+ if (_marker) {
577
+ if (newSettings.onTap !== undefined) {
578
+ _marker.onTap = newSettings.onTap;
579
+ }
580
+ if (newSettings.onCalloutTap !== undefined) {
581
+ _marker.onCalloutTap = newSettings.onCalloutTap;
582
+ }
583
+ if (newSettings.title !== undefined) {
584
+ _marker.title = newSettings.title;
585
+ }
586
+ if (newSettings.subtitle !== undefined) {
587
+ _marker.subtitle = newSettings.subtitle;
588
+ }
589
+ if (newSettings.lat && newSettings.lng) {
590
+ _marker.lat = newSettings.lat;
591
+ _marker.lng = newSettings.lng;
592
+ b.updateMarkerPosition(_marker.id + '', newSettings.lat, newSettings.lng);
593
+ }
594
+ if (newSettings.selected) {
595
+ this.selectMarker(_marker);
596
+ }
597
+ }
598
+ };
599
+ });
600
+ b.addMarkers(JSON.stringify(updated));
601
+ if (markerToSelect) {
602
+ this.selectMarker(markerToSelect);
603
+ }
1062
604
  resolve();
1063
605
  }
1064
606
  catch (ex) {
1065
- if (Trace.isEnabled()) {
1066
- CLog(CLogTypes.info, 'Error in mapbox.addMarkers: ' + ex);
1067
- }
1068
607
  reject(ex);
1069
608
  }
1070
609
  });
1071
610
  }
1072
- removeMarkers(ids, nativeMap) {
1073
- return new Promise((resolve, reject) => {
611
+ async deselectMarker(marker) {
612
+ if (this.selectedMarker === marker || this.selectedMarker?.id === marker.id) {
613
+ this.hideCalloutForMarkerById(marker.id + '');
614
+ this.selectedMarker = null;
615
+ }
616
+ }
617
+ selectMarker(marker) {
618
+ return new Promise(async (resolve, reject) => {
1074
619
  try {
1075
- const theMap = nativeMap || this._mapboxViewInstance;
1076
- const markersToRemove = [];
1077
- _markers.forEach((marker) => {
1078
- if (!ids || (marker.id && ids.indexOf(marker.id) > -1)) {
1079
- markersToRemove.push(marker.ios);
1080
- }
1081
- });
1082
- // remove markers from cache
1083
- if (ids) {
1084
- _markers = _markers.filter((marker) => ids.indexOf(marker.id) < 0);
1085
- }
1086
- else {
1087
- _markers = [];
620
+ if (Trace.isEnabled()) {
621
+ CLog(CLogTypes.info, 'selectMarker():', marker.id);
1088
622
  }
1089
- if (markersToRemove.length > 0) {
1090
- theMap.removeAnnotations(markersToRemove);
623
+ if (this.selectedMarker) {
624
+ this.deselectMarker(this.selectedMarker);
1091
625
  }
626
+ await this.showCalloutForMarkerById(marker.id + '');
1092
627
  resolve();
1093
628
  }
1094
629
  catch (ex) {
1095
630
  if (Trace.isEnabled()) {
1096
- CLog(CLogTypes.info, 'Error in mapbox.removeMarkers: ' + ex);
631
+ CLog(CLogTypes.error, 'selectMarker():', ex, ex.stack);
1097
632
  }
1098
633
  reject(ex);
1099
634
  }
1100
635
  });
1101
636
  }
1102
- setCenter(options, nativeMap) {
637
+ removeMarkers(ids, nativeMap) {
1103
638
  return new Promise((resolve, reject) => {
1104
639
  try {
1105
- const theMap = nativeMap || this._mapboxViewInstance;
1106
- const animated = options.animated === undefined || options.animated;
1107
- const coordinate = CLLocationCoordinate2DMake(options.lat, options.lng);
1108
- theMap.setCenterCoordinateAnimated(coordinate, animated);
640
+ const b = nativeMap ? MapboxBridge.bridgeFor(nativeMap) : this.bridgeInstance;
641
+ if (!b) {
642
+ reject('No bridge available');
643
+ return;
644
+ }
645
+ b.removeMarkers(ids ? JSON.stringify(ids.map((id) => id + '')) : null);
1109
646
  resolve();
1110
647
  }
1111
648
  catch (ex) {
1112
- if (Trace.isEnabled()) {
1113
- CLog(CLogTypes.info, 'Error in mapbox.setCenter: ' + ex);
1114
- }
1115
649
  reject(ex);
1116
650
  }
1117
651
  });
1118
652
  }
1119
- getCenter(nativeMap) {
653
+ updateMarkerPosition(markerId, lat, lng, nativeMap) {
1120
654
  return new Promise((resolve, reject) => {
1121
655
  try {
1122
- const theMap = nativeMap || this._mapboxViewInstance;
1123
- const coordinate = theMap.centerCoordinate;
1124
- resolve({
1125
- lat: coordinate.latitude,
1126
- lng: coordinate.longitude
1127
- });
656
+ const b = nativeMap ? MapboxBridge.bridgeFor(nativeMap) : this.bridgeInstance;
657
+ if (!b) {
658
+ reject('No bridge available');
659
+ return;
660
+ }
661
+ const ok = b.updateMarkerPosition ? b.updateMarkerPosition(markerId, lat, lng) : false;
662
+ try {
663
+ if (b.updateViewAnnotationForMarker)
664
+ b.updateViewAnnotationForMarker(markerId, lat, lng);
665
+ }
666
+ catch { }
667
+ if (ok)
668
+ resolve();
669
+ else
670
+ reject('Marker not found or failed to update');
1128
671
  }
1129
672
  catch (ex) {
1130
- if (Trace.isEnabled()) {
1131
- CLog(CLogTypes.info, 'Error in mapbox.getCenter: ' + ex);
1132
- }
1133
673
  reject(ex);
1134
674
  }
1135
675
  });
1136
676
  }
1137
- setZoomLevel(options, nativeMap) {
677
+ // ---------------- Polylines ----------------
678
+ addPolyline(options, nativeMap) {
1138
679
  return new Promise((resolve, reject) => {
1139
680
  try {
1140
- const theMap = nativeMap || this._mapboxViewInstance;
1141
- const animated = options.animated === undefined || options.animated;
1142
- const level = options.level;
1143
- if (level >= 0 && level <= 20) {
1144
- theMap.setZoomLevelAnimated(level, animated);
1145
- resolve();
681
+ const b = nativeMap ? MapboxBridge.bridgeFor(nativeMap) : this.bridgeInstance;
682
+ if (!b) {
683
+ reject('No bridge available');
684
+ return;
1146
685
  }
1147
- else {
1148
- reject('invalid ZoomLevel, use any double value from 0 to 20 (like 8.3)');
686
+ if (!options.points) {
687
+ reject("Please set the 'points' parameter");
688
+ return;
1149
689
  }
690
+ // const coords = options.points.map((p) => [p.lng, p.lat]);
691
+ const coordsJSON = JSON.stringify(options.points.map((p) => [p.lng, p.lat]));
692
+ const opts = { strokeColor: getIosColor(options.color), strokeWidth: options.width, strokeOpacity: options.opacity };
693
+ const id = (options.id ?? new Date().getTime()) + '';
694
+ const ok = b.addPolyline(id, coordsJSON, JSON.stringify(opts));
695
+ if (ok)
696
+ resolve();
697
+ else
698
+ reject('Failed to add polyline');
1150
699
  }
1151
700
  catch (ex) {
1152
- if (Trace.isEnabled()) {
1153
- CLog(CLogTypes.info, 'Error in mapbox.setZoomLevel: ' + ex);
1154
- }
1155
701
  reject(ex);
1156
702
  }
1157
703
  });
1158
704
  }
1159
- getZoomLevel(nativeMap) {
705
+ async addLinePoint(id, lnglat, sourceId, nativeMap) {
1160
706
  return new Promise((resolve, reject) => {
1161
707
  try {
1162
- const theMap = nativeMap || this._mapboxViewInstance;
1163
- resolve(theMap.zoomLevel);
708
+ const b = nativeMap ? MapboxBridge.bridgeFor(nativeMap) : this.bridgeInstance;
709
+ if (!b) {
710
+ reject('No bridge available');
711
+ return;
712
+ }
713
+ const ok = b.addLinePoint(id, JSON.stringify(lnglat), sourceId);
714
+ if (ok)
715
+ resolve();
716
+ else
717
+ reject('Failed to add line point');
1164
718
  }
1165
719
  catch (ex) {
1166
- if (Trace.isEnabled()) {
1167
- CLog(CLogTypes.info, 'Error in mapbox.getZoomLevel: ' + ex);
1168
- }
1169
720
  reject(ex);
1170
721
  }
1171
722
  });
1172
723
  }
1173
- setTilt(options, nativeMap) {
724
+ removePolylines(ids, nativeMap) {
1174
725
  return new Promise((resolve, reject) => {
1175
726
  try {
1176
- const theMap = nativeMap || this._mapboxViewInstance;
1177
- const cam = theMap.camera;
1178
- cam.pitch = options.tilt;
1179
- const durationMs = options.duration ? options.duration : 5000;
1180
- theMap.setCameraWithDurationAnimationTimingFunction(cam, durationMs / 1000, CAMediaTimingFunction.functionWithName(kCAMediaTimingFunctionEaseInEaseOut));
1181
- setTimeout(() => {
727
+ const b = nativeMap ? MapboxBridge.bridgeFor(nativeMap) : this.bridgeInstance;
728
+ if (!b || !b.removePolylines) {
729
+ reject('No bridge available');
730
+ return;
731
+ }
732
+ const ok = b.removePolylines(ids ? ids.map((s) => s + '') : null);
733
+ if (ok)
1182
734
  resolve();
1183
- }, durationMs);
735
+ else
736
+ reject('Failed to remove polylines');
1184
737
  }
1185
738
  catch (ex) {
1186
- if (Trace.isEnabled()) {
1187
- CLog(CLogTypes.info, 'Error in mapbox.setTilt: ' + ex);
1188
- }
1189
739
  reject(ex);
1190
740
  }
1191
741
  });
1192
742
  }
1193
- getTilt(nativeMap) {
743
+ // ---------------- Polygons ----------------
744
+ addPolygon(options, nativeMap) {
1194
745
  return new Promise((resolve, reject) => {
1195
746
  try {
1196
- const theMap = nativeMap || this._mapboxViewInstance;
1197
- resolve(theMap.camera.pitch);
1198
- }
1199
- catch (ex) {
747
+ const b = nativeMap ? MapboxBridge.bridgeFor(nativeMap) : this.bridgeInstance;
748
+ if (!b) {
749
+ reject('No bridge available');
750
+ return;
751
+ }
752
+ if (!options.points) {
753
+ reject("Please set the 'points' parameter");
754
+ return;
755
+ }
756
+ // const coords = options.points.map((p) => [p.lng, p.lat]);
757
+ const coordsJSON = JSON.stringify(options.points.map((p) => [p.lng, p.lat]));
758
+ const opts = {
759
+ fillColor: getIosColor(options.fillColor),
760
+ fillOpacity: options.fillOpacity,
761
+ strokeColor: getIosColor(options.strokeColor),
762
+ strokeWidth: options.strokeWidth,
763
+ strokeOpacity: options.strokeOpacity
764
+ };
765
+ const id = (options.id ?? new Date().getTime()) + '';
1200
766
  if (Trace.isEnabled()) {
1201
- CLog(CLogTypes.info, 'Error in mapbox.getTilt: ' + ex);
767
+ CLog(CLogTypes.info, 'addPolygon:', id, coordsJSON, JSON.stringify(opts));
1202
768
  }
769
+ const ok = b.addPolygon(id, coordsJSON, JSON.stringify(opts));
770
+ if (ok)
771
+ resolve();
772
+ else
773
+ reject('Failed to add polygon');
774
+ }
775
+ catch (ex) {
1203
776
  reject(ex);
1204
777
  }
1205
778
  });
1206
779
  }
1207
- getUserLocation(nativeMap) {
780
+ // removePolygons / removePolylines (TS wrappers)
781
+ removePolygons(ids, nativeMap) {
1208
782
  return new Promise((resolve, reject) => {
1209
783
  try {
1210
- const theMap = nativeMap || this._mapboxViewInstance;
1211
- const loc = theMap.userLocation;
1212
- if (loc === null) {
1213
- reject('Location not available');
1214
- }
1215
- else {
1216
- resolve(_getLocation(loc));
784
+ const b = nativeMap ? MapboxBridge.bridgeFor(nativeMap) : this.bridgeInstance;
785
+ if (!b) {
786
+ reject('No bridge available');
787
+ return;
1217
788
  }
789
+ const ok = b.removePolygons(ids ? ids.map((s) => s + '') : null);
790
+ if (ok)
791
+ resolve();
792
+ else
793
+ reject('Failed to remove polygons');
1218
794
  }
1219
795
  catch (ex) {
1220
- if (Trace.isEnabled()) {
1221
- CLog(CLogTypes.info, 'Error in mapbox.getUserLocation: ' + ex);
1222
- }
1223
796
  reject(ex);
1224
797
  }
1225
798
  });
1226
799
  }
1227
- /**
1228
- * convert string to camera mode constant.
1229
- *
1230
- * Supported modes on iOS are different than on Android.
1231
- *
1232
- * @todo come up with a reasonable set of cross platform defaults.
1233
- */
1234
- _stringToCameraMode(mode) {
1235
- switch (mode) {
1236
- case 'NONE':
1237
- return 0 /* MGLUserTrackingMode.None */;
1238
- case 'NONE_COMPASS':
1239
- console.log('MapboxView::_stringToCameraMode(): NONE_COMPASS unsupported on iOS');
1240
- return 0 /* MGLUserTrackingMode.None */;
1241
- case 'NONE_GPS':
1242
- console.log('MapboxView::_stringToCameraMode(): NONE_GPS unsupported on iOS');
1243
- return 0 /* MGLUserTrackingMode.None */;
1244
- case 'TRACKING':
1245
- return 1 /* MGLUserTrackingMode.Follow */;
1246
- case 'TRACKING_COMPASS':
1247
- return 2 /* MGLUserTrackingMode.FollowWithHeading */;
1248
- case 'TRACKING_GPS':
1249
- // a reasonable approximation.
1250
- return 1 /* MGLUserTrackingMode.Follow */;
1251
- case 'TRACKING_GPS_NORTH':
1252
- return 3 /* MGLUserTrackingMode.FollowWithCourse */;
1253
- default:
1254
- console.log(`_stringToCameraMode: invalid cameraMode: ${mode}`);
1255
- }
1256
- return 0 /* MGLUserTrackingMode.None */;
1257
- }
1258
- _stringToRenderMode(mode) {
1259
- let renderMode;
1260
- switch (mode) {
1261
- case 'NORMAL':
1262
- return 'NORMAL';
1263
- case 'COMPASS':
1264
- return 'COMPASS';
1265
- case 'GPS':
1266
- return 'GPS';
1267
- }
1268
- }
1269
- _convertCameraMode(mode) {
1270
- switch (mode) {
1271
- case 0 /* MGLUserTrackingMode.None */:
1272
- return 'NONE';
1273
- case 1 /* MGLUserTrackingMode.Follow */:
1274
- return 'TRACKING';
1275
- case 2 /* MGLUserTrackingMode.FollowWithHeading */:
1276
- return 'TRACKING_COMPASS';
1277
- case 3 /* MGLUserTrackingMode.FollowWithCourse */:
1278
- return 'TRACKING_GPS_NORTH';
1279
- }
1280
- }
1281
- /**
1282
- * show a user location marker
1283
- *
1284
- * This method must not be called before location permissions have been granted.
1285
- *
1286
- * Supported options under iOS are:
1287
- *
1288
- * - renderMode
1289
- * - cameraMode
1290
- * - clickListener
1291
- *
1292
- * Other options are ignored. Compare with the android version that supports a
1293
- * different set of options.
1294
- *
1295
- * @param {object} options
1296
- */
1297
- showUserLocationMarker(options, nativeMap) {
1298
- return new Promise((resolve, reject) => {
800
+ // ---------------- GeoJSON Clustered source helper ----------------
801
+ // Adds a clustered GeoJSON source + layers for clusters and unclustered points.
802
+ addGeoJsonClustered(options, nativeMap) {
803
+ return new Promise(async (resolve, reject) => {
1299
804
  try {
1300
- const theMap = nativeMap || this._mapboxViewInstance;
1301
- theMap.showsUserLocation = true;
1302
- theMap.userTrackingMode = this._stringToCameraMode(options.cameraMode);
1303
- theMap.showsUserHeadingIndicator = true;
1304
- this.userLocationRenderMode = this._stringToRenderMode(options.renderMode);
1305
- // the "delegate" needs to know the modes
1306
- const delegate = theMap.delegate;
1307
- // tell the delegate to tell the CustomerLocationAnnotationView to change the
1308
- // appearance of the marker.
1309
- delegate.changeUserLocationRenderMode(this.userLocationRenderMode);
1310
- if (typeof options.clickListener != 'undefined') {
1311
- delegate.setUserLocationClickListener(options.clickListener);
805
+ // options: id, data (geojson object or url), clusterRadius?, clusterMaxZoom?, clusterProperties?, layers styling...
806
+ const b = nativeMap ? MapboxBridge.bridgeFor(nativeMap) : this.bridgeInstance;
807
+ if (!b) {
808
+ reject('No bridge available');
809
+ return;
810
+ }
811
+ if (!options.id) {
812
+ reject("Please provide 'id'");
813
+ return;
1312
814
  }
815
+ const sourceId = options.id;
816
+ let geojsonString = null;
817
+ if (options.data) {
818
+ geojsonString = typeof options.data === 'string' ? options.data : JSON.stringify(options.data);
819
+ }
820
+ else if (options.url) {
821
+ // pass URL string as source (bridge.addSourceGeoJSON expects geojson text or url; uses same param)
822
+ geojsonString = options.url;
823
+ }
824
+ else {
825
+ reject("Please pass 'data' or 'url' in addGeoJsonClustered options");
826
+ return;
827
+ }
828
+ // Build source JSON for clustering
829
+ const sourceObj = {
830
+ type: 'geojson',
831
+ data: options.data ? options.data : options.url,
832
+ cluster: true,
833
+ clusterRadius: typeof options.clusterRadius !== 'undefined' ? options.clusterRadius : 50,
834
+ clusterMaxZoom: typeof options.clusterMaxZoom !== 'undefined' ? options.clusterMaxZoom : 14
835
+ };
836
+ // use addSource (bridge.addSourceGeoJSON expects a geojson string, for clarity we'll add via bridge.addSourceGeoJSON)
837
+ // Some bridge implementations expect raw geojson string; if url, pass as string url
838
+ const sourceOk = b.addSourceGeoJSON(sourceId, JSON.stringify(sourceObj));
839
+ if (!sourceOk) {
840
+ // fallback: try addSource with just data
841
+ try {
842
+ const ok2 = b.addSourceGeoJSON(sourceId, geojsonString || '');
843
+ if (!ok2) {
844
+ reject('Failed to add clustered source');
845
+ return;
846
+ }
847
+ }
848
+ catch (e) {
849
+ reject('Failed to add clustered source: ' + e);
850
+ return;
851
+ }
852
+ }
853
+ // Create cluster layer (circle layer)
854
+ const clusterLayer = {
855
+ id: sourceId + '_clusters',
856
+ type: 'circle',
857
+ source: sourceId,
858
+ filter: ['has', 'point_count'],
859
+ paint: {
860
+ 'circle-color': ['step', ['get', 'point_count'], '#51bbd6', 100, '#f1f075', 750, '#f28cb1'],
861
+ 'circle-radius': ['step', ['get', 'point_count'], 20, 100, 30, 750, 40]
862
+ }
863
+ };
864
+ // Count label for clusters
865
+ const clusterCountLayer = {
866
+ id: sourceId + '_cluster-count',
867
+ type: 'symbol',
868
+ source: sourceId,
869
+ filter: ['has', 'point_count'],
870
+ layout: {
871
+ 'text-field': '{point_count_abbreviated}',
872
+ 'text-font': ['Open Sans Bold', 'Arial Unicode MS Bold'],
873
+ 'text-size': 12
874
+ }
875
+ };
876
+ // Unclustered points layer
877
+ const unclusteredLayer = {
878
+ id: sourceId + '_unclustered',
879
+ type: 'circle',
880
+ source: sourceId,
881
+ filter: ['!', ['has', 'point_count']],
882
+ paint: {
883
+ 'circle-color': options.pointColor || '#11b4da',
884
+ 'circle-radius': options.pointRadius || 6
885
+ }
886
+ };
887
+ // Add layers via LayerFactory / bridge
888
+ const mapboxView = b.getMapView();
889
+ if (!mapboxView)
890
+ return { x: 0, y: 0 };
891
+ // prefer native LayerFactory to create typed layers from JSON
892
+ await LayerFactory.createLayer(mapboxView, clusterLayer, null);
893
+ await LayerFactory.createLayer(mapboxView, clusterCountLayer, null);
894
+ await LayerFactory.createLayer(mapboxView, unclusteredLayer, null);
1313
895
  resolve();
1314
896
  }
1315
897
  catch (ex) {
1316
- if (Trace.isEnabled()) {
1317
- CLog(CLogTypes.info, 'Error in mapbox.getUserLocation: ' + ex);
1318
- }
1319
898
  reject(ex);
1320
899
  }
1321
900
  });
1322
901
  }
1323
- /**
1324
- * hide the user location marker
1325
- *
1326
- * @todo unfinished
1327
- */
1328
- hideUserLocationMarker(nativeMap) {
1329
- return new Promise((resolve, reject) => {
902
+ // ---------------- Extrusion (3D buildings) ----------------
903
+ // Ports the Android approach: add a FillExtrusion layer showing 3D buildings.
904
+ addExtrusion(options, nativeMap) {
905
+ return new Promise(async (resolve, reject) => {
1330
906
  try {
1331
- resolve();
907
+ const b = nativeMap ? MapboxBridge.bridgeFor(nativeMap) : this.bridgeInstance;
908
+ // Build a layer JSON representing the fill-extrusion layer similar to Android sample
909
+ // Default values
910
+ const layerId = options.id || '3d-buildings';
911
+ const source = options.source || 'composite';
912
+ const sourceLayer = options.sourceLayer || 'building';
913
+ const minZoom = typeof options.minZoom !== 'undefined' ? options.minZoom : 15;
914
+ // Build layer JSON
915
+ const layerJson = {
916
+ id: layerId,
917
+ type: 'fill-extrusion',
918
+ source,
919
+ 'source-layer': sourceLayer,
920
+ minzoom: minZoom,
921
+ filter: ['==', ['get', 'extrude'], true],
922
+ paint: {
923
+ 'fill-extrusion-color': options.color || '#d3d3d3',
924
+ // Use a data-driven expression to read properties height/min_height
925
+ 'fill-extrusion-height': ['get', 'height'],
926
+ 'fill-extrusion-base': ['get', 'min_height'],
927
+ 'fill-extrusion-opacity': typeof options.opacity !== 'undefined' ? options.opacity : 0.6
928
+ }
929
+ };
930
+ // Use LayerFactory to apply properties / add layer if possible
931
+ try {
932
+ await LayerFactory.createLayer(b.getMapView(), layerJson, null);
933
+ resolve();
934
+ return;
935
+ }
936
+ catch (e) {
937
+ reject('Failed to add extrusion layer');
938
+ }
1332
939
  }
1333
940
  catch (ex) {
1334
- if (Trace.isEnabled()) {
1335
- CLog(CLogTypes.info, 'Error in mapbox.getUserLocation: ' + ex);
1336
- }
1337
941
  reject(ex);
1338
942
  }
1339
943
  });
1340
944
  }
1341
- /**
1342
- * Change the mode of the user location marker
1343
- *
1344
- * Used to change the camera tracking and render modes of an existing
1345
- * marker.
1346
- *
1347
- * The marker must be configured using showUserLocationMarker before this method
1348
- * can called.
1349
- */
1350
- changeUserLocationMarkerMode(renderModeString, cameraModeString, nativeMap) {
945
+ // ---------------- Camera ----------------
946
+ setCenter(options, nativeMap) {
1351
947
  return new Promise((resolve, reject) => {
1352
948
  try {
1353
- const theMap = nativeMap || this._mapboxViewInstance;
1354
- if (Trace.isEnabled()) {
1355
- CLog(CLogTypes.info, "Mapbox::changeUserLocationMarkerMode(): changing renderMode to '" + renderModeString + "' cameraMode '" + cameraModeString + "'");
949
+ const b = nativeMap ? MapboxBridge.bridgeFor(nativeMap) : this.bridgeInstance;
950
+ if (!b) {
951
+ reject('No bridge available');
952
+ return;
1356
953
  }
1357
- theMap.userTrackingMode = this._stringToCameraMode(cameraModeString);
1358
- const delegate = theMap.delegate;
1359
- const renderMode = this._stringToRenderMode(renderModeString);
1360
- delegate.changeUserLocationRenderMode(renderMode);
954
+ const animated = options.animated === undefined || options.animated;
955
+ b.setCenter(options.lat, options.lng, animated);
956
+ resolve();
1361
957
  }
1362
958
  catch (ex) {
1363
- if (Trace.isEnabled()) {
1364
- CLog(CLogTypes.info, 'Error in mapbox.showUserLocationMarker: ' + ex);
1365
- }
1366
959
  reject(ex);
1367
960
  }
1368
961
  });
1369
962
  }
1370
- /**
1371
- * ignored on iOS
1372
- */
1373
- forceUserLocationUpdate(location, nativeMap) { }
1374
- queryRenderedFeatures(options, nativeMap) {
963
+ getCenter(nativeMap) {
1375
964
  return new Promise((resolve, reject) => {
1376
965
  try {
1377
- const theMap = nativeMap || this._mapboxViewInstance;
1378
- if (options.point === undefined) {
1379
- reject("Please set the 'point' parameter");
966
+ const b = nativeMap ? MapboxBridge.bridgeFor(nativeMap) : this.bridgeInstance;
967
+ if (!b) {
968
+ reject('No bridge available');
1380
969
  return;
1381
970
  }
1382
- if (!options) {
1383
- options = {};
1384
- }
1385
- const { x, y } = theMap.convertCoordinateToPointToView({ latitude: options.point.lat, longitude: options.point.lng }, theMap);
1386
- const queryLayerIds = options.layers ? NSSet.setWithArray(Utils.ios.collections.jsArrayToNSArray(options.layers)) : null;
1387
- const queryFilter = options.filter ? ExpressionParser.parseJson(options.filter) : null;
1388
- const features = theMap.visibleFeaturesAtPointInStyleLayersWithIdentifiersPredicate({ x, y }, queryLayerIds, queryFilter);
1389
- const result = [];
1390
- for (let i = 0; i < features.count; i++) {
1391
- const feature = features.objectAtIndex(i);
1392
- const featureJson = NSJSONSerialization.dataWithJSONObjectOptionsError(feature.geoJSONDictionary(), 0);
1393
- result.push(JSON.parse(NSString.alloc().initWithDataEncoding(featureJson, NSUTF8StringEncoding)));
971
+ const c = b.getCenter();
972
+ if (!c) {
973
+ reject('No center found');
974
+ return;
1394
975
  }
1395
- resolve(result);
976
+ resolve(JSON.parse(c));
1396
977
  }
1397
978
  catch (ex) {
1398
- if (Trace.isEnabled()) {
1399
- CLog(CLogTypes.info, 'Error in mapbox.queryRenderedFeatures: ' + ex);
1400
- }
1401
979
  reject(ex);
1402
980
  }
1403
981
  });
1404
982
  }
1405
- querySourceFeatures(sourceId, options, nativeMap) {
983
+ setZoomLevel(options, nativeMap) {
1406
984
  return new Promise((resolve, reject) => {
1407
985
  try {
1408
- const theMap = nativeMap || this._mapboxViewInstance;
1409
- if (!options) {
1410
- options = {};
1411
- }
1412
- const source = theMap.style.sourceWithIdentifier(sourceId);
1413
- if (!source) {
1414
- throw new Error(`Source with id "${sourceId}" not found.`);
1415
- }
1416
- let features;
1417
- const queryFilter = options.filter ? ExpressionParser.parseJson(options.filter) : null;
1418
- if (source instanceof MGLShapeSource) {
1419
- features = source.featuresMatchingPredicate(queryFilter);
1420
- }
1421
- else if (source instanceof MGLVectorTileSource) {
1422
- if (!options.sourceLayer) {
1423
- throw new Error('The option "sourceLayer" is required for vector sources.');
1424
- }
1425
- const sourceLayerIds = options.sourceLayer ? NSSet.setWithArray(Utils.ios.collections.jsArrayToNSArray([options.sourceLayer])) : null;
1426
- features = source.featuresInSourceLayersWithIdentifiersPredicate(sourceLayerIds, queryFilter);
1427
- }
1428
- else {
1429
- throw new Error('Only sources from type "vector" or "geojson" are supported.');
1430
- }
1431
- const result = [];
1432
- for (let i = 0; i < features.count; i++) {
1433
- const feature = features.objectAtIndex(i);
1434
- const featureJson = NSJSONSerialization.dataWithJSONObjectOptionsError(feature.geoJSONDictionary(), 0);
1435
- result.push(JSON.parse(NSString.alloc().initWithDataEncoding(featureJson, NSUTF8StringEncoding)));
986
+ const b = nativeMap ? MapboxBridge.bridgeFor(nativeMap) : this.bridgeInstance;
987
+ if (!b) {
988
+ reject('No bridge available');
989
+ return;
1436
990
  }
1437
- resolve(result);
991
+ const animated = options.animated === undefined || options.animated;
992
+ b.setZoom(options.level, animated);
993
+ resolve();
1438
994
  }
1439
995
  catch (ex) {
1440
- if (Trace.isEnabled()) {
1441
- CLog(CLogTypes.info, 'Error in mapbox.querySourceFeatures: ' + ex);
1442
- }
1443
996
  reject(ex);
1444
997
  }
1445
998
  });
1446
999
  }
1447
- /**
1448
- * @deprecated
1449
- */
1450
- addPolygon(options, nativeMap) {
1000
+ getZoomLevel(nativeMap) {
1451
1001
  return new Promise((resolve, reject) => {
1452
- const theMap = nativeMap || this._mapboxViewInstance;
1453
- const points = options.points;
1454
- if (points === undefined) {
1455
- reject("Please set the 'points' parameter");
1456
- return;
1002
+ try {
1003
+ const b = nativeMap ? MapboxBridge.bridgeFor(nativeMap) : this.bridgeInstance;
1004
+ if (!b) {
1005
+ reject('No bridge available');
1006
+ return;
1007
+ }
1008
+ const z = b.getZoom();
1009
+ resolve(z);
1457
1010
  }
1458
- const coordinateArray = [];
1459
- points.forEach((point) => coordinateArray.push([point.lng, point.lat]));
1460
- const polygonID = `polygon_${options.id || new Date().getTime()}`;
1461
- if (theMap.style.sourceWithIdentifier(polygonID)) {
1462
- reject("Remove the polygon with this id first with 'removePolygons': " + polygonID);
1463
- return;
1011
+ catch (ex) {
1012
+ reject(ex);
1464
1013
  }
1465
- const geoJSON = `{
1466
- "type": "FeatureCollection",
1467
- "features": [
1468
- {
1469
- "id": ${JSON.stringify(polygonID)},
1470
- "type": "Feature",
1471
- "properties": {
1472
- },
1473
- "geometry": {
1474
- "type": "Polygon",
1475
- "coordinates": [${JSON.stringify(coordinateArray)}]
1476
- }
1477
- }
1478
- ]
1479
- }`;
1480
- const geoDataStr = NSString.stringWithString(geoJSON);
1481
- const geoData = geoDataStr.dataUsingEncoding(NSUTF8StringEncoding);
1482
- const geoDataBase64Enc = geoData.base64EncodedStringWithOptions(0);
1483
- const geo = NSData.alloc().initWithBase64EncodedStringOptions(geoDataBase64Enc, null);
1484
- const shape = MGLShape.shapeWithDataEncodingError(geo, NSUTF8StringEncoding);
1485
- const source = MGLShapeSource.alloc().initWithIdentifierShapeOptions(polygonID, shape, null);
1486
- theMap.style.addSource(source);
1487
- if (options.strokeColor || options.strokeWidth || options.strokeOpacity) {
1488
- const strokeLayer = MGLLineStyleLayer.alloc().initWithIdentifierSource(polygonID + '_stroke', source);
1489
- strokeLayer.lineColor = NSExpression.expressionForConstantValue(!options.strokeColor ? UIColor.blackColor : options.strokeColor instanceof Color ? options.strokeColor.ios : new Color(options.strokeColor).ios);
1490
- strokeLayer.lineWidth = NSExpression.expressionForConstantValue(options.strokeWidth || 5);
1491
- strokeLayer.lineOpacity = NSExpression.expressionForConstantValue(options.strokeOpacity === undefined ? 1 : options.strokeOpacity);
1492
- theMap.style.addLayer(strokeLayer);
1493
- }
1494
- const layer = MGLFillStyleLayer.alloc().initWithIdentifierSource(polygonID, source);
1495
- layer.fillColor = NSExpression.expressionForConstantValue(!options.fillColor ? UIColor.blackColor : options.fillColor instanceof Color ? options.fillColor.ios : new Color(options.fillColor).ios);
1496
- layer.fillOpacity = NSExpression.expressionForConstantValue(options.fillOpacity === undefined ? 1 : options.fillOpacity);
1497
- theMap.style.addLayer(layer);
1498
- resolve();
1499
1014
  });
1500
1015
  }
1501
- addPolyline(options, nativeMap) {
1016
+ setMapStyle(style, nativeMap) {
1502
1017
  return new Promise((resolve, reject) => {
1503
- const theMap = nativeMap || this._mapboxViewInstance;
1504
- const points = options.points;
1505
- if (points === undefined) {
1506
- reject("Please set the 'points' parameter");
1507
- return;
1018
+ try {
1019
+ const b = nativeMap ? MapboxBridge.bridgeFor(nativeMap) : this.bridgeInstance;
1020
+ if (!b) {
1021
+ reject('No bridge available');
1022
+ return;
1023
+ }
1024
+ const styleStr = typeof style === 'string' ? style : style.toString();
1025
+ b.setStyle(styleStr, (success, error) => {
1026
+ if (success)
1027
+ resolve();
1028
+ else
1029
+ reject(error && error.localizedDescription ? error.localizedDescription : error || 'Error setting style');
1030
+ });
1508
1031
  }
1509
- const coordinateArray = [];
1510
- points.forEach((point) => coordinateArray.push([point.lng, point.lat]));
1511
- const polylineID = 'polyline_' + (options.id || new Date().getTime());
1512
- // this would otherwise crash the app
1513
- if (theMap.style.sourceWithIdentifier(polylineID)) {
1514
- reject("Remove the polyline with this id first with 'removePolylines': " + polylineID);
1515
- return;
1032
+ catch (ex) {
1033
+ reject(ex);
1516
1034
  }
1517
- const geoJSON = `{"type": "FeatureCollection", "features": [{"type": "Feature","properties": {},"geometry": {"type": "LineString", "coordinates": ${JSON.stringify(coordinateArray)}}}]}`;
1518
- const geoDataStr = NSString.stringWithString(geoJSON);
1519
- const geoData = geoDataStr.dataUsingEncoding(NSUTF8StringEncoding);
1520
- const geoDataBase64Enc = geoData.base64EncodedStringWithOptions(0);
1521
- const geo = NSData.alloc().initWithBase64EncodedStringOptions(geoDataBase64Enc, null);
1522
- const shape = MGLShape.shapeWithDataEncodingError(geo, NSUTF8StringEncoding);
1523
- const source = MGLShapeSource.alloc().initWithIdentifierShapeOptions(polylineID, shape, null);
1524
- theMap.style.addSource(source);
1525
- const layer = MGLLineStyleLayer.alloc().initWithIdentifierSource(polylineID, source);
1526
- layer.lineColor = NSExpression.expressionForConstantValue(!options.color ? UIColor.blackColor : options.color instanceof Color ? options.color.ios : new Color(options.color).ios);
1527
- layer.lineWidth = NSExpression.expressionForConstantValue(options.width || 5);
1528
- layer.lineOpacity = NSExpression.expressionForConstantValue(options.opacity === undefined ? 1 : options.opacity);
1529
- theMap.style.addLayer(layer);
1530
- resolve();
1531
- });
1532
- }
1533
- removePolyById(theMap, id) {
1534
- let layer = theMap.style.layerWithIdentifier(id);
1535
- if (layer !== null) {
1536
- theMap.style.removeLayer(layer);
1537
- }
1538
- // polygons may have a 'stroke' layer
1539
- layer = theMap.style.layerWithIdentifier(id + '_stroke');
1540
- if (layer !== null) {
1541
- theMap.style.removeLayer(layer);
1542
- }
1543
- const source = theMap.style.sourceWithIdentifier(id);
1544
- if (source !== null) {
1545
- theMap.style.removeSource(source);
1546
- }
1547
- }
1548
- removePolys(polyType, ids, nativeMap) {
1549
- return new Promise((resolve) => {
1550
- const theMap = nativeMap || this._mapboxViewInstance;
1551
- ids.forEach((id) => this.removePolyById(theMap, polyType + id));
1552
- resolve();
1553
1035
  });
1554
1036
  }
1555
- removePolygons(ids, nativeMap) {
1556
- return this.removePolys('polygon_', ids, nativeMap);
1557
- }
1558
- removePolylines(ids, nativeMap) {
1559
- return this.removePolys('polyline_', ids, nativeMap);
1560
- }
1561
1037
  animateCamera(options, nativeMap) {
1562
1038
  return new Promise((resolve, reject) => {
1563
1039
  try {
1564
- const theMap = nativeMap || this._mapboxViewInstance;
1565
- let cam;
1566
- if (options.bounds) {
1567
- const padding = options.padding || 0;
1568
- // ensure padding is an object and assign default values
1569
- const { top = 0, left = 0, bottom = 0, right = 0 } = typeof padding === 'object' ? padding : { top: padding, left: padding, bottom: padding, right: padding };
1570
- // support defined padding
1571
- const insets = { top, left, bottom, right };
1572
- const bounds = {
1573
- sw: CLLocationCoordinate2DMake(options.bounds.south, options.bounds.west),
1574
- ne: CLLocationCoordinate2DMake(options.bounds.north, options.bounds.east)
1575
- };
1576
- cam = theMap.cameraThatFitsCoordinateBoundsEdgePadding(bounds, insets);
1577
- }
1578
- else {
1579
- const target = options.target;
1580
- if (target === undefined) {
1581
- reject("Please set the 'target' parameter");
1582
- return;
1583
- }
1584
- cam = theMap.camera;
1585
- cam.centerCoordinate = CLLocationCoordinate2DMake(target.lat, target.lng);
1586
- }
1587
- if (options.altitude) {
1588
- cam.altitude = options.altitude;
1589
- }
1590
- if (options.bearing) {
1591
- cam.heading = options.bearing;
1592
- }
1593
- if (options.tilt) {
1594
- cam.pitch = options.tilt;
1595
- }
1596
- if (options.zoomLevel && options.target) {
1597
- cam.altitude = MGLAltitudeForZoomLevel(options.zoomLevel, cam.pitch, options.target.lat, theMap.frame.size);
1040
+ const b = nativeMap ? MapboxBridge.bridgeFor(nativeMap) : this.bridgeInstance;
1041
+ if (!b) {
1042
+ reject('No bridge available');
1043
+ return;
1598
1044
  }
1599
- const durationMs = options.duration ? options.duration : 10000;
1600
- theMap.setCameraWithDurationAnimationTimingFunction(cam, durationMs / 1000, CAMediaTimingFunction.functionWithName(kCAMediaTimingFunctionEaseInEaseOut));
1045
+ options.duration = options.duration || 1000;
1046
+ b.animateCamera(JSON.stringify(options));
1601
1047
  setTimeout(() => {
1602
1048
  resolve();
1603
- }, durationMs);
1049
+ }, options.duration);
1604
1050
  }
1605
1051
  catch (ex) {
1052
+ reject(ex);
1053
+ }
1054
+ });
1055
+ }
1056
+ // ---------------- Queries ----------------
1057
+ queryRenderedFeatures(options, nativeMap) {
1058
+ return new Promise((resolve, reject) => {
1059
+ try {
1060
+ const b = nativeMap ? MapboxBridge.bridgeFor(nativeMap) : this.bridgeInstance;
1061
+ if (!b) {
1062
+ reject('No bridge available');
1063
+ return;
1064
+ }
1065
+ if (!options.point) {
1066
+ reject("Please set the 'point' parameter");
1067
+ return;
1068
+ }
1069
+ const screen = this.project({ lat: options.point.lat, lng: options.point.lng });
1606
1070
  if (Trace.isEnabled()) {
1607
- CLog(CLogTypes.info, 'Error in mapbox.animateCamera: ' + ex);
1071
+ CLog(CLogTypes.info, 'queryRenderedFeatures:', options.point, screen);
1608
1072
  }
1073
+ b.queryRenderedFeaturesAtPoint(JSON.stringify(screen), options.layers, (ret) => {
1074
+ if (ret) {
1075
+ resolve(JSON.parse(ret));
1076
+ }
1077
+ else {
1078
+ resolve([]);
1079
+ }
1080
+ });
1081
+ }
1082
+ catch (ex) {
1609
1083
  reject(ex);
1610
1084
  }
1611
1085
  });
1612
1086
  }
1613
- /**
1614
- * sets a map level click listener
1615
- *
1616
- */
1617
- setOnMapClickListener(listener, nativeMap) {
1087
+ // ---------------- Events, filters, queries ----------------
1088
+ // querySourceFeatures now calls native bridge querySourceFeatures which uses MapboxMaps native async API
1089
+ querySourceFeatures(sourceId, options, nativeMap) {
1618
1090
  return new Promise((resolve, reject) => {
1619
1091
  try {
1620
- const theMap = nativeMap || this._mapboxViewInstance;
1621
- if (!theMap) {
1622
- reject('No map has been loaded');
1092
+ const b = nativeMap ? MapboxBridge.bridgeFor(nativeMap) : this.bridgeInstance;
1093
+ if (!b) {
1094
+ reject('No bridge available');
1623
1095
  return;
1624
1096
  }
1625
- theMap['mapTapHandler'] = MapTapHandlerImpl.initWithOwnerAndListenerForMap(new WeakRef(this), listener, theMap);
1626
- const tapGestureRecognizer = UITapGestureRecognizer.alloc().initWithTargetAction(theMap['mapTapHandler'], 'tap');
1627
- for (let i = 0; i < theMap.gestureRecognizers.count; i++) {
1628
- const recognizer = theMap.gestureRecognizers.objectAtIndex(i);
1629
- if (recognizer instanceof UITapGestureRecognizer) {
1630
- tapGestureRecognizer.requireGestureRecognizerToFail(recognizer);
1097
+ if (Trace.isEnabled()) {
1098
+ CLog(CLogTypes.info, 'querySourceFeatures:', sourceId, JSON.stringify(options));
1099
+ }
1100
+ const payload = {};
1101
+ if (options && options.filter)
1102
+ payload.filter = options.filter;
1103
+ if (options && options.sourceLayer)
1104
+ payload.sourceLayer = options.sourceLayer;
1105
+ // call native async method which returns a Cancelable token
1106
+ const cancelable = b.querySourceFeatures(sourceId, JSON.stringify(payload), (retJson) => {
1107
+ if (!retJson) {
1108
+ resolve([]);
1109
+ return;
1631
1110
  }
1632
- }
1633
- theMap.addGestureRecognizer(tapGestureRecognizer);
1634
- resolve();
1111
+ try {
1112
+ const arr = JSON.parse(retJson);
1113
+ resolve(arr);
1114
+ }
1115
+ catch (err) {
1116
+ reject(err);
1117
+ }
1118
+ });
1119
+ // Optionally return cancelable to caller via resolved value? we keep the Promise focused on features.
1120
+ // If you want cancellation, you can expose the cancelable on another API or return { promise, cancelable }.
1635
1121
  }
1636
1122
  catch (ex) {
1637
- if (Trace.isEnabled()) {
1638
- CLog(CLogTypes.info, 'Error in mapbox.setOnMapClickListener: ' + ex);
1639
- }
1640
1123
  reject(ex);
1641
1124
  }
1642
1125
  });
1643
1126
  }
1644
- setOnMapLongClickListener(listener, nativeMap) {
1127
+ // ---------------- Sources / Layers / Geometry ----------------
1128
+ addSource(id, options, nativeMap) {
1645
1129
  return new Promise((resolve, reject) => {
1646
1130
  try {
1647
- const theMap = nativeMap || this._mapboxViewInstance;
1648
- if (!theMap) {
1649
- reject('No map has been loaded');
1131
+ const b = nativeMap ? MapboxBridge.bridgeFor(nativeMap) : this.bridgeInstance;
1132
+ if (!b) {
1133
+ reject('No bridge available');
1650
1134
  return;
1651
1135
  }
1652
- // adding the longPress handler to the map oject so it's not GC'd
1653
- theMap['mapLongPressHandler'] = MapLongPressHandlerImpl.initWithOwnerAndListenerForMap(new WeakRef(this), listener, theMap);
1654
- const longPressGestureRecognizer = UILongPressGestureRecognizer.alloc().initWithTargetAction(theMap['mapLongPressHandler'], 'longPress');
1655
- // cancel the default longPress handler
1656
- for (let i = 0; i < theMap.gestureRecognizers.count; i++) {
1657
- const recognizer = theMap.gestureRecognizers.objectAtIndex(i);
1658
- if (recognizer instanceof UILongPressGestureRecognizer) {
1659
- longPressGestureRecognizer.requireGestureRecognizerToFail(recognizer);
1136
+ if (Trace.isEnabled()) {
1137
+ CLog(CLogTypes.info, 'addSource:', id, JSON.stringify(options));
1138
+ }
1139
+ if (options.type === 'geojson') {
1140
+ const geojson = options.data ? JSON.stringify(options.data) : options.url;
1141
+ if (!geojson) {
1142
+ reject('geojson source requires data or url');
1143
+ return;
1660
1144
  }
1145
+ const ok = b.addSourceGeoJSON(id, geojson);
1146
+ if (ok)
1147
+ resolve();
1148
+ else
1149
+ reject('Failed to add source');
1661
1150
  }
1662
- theMap.addGestureRecognizer(longPressGestureRecognizer);
1663
- resolve();
1151
+ else
1152
+ reject('Only geojson source supported in bridge.addSource');
1664
1153
  }
1665
1154
  catch (ex) {
1666
- if (Trace.isEnabled()) {
1667
- CLog(CLogTypes.info, 'Error in mapbox.setOnMapClickListener: ' + ex);
1668
- }
1669
1155
  reject(ex);
1670
1156
  }
1671
1157
  });
1672
1158
  }
1673
- setOnScrollListener(listener, nativeMap) {
1159
+ updateSource(id, options, nativeMap) {
1674
1160
  return new Promise((resolve, reject) => {
1675
1161
  try {
1676
- const theMap = nativeMap || this._mapboxViewInstance;
1677
- if (!theMap) {
1678
- reject('No map has been loaded');
1162
+ const b = nativeMap ? MapboxBridge.bridgeFor(nativeMap) : this.bridgeInstance;
1163
+ if (!b) {
1164
+ reject('No bridge available');
1679
1165
  return;
1680
1166
  }
1681
- // adding the pan handler to the map oject so it's not GC'd
1682
- if (theMap['mapPanHandler'] === undefined) {
1683
- theMap['mapPanHandler'] = MapPanHandlerImpl.initWithOwnerAndListenerForMap(new WeakRef(this), listener, 2 /* UIGestureRecognizerState.Changed */, theMap);
1167
+ if (options.type === 'geojson') {
1168
+ const data = JSON.stringify(options.data);
1169
+ const ok = b.updateSourceGeoJSON(id, data);
1170
+ if (ok)
1171
+ resolve();
1172
+ else
1173
+ reject('Failed to update source');
1684
1174
  }
1685
- else {
1686
- theMap['mapPanHandler'].addListener(2 /* UIGestureRecognizerState.Changed */, listener);
1687
- }
1688
- // there's already a pan recognizer, so find it and attach a target action
1689
- for (let i = 0; i < theMap.gestureRecognizers.count; i++) {
1690
- const recognizer = theMap.gestureRecognizers.objectAtIndex(i);
1691
- if (recognizer instanceof UIPanGestureRecognizer) {
1692
- recognizer.addTargetAction(theMap['mapPanHandler'], 'pan');
1693
- break;
1694
- }
1175
+ else
1176
+ reject('Only geojson supported for updateSource');
1177
+ }
1178
+ catch (ex) {
1179
+ reject(ex);
1180
+ }
1181
+ });
1182
+ }
1183
+ removeSource(id, nativeMap) {
1184
+ return new Promise((resolve, reject) => {
1185
+ try {
1186
+ const b = nativeMap ? MapboxBridge.bridgeFor(nativeMap) : this.bridgeInstance;
1187
+ if (!b) {
1188
+ reject('No bridge available');
1189
+ return;
1695
1190
  }
1696
- resolve();
1191
+ const ok = b.removeSource(id);
1192
+ if (ok)
1193
+ resolve();
1194
+ else
1195
+ reject('Failed to remove source');
1697
1196
  }
1698
1197
  catch (ex) {
1699
- if (Trace.isEnabled()) {
1700
- CLog(CLogTypes.info, 'Error in mapbox.setOnScrollListener: ' + ex);
1198
+ reject(ex);
1199
+ }
1200
+ });
1201
+ }
1202
+ async addLayer(style, belowLayerId, nativeMap) {
1203
+ const b = nativeMap ? MapboxBridge.bridgeFor(nativeMap) : this.bridgeInstance;
1204
+ // delegate to LayerFactory (TS shim -> native when available)
1205
+ if (Trace.isEnabled()) {
1206
+ CLog(CLogTypes.info, 'addLayer:', belowLayerId, JSON.stringify(style));
1207
+ }
1208
+ await LayerFactory.createLayer(b.getMapView(), style, belowLayerId);
1209
+ }
1210
+ async removeLayer(id, nativeMap) {
1211
+ return new Promise((resolve, reject) => {
1212
+ try {
1213
+ const b = nativeMap ? MapboxBridge.bridgeFor(nativeMap) : this.bridgeInstance;
1214
+ if (!b) {
1215
+ reject('No bridge available');
1216
+ return;
1701
1217
  }
1218
+ const ok = b.removeLayer(id);
1219
+ if (ok)
1220
+ resolve();
1221
+ else
1222
+ reject('Failed to remove layer');
1223
+ }
1224
+ catch (ex) {
1702
1225
  reject(ex);
1703
1226
  }
1704
1227
  });
1705
1228
  }
1706
- /**
1707
- * simulates onMoveBegin single event callback
1708
- *
1709
- * This will call the listener provided once per pan akin to the way
1710
- * onMoveBegin on the Android side works.
1711
- */
1712
- setOnMoveBeginListener(listener, nativeMap) {
1229
+ getLayer(layerId, nativeMap) {
1230
+ return new Promise((resolve, reject) => {
1231
+ const b = nativeMap ? MapboxBridge.bridgeFor(nativeMap) : this.bridgeInstance;
1232
+ const found = NativeLayerFactory.getLayer(b.getMapView(), layerId);
1233
+ resolve(found ? new Layer(b.getMapView(), layerId) : null);
1234
+ });
1235
+ }
1236
+ getLayers(nativeMap) {
1713
1237
  return new Promise((resolve, reject) => {
1714
1238
  try {
1715
- const theMap = nativeMap || this._mapboxViewInstance;
1716
- if (!theMap) {
1717
- reject('No map has been loaded');
1718
- return;
1719
- }
1720
- // adding the pan handler to the map oject so it's not GC'd
1721
- if (theMap['mapPanHandler'] === undefined) {
1722
- theMap['mapPanHandler'] = MapPanHandlerImpl.initWithOwnerAndListenerForMap(new WeakRef(this), listener, 1 /* UIGestureRecognizerState.Began */, theMap);
1723
- }
1724
- else {
1725
- theMap['mapPanHandler'].addListener(1 /* UIGestureRecognizerState.Began */, listener);
1726
- }
1727
- // there's already a pan recognizer, so find it and attach a target action
1728
- for (let i = 0; i < theMap.gestureRecognizers.count; i++) {
1729
- const recognizer = theMap.gestureRecognizers.objectAtIndex(i);
1730
- if (recognizer instanceof UIPanGestureRecognizer) {
1731
- recognizer.addTargetAction(theMap['mapPanHandler'], 'panBegin');
1732
- break;
1733
- }
1734
- }
1735
- resolve();
1239
+ const b = nativeMap ? MapboxBridge.bridgeFor(nativeMap) : this.bridgeInstance;
1240
+ const layersIds = JSON.parse(NativeLayerFactory.getLayers(b.getMapView())) || [];
1241
+ resolve(layersIds.map((id) => new Layer(b.getMapView(), id)));
1736
1242
  }
1737
1243
  catch (ex) {
1738
- if (Trace.isEnabled()) {
1739
- CLog(CLogTypes.info, 'Error in mapbox.setOnMoveBeginListener: ' + ex);
1740
- }
1741
1244
  reject(ex);
1742
1245
  }
1743
1246
  });
1744
1247
  }
1745
- setOnMoveEndListener(listener, nativeMap) {
1248
+ // returns base64 PNG string for the image or null
1249
+ getImage(imageId, nativeMap) {
1746
1250
  return new Promise((resolve, reject) => {
1747
1251
  try {
1748
- const theMap = nativeMap || this._mapboxViewInstance;
1749
- if (!theMap) {
1750
- reject('No map has been loaded');
1252
+ const b = nativeMap ? MapboxBridge.bridgeFor(nativeMap) : this.bridgeInstance;
1253
+ if (!b || !b.getImage) {
1254
+ resolve(null);
1751
1255
  return;
1752
1256
  }
1753
- if (theMap['mapPanHandler'] === undefined) {
1754
- theMap['mapPanHandler'] = MapPanHandlerImpl.initWithOwnerAndListenerForMap(new WeakRef(this), listener, 3 /* UIGestureRecognizerState.Ended */, theMap);
1257
+ // The native bridge now returns a UIImage (native iOS object) or null.
1258
+ const nativeImage = b.getImage(imageId);
1259
+ if (!nativeImage) {
1260
+ resolve(null);
1261
+ return;
1755
1262
  }
1756
- else {
1757
- theMap['mapPanHandler'].addListener(3 /* UIGestureRecognizerState.Ended */, listener);
1758
- }
1759
- // there's already a pan recognizer, so find it and attach a target action
1760
- for (let i = 0; i < theMap.gestureRecognizers.count; i++) {
1761
- const recognizer = theMap.gestureRecognizers.objectAtIndex(i);
1762
- if (recognizer instanceof UIPanGestureRecognizer) {
1763
- recognizer.addTargetAction(theMap['mapPanHandler'], 'panEnd');
1764
- break;
1263
+ // Wrap the native UIImage into a NativeScript ImageSource
1264
+ try {
1265
+ // ImageSource.fromNativeSource accepts a native UIImage on iOS
1266
+ const imgSrc = new ImageSource(nativeImage);
1267
+ resolve(imgSrc || null);
1268
+ }
1269
+ catch (err) {
1270
+ // As a fallback, if the bridge returns base64 string (older fallback), try decode
1271
+ try {
1272
+ const maybeBase64 = nativeImage;
1273
+ if (typeof maybeBase64 === 'string') {
1274
+ const src = ImageSource.fromBase64Sync ? ImageSource.fromBase64Sync(maybeBase64) : ImageSource.fromBase64(maybeBase64);
1275
+ resolve(src || null);
1276
+ }
1277
+ else {
1278
+ resolve(null);
1279
+ }
1280
+ }
1281
+ catch (e) {
1282
+ resolve(null);
1765
1283
  }
1766
1284
  }
1767
- resolve();
1768
1285
  }
1769
1286
  catch (ex) {
1770
- if (Trace.isEnabled()) {
1771
- CLog(CLogTypes.info, 'Error in mapbox.setOnMoveEndListener: ' + ex);
1772
- }
1773
1287
  reject(ex);
1774
1288
  }
1775
1289
  });
1776
1290
  }
1777
- setOnFlingListener(listener, nativeMap) {
1778
- // there's no swipe event we can bind to
1779
- return Promise.reject("'setOnFlingListener' is not supported on iOS");
1780
- }
1781
- async setOnCameraMoveListener(listener, nativeMap) {
1782
- const theMap = nativeMap || this._mapboxViewInstance;
1783
- if (theMap) {
1784
- theMap.delegate.setCameraChangedListener(listener);
1291
+ // ---------------- Callouts ----------------
1292
+ createCalloutView(marker) {
1293
+ if (Trace.isEnabled()) {
1294
+ CLog(CLogTypes.info, 'createCalloutView():', marker.id, marker.title, !!this._reusableCalloutView);
1295
+ }
1296
+ if (this._reusableCalloutView) {
1297
+ const title = this._reusableCalloutView.getViewById('title');
1298
+ title.text = marker?.title || '';
1299
+ const subtitle = this._reusableCalloutView.getViewById('subtitle');
1300
+ subtitle.text = marker?.subtitle;
1301
+ subtitle.visibility = marker?.subtitle ? 'visible' : 'collapse';
1785
1302
  }
1786
1303
  else {
1787
- return Promise.reject('No map has been loaded');
1304
+ this._reusableCalloutView = createInfoWindowView(marker.title, marker.subtitle);
1305
+ }
1306
+ if (Trace.isEnabled()) {
1307
+ CLog(CLogTypes.info, 'createCalloutView1():', marker.id, marker.title, !!this._reusableCalloutView);
1788
1308
  }
1309
+ this._reusableCalloutView.removeEventListener('tap');
1310
+ return this._reusableCalloutView;
1789
1311
  }
1790
- setOnCameraMoveCancelListener(listener, nativeMap) {
1791
- return Promise.reject("'setOnCameraMoveCancelListener' not currently supported on iOS");
1312
+ async showCalloutForMarkerById(markerId) {
1313
+ const m = this._markers.find((x) => `${x.id}` === markerId);
1314
+ if (!m) {
1315
+ return;
1316
+ }
1317
+ if (Trace.isEnabled()) {
1318
+ CLog(CLogTypes.info, 'showCalloutForMarkerById():', typeof markerId, markerId);
1319
+ }
1320
+ if (this.bridgeInstance.hasViewAnnotationForMarker(markerId)) {
1321
+ return;
1322
+ }
1323
+ const callout = this.createCalloutView(m);
1324
+ callout.on('tap', () => {
1325
+ try {
1326
+ const res = m.onCalloutTap ? m.onCalloutTap(m) : undefined;
1327
+ if (res === false)
1328
+ this.deselectMarker(m);
1329
+ }
1330
+ catch (e) {
1331
+ console.error('callout tap handler error', e);
1332
+ }
1333
+ });
1334
+ try {
1335
+ const nativeView = createUIViewAutoSizeUIViewAutoSize(callout);
1336
+ if (Trace.isEnabled()) {
1337
+ CLog(CLogTypes.info, 'showCalloutForMarkerById1():', markerId, nativeView);
1338
+ }
1339
+ m.ios = nativeView;
1340
+ const ok = this.bridgeInstance.addViewAnnotationForMarker(markerId, nativeView, m.lat, m.lng);
1341
+ if (!ok) {
1342
+ console.warn('addViewAnnotationForMarker failed for', markerId);
1343
+ }
1344
+ this.selectedMarker = m;
1345
+ }
1346
+ catch (e) {
1347
+ console.error('Failed to add native view annotation', e);
1348
+ }
1792
1349
  }
1793
- async setOnCameraIdleListener(listener, nativeMap) {
1794
- const theMap = nativeMap || this._mapboxViewInstance;
1795
- if (theMap) {
1796
- theMap.delegate.setCameraIdledListener(listener);
1350
+ hideCalloutForMarkerById(markerId) {
1351
+ const m = this._markers.find((x) => `${x.id}` === markerId);
1352
+ if (!m)
1353
+ return;
1354
+ try {
1355
+ this.bridgeInstance.removeViewAnnotationForMarker(markerId);
1356
+ }
1357
+ catch (e) {
1358
+ console.error(e, e.stack);
1359
+ }
1360
+ // const cv = this._calloutViews[m.id];
1361
+ // if (cv) {
1362
+ // cv.off('tap');
1363
+ // delete this._calloutViews[m.id];
1364
+ // }
1365
+ }
1366
+ toggleCalloutForMarkerById(markerId) {
1367
+ const m = this._markers.find((x) => `${x.id}` === markerId);
1368
+ if (!m || !m.id)
1369
+ return;
1370
+ const exists = this.bridgeInstance.hasViewAnnotationForMarker(markerId);
1371
+ if (exists)
1372
+ this.hideCalloutForMarkerById(markerId);
1373
+ else
1374
+ this.showCalloutForMarkerById(markerId);
1375
+ }
1376
+ onNativeAnnotationTap(userInfo) {
1377
+ if (Trace.isEnabled()) {
1378
+ CLog(CLogTypes.info, 'onNativeAnnotationTap:', JSON.stringify(userInfo));
1379
+ }
1380
+ const markerId = userInfo.id;
1381
+ if (!markerId)
1382
+ return;
1383
+ const marker = this._markers.find((m) => `${m.id}` === markerId);
1384
+ if (!marker)
1385
+ return;
1386
+ if (marker === this.selectedMarker) {
1387
+ this.deselectMarker(marker);
1797
1388
  }
1798
1389
  else {
1799
- return Promise.reject('No map has been loaded');
1390
+ this.selectMarker(marker);
1800
1391
  }
1801
1392
  }
1802
- getViewport(nativeMap) {
1393
+ addNotificationCenterObserver(event, map, callback) {
1394
+ this.pushToken(NSNotificationCenter.defaultCenter.addObserverForNameObjectQueueUsingBlock(event, map, NSOperationQueue.mainQueue, (notification) => {
1395
+ callback(convertToJSON(notification.userInfo));
1396
+ }));
1397
+ }
1398
+ setOnEventChangeListener(event, listener, nativeMap) {
1803
1399
  return new Promise((resolve, reject) => {
1804
1400
  try {
1805
- const theMap = nativeMap || this._mapboxViewInstance;
1806
- if (!theMap) {
1401
+ const map = nativeMap || this._mapboxViewInstance;
1402
+ if (!map) {
1807
1403
  reject('No map has been loaded');
1808
1404
  return;
1809
1405
  }
1810
- const visibleBounds = theMap.visibleCoordinateBounds;
1811
- const bounds = {
1812
- north: visibleBounds.ne.latitude,
1813
- east: visibleBounds.ne.longitude,
1814
- south: visibleBounds.sw.latitude,
1815
- west: visibleBounds.sw.longitude
1816
- };
1817
- resolve({
1818
- bounds,
1819
- zoomLevel: theMap.zoomLevel
1820
- });
1406
+ this.addNotificationCenterObserver(event, map, listener);
1407
+ resolve();
1821
1408
  }
1822
1409
  catch (ex) {
1823
- if (Trace.isEnabled()) {
1824
- CLog(CLogTypes.info, 'Error in mapbox.getViewport: ' + ex);
1825
- }
1826
1410
  reject(ex);
1827
1411
  }
1828
1412
  });
1829
1413
  }
1830
- setViewport(options, nativeMap) {
1414
+ setOnCameraChangeListener(listener, nativeMap) {
1415
+ return this.setOnEventChangeListener(MAPBOX_BRIDGE_CAMERA_CHANGED, listener, nativeMap);
1416
+ }
1417
+ setOnMapClickListener(listener, nativeMap) {
1418
+ return this.setOnEventChangeListener(MAPBOX_BRIDGE_MAP_CLICK, listener, nativeMap);
1419
+ }
1420
+ setOnMapLongClickListener(listener, nativeMap) {
1421
+ return this.setOnEventChangeListener(MAPBOX_BRIDGE_MAP_LONGPRESS, listener, nativeMap);
1422
+ }
1423
+ setOnScrollListener(listener, nativeMap) {
1424
+ return this.setOnEventChangeListener(MAPBOX_BRIDGE_MAP_SCROLL, listener, nativeMap);
1425
+ }
1426
+ setOnMoveBeginListener(listener, nativeMap) {
1427
+ return this.setOnEventChangeListener(MAPBOX_BRIDGE_MAP_MOVE_BEGIN, listener, nativeMap);
1428
+ }
1429
+ setOnMoveEndListener(listener, nativeMap) {
1430
+ return this.setOnEventChangeListener(MAPBOX_BRIDGE_MAP_MOVE_END, listener, nativeMap);
1431
+ }
1432
+ setOnFlingListener(listener, nativeMap) {
1433
+ return this.setOnEventChangeListener(MAPBOX_BRIDGE_MAP_FLING, listener, nativeMap);
1434
+ }
1435
+ setOnCameraMoveCancelListener(listener, nativeMap) {
1436
+ return this.setOnEventChangeListener(MAPBOX_BRIDGE_CAMERA_MOVE_CANCEL, listener, nativeMap);
1437
+ }
1438
+ setOnMapIdleListener(listener, nativeMap) {
1439
+ return this.setOnEventChangeListener(MAPBOX_BRIDGE_CAMERA_IDLE, listener, nativeMap);
1440
+ }
1441
+ // ---------------- Offline helpers ----------------
1442
+ downloadOfflineRegion(options, nativeMap) {
1831
1443
  return new Promise((resolve, reject) => {
1832
1444
  try {
1833
- const theMap = nativeMap || this._mapboxViewInstance;
1834
- if (!theMap) {
1835
- reject('No map has been loaded');
1445
+ const b = nativeMap ? MapboxBridge.bridgeFor(nativeMap) : this.bridgeInstance;
1446
+ if (!b) {
1447
+ reject('No bridge available');
1836
1448
  return;
1837
1449
  }
1838
- const bounds = {
1839
- sw: CLLocationCoordinate2DMake(options.bounds.south, options.bounds.west),
1840
- ne: CLLocationCoordinate2DMake(options.bounds.north, options.bounds.east)
1450
+ const progressCb = (info) => {
1451
+ options.onProgress?.(JSON.parse(info));
1841
1452
  };
1842
- const animated = options.animated === undefined || options.animated;
1843
- // define default padding
1844
- const defaultPadding = 25;
1845
- // check if padding is defined and whether it's an object or a single value
1846
- const padding = options.padding !== undefined
1847
- ? typeof options.padding === 'object'
1848
- ? {
1849
- top: options.padding.top ?? 0,
1850
- left: options.padding.left ?? 0,
1851
- bottom: options.padding.bottom ?? 0,
1852
- right: options.padding.right ?? 0
1853
- }
1854
- : {
1855
- top: options.padding,
1856
- left: options.padding,
1857
- bottom: options.padding,
1858
- right: options.padding
1859
- }
1860
- : {
1861
- top: defaultPadding,
1862
- left: defaultPadding,
1863
- bottom: defaultPadding,
1864
- right: defaultPadding
1865
- };
1866
- theMap.setVisibleCoordinateBoundsEdgePaddingAnimated(bounds, padding, animated);
1867
- resolve();
1453
+ b.downloadOfflineRegion(JSON.stringify(options), progressCb, (success, error) => {
1454
+ if (success)
1455
+ resolve();
1456
+ else {
1457
+ const msg = error && error.localizedDescription ? error.localizedDescription : error || 'Failed to download offline region';
1458
+ reject(msg);
1459
+ }
1460
+ });
1868
1461
  }
1869
1462
  catch (ex) {
1870
- if (Trace.isEnabled()) {
1871
- CLog(CLogTypes.info, 'Error in mapbox.setViewport: ' + ex);
1872
- }
1873
1463
  reject(ex);
1874
1464
  }
1875
1465
  });
1876
1466
  }
1877
- downloadOfflineRegion(options) {
1467
+ listOfflineRegions(options, nativeMap) {
1878
1468
  return new Promise((resolve, reject) => {
1879
1469
  try {
1880
- const styleURL = _getMapStyle(options.style);
1881
- const swCoordinate = CLLocationCoordinate2DMake(options.bounds.south, options.bounds.west);
1882
- const neCoordinate = CLLocationCoordinate2DMake(options.bounds.north, options.bounds.east);
1883
- const bounds = {
1884
- sw: swCoordinate,
1885
- ne: neCoordinate
1886
- };
1887
- const region = MGLTilePyramidOfflineRegion.alloc().initWithStyleURLBoundsFromZoomLevelToZoomLevel(styleURL, bounds, options.minZoom, options.maxZoom);
1888
- if (options.accessToken) {
1889
- MGLAccountManager.accessToken = options.accessToken;
1890
- }
1891
- // TODO there's more observers, see https://www.mapbox.com/ios-sdk/examples/offline-pack/
1892
- if (options.onProgress) {
1893
- _addObserver(MGLOfflinePackProgressChangedNotification, (notification) => {
1894
- const offlinePack = notification.object;
1895
- const offlinePackProgress = offlinePack.progress;
1896
- const userInfo = NSKeyedUnarchiver.unarchiveObjectWithData(offlinePack.context);
1897
- const complete = offlinePackProgress.countOfResourcesCompleted === offlinePackProgress.countOfResourcesExpected;
1898
- options.onProgress({
1899
- name: userInfo.objectForKey('name'),
1900
- completed: offlinePackProgress.countOfResourcesCompleted,
1901
- expected: offlinePackProgress.countOfResourcesExpected,
1902
- percentage: Math.round((offlinePackProgress.countOfResourcesCompleted / offlinePackProgress.countOfResourcesExpected) * 10000) / 100,
1903
- complete
1904
- });
1905
- if (complete) {
1906
- resolve();
1907
- }
1908
- });
1470
+ const b = nativeMap ? MapboxBridge.bridgeFor(nativeMap) : this.bridgeInstance;
1471
+ if (!b) {
1472
+ reject('No bridge available');
1473
+ return;
1909
1474
  }
1910
- _addObserver(MGLOfflinePackErrorNotification, (notification) => {
1911
- const offlinePack = notification.object;
1912
- const userInfo = NSKeyedUnarchiver.unarchiveObjectWithData(offlinePack.context);
1913
- const error = notification.userInfo[MGLOfflinePackUserInfoKeyError];
1914
- reject({
1915
- name: userInfo.objectForKey('name'),
1916
- error: 'Download error. ' + error
1917
- });
1918
- });
1919
- _addObserver(MGLOfflinePackMaximumMapboxTilesReachedNotification, (notification) => {
1920
- const offlinePack = notification.object;
1921
- const userInfo = NSKeyedUnarchiver.unarchiveObjectWithData(offlinePack.context);
1922
- const maximumCount = notification.userInfo[MGLOfflinePackUserInfoKeyMaximumCount];
1923
- console.log(`Offline region '${userInfo.objectForKey('name')}' reached the tile limit of ${maximumCount}`);
1924
- });
1925
- // Store some data for identification purposes alongside the downloaded resources.
1926
- const userInfo = { name: options.name };
1927
- const context = NSKeyedArchiver.archivedDataWithRootObject(userInfo);
1928
- // Create and register an offline pack with the shared offline storage object.
1929
- MGLOfflineStorage.sharedOfflineStorage.addPackForRegionWithContextCompletionHandler(region, context, (pack, error) => {
1930
- if (error) {
1931
- // The pack couldn’t be created for some reason.
1932
- reject(error.localizedFailureReason);
1933
- }
1934
- else {
1935
- // Start downloading.
1936
- pack.resume();
1937
- }
1475
+ b.listOfflineRegions((res) => {
1476
+ resolve(JSON.parse(res));
1938
1477
  });
1939
1478
  }
1940
1479
  catch (ex) {
1941
- if (Trace.isEnabled()) {
1942
- CLog(CLogTypes.info, 'Error in mapbox.downloadOfflineRegion: ' + ex);
1943
- }
1944
1480
  reject(ex);
1945
1481
  }
1946
1482
  });
1947
1483
  }
1948
- listOfflineRegions(options) {
1484
+ deleteOfflineRegion(options, nativeMap) {
1949
1485
  return new Promise((resolve, reject) => {
1950
1486
  try {
1951
- const packs = MGLOfflineStorage.sharedOfflineStorage.packs;
1952
- if (!packs) {
1953
- reject('No packs found or Mapbox not ready yet');
1487
+ const b = nativeMap ? MapboxBridge.bridgeFor(nativeMap) : this.bridgeInstance;
1488
+ if (!b) {
1489
+ reject('No bridge available');
1954
1490
  return;
1955
1491
  }
1956
- const regions = [];
1957
- for (let i = 0; i < packs.count; i++) {
1958
- const pack = packs.objectAtIndex(i);
1959
- const region = pack.region;
1960
- const userInfo = NSKeyedUnarchiver.unarchiveObjectWithData(pack.context);
1961
- regions.push({
1962
- name: userInfo.objectForKey('name'),
1963
- style: '' + region.styleURL,
1964
- minZoom: region.minimumZoomLevel,
1965
- maxZoom: region.maximumZoomLevel,
1966
- bounds: {
1967
- north: region.bounds.ne.latitude,
1968
- east: region.bounds.ne.longitude,
1969
- south: region.bounds.sw.latitude,
1970
- west: region.bounds.sw.longitude
1971
- }
1972
- });
1492
+ const idOrName = options.id || options.name;
1493
+ if (!idOrName) {
1494
+ reject("Pass in the 'id' or 'name' param");
1495
+ return;
1973
1496
  }
1974
- resolve(regions);
1497
+ b.deleteOfflineRegion(idOrName);
1498
+ resolve();
1975
1499
  }
1976
1500
  catch (ex) {
1977
- if (Trace.isEnabled()) {
1978
- CLog(CLogTypes.info, 'Error in mapbox.listOfflineRegions: ' + ex);
1979
- }
1980
1501
  reject(ex);
1981
1502
  }
1982
1503
  });
1983
1504
  }
1984
- deleteOfflineRegion(options) {
1505
+ // ---------------- User location & tilt ----------------
1506
+ showUserLocationMarker(show) {
1985
1507
  return new Promise((resolve, reject) => {
1986
1508
  try {
1987
- if (!options || (!options.id && !options.name)) {
1988
- reject("Pass in the 'id' or 'name' param");
1509
+ const b = this.bridgeInstance;
1510
+ if (!b) {
1511
+ reject('No bridge available');
1989
1512
  return;
1990
1513
  }
1991
- const packs = MGLOfflineStorage.sharedOfflineStorage.packs;
1992
- let found = false;
1993
- for (let i = 0; i < packs.count; i++) {
1994
- const pack = packs.objectAtIndex(i);
1995
- const userInfo = NSKeyedUnarchiver.unarchiveObjectWithData(pack.context);
1996
- const regionId = options.id ? userInfo.objectForKey('id') : userInfo.objectForKey('name');
1997
- if (regionId === (options.id || options.name)) {
1998
- found = true;
1999
- MGLOfflineStorage.sharedOfflineStorage.removePackWithCompletionHandler(pack, (error) => {
2000
- if (error) {
2001
- // The pack couldn’t be deleted for some reason.
2002
- reject(error.localizedFailureReason);
2003
- }
2004
- else {
2005
- resolve();
2006
- // don't return, see note below
2007
- }
2008
- });
2009
- // don't break the loop as there may be multiple packs with the same name
2010
- }
2011
- }
2012
- if (!found) {
2013
- reject('Region not found');
2014
- }
1514
+ b.showUserLocationMarker(show);
1515
+ resolve();
2015
1516
  }
2016
1517
  catch (ex) {
2017
- if (Trace.isEnabled()) {
2018
- CLog(CLogTypes.info, 'Error in mapbox.deleteOfflineRegion: ' + ex);
2019
- }
2020
1518
  reject(ex);
2021
1519
  }
2022
1520
  });
2023
1521
  }
2024
- addExtrusion(options, nativeMap) {
1522
+ hideUserLocationMarker(nativeMap) {
2025
1523
  return new Promise((resolve, reject) => {
2026
1524
  try {
2027
- const theMap = nativeMap || this._mapboxViewInstance;
2028
- if (!theMap) {
2029
- reject('No map has been loaded');
1525
+ const b = nativeMap ? MapboxBridge.bridgeFor(nativeMap) : this.bridgeInstance;
1526
+ if (!b) {
1527
+ reject('No bridge available');
2030
1528
  return;
2031
1529
  }
1530
+ b.stopTrackingUser();
2032
1531
  resolve();
2033
1532
  }
2034
1533
  catch (ex) {
2035
- if (Trace.isEnabled()) {
2036
- CLog(CLogTypes.info, 'Error in mapbox.deleteOfflineRegion: ' + ex);
2037
- }
2038
1534
  reject(ex);
2039
1535
  }
2040
1536
  });
2041
1537
  }
2042
- /**
2043
- * update a geojson source
2044
- *
2045
- */
2046
- updateSource(id, options, nativeMap) {
1538
+ forceUserLocationUpdate(nativeMap) {
2047
1539
  return new Promise((resolve, reject) => {
2048
1540
  try {
2049
- const theMap = nativeMap || this._mapboxViewInstance;
2050
- if (!theMap) {
2051
- reject('No map has been loaded');
2052
- return;
2053
- }
2054
- const source = theMap.style.sourceWithIdentifier(id);
2055
- if (!source) {
2056
- reject('Source does not exists: ' + id);
1541
+ const b = nativeMap ? MapboxBridge.bridgeFor(nativeMap) : this.bridgeInstance;
1542
+ if (!b) {
1543
+ reject('No bridge available');
2057
1544
  return;
2058
1545
  }
2059
- switch (options.type) {
2060
- case 'geojson':
2061
- const content = NSString.stringWithString(JSON.stringify(options.data));
2062
- const nsData = content.dataUsingEncoding(NSUTF8StringEncoding);
2063
- const geoJsonShape = MGLShape.shapeWithDataEncodingError(nsData, NSUTF8StringEncoding);
2064
- source.shape = geoJsonShape;
2065
- resolve();
2066
- break;
2067
- default:
2068
- reject('Invalid source type: ' + options['type']);
2069
- return;
2070
- }
1546
+ const ok = b.forceUserLocationUpdate ? b.forceUserLocationUpdate() : false;
1547
+ resolve(!!ok);
2071
1548
  }
2072
1549
  catch (ex) {
2073
- if (Trace.isEnabled()) {
2074
- CLog(CLogTypes.info, 'Error in mapbox.addSource: ' + ex);
2075
- }
2076
1550
  reject(ex);
2077
1551
  }
2078
1552
  });
2079
1553
  }
2080
- /**
2081
- * add a vector or geojson source
2082
- *
2083
- * Add a source that can then be referenced in the style specification
2084
- * passed to addLayer().
2085
- *
2086
- * @link https://docs.mapbox.com/mapbox-gl-js/api/#map#addsource
2087
- */
2088
- addSource(id, options, nativeMap) {
1554
+ trackUser(options, nativeMap) {
2089
1555
  return new Promise((resolve, reject) => {
2090
1556
  try {
2091
- const theMap = nativeMap || this._mapboxViewInstance;
2092
- let source;
2093
- if (!theMap) {
2094
- reject('No map has been loaded');
1557
+ const b = nativeMap ? MapboxBridge.bridgeFor(nativeMap) : this.bridgeInstance;
1558
+ if (!b) {
1559
+ reject('No bridge available');
2095
1560
  return;
2096
1561
  }
2097
- if (theMap.style.sourceWithIdentifier(id)) {
2098
- reject('Source exists: ' + id);
2099
- return;
1562
+ if (Trace.isEnabled()) {
1563
+ CLog(CLogTypes.info, 'trackUser():', JSON.stringify(options));
2100
1564
  }
2101
- switch (options.type) {
2102
- case 'vector': {
2103
- if (options.url) {
2104
- source = MGLVectorTileSource.alloc().initWithIdentifierConfigurationURL(id, NSURL.URLWithString(options.url));
2105
- }
2106
- else {
2107
- const sourceOptions = {};
2108
- if (options.minzoom !== undefined) {
2109
- sourceOptions[MGLTileSourceOptionMinimumZoomLevel] = options.minzoom;
2110
- }
2111
- if (options.maxzoom !== undefined) {
2112
- sourceOptions[MGLTileSourceOptionMaximumZoomLevel] = options.maxzoom;
2113
- }
2114
- if (options.scheme) {
2115
- switch (options.scheme) {
2116
- case 'xyz':
2117
- sourceOptions[MGLTileSourceOptionTileCoordinateSystem] = 0 /* MGLTileCoordinateSystem.XYZ */;
2118
- break;
2119
- case 'tms':
2120
- sourceOptions[MGLTileSourceOptionTileCoordinateSystem] = 1 /* MGLTileCoordinateSystem.TMS */;
2121
- break;
2122
- default:
2123
- throw new Error('Unknown raster tile scheme.');
2124
- }
2125
- }
2126
- if (options.bounds) {
2127
- sourceOptions[MGLTileSourceOptionCoordinateBounds] = NSValue.valueWithMGLCoordinateBounds({
2128
- sw: CLLocationCoordinate2DMake(options.bounds[1], options.bounds[0]),
2129
- ne: CLLocationCoordinate2DMake(options.bounds[3], options.bounds[2])
2130
- });
2131
- }
2132
- source = MGLVectorTileSource.alloc().initWithIdentifierTileURLTemplatesOptions(id, options.tiles, sourceOptions);
2133
- }
2134
- break;
2135
- }
2136
- case 'geojson':
2137
- if (theMap.style.sourceWithIdentifier(id)) {
2138
- reject("Remove the layer with this id first with 'removeLayer': " + id);
2139
- return;
2140
- }
2141
- let geoJsonShape;
2142
- if (options.data) {
2143
- const content = NSString.stringWithString(JSON.stringify(options.data));
2144
- const nsData = content.dataUsingEncoding(NSUTF8StringEncoding);
2145
- geoJsonShape = MGLShape.shapeWithDataEncodingError(nsData, NSUTF8StringEncoding);
2146
- }
2147
- const sourceOptions = {};
2148
- if (options.minzoom !== undefined) {
2149
- sourceOptions[MGLShapeSourceOptionMinimumZoomLevel] = options.minzoom;
2150
- }
2151
- if (options.maxzoom !== undefined) {
2152
- sourceOptions[MGLShapeSourceOptionMaximumZoomLevel] = options.maxzoom;
2153
- }
2154
- if (options.lineMetrics !== undefined) {
2155
- sourceOptions[MGLShapeSourceOptionLineDistanceMetrics] = options.lineMetrics;
2156
- }
2157
- if (options.cluster) {
2158
- sourceOptions[MGLShapeSourceOptionClustered] = true;
2159
- sourceOptions[MGLShapeSourceOptionClusterRadius] = options.cluster.radius || 40;
2160
- sourceOptions[MGLShapeSourceOptionMaximumZoomLevelForClustering] = options.cluster.maxZoom || 13;
2161
- if (options.cluster.properties) {
2162
- const clusterProperties = {};
2163
- for (const property of Object.keys(options.cluster.properties)) {
2164
- // eslint-disable-next-line prefer-const
2165
- let [operator, operand] = options.cluster.properties[property];
2166
- if (!Array.isArray(operator)) {
2167
- operator = [operator];
2168
- }
2169
- const expressions = Utils.ios.collections.jsArrayToNSArray([ExpressionParser.parseJson(operator), ExpressionParser.parseJson(operand)]);
2170
- clusterProperties[property] = expressions;
2171
- }
2172
- sourceOptions[MGLShapeSourceOptionClusterProperties] = clusterProperties;
2173
- }
2174
- }
2175
- source = MGLShapeSource.alloc().initWithIdentifierShapeOptions(id, geoJsonShape, sourceOptions);
2176
- break;
2177
- case 'raster': {
2178
- const sourceOptions = {
2179
- [MGLTileSourceOptionTileSize]: options.tileSize || 256
2180
- };
2181
- if (options.minzoom !== undefined) {
2182
- sourceOptions[MGLTileSourceOptionMinimumZoomLevel] = options.minzoom;
2183
- }
2184
- if (options.maxzoom !== undefined) {
2185
- sourceOptions[MGLTileSourceOptionMaximumZoomLevel] = options.maxzoom;
2186
- }
2187
- if (options.scheme) {
2188
- switch (options.scheme || 'xyz') {
2189
- case 'xyz':
2190
- sourceOptions[MGLTileSourceOptionTileCoordinateSystem] = 0 /* MGLTileCoordinateSystem.XYZ */;
2191
- break;
2192
- case 'tms':
2193
- sourceOptions[MGLTileSourceOptionTileCoordinateSystem] = 1 /* MGLTileCoordinateSystem.TMS */;
2194
- break;
2195
- default:
2196
- throw new Error('Unknown raster tile scheme.');
2197
- }
2198
- }
2199
- if (options.bounds) {
2200
- sourceOptions[MGLTileSourceOptionCoordinateBounds] = NSValue.valueWithMGLCoordinateBounds({
2201
- sw: CLLocationCoordinate2DMake(options.bounds[1], options.bounds[0]),
2202
- ne: CLLocationCoordinate2DMake(options.bounds[3], options.bounds[2])
2203
- });
2204
- }
2205
- source = MGLRasterTileSource.alloc().initWithIdentifierTileURLTemplatesOptions(id, options.tiles, sourceOptions);
2206
- break;
2207
- }
2208
- default:
2209
- reject('Invalid source type: ' + options['type']);
2210
- return;
1565
+ const ok = b.trackUser(JSON.stringify(options));
1566
+ if (ok) {
1567
+ resolve();
2211
1568
  }
2212
- if (!source) {
2213
- const ex = 'No source to add';
2214
- if (Trace.isEnabled()) {
2215
- CLog(CLogTypes.info, 'Error in mapbox.addSource: ' + ex);
2216
- }
2217
- reject(ex);
2218
- return;
1569
+ else {
1570
+ reject();
2219
1571
  }
2220
- theMap.style.addSource(source);
2221
- resolve();
2222
1572
  }
2223
1573
  catch (ex) {
2224
- if (Trace.isEnabled()) {
2225
- CLog(CLogTypes.info, 'Error in mapbox.addSource: ' + ex);
2226
- }
2227
1574
  reject(ex);
2228
1575
  }
2229
1576
  });
2230
1577
  }
2231
- /**
2232
- * remove source by id
2233
- */
2234
- removeSource(id, nativeMap) {
1578
+ getTilt(nativeMap) {
2235
1579
  return new Promise((resolve, reject) => {
2236
1580
  try {
2237
- const theMap = nativeMap || this._mapboxViewInstance;
2238
- if (!theMap) {
2239
- reject('No map has been loaded');
1581
+ const b = nativeMap ? MapboxBridge.bridgeFor(nativeMap) : this.bridgeInstance;
1582
+ if (!b) {
1583
+ reject('No bridge available');
2240
1584
  return;
2241
1585
  }
2242
- const source = theMap.style.sourceWithIdentifier(id);
2243
- if (!source) {
2244
- reject('Source does not exist');
1586
+ resolve(b.getTilt());
1587
+ }
1588
+ catch (ex) {
1589
+ reject(ex);
1590
+ }
1591
+ });
1592
+ }
1593
+ setTilt(options, nativeMap) {
1594
+ return new Promise((resolve, reject) => {
1595
+ try {
1596
+ const b = nativeMap ? MapboxBridge.bridgeFor(nativeMap) : this.bridgeInstance;
1597
+ if (!b) {
1598
+ reject('No bridge available');
2245
1599
  return;
2246
1600
  }
2247
- theMap.style.removeSource(source);
1601
+ const animated = options.animated === undefined ? true : options.animated;
1602
+ b.setTilt(options.tilt, animated);
2248
1603
  resolve();
2249
1604
  }
2250
1605
  catch (ex) {
2251
- if (Trace.isEnabled()) {
2252
- CLog(CLogTypes.info, 'Error in mapbox.removeSource: ' + ex);
2253
- }
2254
1606
  reject(ex);
2255
1607
  }
2256
1608
  });
2257
1609
  }
2258
- /**
2259
- * a rough analogue to the mapbox-gl-js addLayer() method
2260
- *
2261
- * It would be nice if this {N} API matched the mapbox-gl-js API which
2262
- * would make it much easier to share mapping applications between the web
2263
- * and {N} apps.
2264
- *
2265
- * This method accepts a Mapbox-GL-JS style specification JSON object with some
2266
- * limitations:
2267
- *
2268
- * - the source: must be a GeoJSON object.
2269
- * - only a subset of paint properties are available.
2270
- *
2271
- * @param {object} style - a style following the Mapbox style specification.
2272
- * @param {any} nativeMapView - native map view (com.mapbox.mapboxsdk.maps.MapView)
2273
- *
2274
- * @link https://docs.mapbox.com/mapbox-gl-js/style-spec/#layers
2275
- */
2276
- async addLayer(style, belowLayerId, nativeMapView) {
2277
- const theMap = nativeMapView || this._mapboxViewInstance;
2278
- let source = null;
2279
- if (typeof style.source != 'string') {
2280
- await this.addSource(style.id + '_source', style.source);
2281
- source = theMap.style.sourceWithIdentifier(style.id + '_source');
2282
- }
2283
- else {
2284
- source = theMap.style.sourceWithIdentifier(style.source);
2285
- }
2286
- const layer = await LayerFactory.createLayer(style, source);
2287
- if (belowLayerId) {
2288
- const belowlayer = theMap.style.layerWithIdentifier(belowLayerId);
2289
- if (belowlayer) {
2290
- theMap.style.insertLayerBelowLayer(layer.getNativeInstance(), belowlayer);
2291
- return;
2292
- }
2293
- }
2294
- theMap.style.addLayer(layer.getNativeInstance());
2295
- }
2296
- /**
2297
- * remove layer by ID
2298
- *
2299
- * Removes a layer given a layer id
2300
- *
2301
- * @param {string} id
2302
- */
2303
- async removeLayer(id, nativeMapViewInstance) {
2304
- const theMap = nativeMapViewInstance || this._mapboxViewInstance;
2305
- if (Trace.isEnabled()) {
2306
- CLog(CLogTypes.info, "Mapbox::removeLayer(): attempting to remove layer '" + id + "'");
2307
- }
2308
- const layer = theMap.style.layerWithIdentifier(id);
2309
- if (Trace.isEnabled()) {
2310
- CLog(CLogTypes.info, 'Mapbox:removeLayer(): got layer object: ', layer);
2311
- }
2312
- if (!layer) {
2313
- throw new Error("Layer '" + id + "' not found when attempting to remove it.");
2314
- }
2315
- theMap.style.removeLayer(layer);
2316
- if (Trace.isEnabled()) {
2317
- CLog(CLogTypes.info, 'Mapbox:removeLayer(): after removing layer ' + id);
2318
- }
2319
- }
2320
- /**
2321
- * @deprecated
2322
- * Add a point to a line
2323
- *
2324
- * This method appends a point to a line and is useful for drawing a users track.
2325
- *
2326
- * The process for adding a point to a line is different in the iOS sdk than in
2327
- * the Android java sdk.
2328
- *
2329
- * @param {id} id - id of line to add a point to.
2330
- * @param {array} lnglat - [lng,lat] to append to the line.
2331
- *
2332
- * @link https://github.com/mapbox/mapbox-gl-native/issues/13983
2333
- * @link https://docs.mapbox.com/ios/maps/examples/runtime-animate-line/
2334
- */
2335
- async addLinePoint(id, lnglat, sourceId, nativeMapView) {
2336
- const theMap = nativeMapView || this._mapboxViewInstance;
2337
- const sId = !!sourceId ? sourceId : id + '_source';
2338
- const lineSource = theMap.style.sourceWithIdentifier(sId);
2339
- if (!lineSource) {
2340
- throw new Error(`no source found with id: ${sId}`);
2341
- }
2342
- try {
2343
- const lineFeatures = lineSource.featuresMatchingPredicate(ExpressionParser.parseJson(['==', '$type', 'LineString']));
2344
- if (lineFeatures.count === 0) {
2345
- throw new Error('no line string feature found');
2346
- }
2347
- const lineFeature = lineFeatures.objectAtIndex(0);
2348
- const newCoord = CLLocationCoordinate2DMake(lnglat[1], lnglat[0]);
2349
- const newCoordPointer = new interop.Reference(newCoord);
2350
- lineFeature.appendCoordinatesCount(newCoordPointer, 1);
2351
- lineSource.shape = lineFeature;
2352
- }
2353
- catch (error) {
2354
- console.log(error);
2355
- throw error;
2356
- }
2357
- }
2358
- addGeoJsonClustered(options, nativeMapViewInstance) {
2359
- throw new Error('Method not implemented.');
2360
- // return new Promise((resolve, reject) => {
2361
- // const theMap: MGLMapView = nativeMapViewInstance || this._mapboxViewInstance;
2362
- // try {
2363
- // const source = MGLShapeSource.alloc().initWithIdentifierURLOptions(options.name, NSURL.URLWithString(options.data), null);
2364
- // theMap.style.addSource(source);
2365
- // const layers = [];
2366
- // if (options.clusters) {
2367
- // for (let i = 0; i < options.clusters.length; i++) {
2368
- // // TODO also allow Color object
2369
- // layers.push([options.clusters[i].points, new Color(options.clusters[i].color).ios]);
2370
- // }
2371
- // } else {
2372
- // layers.push([150, new Color('red').ios]);
2373
- // layers.push([20, new Color('green').ios]);
2374
- // layers.push([0, new Color('blue').ios]);
2375
- // }
2376
- // const unclustered = MGLCircleStyleLayer.alloc().initWithIdentifierSource(options.name, source);
2377
- // unclustered.circleColor = NSExpression.expressionWithFormatArgumentArray('%@', new Color('red').ios);
2378
- // unclustered.circleRadius = NSExpression.expressionWithFormatArgumentArray('16', null);
2379
- // unclustered.circleBlur = NSExpression.expressionWithFormatArgumentArray('0.2', null);
2380
- // // unclustered.setFilter(com.mapbox.mapboxsdk.style.expressions.Expression.neq(com.mapbox.mapboxsdk.style.expressions.Expression.get('cluster'), true));
2381
- // // theMap.style.addLayer(unclustered); // , "building");
2382
- // for (let i = 0; i < layers.length; i++) {
2383
- // // Add some nice circles
2384
- // const circles = MGLCircleStyleLayer.alloc().initWithIdentifierSource(options.name, source);
2385
- // const circles = new com.mapbox.mapboxsdk.style.layers.CircleLayer('cluster-' + i, options.name);
2386
- // // circles.setProperties([
2387
- // // // com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconImage("icon")
2388
- // // com.mapbox.mapboxsdk.style.layers.PropertyFactory.circleColor(layers[i][1]),
2389
- // // com.mapbox.mapboxsdk.style.layers.PropertyFactory.circleRadius(new java.lang.Float(22.0)),
2390
- // // com.mapbox.mapboxsdk.style.layers.PropertyFactory.circleBlur(new java.lang.Float(0.2)),
2391
- // // ]);
2392
- // // const pointCount = com.mapbox.mapboxsdk.style.expressions.Expression.toNumber(com.mapbox.mapboxsdk.style.expressions.Expression.get('point_count'));
2393
- // // if (i === 0) {
2394
- // // circles.setFilter(
2395
- // // com.mapbox.mapboxsdk.style.expressions.Expression.gte(pointCount, com.mapbox.mapboxsdk.style.expressions.Expression.literal(java.lang.Integer.valueOf(layers[i][0])))
2396
- // // );
2397
- // // } else {
2398
- // // circles.setFilter(
2399
- // // com.mapbox.mapboxsdk.style.expressions.Expression.all([
2400
- // // com.mapbox.mapboxsdk.style.expressions.Expression.gte(pointCount, com.mapbox.mapboxsdk.style.expressions.Expression.literal(java.lang.Integer.valueOf(layers[i][0]))),
2401
- // // com.mapbox.mapboxsdk.style.expressions.Expression.lt(
2402
- // // pointCount,
2403
- // // com.mapbox.mapboxsdk.style.expressions.Expression.literal(java.lang.Integer.valueOf(layers[i - 1][0]))
2404
- // // ),
2405
- // // ])
2406
- // // );
2407
- // // }
2408
- // // this._mapboxMapInstance.getStyle().addLayer(circles); // , "building");
2409
- // }
2410
- // // // Add the count labels (note that this doesn't show.. #sad)
2411
- // // const count = new com.mapbox.mapboxsdk.style.layers.SymbolLayer('count', options.name);
2412
- // // count.setProperties([
2413
- // // com.mapbox.mapboxsdk.style.layers.PropertyFactory.textField(com.mapbox.mapboxsdk.style.expressions.Expression.get('point_count')),
2414
- // // com.mapbox.mapboxsdk.style.layers.PropertyFactory.textSize(new java.lang.Float(12.0)),
2415
- // // com.mapbox.mapboxsdk.style.layers.PropertyFactory.textColor(new Color('white').android),
2416
- // // ]);
2417
- // // this._mapboxMapInstance.getStyle().addLayer(count);
2418
- // resolve();
2419
- // } catch (ex) {
2420
- // if (Trace.isEnabled()) {
2421
- // CLog(CLogTypes.info, 'Error in mapbox.addGeoJsonClustered: ' + ex);
2422
- // }
2423
- // reject(ex);
2424
- // }
2425
- // });
2426
- }
2427
- trackUser(options, nativeMap) {
1610
+ getUserLocation(nativeMap) {
2428
1611
  return new Promise((resolve, reject) => {
2429
1612
  try {
2430
- const theMap = nativeMap || this._mapboxViewInstance;
2431
- if (!theMap) {
2432
- reject('No map has been loaded');
1613
+ const b = nativeMap ? MapboxBridge.bridgeFor(nativeMap) : this.bridgeInstance;
1614
+ if (!b) {
1615
+ reject('No bridge available');
2433
1616
  return;
2434
1617
  }
2435
- if (!theMap.showsUserLocation) {
2436
- reject('The map is not currently showing the user location');
1618
+ const loc = b.getUserLocation();
1619
+ if (!loc) {
1620
+ reject('No user location');
2437
1621
  return;
2438
1622
  }
2439
- theMap.setUserTrackingModeAnimated(this._stringToCameraMode(options.cameraMode), options.animated !== false);
2440
- resolve();
1623
+ resolve(JSON.parse(loc));
2441
1624
  }
2442
1625
  catch (ex) {
2443
- if (Trace.isEnabled()) {
2444
- CLog(CLogTypes.info, 'Error in mapbox.trackUser: ' + ex);
2445
- }
2446
1626
  reject(ex);
2447
1627
  }
2448
1628
  });
2449
1629
  }
2450
- getLayer(name, nativeMap) {
1630
+ // ---------------- Viewport ----------------
1631
+ setViewport(options, nativeMap) {
2451
1632
  return new Promise((resolve, reject) => {
2452
1633
  try {
2453
- const theMap = nativeMap || this._mapboxViewInstance;
2454
- if (!theMap) {
2455
- reject('No map has been loaded');
1634
+ const b = nativeMap ? MapboxBridge.bridgeFor(nativeMap) : this.bridgeInstance;
1635
+ if (!b || !b.setViewport) {
1636
+ reject('No bridge available');
2456
1637
  return;
2457
1638
  }
2458
- const layer = theMap.style.layerWithIdentifier(name);
2459
- resolve(layer ? new Layer(layer) : null);
1639
+ const payload = typeof options === 'string' ? options : JSON.stringify(options);
1640
+ const ok = b.setViewport(payload);
1641
+ resolve(!!ok);
2460
1642
  }
2461
1643
  catch (ex) {
2462
- if (Trace.isEnabled()) {
2463
- CLog(CLogTypes.info, 'Error in mapbox.getLayer: ' + ex);
2464
- }
2465
1644
  reject(ex);
2466
1645
  }
2467
1646
  });
2468
1647
  }
2469
- getLayers(nativeMap) {
1648
+ getViewport(nativeMap) {
2470
1649
  return new Promise((resolve, reject) => {
2471
1650
  try {
2472
- const theMap = nativeMap || this._mapboxViewInstance;
2473
- if (!theMap) {
2474
- reject('No map has been loaded');
1651
+ const b = nativeMap ? MapboxBridge.bridgeFor(nativeMap) : this.bridgeInstance;
1652
+ if (!b || !b.getViewport) {
1653
+ resolve(null);
2475
1654
  return;
2476
1655
  }
2477
- const layers = theMap.style.layers;
2478
- const result = [];
2479
- for (let i = 0; i < layers.count; i++) {
2480
- result.push(new Layer(layers[i]));
1656
+ const vp = b.getViewport();
1657
+ if (!vp) {
1658
+ reject('viewport could not be determined');
1659
+ return;
2481
1660
  }
2482
- resolve(result);
1661
+ resolve(JSON.parse(vp));
2483
1662
  }
2484
1663
  catch (ex) {
2485
- if (Trace.isEnabled()) {
2486
- CLog(CLogTypes.info, 'Error in mapbox.getLayers: ' + ex);
2487
- }
2488
1664
  reject(ex);
2489
1665
  }
2490
1666
  });
2491
1667
  }
2492
- project(data) {
2493
- const theMap = this._mapboxViewInstance;
2494
- const { x, y } = theMap.convertCoordinateToPointToView({ latitude: data.lat, longitude: data.lng }, theMap);
2495
- return { x, y };
2496
- }
2497
- projectBack(screenCoordinate) {
2498
- const theMap = this._mapboxViewInstance;
2499
- const cgPoint = {
2500
- x: screenCoordinate.x,
2501
- y: screenCoordinate.y
2502
- };
2503
- const coordinate = theMap.convertPointToCoordinateFromView(cgPoint, theMap);
2504
- return {
2505
- lat: coordinate.latitude,
2506
- lng: coordinate.longitude
2507
- };
2508
- }
2509
- getUserLocationCameraMode(nativeMap) {
2510
- const theMap = nativeMap || this._mapboxViewInstance;
2511
- if (!theMap) {
2512
- return 'NONE';
1668
+ // ---------------- Project helpers ----------------
1669
+ project(data, nativeMap) {
1670
+ const b = nativeMap ? MapboxBridge.bridgeFor(nativeMap) : this.bridgeInstance;
1671
+ if (!b)
1672
+ return { x: 0, y: 0 };
1673
+ try {
1674
+ if (Trace.isEnabled()) {
1675
+ CLog(CLogTypes.info, 'project:', JSON.stringify(data));
1676
+ }
1677
+ const pt = b.coordinateToPoint(data.lat, data.lng);
1678
+ return JSON.parse(pt);
2513
1679
  }
2514
- return this._convertCameraMode(theMap.userTrackingMode);
2515
- }
2516
- }
2517
- const _addObserver = (eventName, callback) => NSNotificationCenter.defaultCenter.addObserverForNameObjectQueueUsingBlock(eventName, null, NSOperationQueue.mainQueue, callback);
2518
- function _downloadImage(marker) {
2519
- return new Promise((resolve, reject) => {
2520
- if (Trace.isEnabled()) {
2521
- CLog(CLogTypes.info, '>> _downloadImage');
1680
+ catch (e) {
1681
+ return { x: 0, y: 0 };
2522
1682
  }
2523
- // to cache..
2524
- if (_markerIconDownloadCache[marker.icon]) {
2525
- marker.iconDownloaded = _markerIconDownloadCache[marker.icon];
1683
+ }
1684
+ projectBack(screenCoordinate, nativeMap) {
1685
+ const b = nativeMap ? MapboxBridge.bridgeFor(nativeMap) : this.bridgeInstance;
1686
+ if (!b)
1687
+ return { lat: 0, lng: 0 };
1688
+ try {
2526
1689
  if (Trace.isEnabled()) {
2527
- CLog(CLogTypes.info, '>> marker.iconDownloaded: ' + marker.iconDownloaded);
1690
+ CLog(CLogTypes.info, 'projectBack:', JSON.stringify(screenCoordinate));
2528
1691
  }
2529
- resolve(marker);
2530
- return;
1692
+ const coord = b.pointToCoordinate(screenCoordinate.x, screenCoordinate.y);
1693
+ return JSON.parse(coord);
2531
1694
  }
2532
- // ..or not to cache
2533
- Http.getImage(marker.icon).then((output) => {
2534
- marker.iconDownloaded = output.ios;
2535
- _markerIconDownloadCache[marker.icon] = marker.iconDownloaded;
2536
- resolve(marker);
2537
- }, (ignoredError) => {
2538
- console.log(`Download failed for ${marker.icon} with error: ${ignoredError}`);
2539
- resolve(marker);
2540
- });
2541
- });
2542
- }
2543
- const _downloadMarkerImages = (markers) => {
2544
- const iterations = [];
2545
- const result = [];
2546
- markers.forEach((marker) => {
2547
- if (marker.icon && marker.icon.startsWith('http')) {
2548
- const p = _downloadImage(marker).then((mark) => result.push(mark));
2549
- iterations.push(p);
2550
- }
2551
- else {
2552
- result.push(marker);
1695
+ catch (e) {
1696
+ return { lat: 0, lng: 0 };
2553
1697
  }
2554
- });
2555
- return Promise.all(iterations).then(() => result);
2556
- };
1698
+ }
1699
+ // ---------------- Lifecycle stubs ----------------
1700
+ onStart(nativeMap) {
1701
+ return Promise.resolve();
1702
+ }
1703
+ onResume(nativeMap) {
1704
+ return Promise.resolve();
1705
+ }
1706
+ onPause(nativeMap) {
1707
+ return Promise.resolve();
1708
+ }
1709
+ onStop(nativeMap) {
1710
+ return Promise.resolve();
1711
+ }
1712
+ onLowMemory(nativeMap) {
1713
+ return Promise.resolve();
1714
+ }
1715
+ onDestroy(nativeMap) {
1716
+ return Promise.resolve();
1717
+ }
1718
+ }
2557
1719
  //# sourceMappingURL=index.ios.js.map