@nativescript-community/ui-mapbox 6.2.8 → 6.2.12

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.
@@ -1,1227 +1,1289 @@
1
- import { Color, File, ImageSource, Trace, knownFolders, path } from '@nativescript/core';
2
- import { CLog, CLogTypes, MapStyle, MapboxCommon, MapboxTraceCategory, MapboxViewBase, telemetryProperty } from './mapbox.common';
3
- import { iOSNativeHelper } from '@nativescript/core/utils';
4
- import { getImage } from '@nativescript/core/http';
5
- import { LayerFactory } from './layers/layer-factory';
6
- import { FilterParser } from './filter/filter-parser.ios';
7
- export { MapboxTraceCategory, MapStyle };
8
- let _markers = [];
9
- const _markerIconDownloadCache = [];
10
- const _setMapboxMapOptions = (mapView, settings) => {
11
- mapView.logoView.hidden = settings.hideLogo;
12
- mapView.attributionButton.hidden = settings.hideAttribution;
13
- mapView.compassView.hidden = settings.hideCompass;
14
- mapView.rotateEnabled = !settings.disableRotation;
15
- mapView.scrollEnabled = !settings.disableScroll;
16
- mapView.zoomEnabled = !settings.disableZoom;
17
- mapView.allowsTilting = !settings.disableTilt;
18
- if (settings.center && settings.center.lat && settings.center.lng) {
19
- const centerCoordinate = CLLocationCoordinate2DMake(settings.center.lat, settings.center.lng);
20
- mapView.setCenterCoordinateZoomLevelAnimated(centerCoordinate, settings.zoomLevel, false);
21
- }
22
- else {
23
- mapView.setZoomLevelAnimated(settings.zoomLevel, false);
24
- }
25
- mapView.showsUserLocation = settings.showUserLocation;
26
- mapView.autoresizingMask = 2 | 16;
27
- };
28
- const _getMapStyle = (input) => {
29
- if (input.startsWith('mapbox://styles') || input.startsWith('http://') || input.startsWith('https://')) {
30
- return NSURL.URLWithString(input);
31
- }
32
- else if (input.startsWith('~/')) {
33
- return NSURL.URLWithString('file://' + path.join(knownFolders.currentApp().path, input.replace('~/', '')));
34
- }
35
- else if (input === MapStyle.LIGHT) {
36
- return MGLStyle.lightStyleURL;
37
- }
38
- else if (input === MapStyle.DARK) {
39
- return MGLStyle.darkStyleURL;
40
- }
41
- else if (input === MapStyle.OUTDOORS) {
42
- return MGLStyle.outdoorsStyleURL;
43
- }
44
- else if (input === MapStyle.SATELLITE) {
45
- return MGLStyle.satelliteStyleURL;
46
- }
47
- else if (input === MapStyle.SATELLITE_STREETS) {
48
- return MGLStyle.satelliteStreetsStyleURL;
49
- }
50
- else if (input === MapStyle.TRAFFIC_DAY) {
51
- return NSURL.URLWithString('mapbox://styles/mapbox/traffic-day-v2');
52
- }
53
- else if (input === MapStyle.TRAFFIC_NIGHT) {
54
- return NSURL.URLWithString('mapbox://styles/mapbox/traffic-night-v2');
55
- }
56
- else {
57
- return MGLStyle.streetsStyleURL;
58
- }
59
- };
60
- function _getTrackingMode(input) {
61
- return 0;
62
- }
63
- function _getLocation(loc) {
64
- if (loc === null) {
65
- return null;
66
- }
67
- else {
68
- return {
69
- location: {
70
- lat: loc.coordinate.latitude,
71
- lng: loc.coordinate.longitude
72
- },
73
- speed: loc.location ? loc.location.speed : 0
74
- };
75
- }
76
- }
77
- export function setLogLevel(level) {
78
- let loggingLevel;
79
- switch (level) {
80
- case 'none':
81
- loggingLevel = 0;
82
- break;
83
- case 'info':
84
- loggingLevel = 1;
85
- break;
86
- case 'verbose':
87
- case 'debug':
88
- loggingLevel = 2;
89
- break;
90
- case 'error':
91
- loggingLevel = 3;
92
- break;
93
- case 'fault':
94
- loggingLevel = 4;
95
- break;
96
- }
97
- MGLLoggingConfiguration.sharedConfiguration.loggingLevel = loggingLevel;
98
- }
99
- export class MapboxView extends MapboxViewBase {
100
- constructor() {
101
- super(...arguments);
102
- this.nativeMapView = null;
103
- this.delegate = null;
104
- this.settings = null;
105
- this.initialized = false;
106
- this.initCountHack = 50;
1
+ import { Color, File, Http, ImageSource, Trace, Utils, knownFolders, path } from '@nativescript/core';
2
+ import { CLog, CLogTypes, MapStyle, MapboxCommon, MapboxViewBase, telemetryProperty } from './common';
3
+ import { Layer, LayerFactory } from './layers/layer-factory';
4
+ import { FilterParser } from './filter/filter-parser';
5
+ var MGLMapViewDelegateImpl = /** @class */ (function (_super) {
6
+ __extends(MGLMapViewDelegateImpl, _super);
7
+ function MGLMapViewDelegateImpl() {
8
+ return _super !== null && _super.apply(this, arguments) || this;
107
9
  }
108
- setConfig(settings) {
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) {
109
17
  if (Trace.isEnabled()) {
110
- CLog(CLogTypes.info, 'setConfig(): settings:', settings);
18
+ CLog(CLogTypes.info, 'MGLMapViewDelegateImpl::initWithCallback()');
111
19
  }
112
- this.settings = settings;
113
- }
114
- getNativeMapView() {
115
- return this.nativeMapView;
116
- }
117
- createNativeView() {
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
+ this.userLocationAnnotationView.changeUserLocationRenderMode(userLocationRenderMode);
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) {
118
76
  if (Trace.isEnabled()) {
119
- CLog(CLogTypes.info, 'createNativeView(): top');
77
+ CLog(CLogTypes.info, 'MGLMapViewDelegateImpl:mapViewDidFinishLoadingMap(): top');
120
78
  }
121
- const v = super.createNativeView();
122
- return v;
123
- }
124
- onLoaded() {
125
- super.onLoaded();
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) {
126
86
  if (Trace.isEnabled()) {
127
- CLog(CLogTypes.info, 'initNativeView(): on - loaded');
87
+ CLog(CLogTypes.info, 'MGLMapViewDelegateImpl:mapViewDidFinishRenderingMapFullyRendered(): rendered is:', fullyRendered);
128
88
  }
129
- if (this.telemetry === false) {
130
- NSUserDefaults.standardUserDefaults.setBoolForKey(false, 'MGLMapboxMetricsEnabled');
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.');
131
102
  }
132
- if (!this.initialized) {
133
- this.initMap();
134
- this.initialized = true;
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;
135
107
  }
136
- }
137
- initNativeView() {
138
- super.initNativeView();
139
- this.nativeView.owner = this;
140
- }
141
- async disposeNativeView() {
142
- if (Trace.isEnabled()) {
143
- CLog(CLogTypes.info, 'disposeNativeView(): top');
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;
144
119
  }
145
- this.nativeView.owner = null;
146
- await this.mapbox.destroy();
147
- if (Trace.isEnabled()) {
148
- CLog(CLogTypes.info, 'disposeNativeView(): after mapbox.destroy()');
120
+ else {
121
+ return true;
149
122
  }
150
- super.disposeNativeView();
123
+ };
124
+ MGLMapViewDelegateImpl.prototype.mapViewDidFailLoadingMapWithError = function (mapView, error) {
151
125
  if (Trace.isEnabled()) {
152
- CLog(CLogTypes.info, 'disposeNativeView(): bottom');
126
+ CLog(CLogTypes.info, 'mapViewDidFailLoadingMapWithError: ' + error);
153
127
  }
154
- }
155
- getMapboxApi() {
156
- return this.mapbox;
157
- }
158
- initMap() {
128
+ };
129
+ MGLMapViewDelegateImpl.prototype.mapViewDidChangeUserTrackingModeAnimated = function (mapView, mode, animated) {
159
130
  if (Trace.isEnabled()) {
160
- CLog(CLogTypes.info, 'initMap() top with settings:', this.settings);
131
+ CLog(CLogTypes.info, 'mapViewDidChangeUserTrackingModeAnimated: ' + mode);
161
132
  }
162
- if (!this.settings && !this.config.accessToken) {
163
- if (Trace.isEnabled()) {
164
- CLog(CLogTypes.info, 'initMap() no access token. Race condition on XML property evaluation?');
165
- }
166
- if (this.initCountHack > 50) {
167
- return;
168
- }
169
- setTimeout(() => {
170
- this.initMap();
171
- }, 50);
172
- this.initCountHack++;
173
- return;
174
- }
175
- if (!this.settings) {
176
- this.settings = Mapbox.merge(this.config, Mapbox.defaults);
177
- }
178
- else {
179
- this.settings = Mapbox.merge(this.settings, Mapbox.defaults);
180
- }
181
- if (!this.nativeMapView) {
182
- this.mapbox = new Mapbox(this);
183
- if (Trace.isEnabled()) {
184
- CLog(CLogTypes.info, 'initMap(): after new Mapbox()');
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
+ }
185
145
  }
186
- const drawMap = () => {
187
- MGLAccountManager.accessToken = this.settings.accessToken;
188
- this.nativeMapView = MGLMapView.alloc().initWithFrameStyleURL(CGRectMake(0, 0, this.nativeView.frame.size.width, this.nativeView.frame.size.height), _getMapStyle(this.settings.style));
189
- this.nativeMapView.delegate = this.delegate = MGLMapViewDelegateImpl.new().initWithCallback(() => {
190
- if (Trace.isEnabled()) {
191
- CLog(CLogTypes.info, 'initMap(): MLMapViewDeleteImpl onMapReady callback');
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));
192
154
  }
193
- this.mapbox.setMapboxViewInstance(this.nativeMapView);
194
- this.mapbox.initEventHandlerShim(this.settings, this.nativeMapView);
195
- this.notify({
196
- eventName: MapboxViewBase.mapReadyEvent,
197
- object: this,
198
- map: this,
199
- ios: this.nativeMapView
200
- });
201
- this.notify({
202
- eventName: MapboxViewBase.locationPermissionGrantedEvent,
203
- object: this,
204
- map: this,
205
- ios: this.nativeMapView
206
- });
207
- });
208
- _setMapboxMapOptions(this.nativeMapView, this.settings);
209
- _markers = [];
210
- this.nativeView.addSubview(this.nativeMapView);
211
- this.mapbox.setOnMoveBeginListener((data) => {
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 {
212
167
  if (Trace.isEnabled()) {
213
- CLog(CLogTypes.info, 'initMap(): onMoveBegin listener');
168
+ CLog(CLogTypes.info, 'Please use res://resourceName, http(s)://imageUrl or iconPath to use a local path');
214
169
  }
215
- this.notify({
216
- eventName: MapboxViewBase.moveBeginEvent,
217
- object: this,
218
- map: this,
219
- ios: this.nativeMapView
220
- });
221
- }, this.nativeMapView);
222
- };
223
- setTimeout(drawMap, this.settings.delay ? this.settings.delay : 0);
224
- }
225
- }
226
- onLayout(left, top, right, bottom) {
227
- super.onLayout(left, top, right, bottom);
228
- if (this.nativeMapView) {
229
- this.nativeMapView.layer.frame = this.ios.layer.bounds;
230
- }
231
- }
232
- [telemetryProperty.setNative](value) {
233
- NSUserDefaults.standardUserDefaults.setBoolForKey(false, 'MGLMapboxMetricsEnabled');
234
- }
235
- }
236
- "use strict";
237
- Object.defineProperty(exports, "__esModule", { value: true });
238
- exports.CustomUserLocationAnnotationView = void 0;
239
- var CustomUserLocationAnnotationView = /** @class */ (function (_super) {
240
- __extends(CustomUserLocationAnnotationView, _super);
241
- function CustomUserLocationAnnotationView() {
242
- return _super !== null && _super.apply(this, arguments) || this;
243
- }
244
- /**
245
- * init
246
- *
247
- * @link https://docs.nativescript.org/core-concepts/ios-runtime/HelloWorld
248
- */
249
- CustomUserLocationAnnotationView.prototype.init = function () {
250
- this.size = 48;
251
- _super.prototype.initWithFrame.call(this, CGRectMake(0, 0, this.size, this.size));
252
- this.renderModeChanged = true;
253
- this.userLocationRenderMode = 'NORMAL';
254
- return this;
255
- };
256
- /**
257
- * update
258
- *
259
- * The note from the Objective-C sample indicates this method may be called quite
260
- * often so it needs to be kept lightweight.
261
- */
262
- CustomUserLocationAnnotationView.prototype.update = function () {
263
- if (CLLocationCoordinate2DIsValid(this.userLocation.coordinate)) {
264
- // if it's the first time here, setup the layers that make up the
265
- // location marker.
266
- if (!this.dot) {
267
- this.drawNonTrackingLocationMarker();
170
+ }
268
171
  }
269
- if (this.userLocationRenderMode === 'GPS') {
270
- this.updateHeading();
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
+ }
271
181
  }
272
182
  }
183
+ return null;
273
184
  };
274
185
  /**
275
- * Draw the GPS tracking arrow.
276
- *
277
- * @link https://docs.nativescript.org/ns-framework-modules/color
186
+ * fired when one of the callout's accessoryviews is tapped (not currently used)
278
187
  */
279
- CustomUserLocationAnnotationView.prototype.drawTrackingLocationMarker = function () {
280
- if (Trace.isEnabled()) {
281
- CLog(CLogTypes.info, 'CustomerUserLocationAnnotatinView::drawTrackingLocationMarker()');
282
- }
283
- this.drawTrackingDot();
284
- this.drawArrow();
285
- }; // end of setupLayers()
188
+ MGLMapViewDelegateImpl.prototype.mapViewAnnotationCalloutAccessoryControlTapped = function (mapView, annotation, control) { };
286
189
  /**
287
- * draw the non-tracking marker
190
+ * fired when a marker is tapped
288
191
  */
289
- CustomUserLocationAnnotationView.prototype.drawNonTrackingLocationMarker = function () {
192
+ MGLMapViewDelegateImpl.prototype.mapViewDidSelectAnnotation = function (mapView, annotation) {
290
193
  if (Trace.isEnabled()) {
291
- CLog(CLogTypes.info, 'CustomerUserLocationAnnotatinView::drawNonTrackingLocationMarker()');
194
+ CLog(CLogTypes.info, 'MGLMapViewDelegateImpl::mapViewDidSelectAnntation()');
292
195
  }
293
- this.drawNonTrackingDot();
294
- if (this.arrow) {
295
- this.arrow.removeFromSuperlayer();
296
- this.arrow = null;
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);
297
209
  }
298
210
  };
299
211
  /**
300
- * draw the tracking dot.
212
+ * fired when a callout is tapped
301
213
  */
302
- CustomUserLocationAnnotationView.prototype.drawTrackingDot = function () {
303
- this.size = 48;
304
- // we need to adjust the size of the bounds of the marker. The Tracking marker
305
- // is larger than the non tracking marker.
306
- this.bounds = CGRectMake(0, 0, this.size, this.size);
307
- var dot = CALayer.layer();
308
- dot.frame = this.bounds;
309
- // user corner radius to turn the layer into a circle
310
- dot.cornerRadius = this.size / 2;
311
- dot.backgroundColor = this.tintColor.CGColor;
312
- dot.borderWidth = 4;
313
- var whiteColor = new Color('#FFFFFF');
314
- dot.borderColor = whiteColor.ios.CGColor;
315
- if (!this.dot) {
316
- this.layer.addSublayer(dot);
214
+ MGLMapViewDelegateImpl.prototype.mapViewTapOnCalloutForAnnotation = function (mapView, annotation) {
215
+ var cachedMarker = this.getTappedMarkerDetails(annotation);
216
+ if (cachedMarker && cachedMarker.onCalloutTap) {
217
+ cachedMarker.onCalloutTap(cachedMarker);
317
218
  }
318
- else {
319
- this.layer.replaceSublayerWith(this.dot, dot);
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
+ }
320
235
  }
321
- // QUESTION: does GC catch this?
322
- this.dot = dot;
323
236
  };
324
237
  /**
325
- * draw the non-tracking dot.
238
+ * override the standard location marker
326
239
  */
327
- CustomUserLocationAnnotationView.prototype.drawNonTrackingDot = function () {
328
- this.size = 24;
329
- this.bounds = CGRectMake(0, 0, this.size, this.size);
330
- var dot = CALayer.layer();
331
- dot.frame = this.bounds;
332
- // user corner radius to turn the layer into a circle
333
- dot.cornerRadius = this.size / 2;
334
- dot.backgroundColor = this.tintColor.CGColor;
335
- dot.borderWidth = 1;
336
- var whiteColor = new Color('#FFFFFF');
337
- dot.borderColor = whiteColor.ios.CGColor;
338
- if (!this.dot) {
339
- this.layer.addSublayer(dot);
240
+ MGLMapViewDelegateImpl.prototype.mapViewViewForAnnotation = function (mapView, annotation) {
241
+ if (Trace.isEnabled()) {
242
+ CLog(CLogTypes.info, 'MGLMapViewDelegateImpl::mapViewViewForAnnotation() top');
340
243
  }
341
- else {
342
- this.layer.replaceSublayerWith(this.dot, dot);
244
+ if (annotation.isKindOfClass(MGLUserLocation.class())) {
245
+ this.userLocationAnnotationView = CustomUserLocationAnnotationView.alloc().init();
246
+ return this.userLocationAnnotationView;
343
247
  }
344
- // QUESTION: does GC catch this?
345
- this.dot = dot;
248
+ return null;
346
249
  };
347
- /**
348
- * draw an arrow
349
- */
350
- CustomUserLocationAnnotationView.prototype.drawArrow = function () {
351
- var arrow = CAShapeLayer.layer();
352
- arrow.path = this.arrowPath();
353
- arrow.frame = CGRectMake(0, 0, this.size / 2, this.size / 2);
354
- arrow.position = CGPointMake(CGRectGetMidX(this.dot.frame), CGRectGetMidY(this.dot.frame));
355
- arrow.fillColor = this.dot.borderColor;
356
- if (!this.arrow) {
357
- this.layer.addSublayer(arrow);
250
+ MGLMapViewDelegateImpl.prototype.mapViewRegionIsChangingWithReason = function (mapView, reason) {
251
+ if (Trace.isEnabled()) {
252
+ CLog(CLogTypes.info, 'MGLMapViewDelegateImpl::mapViewRegionIsChanging()');
358
253
  }
359
- else {
360
- this.layer.replaceSublayerWith(this.arrow, arrow);
254
+ if (this.cameraChangedListener) {
255
+ this.cameraChangedListener(reason);
361
256
  }
362
- // QUESTION: Does GC catch this?
363
- this.arrow = arrow;
364
257
  };
365
- /**
366
- * update arrow heading
367
- *
368
- * @link https://docs.nativescript.org/core-concepts/ios-runtime/types/C-Functions
369
- */
370
- CustomUserLocationAnnotationView.prototype.updateHeading = function () {
371
- // just to avoid a possible race condition where the arrow isnt' drawn yet
372
- if (!this.arrow) {
373
- return;
374
- }
375
- if (typeof this.userLocation == 'undefined') {
376
- return;
258
+ MGLMapViewDelegateImpl.prototype.mapViewRegionDidChangeWithReasonAnimated = function (mapView, reason, animated) {
259
+ if (Trace.isEnabled()) {
260
+ CLog(CLogTypes.info, 'MGLMapViewDelegateImpl::mapViewRegionDidChangeAnimated()');
377
261
  }
378
- if (typeof this.userLocation.heading == 'undefined' || this.userLocation.heading === null) {
379
- return;
262
+ if (this.cameraChangedListener) {
263
+ this.cameraChangedListener(reason, animated);
380
264
  }
381
- if (typeof this.userLocation.heading.trueHeading == 'undefined' || this.userLocation.heading.trueHeading === null) {
382
- return;
265
+ if (this.cameraIdledListener) {
266
+ this.cameraIdledListener();
383
267
  }
384
- if (this.userLocation.heading.trueHeading > 0) {
385
- this.arrow.hidden = false;
386
- // get the difference between the map's current direction and the
387
- // user's heading, then convert it from degrees to radians
388
- //
389
- // The original Objective-C example uses the inline C function MGLRadiansFromDegrees but because
390
- // it's declared as inline it is not available for NativeScript. See linked article above.
391
- // let rotation : number = MGLRadiansFromDegrees( this.mapView.direction - this.userLocation.heading.trueHeading );
392
- var degrees = this.mapView.direction - this.userLocation.heading.trueHeading;
393
- // in radians
394
- var rotation = (degrees * Math.PI) / 180;
395
- rotation = -rotation;
396
- // if the difference would be perceptible, rotate the arrow.
397
- if (fabs(rotation) > 0.01) {
398
- // Disable implicit animations of this rotation, which reduces lag between updates
399
- CATransaction.begin();
400
- CATransaction.setDisableActions(true);
401
- this.arrow.setAffineTransform(CGAffineTransformRotate(CGAffineTransformIdentity, rotation));
402
- CATransaction.commit();
403
- }
268
+ };
269
+ MGLMapViewDelegateImpl.prototype.mapViewDidUpdateUserLocation = function (mapView, userLocation) {
270
+ if (Trace.isEnabled()) {
271
+ CLog(CLogTypes.info, 'MGLMapViewDelegateImpl::mapViewDidUpdateUserLocation()');
404
272
  }
405
- else {
406
- this.arrow.hidden = true;
273
+ if (this.userLocationChangedListener) {
274
+ this.userLocationChangedListener(_getLocation(userLocation));
407
275
  }
408
276
  };
409
- /**
410
- * Calculate the vector path for an arrow
411
- */
412
- CustomUserLocationAnnotationView.prototype.arrowPath = function () {
413
- var max = this.size / 2;
414
- var pad = 3;
415
- var top = CGPointMake(max * 0.5, 0);
416
- var left = CGPointMake(0 + pad, max - pad);
417
- var right = CGPointMake(max - pad, max - pad);
418
- var center = CGPointMake(max * 0.5, max * 0.6);
419
- var bezierPath = UIBezierPath.bezierPath();
420
- bezierPath.moveToPoint(top);
421
- bezierPath.addLineToPoint(left);
422
- bezierPath.addLineToPoint(center);
423
- bezierPath.addLineToPoint(right);
424
- bezierPath.addLineToPoint(top);
425
- bezierPath.closePath();
426
- return bezierPath.CGPath;
277
+ MGLMapViewDelegateImpl.ObjCProtocols = [MGLMapViewDelegate];
278
+ return MGLMapViewDelegateImpl;
279
+ }(NSObject));
280
+ var MapTapHandlerImpl = /** @class */ (function (_super) {
281
+ __extends(MapTapHandlerImpl, _super);
282
+ function MapTapHandlerImpl() {
283
+ return _super !== null && _super.apply(this, arguments) || this;
284
+ }
285
+ MapTapHandlerImpl.initWithOwnerAndListenerForMap = function (owner, listener, mapView) {
286
+ var handler = MapTapHandlerImpl.new();
287
+ handler._owner = owner;
288
+ handler._listener = listener;
289
+ handler._mapView = mapView;
290
+ return handler;
427
291
  };
428
- /**
429
- * change Render mode
430
- *
431
- * @param {string} renderMode
432
- */
433
- CustomUserLocationAnnotationView.prototype.changeUserLocationRenderMode = function (renderMode) {
292
+ MapTapHandlerImpl.prototype.tap = function (recognizer) {
293
+ var tapPoint = recognizer.locationInView(this._mapView);
294
+ var tapCoordinate = this._mapView.convertPointToCoordinateFromView(tapPoint, this._mapView);
295
+ this._listener({
296
+ lat: tapCoordinate.latitude,
297
+ lng: tapCoordinate.longitude
298
+ });
299
+ };
300
+ MapTapHandlerImpl.ObjCExposedMethods = {
301
+ tap: { returns: interop.types.void, params: [interop.types.id] }
302
+ };
303
+ return MapTapHandlerImpl;
304
+ }(NSObject));
305
+ var MapLongPressHandlerImpl = /** @class */ (function (_super) {
306
+ __extends(MapLongPressHandlerImpl, _super);
307
+ function MapLongPressHandlerImpl() {
308
+ return _super !== null && _super.apply(this, arguments) || this;
309
+ }
310
+ MapLongPressHandlerImpl.initWithOwnerAndListenerForMap = function (owner, listener, mapView) {
311
+ var handler = MapLongPressHandlerImpl.new();
312
+ handler._owner = owner;
313
+ handler._listener = listener;
314
+ handler._mapView = mapView;
315
+ return handler;
316
+ };
317
+ MapLongPressHandlerImpl.prototype.longPress = function (recognizer) {
318
+ var longPressPoint = recognizer.locationInView(this._mapView);
319
+ var longPressCoordinate = this._mapView.convertPointToCoordinateFromView(longPressPoint, this._mapView);
320
+ this._listener({
321
+ lat: longPressCoordinate.latitude,
322
+ lng: longPressCoordinate.longitude
323
+ });
324
+ };
325
+ MapLongPressHandlerImpl.ObjCExposedMethods = {
326
+ longPress: { returns: interop.types.void, params: [interop.types.id] }
327
+ };
328
+ return MapLongPressHandlerImpl;
329
+ }(NSObject));
330
+ var MapPanHandlerImpl = /** @class */ (function (_super) {
331
+ __extends(MapPanHandlerImpl, _super);
332
+ function MapPanHandlerImpl() {
333
+ return _super !== null && _super.apply(this, arguments) || this;
334
+ }
335
+ MapPanHandlerImpl.initWithOwnerAndListenerForMap = function (owner, listener, panState, mapView) {
336
+ var handler = MapPanHandlerImpl.new();
337
+ handler._owner = owner;
338
+ handler._listener = new Map([[panState, listener]]);
339
+ handler._mapView = mapView;
340
+ return handler;
341
+ };
342
+ MapPanHandlerImpl.prototype.addListener = function (panState, listener) {
343
+ this._listener.set(panState, listener);
344
+ };
345
+ MapPanHandlerImpl.prototype.pan = function (recognizer) {
346
+ var panCoordinate = this.getCoordinates(recognizer);
434
347
  if (Trace.isEnabled()) {
435
- CLog(CLogTypes.info, "CustomUserLocationAnnotatinView::changeUserLocationRenderMode(): changing mode to '" + renderMode + "'");
348
+ CLog(CLogTypes.info, 'MapPanHandlerImpl::pan(): top with state:', recognizer.state);
436
349
  }
437
- this.userLocationRenderMode = renderMode;
438
- if (renderMode === 'GPS') {
439
- this.drawTrackingLocationMarker();
350
+ if (recognizer.state === UIGestureRecognizerState.Changed) {
351
+ this.notifyListener(recognizer.state, panCoordinate.latitude, panCoordinate.longitude);
440
352
  }
441
- else {
442
- this.drawNonTrackingLocationMarker();
353
+ };
354
+ MapPanHandlerImpl.prototype.panEnd = function (recognizer) {
355
+ var panCoordinate = this.getCoordinates(recognizer);
356
+ if (Trace.isEnabled()) {
357
+ CLog(CLogTypes.info, 'MapPanHandlerImpl::panEnd(): top with state:', recognizer.state);
358
+ }
359
+ if (recognizer.state === UIGestureRecognizerState.Ended) {
360
+ this.notifyListener(recognizer.state, panCoordinate.latitude, panCoordinate.longitude);
443
361
  }
444
362
  };
445
- return CustomUserLocationAnnotationView;
446
- }(MGLUserLocationAnnotationView));
447
- exports.CustomUserLocationAnnotationView = CustomUserLocationAnnotationView;
448
- export class Mapbox extends MapboxCommon {
449
- constructor() {
450
- super(...arguments);
451
- this.eventCallbacks = {};
452
- }
453
- setMapboxViewInstance(mapboxViewInstance) {
454
- this._mapboxViewInstance = mapboxViewInstance;
455
- }
456
- initEventHandlerShim(settings, mapboxNativeViewInstance) {
363
+ MapPanHandlerImpl.prototype.panBegin = function (recognizer) {
364
+ var panCoordinate = this.getCoordinates(recognizer);
457
365
  if (Trace.isEnabled()) {
458
- CLog(CLogTypes.info, 'Mapbox:initEventHandlerShim(): top');
366
+ CLog(CLogTypes.info, 'MapPanHandlerImpl::panBegin(): top with state:', recognizer.state);
459
367
  }
460
- this.setOnMapClickListener((point) => this.checkForClickEvent(point), mapboxNativeViewInstance);
461
- }
462
- onMapEvent(eventName, id, callback, nativeMapView) {
463
- if (typeof this.eventCallbacks[eventName] == 'undefined') {
464
- this.eventCallbacks[eventName] = [];
368
+ if (recognizer.state === UIGestureRecognizerState.Began) {
369
+ this.notifyListener(recognizer.state, panCoordinate.latitude, panCoordinate.longitude);
465
370
  }
466
- this.eventCallbacks[eventName].push({
467
- id,
468
- callback
371
+ };
372
+ MapPanHandlerImpl.prototype.getCoordinates = function (recognizer) {
373
+ var panPoint = recognizer.locationInView(this._mapView);
374
+ return this._mapView.convertPointToCoordinateFromView(panPoint, this._mapView);
375
+ };
376
+ MapPanHandlerImpl.prototype.notifyListener = function (panState, latitude, longitude) {
377
+ if (this._listener.has(panState)) {
378
+ this._listener.get(panState)({ lat: latitude, lng: longitude });
379
+ }
380
+ };
381
+ MapPanHandlerImpl.ObjCExposedMethods = {
382
+ pan: { returns: interop.types.void, params: [interop.types.id] },
383
+ panEnd: { returns: interop.types.void, params: [interop.types.id] },
384
+ panBegin: { returns: interop.types.void, params: [interop.types.id] }
385
+ };
386
+ return MapPanHandlerImpl;
387
+ }(NSObject));
388
+ var MapSwipeHandlerImpl = /** @class */ (function (_super) {
389
+ __extends(MapSwipeHandlerImpl, _super);
390
+ function MapSwipeHandlerImpl() {
391
+ return _super !== null && _super.apply(this, arguments) || this;
392
+ }
393
+ MapSwipeHandlerImpl.initWithOwnerAndListenerForMap = function (owner, listener, mapView) {
394
+ var handler = MapSwipeHandlerImpl.new();
395
+ handler._owner = owner;
396
+ handler._listener = listener;
397
+ handler._mapView = mapView;
398
+ return handler;
399
+ };
400
+ MapSwipeHandlerImpl.prototype.swipe = function (recognizer) {
401
+ var swipePoint = recognizer.locationInView(this._mapView);
402
+ var swipeCoordinate = this._mapView.convertPointToCoordinateFromView(swipePoint, this._mapView);
403
+ this._listener({
404
+ lat: swipeCoordinate.latitude,
405
+ lng: swipeCoordinate.longitude
469
406
  });
407
+ };
408
+ MapSwipeHandlerImpl.ObjCExposedMethods = {
409
+ swipe: { returns: interop.types.void, params: [interop.types.id] }
410
+ };
411
+ return MapSwipeHandlerImpl;
412
+ }(NSObject));
413
+ export * from './common';
414
+ let _markers = [];
415
+ const _markerIconDownloadCache = [];
416
+ const _setMapboxMapOptions = (mapView, settings) => {
417
+ mapView.logoView.hidden = settings.hideLogo;
418
+ mapView.attributionButton.hidden = settings.hideAttribution;
419
+ mapView.compassView.hidden = settings.hideCompass;
420
+ mapView.rotateEnabled = !settings.disableRotation;
421
+ mapView.scrollEnabled = !settings.disableScroll;
422
+ mapView.zoomEnabled = !settings.disableZoom;
423
+ mapView.allowsTilting = !settings.disableTilt;
424
+ if (settings.center && settings.center.lat && settings.center.lng) {
425
+ const centerCoordinate = CLLocationCoordinate2DMake(settings.center.lat, settings.center.lng);
426
+ mapView.setCenterCoordinateZoomLevelAnimated(centerCoordinate, settings.zoomLevel, false);
470
427
  }
471
- offMapEvent(eventName, id, nativeMapView) {
472
- if (typeof this.eventCallbacks[eventName] == 'undefined') {
473
- return;
474
- }
475
- this.eventCallbacks[eventName] = this.eventCallbacks[eventName].filter((entry) => entry.id !== id);
428
+ else {
429
+ mapView.setZoomLevelAnimated(settings.zoomLevel, false);
476
430
  }
477
- checkForClickEvent(point, nativeMap) {
478
- if (Trace.isEnabled()) {
479
- CLog(CLogTypes.info, 'Mapbox:checkForClickEvent(): got click event with point:', point);
480
- }
481
- this.eventCallbacks['click'] &&
482
- this.eventCallbacks['click'].forEach((eventListener) => {
483
- this.queryRenderedFeatures({ point, layers: [eventListener.id] }, nativeMap)
484
- .then((response) => {
485
- if (response.length > 0) {
486
- eventListener.callback(response);
487
- }
488
- })
489
- .catch((err) => {
490
- console.error('click error ', eventListener.id, err);
491
- });
492
- });
493
- this.view && this.view.notify({ eventName: 'mapClick', object: this.view, point });
494
- return false;
431
+ mapView.showsUserLocation = settings.showUserLocation;
432
+ mapView.autoresizingMask = 2 | 16;
433
+ };
434
+ const _getMapStyle = (input) => {
435
+ if (input.startsWith('mapbox://styles') || input.startsWith('http://') || input.startsWith('https://')) {
436
+ return NSURL.URLWithString(input);
495
437
  }
496
- _addMarkers(markers, nativeMap) {
497
- if (!markers) {
498
- if (Trace.isEnabled()) {
499
- CLog(CLogTypes.info, 'No markers passed');
500
- }
501
- return;
502
- }
503
- if (!Array.isArray(markers)) {
504
- if (Trace.isEnabled()) {
505
- CLog(CLogTypes.info, "markers must be passed as an Array: [{title: 'foo'}]");
506
- }
507
- return;
508
- }
509
- const theMap = nativeMap || this._mapboxViewInstance;
510
- _downloadMarkerImages(markers).then((updatedMarkers) => {
511
- updatedMarkers.forEach((marker) => {
512
- const lat = marker.lat;
513
- const lng = marker.lng;
514
- const point = MGLPointAnnotation.new();
515
- point.coordinate = CLLocationCoordinate2DMake(lat, lng);
516
- point.title = marker.title;
517
- point.subtitle = marker.subtitle;
518
- _markers.push(marker);
519
- theMap.addAnnotation(point);
520
- if (marker.selected) {
521
- theMap.selectAnnotationAnimated(point, false);
522
- }
523
- marker.ios = point;
524
- marker.update = (newSettings) => {
525
- _markers.forEach((_marker) => {
526
- if (marker.id === _marker.id) {
527
- if (newSettings.onTap !== undefined) {
528
- _marker.onTap = newSettings.onTap;
529
- }
530
- if (newSettings.onCalloutTap !== undefined) {
531
- _marker.onCalloutTap = newSettings.onCalloutTap;
532
- }
533
- if (newSettings.title !== undefined) {
534
- _marker.ios.title = _marker.title = newSettings.title;
535
- }
536
- if (newSettings.subtitle !== undefined) {
537
- _marker.ios.subtitle = _marker.subtitle = newSettings.subtitle;
538
- }
539
- if (newSettings.lat && newSettings.lng) {
540
- _marker.lat = newSettings.lat;
541
- _marker.lng = newSettings.lng;
542
- _marker.ios.coordinate = CLLocationCoordinate2DMake(newSettings.lat, newSettings.lng);
543
- }
544
- if (newSettings.selected) {
545
- theMap.selectAnnotationAnimated(_marker.ios, false);
546
- }
547
- }
548
- });
549
- };
550
- });
551
- });
438
+ else if (input.startsWith('~/')) {
439
+ return NSURL.URLWithString('file://' + path.join(knownFolders.currentApp().path, input.replace('~/', '')));
552
440
  }
553
- show(options) {
554
- if (Trace.isEnabled()) {
555
- CLog(CLogTypes.info, 'show(): top with options:', options);
556
- }
557
- return new Promise((resolve, reject) => {
558
- try {
559
- const settings = Mapbox.merge(options, Mapbox.defaults);
560
- if (settings.accessToken === undefined) {
561
- reject("Please set the 'accessToken' parameter");
562
- return;
563
- }
564
- if (this._mapboxViewInstance) {
565
- this._mapboxViewInstance.removeFromSuperview();
566
- }
567
- 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);
568
- MGLAccountManager.accessToken = settings.accessToken;
569
- this._mapboxViewInstance = MGLMapView.alloc().initWithFrameStyleURL(mapFrame, styleURL);
570
- _setMapboxMapOptions(this._mapboxViewInstance, settings);
571
- this._mapboxViewInstance.delegate = MGLMapViewDelegateImpl.new().initWithCallback((mapView) => {
572
- resolve({
573
- ios: mapView
574
- });
575
- });
576
- _markers = [];
577
- this._addMarkers(settings.markers);
578
- setTimeout(() => {
579
- view.addSubview(this._mapboxViewInstance);
580
- }, 500);
581
- }
582
- catch (ex) {
583
- if (Trace.isEnabled()) {
584
- CLog(CLogTypes.info, 'Error in mapbox.show: ' + ex);
585
- }
586
- reject(ex);
587
- }
588
- });
441
+ else if (input === MapStyle.LIGHT) {
442
+ return MGLStyle.lightStyleURL;
589
443
  }
590
- hide() {
591
- return new Promise((resolve, reject) => {
592
- try {
593
- if (this._mapboxViewInstance) {
594
- this._mapboxViewInstance.removeFromSuperview();
595
- }
596
- resolve();
597
- }
598
- catch (ex) {
599
- if (Trace.isEnabled()) {
600
- CLog(CLogTypes.info, 'Error in mapbox.hide: ' + ex);
601
- }
602
- reject(ex);
603
- }
604
- });
444
+ else if (input === MapStyle.DARK) {
445
+ return MGLStyle.darkStyleURL;
605
446
  }
606
- unhide() {
607
- return new Promise((resolve, reject) => {
608
- try {
609
- if (this._mapboxViewInstance) {
610
- const view = UIApplication.sharedApplication.keyWindow.rootViewController.view;
611
- view.addSubview(this._mapboxViewInstance);
612
- resolve();
613
- }
614
- else {
615
- reject('No map found');
616
- }
617
- }
618
- catch (ex) {
619
- if (Trace.isEnabled()) {
620
- CLog(CLogTypes.info, 'Error in mapbox.unhide: ' + ex);
621
- }
622
- reject(ex);
623
- }
624
- });
447
+ else if (input === MapStyle.OUTDOORS) {
448
+ return MGLStyle.outdoorsStyleURL;
625
449
  }
626
- destroy(nativeMap) {
627
- return new Promise((resolve, reject) => {
628
- const theMap = nativeMap || this._mapboxViewInstance;
629
- if (theMap) {
630
- theMap.removeFromSuperview();
631
- theMap.delegate = null;
632
- }
633
- resolve();
634
- });
450
+ else if (input === MapStyle.SATELLITE) {
451
+ return MGLStyle.satelliteStyleURL;
635
452
  }
636
- onStart(nativeMap) {
637
- return Promise.resolve();
453
+ else if (input === MapStyle.SATELLITE_STREETS) {
454
+ return MGLStyle.satelliteStreetsStyleURL;
638
455
  }
639
- onResume(nativeMap) {
640
- return Promise.resolve();
456
+ else if (input === MapStyle.TRAFFIC_DAY) {
457
+ return NSURL.URLWithString('mapbox://styles/mapbox/traffic-day-v2');
641
458
  }
642
- onPause(nativeMap) {
643
- return Promise.resolve();
459
+ else if (input === MapStyle.TRAFFIC_NIGHT) {
460
+ return NSURL.URLWithString('mapbox://styles/mapbox/traffic-night-v2');
644
461
  }
645
- onStop(nativeMap) {
646
- return Promise.resolve();
462
+ else {
463
+ return MGLStyle.streetsStyleURL;
647
464
  }
648
- onLowMemory(nativeMap) {
649
- return Promise.resolve();
465
+ };
466
+ function _getTrackingMode(input) {
467
+ return 0;
468
+ }
469
+ function _getLocation(loc) {
470
+ if (loc === null) {
471
+ return null;
650
472
  }
651
- onDestroy(nativeMap) {
652
- return Promise.resolve();
473
+ 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
+ };
653
481
  }
654
- setMapStyle(style, nativeMap) {
655
- return new Promise((resolve, reject) => {
656
- try {
657
- const theMap = nativeMap || this._mapboxViewInstance;
658
- const delegate = theMap.delegate;
659
- delegate.setStyleLoadedCallback((mapView) => {
660
- if (Trace.isEnabled()) {
661
- CLog(CLogTypes.info, 'Mapbox:setMapStyle(): style loaded callback returned.');
662
- }
663
- resolve();
664
- });
665
- theMap.styleURL = _getMapStyle(style);
666
- }
667
- catch (ex) {
668
- if (Trace.isEnabled()) {
669
- CLog(CLogTypes.info, 'Error in mapbox.setMapStyle: ' + ex);
670
- }
671
- reject(ex);
672
- }
673
- });
482
+ }
483
+ export function setLogLevel(level) {
484
+ let loggingLevel;
485
+ switch (level) {
486
+ case 'none':
487
+ loggingLevel = 0;
488
+ break;
489
+ case 'info':
490
+ loggingLevel = 1;
491
+ break;
492
+ case 'verbose':
493
+ case 'debug':
494
+ loggingLevel = 2;
495
+ break;
496
+ case 'error':
497
+ loggingLevel = 3;
498
+ break;
499
+ case 'fault':
500
+ loggingLevel = 4;
501
+ break;
674
502
  }
675
- async getImage(imageId, nativeMap) {
676
- return new Promise((resolve, reject) => {
677
- const theMap = nativeMap || this._mapboxViewInstance;
678
- if (!theMap) {
679
- reject('No map has been loaded');
680
- return;
681
- }
682
- try {
683
- const nativeImage = theMap.style.imageForName(imageId);
684
- const img = new ImageSource(nativeImage);
685
- resolve(img);
686
- }
687
- catch (ex) {
688
- reject('Error during getImage: ' + ex);
689
- if (Trace.isEnabled()) {
690
- CLog(CLogTypes.info, 'Error in mapbox.getImage: ' + ex);
691
- }
692
- throw ex;
693
- }
694
- });
503
+ MGLLoggingConfiguration.sharedConfiguration.loggingLevel = loggingLevel;
504
+ }
505
+ export class MapboxView extends MapboxViewBase {
506
+ constructor() {
507
+ super(...arguments);
508
+ this.nativeMapView = null;
509
+ this.delegate = null;
510
+ this.settings = null;
511
+ this.initialized = false;
512
+ this.initCountHack = 50;
695
513
  }
696
- async addImage(imageId, image, nativeMap) {
697
- return new Promise((resolve, reject) => {
698
- const theMap = nativeMap || this._mapboxViewInstance;
699
- if (!theMap) {
700
- reject('No map has been loaded');
701
- return;
702
- }
703
- if (!image.startsWith('res://')) {
704
- const appPath = knownFolders.currentApp().path;
705
- image = appPath + '/' + image.replace('~/', '');
514
+ setConfig(settings) {
515
+ if (Trace.isEnabled()) {
516
+ CLog(CLogTypes.info, 'setConfig(): settings:', settings);
517
+ }
518
+ this.settings = settings;
519
+ }
520
+ getNativeMapView() {
521
+ return this.nativeMapView;
522
+ }
523
+ createNativeView() {
524
+ if (Trace.isEnabled()) {
525
+ CLog(CLogTypes.info, 'createNativeView(): top');
526
+ }
527
+ const v = super.createNativeView();
528
+ return v;
529
+ }
530
+ onLoaded() {
531
+ super.onLoaded();
532
+ if (Trace.isEnabled()) {
533
+ CLog(CLogTypes.info, 'initNativeView(): on - loaded');
534
+ }
535
+ if (this.telemetry === false) {
536
+ NSUserDefaults.standardUserDefaults.setBoolForKey(false, 'MGLMapboxMetricsEnabled');
537
+ }
538
+ if (!this.initialized) {
539
+ this.initMap();
540
+ this.initialized = true;
541
+ }
542
+ }
543
+ initNativeView() {
544
+ super.initNativeView();
545
+ this.nativeView.owner = this;
546
+ }
547
+ async disposeNativeView() {
548
+ if (Trace.isEnabled()) {
549
+ CLog(CLogTypes.info, 'disposeNativeView(): top');
550
+ }
551
+ this.nativeView.owner = null;
552
+ await this.mapbox.destroy();
553
+ if (Trace.isEnabled()) {
554
+ CLog(CLogTypes.info, 'disposeNativeView(): after mapbox.destroy()');
555
+ }
556
+ super.disposeNativeView();
557
+ if (Trace.isEnabled()) {
558
+ CLog(CLogTypes.info, 'disposeNativeView(): bottom');
559
+ }
560
+ }
561
+ getMapboxApi() {
562
+ return this.mapbox;
563
+ }
564
+ initMap() {
565
+ if (Trace.isEnabled()) {
566
+ CLog(CLogTypes.info, 'initMap() top with settings:', this.settings);
567
+ }
568
+ if (!this.settings && !this.config.accessToken) {
569
+ if (Trace.isEnabled()) {
570
+ CLog(CLogTypes.info, 'initMap() no access token. Race condition on XML property evaluation?');
706
571
  }
707
- const img = ImageSource.fromFileOrResourceSync(image);
708
- try {
709
- theMap.style.setImageForName(img.ios, imageId);
710
- resolve();
572
+ if (this.initCountHack > 50) {
573
+ return;
711
574
  }
712
- catch (ex) {
713
- reject('Error during addImage: ' + ex);
714
- if (Trace.isEnabled()) {
715
- CLog(CLogTypes.info, 'Error in mapbox.addImage: ' + ex);
716
- }
717
- throw ex;
575
+ setTimeout(() => {
576
+ this.initMap();
577
+ }, 50);
578
+ this.initCountHack++;
579
+ return;
580
+ }
581
+ if (!this.settings) {
582
+ this.settings = Mapbox.merge(this.config, Mapbox.defaults);
583
+ }
584
+ else {
585
+ this.settings = Mapbox.merge(this.settings, Mapbox.defaults);
586
+ }
587
+ if (!this.nativeMapView) {
588
+ this.mapbox = new Mapbox(this);
589
+ if (Trace.isEnabled()) {
590
+ CLog(CLogTypes.info, 'initMap(): after new Mapbox()');
718
591
  }
719
- });
592
+ const drawMap = () => {
593
+ MGLAccountManager.accessToken = this.settings.accessToken;
594
+ this.nativeMapView = MGLMapView.alloc().initWithFrameStyleURL(CGRectMake(0, 0, this.nativeView.frame.size.width, this.nativeView.frame.size.height), _getMapStyle(this.settings.style));
595
+ this.nativeMapView.delegate = this.delegate = MGLMapViewDelegateImpl.new().initWithCallback(() => {
596
+ if (Trace.isEnabled()) {
597
+ CLog(CLogTypes.info, 'initMap(): MLMapViewDeleteImpl onMapReady callback');
598
+ }
599
+ this.mapbox.setMapboxViewInstance(this.nativeMapView);
600
+ this.mapbox.initEventHandlerShim(this.settings, this.nativeMapView);
601
+ this.notify({
602
+ eventName: MapboxViewBase.mapReadyEvent,
603
+ object: this,
604
+ map: this,
605
+ ios: this.nativeMapView
606
+ });
607
+ this.notify({
608
+ eventName: MapboxViewBase.locationPermissionGrantedEvent,
609
+ object: this,
610
+ map: this,
611
+ ios: this.nativeMapView
612
+ });
613
+ });
614
+ _setMapboxMapOptions(this.nativeMapView, this.settings);
615
+ _markers = [];
616
+ this.nativeView.addSubview(this.nativeMapView);
617
+ this.mapbox.setOnMoveBeginListener((data) => {
618
+ if (Trace.isEnabled()) {
619
+ CLog(CLogTypes.info, 'initMap(): onMoveBegin listener');
620
+ }
621
+ this.notify({
622
+ eventName: MapboxViewBase.moveBeginEvent,
623
+ object: this,
624
+ map: this,
625
+ ios: this.nativeMapView
626
+ });
627
+ }, this.nativeMapView);
628
+ this.mapbox.setOnMoveEndListener((data) => {
629
+ if (Trace.isEnabled()) {
630
+ CLog(CLogTypes.info, 'initMap(): onMoveEnd listener');
631
+ }
632
+ this.notify({
633
+ eventName: MapboxViewBase.moveEndEvent,
634
+ object: this,
635
+ map: this,
636
+ ios: this.nativeMapView
637
+ });
638
+ }, this.nativeMapView);
639
+ this.mapbox.setOnScrollListener((data) => {
640
+ if (Trace.isEnabled()) {
641
+ CLog(CLogTypes.info, 'initMap(): onScroll listener');
642
+ }
643
+ this.notify({
644
+ eventName: MapboxViewBase.scrollEvent,
645
+ object: this,
646
+ map: this,
647
+ ios: this.nativeMapView
648
+ });
649
+ }, this.nativeMapView);
650
+ };
651
+ setTimeout(drawMap, this.settings.delay ? this.settings.delay : 0);
652
+ }
653
+ }
654
+ onLayout(left, top, right, bottom) {
655
+ super.onLayout(left, top, right, bottom);
656
+ if (this.nativeMapView) {
657
+ this.nativeMapView.layer.frame = this.ios.layer.bounds;
658
+ }
659
+ }
660
+ [telemetryProperty.setNative](value) {
661
+ NSUserDefaults.standardUserDefaults.setBoolForKey(false, 'MGLMapboxMetricsEnabled');
662
+ }
663
+ }
664
+ var CustomUserLocationAnnotationView = /** @class */ (function (_super) {
665
+ __extends(CustomUserLocationAnnotationView, _super);
666
+ function CustomUserLocationAnnotationView() {
667
+ return _super !== null && _super.apply(this, arguments) || this;
668
+ }
669
+ /**
670
+ * init
671
+ *
672
+ * @link https://docs.nativescript.org/core-concepts/ios-runtime/HelloWorld
673
+ */
674
+ CustomUserLocationAnnotationView.prototype.init = function () {
675
+ this.size = 48;
676
+ _super.prototype.initWithFrame.call(this, CGRectMake(0, 0, this.size, this.size));
677
+ this.renderModeChanged = true;
678
+ this.userLocationRenderMode = 'NORMAL';
679
+ return this;
680
+ };
681
+ /**
682
+ * update
683
+ *
684
+ * The note from the Objective-C sample indicates this method may be called quite
685
+ * often so it needs to be kept lightweight.
686
+ */
687
+ CustomUserLocationAnnotationView.prototype.update = function () {
688
+ if (CLLocationCoordinate2DIsValid(this.userLocation.coordinate)) {
689
+ // if it's the first time here, setup the layers that make up the
690
+ // location marker.
691
+ if (!this.dot) {
692
+ this.drawNonTrackingLocationMarker();
693
+ }
694
+ if (this.userLocationRenderMode === 'GPS') {
695
+ this.updateHeading();
696
+ }
697
+ }
698
+ };
699
+ /**
700
+ * Draw the GPS tracking arrow.
701
+ *
702
+ * @link https://docs.nativescript.org/ns-framework-modules/color
703
+ */
704
+ CustomUserLocationAnnotationView.prototype.drawTrackingLocationMarker = function () {
705
+ if (Trace.isEnabled()) {
706
+ CLog(CLogTypes.info, 'CustomerUserLocationAnnotatinView::drawTrackingLocationMarker()');
707
+ }
708
+ this.drawTrackingDot();
709
+ this.drawArrow();
710
+ }; // end of setupLayers()
711
+ /**
712
+ * draw the non-tracking marker
713
+ */
714
+ CustomUserLocationAnnotationView.prototype.drawNonTrackingLocationMarker = function () {
715
+ if (Trace.isEnabled()) {
716
+ CLog(CLogTypes.info, 'CustomerUserLocationAnnotatinView::drawNonTrackingLocationMarker()');
717
+ }
718
+ this.drawNonTrackingDot();
719
+ if (this.arrow) {
720
+ this.arrow.removeFromSuperlayer();
721
+ this.arrow = null;
722
+ }
723
+ };
724
+ /**
725
+ * draw the tracking dot.
726
+ */
727
+ CustomUserLocationAnnotationView.prototype.drawTrackingDot = function () {
728
+ this.size = 48;
729
+ // we need to adjust the size of the bounds of the marker. The Tracking marker
730
+ // is larger than the non tracking marker.
731
+ this.bounds = CGRectMake(0, 0, this.size, this.size);
732
+ var dot = CALayer.layer();
733
+ dot.frame = this.bounds;
734
+ // user corner radius to turn the layer into a circle
735
+ dot.cornerRadius = this.size / 2;
736
+ dot.backgroundColor = this.tintColor.CGColor;
737
+ dot.borderWidth = 4;
738
+ var whiteColor = new Color('#FFFFFF');
739
+ dot.borderColor = whiteColor.ios.CGColor;
740
+ if (!this.dot) {
741
+ this.layer.addSublayer(dot);
742
+ }
743
+ else {
744
+ this.layer.replaceSublayerWith(this.dot, dot);
745
+ }
746
+ // QUESTION: does GC catch this?
747
+ this.dot = dot;
748
+ };
749
+ /**
750
+ * draw the non-tracking dot.
751
+ */
752
+ CustomUserLocationAnnotationView.prototype.drawNonTrackingDot = function () {
753
+ this.size = 24;
754
+ this.bounds = CGRectMake(0, 0, this.size, this.size);
755
+ var dot = CALayer.layer();
756
+ dot.frame = this.bounds;
757
+ // user corner radius to turn the layer into a circle
758
+ dot.cornerRadius = this.size / 2;
759
+ dot.backgroundColor = this.tintColor.CGColor;
760
+ dot.borderWidth = 1;
761
+ var whiteColor = new Color('#FFFFFF');
762
+ dot.borderColor = whiteColor.ios.CGColor;
763
+ if (!this.dot) {
764
+ this.layer.addSublayer(dot);
765
+ }
766
+ else {
767
+ this.layer.replaceSublayerWith(this.dot, dot);
768
+ }
769
+ // QUESTION: does GC catch this?
770
+ this.dot = dot;
771
+ };
772
+ /**
773
+ * draw an arrow
774
+ */
775
+ CustomUserLocationAnnotationView.prototype.drawArrow = function () {
776
+ var arrow = CAShapeLayer.layer();
777
+ arrow.path = this.arrowPath();
778
+ arrow.frame = CGRectMake(0, 0, this.size / 2, this.size / 2);
779
+ arrow.position = CGPointMake(CGRectGetMidX(this.dot.frame), CGRectGetMidY(this.dot.frame));
780
+ arrow.fillColor = this.dot.borderColor;
781
+ if (!this.arrow) {
782
+ this.layer.addSublayer(arrow);
783
+ }
784
+ else {
785
+ this.layer.replaceSublayerWith(this.arrow, arrow);
786
+ }
787
+ // QUESTION: Does GC catch this?
788
+ this.arrow = arrow;
789
+ };
790
+ /**
791
+ * update arrow heading
792
+ *
793
+ * @link https://docs.nativescript.org/core-concepts/ios-runtime/types/C-Functions
794
+ */
795
+ CustomUserLocationAnnotationView.prototype.updateHeading = function () {
796
+ // just to avoid a possible race condition where the arrow isnt' drawn yet
797
+ if (!this.arrow) {
798
+ return;
799
+ }
800
+ if (typeof this.userLocation == 'undefined') {
801
+ return;
802
+ }
803
+ if (typeof this.userLocation.heading == 'undefined' || this.userLocation.heading === null) {
804
+ return;
805
+ }
806
+ if (typeof this.userLocation.heading.trueHeading == 'undefined' || this.userLocation.heading.trueHeading === null) {
807
+ return;
808
+ }
809
+ if (this.userLocation.heading.trueHeading > 0) {
810
+ this.arrow.hidden = false;
811
+ // get the difference between the map's current direction and the
812
+ // user's heading, then convert it from degrees to radians
813
+ //
814
+ // The original Objective-C example uses the inline C function MGLRadiansFromDegrees but because
815
+ // it's declared as inline it is not available for NativeScript. See linked article above.
816
+ // let rotation : number = MGLRadiansFromDegrees( this.mapView.direction - this.userLocation.heading.trueHeading );
817
+ var degrees = this.mapView.direction - this.userLocation.heading.trueHeading;
818
+ // in radians
819
+ var rotation = (degrees * Math.PI) / 180;
820
+ rotation = -rotation;
821
+ // if the difference would be perceptible, rotate the arrow.
822
+ if (fabs(rotation) > 0.01) {
823
+ // Disable implicit animations of this rotation, which reduces lag between updates
824
+ CATransaction.begin();
825
+ CATransaction.setDisableActions(true);
826
+ this.arrow.setAffineTransform(CGAffineTransformRotate(CGAffineTransformIdentity, rotation));
827
+ CATransaction.commit();
828
+ }
829
+ }
830
+ else {
831
+ this.arrow.hidden = true;
832
+ }
833
+ };
834
+ /**
835
+ * Calculate the vector path for an arrow
836
+ */
837
+ CustomUserLocationAnnotationView.prototype.arrowPath = function () {
838
+ var max = this.size / 2;
839
+ var pad = 3;
840
+ var top = CGPointMake(max * 0.5, 0);
841
+ var left = CGPointMake(0 + pad, max - pad);
842
+ var right = CGPointMake(max - pad, max - pad);
843
+ var center = CGPointMake(max * 0.5, max * 0.6);
844
+ var bezierPath = UIBezierPath.bezierPath();
845
+ bezierPath.moveToPoint(top);
846
+ bezierPath.addLineToPoint(left);
847
+ bezierPath.addLineToPoint(center);
848
+ bezierPath.addLineToPoint(right);
849
+ bezierPath.addLineToPoint(top);
850
+ bezierPath.closePath();
851
+ return bezierPath.CGPath;
852
+ };
853
+ /**
854
+ * change Render mode
855
+ *
856
+ * @param {string} renderMode
857
+ */
858
+ CustomUserLocationAnnotationView.prototype.changeUserLocationRenderMode = function (renderMode) {
859
+ if (Trace.isEnabled()) {
860
+ CLog(CLogTypes.info, "CustomUserLocationAnnotatinView::changeUserLocationRenderMode(): changing mode to '" + renderMode + "'");
861
+ }
862
+ this.userLocationRenderMode = renderMode;
863
+ if (renderMode === 'GPS') {
864
+ this.drawTrackingLocationMarker();
865
+ }
866
+ else {
867
+ this.drawNonTrackingLocationMarker();
868
+ }
869
+ };
870
+ return CustomUserLocationAnnotationView;
871
+ }(MGLUserLocationAnnotationView));
872
+ export class Mapbox extends MapboxCommon {
873
+ constructor() {
874
+ super(...arguments);
875
+ this.eventCallbacks = {};
720
876
  }
721
- async removeImage(imageId, nativeMap) {
722
- return new Promise((resolve, reject) => {
723
- const theMap = nativeMap || this._mapboxViewInstance;
724
- if (!theMap) {
725
- reject('No map has been loaded');
726
- return;
727
- }
728
- try {
729
- theMap.style.removeImageForName(imageId);
730
- resolve();
731
- }
732
- catch (ex) {
733
- reject('Error during removeImage: ' + ex);
734
- if (Trace.isEnabled()) {
735
- CLog(CLogTypes.info, 'Error in mapbox.removeImage: ' + ex);
736
- }
737
- throw ex;
738
- }
739
- });
877
+ setMapboxViewInstance(mapboxViewInstance) {
878
+ this._mapboxViewInstance = mapboxViewInstance;
740
879
  }
741
- addMarkers(markers, nativeMap) {
742
- return new Promise((resolve, reject) => {
743
- try {
744
- const theMap = nativeMap || this._mapboxViewInstance;
745
- this._addMarkers(markers, theMap);
746
- resolve();
747
- }
748
- catch (ex) {
749
- if (Trace.isEnabled()) {
750
- CLog(CLogTypes.info, 'Error in mapbox.addMarkers: ' + ex);
751
- }
752
- reject(ex);
753
- }
880
+ initEventHandlerShim(settings, mapboxNativeViewInstance) {
881
+ if (Trace.isEnabled()) {
882
+ CLog(CLogTypes.info, 'Mapbox:initEventHandlerShim(): top');
883
+ }
884
+ this.setOnMapClickListener((point) => this.checkForClickEvent(point), mapboxNativeViewInstance);
885
+ }
886
+ onMapEvent(eventName, id, callback, nativeMapView) {
887
+ if (typeof this.eventCallbacks[eventName] == 'undefined') {
888
+ this.eventCallbacks[eventName] = [];
889
+ }
890
+ this.eventCallbacks[eventName].push({
891
+ id,
892
+ callback
754
893
  });
755
894
  }
756
- removeMarkers(ids, nativeMap) {
757
- return new Promise((resolve, reject) => {
758
- try {
759
- const theMap = nativeMap || this._mapboxViewInstance;
760
- const markersToRemove = [];
761
- _markers.forEach((marker) => {
762
- if (!ids || (marker.id && ids.indexOf(marker.id) > -1)) {
763
- markersToRemove.push(marker.ios);
895
+ offMapEvent(eventName, id, nativeMapView) {
896
+ if (typeof this.eventCallbacks[eventName] == 'undefined') {
897
+ return;
898
+ }
899
+ this.eventCallbacks[eventName] = this.eventCallbacks[eventName].filter((entry) => entry.id !== id);
900
+ }
901
+ checkForClickEvent(point, nativeMap) {
902
+ if (Trace.isEnabled()) {
903
+ CLog(CLogTypes.info, 'Mapbox:checkForClickEvent(): got click event with point:', point);
904
+ }
905
+ this.eventCallbacks['click'] &&
906
+ this.eventCallbacks['click'].forEach((eventListener) => {
907
+ this.queryRenderedFeatures({ point, layers: [eventListener.id] }, nativeMap)
908
+ .then((response) => {
909
+ if (response.length > 0) {
910
+ eventListener.callback(response);
764
911
  }
912
+ })
913
+ .catch((err) => {
914
+ console.error('click error ', eventListener.id, err);
765
915
  });
766
- if (ids) {
767
- _markers = _markers.filter((marker) => ids.indexOf(marker.id) < 0);
768
- }
769
- else {
770
- _markers = [];
771
- }
772
- if (markersToRemove.length > 0) {
773
- theMap.removeAnnotations(markersToRemove);
774
- }
775
- resolve();
776
- }
777
- catch (ex) {
778
- if (Trace.isEnabled()) {
779
- CLog(CLogTypes.info, 'Error in mapbox.removeMarkers: ' + ex);
780
- }
781
- reject(ex);
782
- }
783
- });
916
+ });
917
+ this.view && this.view.notify({ eventName: 'mapClick', object: this.view, point });
918
+ return false;
784
919
  }
785
- setCenter(options, nativeMap) {
786
- return new Promise((resolve, reject) => {
787
- try {
788
- const theMap = nativeMap || this._mapboxViewInstance;
789
- const animated = options.animated === undefined || options.animated;
790
- const coordinate = CLLocationCoordinate2DMake(options.lat, options.lng);
791
- theMap.setCenterCoordinateAnimated(coordinate, animated);
792
- resolve();
793
- }
794
- catch (ex) {
795
- if (Trace.isEnabled()) {
796
- CLog(CLogTypes.info, 'Error in mapbox.setCenter: ' + ex);
797
- }
798
- reject(ex);
920
+ _addMarkers(markers, nativeMap) {
921
+ if (!markers) {
922
+ if (Trace.isEnabled()) {
923
+ CLog(CLogTypes.info, 'No markers passed');
799
924
  }
800
- });
801
- }
802
- getCenter(nativeMap) {
803
- return new Promise((resolve, reject) => {
804
- try {
805
- const theMap = nativeMap || this._mapboxViewInstance;
806
- const coordinate = theMap.centerCoordinate;
807
- resolve({
808
- lat: coordinate.latitude,
809
- lng: coordinate.longitude
810
- });
925
+ return;
926
+ }
927
+ if (!Array.isArray(markers)) {
928
+ if (Trace.isEnabled()) {
929
+ CLog(CLogTypes.info, "markers must be passed as an Array: [{title: 'foo'}]");
811
930
  }
812
- catch (ex) {
813
- if (Trace.isEnabled()) {
814
- CLog(CLogTypes.info, 'Error in mapbox.getCenter: ' + ex);
931
+ return;
932
+ }
933
+ const theMap = nativeMap || this._mapboxViewInstance;
934
+ _downloadMarkerImages(markers).then((updatedMarkers) => {
935
+ updatedMarkers.forEach((marker) => {
936
+ const lat = marker.lat;
937
+ const lng = marker.lng;
938
+ const point = MGLPointAnnotation.new();
939
+ point.coordinate = CLLocationCoordinate2DMake(lat, lng);
940
+ point.title = marker.title;
941
+ point.subtitle = marker.subtitle;
942
+ _markers.push(marker);
943
+ theMap.addAnnotation(point);
944
+ if (marker.selected) {
945
+ theMap.selectAnnotationAnimated(point, false);
815
946
  }
816
- reject(ex);
817
- }
947
+ marker.ios = point;
948
+ marker.update = (newSettings) => {
949
+ _markers.forEach((_marker) => {
950
+ if (marker.id === _marker.id) {
951
+ if (newSettings.onTap !== undefined) {
952
+ _marker.onTap = newSettings.onTap;
953
+ }
954
+ if (newSettings.onCalloutTap !== undefined) {
955
+ _marker.onCalloutTap = newSettings.onCalloutTap;
956
+ }
957
+ if (newSettings.title !== undefined) {
958
+ _marker.ios.title = _marker.title = newSettings.title;
959
+ }
960
+ if (newSettings.subtitle !== undefined) {
961
+ _marker.ios.subtitle = _marker.subtitle = newSettings.subtitle;
962
+ }
963
+ if (newSettings.lat && newSettings.lng) {
964
+ _marker.lat = newSettings.lat;
965
+ _marker.lng = newSettings.lng;
966
+ _marker.ios.coordinate = CLLocationCoordinate2DMake(newSettings.lat, newSettings.lng);
967
+ }
968
+ if (newSettings.selected) {
969
+ theMap.selectAnnotationAnimated(_marker.ios, false);
970
+ }
971
+ }
972
+ });
973
+ };
974
+ });
818
975
  });
819
976
  }
820
- setZoomLevel(options, nativeMap) {
977
+ show(options) {
978
+ if (Trace.isEnabled()) {
979
+ CLog(CLogTypes.info, 'show(): top with options:', options);
980
+ }
821
981
  return new Promise((resolve, reject) => {
822
982
  try {
823
- const theMap = nativeMap || this._mapboxViewInstance;
824
- const animated = options.animated === undefined || options.animated;
825
- const level = options.level;
826
- if (level >= 0 && level <= 20) {
827
- theMap.setZoomLevelAnimated(level, animated);
828
- resolve();
829
- }
830
- else {
831
- reject('invalid ZoomLevel, use any double value from 0 to 20 (like 8.3)');
832
- }
833
- }
834
- catch (ex) {
835
- if (Trace.isEnabled()) {
836
- CLog(CLogTypes.info, 'Error in mapbox.setZoomLevel: ' + ex);
983
+ const settings = Mapbox.merge(options, Mapbox.defaults);
984
+ if (settings.accessToken === undefined) {
985
+ reject("Please set the 'accessToken' parameter");
986
+ return;
837
987
  }
838
- reject(ex);
839
- }
840
- });
841
- }
842
- getZoomLevel(nativeMap) {
843
- return new Promise((resolve, reject) => {
844
- try {
845
- const theMap = nativeMap || this._mapboxViewInstance;
846
- resolve(theMap.zoomLevel);
847
- }
848
- catch (ex) {
849
- if (Trace.isEnabled()) {
850
- CLog(CLogTypes.info, 'Error in mapbox.getZoomLevel: ' + ex);
988
+ if (this._mapboxViewInstance) {
989
+ this._mapboxViewInstance.removeFromSuperview();
851
990
  }
852
- reject(ex);
853
- }
854
- });
855
- }
856
- setTilt(options, nativeMap) {
857
- return new Promise((resolve, reject) => {
858
- try {
859
- const theMap = nativeMap || this._mapboxViewInstance;
860
- const cam = theMap.camera;
861
- cam.pitch = options.tilt;
862
- const durationMs = options.duration ? options.duration : 5000;
863
- theMap.setCameraWithDurationAnimationTimingFunction(cam, durationMs / 1000, CAMediaTimingFunction.functionWithName(kCAMediaTimingFunctionEaseInEaseOut));
991
+ 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);
992
+ MGLAccountManager.accessToken = settings.accessToken;
993
+ this._mapboxViewInstance = MGLMapView.alloc().initWithFrameStyleURL(mapFrame, styleURL);
994
+ _setMapboxMapOptions(this._mapboxViewInstance, settings);
995
+ this._mapboxViewInstance.delegate = MGLMapViewDelegateImpl.new().initWithCallback((mapView) => {
996
+ resolve({
997
+ ios: mapView
998
+ });
999
+ });
1000
+ _markers = [];
1001
+ this._addMarkers(settings.markers);
864
1002
  setTimeout(() => {
865
- resolve();
866
- }, durationMs);
1003
+ view.addSubview(this._mapboxViewInstance);
1004
+ }, 500);
867
1005
  }
868
1006
  catch (ex) {
869
1007
  if (Trace.isEnabled()) {
870
- CLog(CLogTypes.info, 'Error in mapbox.setTilt: ' + ex);
1008
+ CLog(CLogTypes.info, 'Error in mapbox.show: ' + ex);
871
1009
  }
872
1010
  reject(ex);
873
1011
  }
874
1012
  });
875
1013
  }
876
- getTilt(nativeMap) {
1014
+ hide() {
877
1015
  return new Promise((resolve, reject) => {
878
1016
  try {
879
- const theMap = nativeMap || this._mapboxViewInstance;
880
- resolve(theMap.camera.pitch);
1017
+ if (this._mapboxViewInstance) {
1018
+ this._mapboxViewInstance.removeFromSuperview();
1019
+ }
1020
+ resolve();
881
1021
  }
882
1022
  catch (ex) {
883
1023
  if (Trace.isEnabled()) {
884
- CLog(CLogTypes.info, 'Error in mapbox.getTilt: ' + ex);
1024
+ CLog(CLogTypes.info, 'Error in mapbox.hide: ' + ex);
885
1025
  }
886
1026
  reject(ex);
887
1027
  }
888
1028
  });
889
1029
  }
890
- getUserLocation(nativeMap) {
1030
+ unhide() {
891
1031
  return new Promise((resolve, reject) => {
892
1032
  try {
893
- const theMap = nativeMap || this._mapboxViewInstance;
894
- const loc = theMap.userLocation;
895
- if (loc === null) {
896
- reject('Location not available');
1033
+ if (this._mapboxViewInstance) {
1034
+ const view = UIApplication.sharedApplication.keyWindow.rootViewController.view;
1035
+ view.addSubview(this._mapboxViewInstance);
1036
+ resolve();
897
1037
  }
898
1038
  else {
899
- resolve(_getLocation(loc));
1039
+ reject('No map found');
900
1040
  }
901
1041
  }
902
1042
  catch (ex) {
903
1043
  if (Trace.isEnabled()) {
904
- CLog(CLogTypes.info, 'Error in mapbox.getUserLocation: ' + ex);
1044
+ CLog(CLogTypes.info, 'Error in mapbox.unhide: ' + ex);
905
1045
  }
906
1046
  reject(ex);
907
1047
  }
908
1048
  });
909
1049
  }
910
- _stringToCameraMode(mode) {
911
- switch (mode) {
912
- case 'NONE':
913
- return 0;
914
- case 'NONE_COMPASS':
915
- if (Trace.isEnabled()) {
916
- CLog(CLogTypes.info, '_stringToCameraMode(): NONE_COMPASS unsupported on iOS');
917
- }
918
- return 0;
919
- case 'NONE_GPS':
920
- if (Trace.isEnabled()) {
921
- CLog(CLogTypes.info, '_stringToCameraMode(): NONE_GPS unsupported on iOS');
922
- }
923
- return 0;
924
- case 'TRACKING':
925
- return 1;
926
- case 'TRACK_COMPASS':
927
- return 2;
928
- case 'TRACKING_GPS':
929
- return 1;
930
- case 'TRACK_GPS_NORTH':
931
- return 3;
932
- }
1050
+ destroy(nativeMap) {
1051
+ return new Promise((resolve, reject) => {
1052
+ const theMap = nativeMap || this._mapboxViewInstance;
1053
+ if (theMap) {
1054
+ theMap.removeFromSuperview();
1055
+ theMap.delegate = null;
1056
+ }
1057
+ resolve();
1058
+ });
933
1059
  }
934
- _stringToRenderMode(mode) {
935
- let renderMode;
936
- switch (mode) {
937
- case 'NORMAL':
938
- return 'NORMAL';
939
- case 'COMPASS':
940
- return 'COMPASS';
941
- case 'GPS':
942
- return 'GPS';
943
- }
1060
+ onStart(nativeMap) {
1061
+ return Promise.resolve();
944
1062
  }
945
- showUserLocationMarker(options, nativeMap) {
1063
+ onResume(nativeMap) {
1064
+ return Promise.resolve();
1065
+ }
1066
+ onPause(nativeMap) {
1067
+ return Promise.resolve();
1068
+ }
1069
+ onStop(nativeMap) {
1070
+ return Promise.resolve();
1071
+ }
1072
+ onLowMemory(nativeMap) {
1073
+ return Promise.resolve();
1074
+ }
1075
+ onDestroy(nativeMap) {
1076
+ return Promise.resolve();
1077
+ }
1078
+ setMapStyle(style, nativeMap) {
946
1079
  return new Promise((resolve, reject) => {
947
1080
  try {
948
1081
  const theMap = nativeMap || this._mapboxViewInstance;
949
- theMap.showsUserLocation = true;
950
- theMap.userTrackingMode = this._stringToCameraMode(options.cameraMode);
951
- theMap.showsUserHeadingIndicator = true;
952
- this.userLocationRenderMode = this._stringToRenderMode(options.renderMode);
953
1082
  const delegate = theMap.delegate;
954
- delegate.changeUserLocationRenderMode(this.userLocationRenderMode);
955
- if (typeof options.clickListener != 'undefined') {
956
- delegate.setUserLocationClickListener(options.clickListener);
957
- }
958
- resolve();
1083
+ delegate.setStyleLoadedCallback((mapView) => {
1084
+ if (Trace.isEnabled()) {
1085
+ CLog(CLogTypes.info, 'Mapbox:setMapStyle(): style loaded callback returned.');
1086
+ }
1087
+ resolve();
1088
+ });
1089
+ theMap.styleURL = _getMapStyle(style);
959
1090
  }
960
1091
  catch (ex) {
961
1092
  if (Trace.isEnabled()) {
962
- CLog(CLogTypes.info, 'Error in mapbox.getUserLocation: ' + ex);
1093
+ CLog(CLogTypes.info, 'Error in mapbox.setMapStyle: ' + ex);
963
1094
  }
964
1095
  reject(ex);
965
1096
  }
966
1097
  });
967
1098
  }
968
- hideUserLocationMarker(nativeMap) {
1099
+ async getImage(imageId, nativeMap) {
969
1100
  return new Promise((resolve, reject) => {
1101
+ const theMap = nativeMap || this._mapboxViewInstance;
1102
+ if (!theMap) {
1103
+ reject('No map has been loaded');
1104
+ return;
1105
+ }
970
1106
  try {
971
- resolve();
1107
+ const nativeImage = theMap.style.imageForName(imageId);
1108
+ const img = new ImageSource(nativeImage);
1109
+ resolve(img);
972
1110
  }
973
1111
  catch (ex) {
1112
+ reject('Error during getImage: ' + ex);
974
1113
  if (Trace.isEnabled()) {
975
- CLog(CLogTypes.info, 'Error in mapbox.getUserLocation: ' + ex);
1114
+ CLog(CLogTypes.info, 'Error in mapbox.getImage: ' + ex);
976
1115
  }
977
- reject(ex);
1116
+ throw ex;
978
1117
  }
979
1118
  });
980
1119
  }
981
- changeUserLocationMarkerMode(renderModeString, cameraModeString, nativeMap) {
1120
+ async addImage(imageId, image, nativeMap) {
982
1121
  return new Promise((resolve, reject) => {
1122
+ const theMap = nativeMap || this._mapboxViewInstance;
1123
+ if (!theMap) {
1124
+ reject('No map has been loaded');
1125
+ return;
1126
+ }
1127
+ if (!image.startsWith('res://')) {
1128
+ const appPath = knownFolders.currentApp().path;
1129
+ image = appPath + '/' + image.replace('~/', '');
1130
+ }
1131
+ const img = ImageSource.fromFileOrResourceSync(image);
983
1132
  try {
984
- const theMap = nativeMap || this._mapboxViewInstance;
985
- if (Trace.isEnabled()) {
986
- CLog(CLogTypes.info, "Mapbox::changeUserLocationMarkerMode(): changing renderMode to '" + renderModeString + "' cameraMode '" + cameraModeString + "'");
987
- }
988
- theMap.userTrackingMode = this._stringToCameraMode(cameraModeString);
989
- const delegate = theMap.delegate;
990
- const renderMode = this._stringToRenderMode(renderModeString);
991
- delegate.changeUserLocationRenderMode(renderMode);
1133
+ theMap.style.setImageForName(img.ios, imageId);
1134
+ resolve();
992
1135
  }
993
1136
  catch (ex) {
1137
+ reject('Error during addImage: ' + ex);
994
1138
  if (Trace.isEnabled()) {
995
- CLog(CLogTypes.info, 'Error in mapbox.showUserLocationMarker: ' + ex);
1139
+ CLog(CLogTypes.info, 'Error in mapbox.addImage: ' + ex);
996
1140
  }
997
- reject(ex);
1141
+ throw ex;
998
1142
  }
999
1143
  });
1000
1144
  }
1001
- forceUserLocationUpdate(location, nativeMap) { }
1002
- queryRenderedFeatures(options, nativeMap) {
1145
+ async removeImage(imageId, nativeMap) {
1003
1146
  return new Promise((resolve, reject) => {
1147
+ const theMap = nativeMap || this._mapboxViewInstance;
1148
+ if (!theMap) {
1149
+ reject('No map has been loaded');
1150
+ return;
1151
+ }
1004
1152
  try {
1005
- const theMap = nativeMap || this._mapboxViewInstance;
1006
- if (options.point === undefined) {
1007
- reject("Please set the 'point' parameter");
1008
- return;
1009
- }
1010
- if (!options) {
1011
- options = {};
1012
- }
1013
- const { x, y } = theMap.convertCoordinateToPointToView({ latitude: options.point.lat, longitude: options.point.lng }, theMap);
1014
- const queryLayerIds = options.layers ? NSSet.setWithArray(iOSNativeHelper.collections.jsArrayToNSArray(options.layers)) : null;
1015
- const queryFilter = options.filter ? FilterParser.parseJson(options.filter) : null;
1016
- const features = theMap.visibleFeaturesAtPointInStyleLayersWithIdentifiersPredicate({ x, y }, queryLayerIds, queryFilter);
1017
- const result = [];
1018
- for (let i = 0; i < features.count; i++) {
1019
- const feature = features.objectAtIndex(i);
1020
- const featureJson = NSJSONSerialization.dataWithJSONObjectOptionsError(feature.geoJSONDictionary(), 0);
1021
- result.push(JSON.parse(NSString.alloc().initWithDataEncoding(featureJson, NSUTF8StringEncoding)));
1022
- }
1023
- resolve(result);
1153
+ theMap.style.removeImageForName(imageId);
1154
+ resolve();
1024
1155
  }
1025
1156
  catch (ex) {
1157
+ reject('Error during removeImage: ' + ex);
1026
1158
  if (Trace.isEnabled()) {
1027
- CLog(CLogTypes.info, 'Error in mapbox.queryRenderedFeatures: ' + ex);
1159
+ CLog(CLogTypes.info, 'Error in mapbox.removeImage: ' + ex);
1028
1160
  }
1029
- reject(ex);
1161
+ throw ex;
1030
1162
  }
1031
1163
  });
1032
1164
  }
1033
- querySourceFeatures(sourceId, options, nativeMap) {
1165
+ addMarkers(markers, nativeMap) {
1034
1166
  return new Promise((resolve, reject) => {
1035
1167
  try {
1036
1168
  const theMap = nativeMap || this._mapboxViewInstance;
1037
- if (!options) {
1038
- options = {};
1039
- }
1040
- const source = theMap.style.sourceWithIdentifier(sourceId);
1041
- if (!source) {
1042
- throw new Error(`Source with id "${sourceId}" not found.`);
1043
- }
1044
- let features;
1045
- const queryFilter = options.filter ? FilterParser.parseJson(options.filter) : null;
1046
- if (source instanceof MGLShapeSource) {
1047
- features = source.featuresMatchingPredicate(queryFilter);
1048
- }
1049
- else if (source instanceof MGLVectorTileSource) {
1050
- if (!options.sourceLayer) {
1051
- throw new Error('The option "sourceLayer" is required for vector sources.');
1052
- }
1053
- const sourceLayerIds = options.sourceLayer ? NSSet.setWithArray(iOSNativeHelper.collections.jsArrayToNSArray([options.sourceLayer])) : null;
1054
- features = source.featuresInSourceLayersWithIdentifiersPredicate(sourceLayerIds, queryFilter);
1055
- }
1056
- else {
1057
- throw new Error('Only sources from type "vector" or "geojson" are supported.');
1058
- }
1059
- const result = [];
1060
- for (let i = 0; i < features.count; i++) {
1061
- const feature = features.objectAtIndex(i);
1062
- const featureJson = NSJSONSerialization.dataWithJSONObjectOptionsError(feature.geoJSONDictionary(), 0);
1063
- result.push(JSON.parse(NSString.alloc().initWithDataEncoding(featureJson, NSUTF8StringEncoding)));
1064
- }
1065
- resolve(result);
1169
+ this._addMarkers(markers, theMap);
1170
+ resolve();
1066
1171
  }
1067
1172
  catch (ex) {
1068
1173
  if (Trace.isEnabled()) {
1069
- CLog(CLogTypes.info, 'Error in mapbox.querySourceFeatures: ' + ex);
1174
+ CLog(CLogTypes.info, 'Error in mapbox.addMarkers: ' + ex);
1070
1175
  }
1071
1176
  reject(ex);
1072
1177
  }
1073
1178
  });
1074
1179
  }
1075
- addPolygon(options, nativeMap) {
1180
+ removeMarkers(ids, nativeMap) {
1076
1181
  return new Promise((resolve, reject) => {
1077
- const theMap = nativeMap || this._mapboxViewInstance;
1078
- const points = options.points;
1079
- if (points === undefined) {
1080
- reject("Please set the 'points' parameter");
1081
- return;
1082
- }
1083
- const coordinateArray = [];
1084
- points.forEach((point) => coordinateArray.push([point.lng, point.lat]));
1085
- const polygonID = `polygon_${options.id || new Date().getTime()}`;
1086
- if (theMap.style.sourceWithIdentifier(polygonID)) {
1087
- reject("Remove the polygon with this id first with 'removePolygons': " + polygonID);
1088
- return;
1089
- }
1090
- const geoJSON = `{
1091
- "type": "FeatureCollection",
1092
- "features": [
1093
- {
1094
- "id": ${JSON.stringify(polygonID)},
1095
- "type": "Feature",
1096
- "properties": {
1097
- },
1098
- "geometry": {
1099
- "type": "Polygon",
1100
- "coordinates": [${JSON.stringify(coordinateArray)}]
1182
+ try {
1183
+ const theMap = nativeMap || this._mapboxViewInstance;
1184
+ const markersToRemove = [];
1185
+ _markers.forEach((marker) => {
1186
+ if (!ids || (marker.id && ids.indexOf(marker.id) > -1)) {
1187
+ markersToRemove.push(marker.ios);
1101
1188
  }
1189
+ });
1190
+ if (ids) {
1191
+ _markers = _markers.filter((marker) => ids.indexOf(marker.id) < 0);
1102
1192
  }
1103
- ]
1104
- }`;
1105
- const geoDataStr = NSString.stringWithString(geoJSON);
1106
- const geoData = geoDataStr.dataUsingEncoding(NSUTF8StringEncoding);
1107
- const geoDataBase64Enc = geoData.base64EncodedStringWithOptions(0);
1108
- const geo = NSData.alloc().initWithBase64EncodedStringOptions(geoDataBase64Enc, null);
1109
- const shape = MGLShape.shapeWithDataEncodingError(geo, NSUTF8StringEncoding);
1110
- const source = MGLShapeSource.alloc().initWithIdentifierShapeOptions(polygonID, shape, null);
1111
- theMap.style.addSource(source);
1112
- if (options.strokeColor || options.strokeWidth || options.strokeOpacity) {
1113
- const strokeLayer = MGLLineStyleLayer.alloc().initWithIdentifierSource(polygonID + '_stroke', source);
1114
- strokeLayer.lineColor = NSExpression.expressionForConstantValue(!options.strokeColor ? UIColor.blackColor : options.strokeColor instanceof Color ? options.strokeColor.ios : new Color(options.strokeColor).ios);
1115
- strokeLayer.lineWidth = NSExpression.expressionForConstantValue(options.strokeWidth || 5);
1116
- strokeLayer.lineOpacity = NSExpression.expressionForConstantValue(options.strokeOpacity === undefined ? 1 : options.strokeOpacity);
1117
- theMap.style.addLayer(strokeLayer);
1193
+ else {
1194
+ _markers = [];
1195
+ }
1196
+ if (markersToRemove.length > 0) {
1197
+ theMap.removeAnnotations(markersToRemove);
1198
+ }
1199
+ resolve();
1200
+ }
1201
+ catch (ex) {
1202
+ if (Trace.isEnabled()) {
1203
+ CLog(CLogTypes.info, 'Error in mapbox.removeMarkers: ' + ex);
1204
+ }
1205
+ reject(ex);
1118
1206
  }
1119
- const layer = MGLFillStyleLayer.alloc().initWithIdentifierSource(polygonID, source);
1120
- layer.fillColor = NSExpression.expressionForConstantValue(!options.fillColor ? UIColor.blackColor : options.fillColor instanceof Color ? options.fillColor.ios : new Color(options.fillColor).ios);
1121
- layer.fillOpacity = NSExpression.expressionForConstantValue(options.fillOpacity === undefined ? 1 : options.fillOpacity);
1122
- theMap.style.addLayer(layer);
1123
- resolve();
1124
1207
  });
1125
1208
  }
1126
- addPolyline(options, nativeMap) {
1209
+ setCenter(options, nativeMap) {
1127
1210
  return new Promise((resolve, reject) => {
1128
- const theMap = nativeMap || this._mapboxViewInstance;
1129
- const points = options.points;
1130
- if (points === undefined) {
1131
- reject("Please set the 'points' parameter");
1132
- return;
1211
+ try {
1212
+ const theMap = nativeMap || this._mapboxViewInstance;
1213
+ const animated = options.animated === undefined || options.animated;
1214
+ const coordinate = CLLocationCoordinate2DMake(options.lat, options.lng);
1215
+ theMap.setCenterCoordinateAnimated(coordinate, animated);
1216
+ resolve();
1133
1217
  }
1134
- const coordinateArray = [];
1135
- points.forEach((point) => coordinateArray.push([point.lng, point.lat]));
1136
- const polylineID = 'polyline_' + (options.id || new Date().getTime());
1137
- if (theMap.style.sourceWithIdentifier(polylineID)) {
1138
- reject("Remove the polyline with this id first with 'removePolylines': " + polylineID);
1139
- return;
1218
+ catch (ex) {
1219
+ if (Trace.isEnabled()) {
1220
+ CLog(CLogTypes.info, 'Error in mapbox.setCenter: ' + ex);
1221
+ }
1222
+ reject(ex);
1140
1223
  }
1141
- const geoJSON = `{"type": "FeatureCollection", "features": [{"type": "Feature","properties": {},"geometry": {"type": "LineString", "coordinates": ${JSON.stringify(coordinateArray)}}}]}`;
1142
- const geoDataStr = NSString.stringWithString(geoJSON);
1143
- const geoData = geoDataStr.dataUsingEncoding(NSUTF8StringEncoding);
1144
- const geoDataBase64Enc = geoData.base64EncodedStringWithOptions(0);
1145
- const geo = NSData.alloc().initWithBase64EncodedStringOptions(geoDataBase64Enc, null);
1146
- const shape = MGLShape.shapeWithDataEncodingError(geo, NSUTF8StringEncoding);
1147
- const source = MGLShapeSource.alloc().initWithIdentifierShapeOptions(polylineID, shape, null);
1148
- theMap.style.addSource(source);
1149
- const layer = MGLLineStyleLayer.alloc().initWithIdentifierSource(polylineID, source);
1150
- layer.lineColor = NSExpression.expressionForConstantValue(!options.color ? UIColor.blackColor : options.color instanceof Color ? options.color.ios : new Color(options.color).ios);
1151
- layer.lineWidth = NSExpression.expressionForConstantValue(options.width || 5);
1152
- layer.lineOpacity = NSExpression.expressionForConstantValue(options.opacity === undefined ? 1 : options.opacity);
1153
- theMap.style.addLayer(layer);
1154
- resolve();
1155
1224
  });
1156
1225
  }
1157
- removePolyById(theMap, id) {
1158
- let layer = theMap.style.layerWithIdentifier(id);
1159
- if (layer !== null) {
1160
- theMap.style.removeLayer(layer);
1161
- }
1162
- layer = theMap.style.layerWithIdentifier(id + '_stroke');
1163
- if (layer !== null) {
1164
- theMap.style.removeLayer(layer);
1165
- }
1166
- const source = theMap.style.sourceWithIdentifier(id);
1167
- if (source !== null) {
1168
- theMap.style.removeSource(source);
1169
- }
1170
- }
1171
- removePolys(polyType, ids, nativeMap) {
1172
- return new Promise((resolve) => {
1173
- const theMap = nativeMap || this._mapboxViewInstance;
1174
- ids.forEach((id) => this.removePolyById(theMap, polyType + id));
1175
- resolve();
1226
+ getCenter(nativeMap) {
1227
+ return new Promise((resolve, reject) => {
1228
+ try {
1229
+ const theMap = nativeMap || this._mapboxViewInstance;
1230
+ const coordinate = theMap.centerCoordinate;
1231
+ resolve({
1232
+ lat: coordinate.latitude,
1233
+ lng: coordinate.longitude
1234
+ });
1235
+ }
1236
+ catch (ex) {
1237
+ if (Trace.isEnabled()) {
1238
+ CLog(CLogTypes.info, 'Error in mapbox.getCenter: ' + ex);
1239
+ }
1240
+ reject(ex);
1241
+ }
1176
1242
  });
1177
1243
  }
1178
- removePolygons(ids, nativeMap) {
1179
- return this.removePolys('polygon_', ids, nativeMap);
1180
- }
1181
- removePolylines(ids, nativeMap) {
1182
- return this.removePolys('polyline_', ids, nativeMap);
1183
- }
1184
- animateCamera(options, nativeMap) {
1244
+ setZoomLevel(options, nativeMap) {
1185
1245
  return new Promise((resolve, reject) => {
1186
1246
  try {
1187
1247
  const theMap = nativeMap || this._mapboxViewInstance;
1188
- let cam;
1189
- if (options.bounds) {
1190
- const padding = options.padding || 0;
1191
- const insets = {
1192
- top: padding,
1193
- left: padding,
1194
- bottom: padding,
1195
- right: padding
1196
- };
1197
- const bounds = {
1198
- sw: CLLocationCoordinate2DMake(options.bounds.south, options.bounds.west),
1199
- ne: CLLocationCoordinate2DMake(options.bounds.north, options.bounds.east)
1200
- };
1201
- cam = theMap.cameraThatFitsCoordinateBoundsEdgePadding(bounds, insets);
1248
+ const animated = options.animated === undefined || options.animated;
1249
+ const level = options.level;
1250
+ if (level >= 0 && level <= 20) {
1251
+ theMap.setZoomLevelAnimated(level, animated);
1252
+ resolve();
1202
1253
  }
1203
1254
  else {
1204
- const target = options.target;
1205
- if (target === undefined) {
1206
- reject("Please set the 'target' parameter");
1207
- return;
1208
- }
1209
- cam = theMap.camera;
1210
- cam.centerCoordinate = CLLocationCoordinate2DMake(target.lat, target.lng);
1211
- }
1212
- if (options.altitude) {
1213
- cam.altitude = options.altitude;
1214
- }
1215
- if (options.bearing) {
1216
- cam.heading = options.bearing;
1255
+ reject('invalid ZoomLevel, use any double value from 0 to 20 (like 8.3)');
1217
1256
  }
1218
- if (options.tilt) {
1219
- cam.pitch = options.tilt;
1257
+ }
1258
+ catch (ex) {
1259
+ if (Trace.isEnabled()) {
1260
+ CLog(CLogTypes.info, 'Error in mapbox.setZoomLevel: ' + ex);
1220
1261
  }
1221
- if (options.zoomLevel && options.target) {
1222
- cam.altitude = MGLAltitudeForZoomLevel(options.zoomLevel, cam.pitch, options.target.lat, theMap.frame.size);
1262
+ reject(ex);
1263
+ }
1264
+ });
1265
+ }
1266
+ getZoomLevel(nativeMap) {
1267
+ return new Promise((resolve, reject) => {
1268
+ try {
1269
+ const theMap = nativeMap || this._mapboxViewInstance;
1270
+ resolve(theMap.zoomLevel);
1271
+ }
1272
+ catch (ex) {
1273
+ if (Trace.isEnabled()) {
1274
+ CLog(CLogTypes.info, 'Error in mapbox.getZoomLevel: ' + ex);
1223
1275
  }
1224
- const durationMs = options.duration ? options.duration : 10000;
1276
+ reject(ex);
1277
+ }
1278
+ });
1279
+ }
1280
+ setTilt(options, nativeMap) {
1281
+ return new Promise((resolve, reject) => {
1282
+ try {
1283
+ const theMap = nativeMap || this._mapboxViewInstance;
1284
+ const cam = theMap.camera;
1285
+ cam.pitch = options.tilt;
1286
+ const durationMs = options.duration ? options.duration : 5000;
1225
1287
  theMap.setCameraWithDurationAnimationTimingFunction(cam, durationMs / 1000, CAMediaTimingFunction.functionWithName(kCAMediaTimingFunctionEaseInEaseOut));
1226
1288
  setTimeout(() => {
1227
1289
  resolve();
@@ -1229,341 +1291,375 @@ export class Mapbox extends MapboxCommon {
1229
1291
  }
1230
1292
  catch (ex) {
1231
1293
  if (Trace.isEnabled()) {
1232
- CLog(CLogTypes.info, 'Error in mapbox.animateCamera: ' + ex);
1294
+ CLog(CLogTypes.info, 'Error in mapbox.setTilt: ' + ex);
1233
1295
  }
1234
1296
  reject(ex);
1235
1297
  }
1236
1298
  });
1237
1299
  }
1238
- setOnMapClickListener(listener, nativeMap) {
1300
+ getTilt(nativeMap) {
1239
1301
  return new Promise((resolve, reject) => {
1240
1302
  try {
1241
1303
  const theMap = nativeMap || this._mapboxViewInstance;
1242
- if (!theMap) {
1243
- reject('No map has been loaded');
1244
- return;
1245
- }
1246
- theMap['mapTapHandler'] = MapTapHandlerImpl.initWithOwnerAndListenerForMap(new WeakRef(this), listener, theMap);
1247
- const tapGestureRecognizer = UITapGestureRecognizer.alloc().initWithTargetAction(theMap['mapTapHandler'], 'tap');
1248
- for (let i = 0; i < theMap.gestureRecognizers.count; i++) {
1249
- const recognizer = theMap.gestureRecognizers.objectAtIndex(i);
1250
- if (recognizer instanceof UITapGestureRecognizer) {
1251
- tapGestureRecognizer.requireGestureRecognizerToFail(recognizer);
1252
- }
1253
- }
1254
- theMap.addGestureRecognizer(tapGestureRecognizer);
1255
- resolve();
1304
+ resolve(theMap.camera.pitch);
1256
1305
  }
1257
1306
  catch (ex) {
1258
1307
  if (Trace.isEnabled()) {
1259
- CLog(CLogTypes.info, 'Error in mapbox.setOnMapClickListener: ' + ex);
1308
+ CLog(CLogTypes.info, 'Error in mapbox.getTilt: ' + ex);
1260
1309
  }
1261
1310
  reject(ex);
1262
1311
  }
1263
1312
  });
1264
1313
  }
1265
- setOnMapLongClickListener(listener, nativeMap) {
1314
+ getUserLocation(nativeMap) {
1266
1315
  return new Promise((resolve, reject) => {
1267
1316
  try {
1268
1317
  const theMap = nativeMap || this._mapboxViewInstance;
1269
- if (!theMap) {
1270
- reject('No map has been loaded');
1271
- return;
1318
+ const loc = theMap.userLocation;
1319
+ if (loc === null) {
1320
+ reject('Location not available');
1272
1321
  }
1273
- theMap['mapLongPressHandler'] = MapLongPressHandlerImpl.initWithOwnerAndListenerForMap(new WeakRef(this), listener, theMap);
1274
- const longPressGestureRecognizer = UILongPressGestureRecognizer.alloc().initWithTargetAction(theMap['mapLongPressHandler'], 'longPress');
1275
- for (let i = 0; i < theMap.gestureRecognizers.count; i++) {
1276
- const recognizer = theMap.gestureRecognizers.objectAtIndex(i);
1277
- if (recognizer instanceof UILongPressGestureRecognizer) {
1278
- longPressGestureRecognizer.requireGestureRecognizerToFail(recognizer);
1279
- }
1322
+ else {
1323
+ resolve(_getLocation(loc));
1280
1324
  }
1281
- theMap.addGestureRecognizer(longPressGestureRecognizer);
1282
- resolve();
1283
1325
  }
1284
1326
  catch (ex) {
1285
1327
  if (Trace.isEnabled()) {
1286
- CLog(CLogTypes.info, 'Error in mapbox.setOnMapClickListener: ' + ex);
1328
+ CLog(CLogTypes.info, 'Error in mapbox.getUserLocation: ' + ex);
1287
1329
  }
1288
1330
  reject(ex);
1289
1331
  }
1290
1332
  });
1291
1333
  }
1292
- setOnScrollListener(listener, nativeMap) {
1334
+ _stringToCameraMode(mode) {
1335
+ switch (mode) {
1336
+ case 'NONE':
1337
+ return 0;
1338
+ case 'NONE_COMPASS':
1339
+ if (Trace.isEnabled()) {
1340
+ CLog(CLogTypes.info, '_stringToCameraMode(): NONE_COMPASS unsupported on iOS');
1341
+ }
1342
+ return 0;
1343
+ case 'NONE_GPS':
1344
+ if (Trace.isEnabled()) {
1345
+ CLog(CLogTypes.info, '_stringToCameraMode(): NONE_GPS unsupported on iOS');
1346
+ }
1347
+ return 0;
1348
+ case 'TRACKING':
1349
+ return 1;
1350
+ case 'TRACKING_COMPASS':
1351
+ return 2;
1352
+ case 'TRACKING_GPS':
1353
+ return 1;
1354
+ case 'TRACKING_GPS_NORTH':
1355
+ return 3;
1356
+ }
1357
+ }
1358
+ _stringToRenderMode(mode) {
1359
+ let renderMode;
1360
+ switch (mode) {
1361
+ case 'NORMAL':
1362
+ return 'NORMAL';
1363
+ case 'COMPASS':
1364
+ return 'COMPASS';
1365
+ case 'GPS':
1366
+ return 'GPS';
1367
+ }
1368
+ }
1369
+ showUserLocationMarker(options, nativeMap) {
1293
1370
  return new Promise((resolve, reject) => {
1294
1371
  try {
1295
1372
  const theMap = nativeMap || this._mapboxViewInstance;
1296
- if (!theMap) {
1297
- reject('No map has been loaded');
1298
- return;
1299
- }
1300
- theMap['mapPanHandler'] = MapPanHandlerImpl.initWithOwnerAndListenerForMap(new WeakRef(this), listener, theMap);
1301
- for (let i = 0; i < theMap.gestureRecognizers.count; i++) {
1302
- const recognizer = theMap.gestureRecognizers.objectAtIndex(i);
1303
- if (recognizer instanceof UIPanGestureRecognizer) {
1304
- recognizer.addTargetAction(theMap['mapPanHandler'], 'pan');
1305
- break;
1306
- }
1373
+ theMap.showsUserLocation = true;
1374
+ theMap.userTrackingMode = this._stringToCameraMode(options.cameraMode);
1375
+ theMap.showsUserHeadingIndicator = true;
1376
+ this.userLocationRenderMode = this._stringToRenderMode(options.renderMode);
1377
+ const delegate = theMap.delegate;
1378
+ delegate.changeUserLocationRenderMode(this.userLocationRenderMode);
1379
+ if (typeof options.clickListener != 'undefined') {
1380
+ delegate.setUserLocationClickListener(options.clickListener);
1307
1381
  }
1308
1382
  resolve();
1309
1383
  }
1310
1384
  catch (ex) {
1311
1385
  if (Trace.isEnabled()) {
1312
- CLog(CLogTypes.info, 'Error in mapbox.setOnScrollListener: ' + ex);
1386
+ CLog(CLogTypes.info, 'Error in mapbox.getUserLocation: ' + ex);
1313
1387
  }
1314
1388
  reject(ex);
1315
1389
  }
1316
1390
  });
1317
1391
  }
1318
- setOnMoveBeginListener(listener, nativeMap) {
1392
+ hideUserLocationMarker(nativeMap) {
1319
1393
  return new Promise((resolve, reject) => {
1320
1394
  try {
1321
- const theMap = nativeMap || this._mapboxViewInstance;
1322
- if (!theMap) {
1323
- reject('No map has been loaded');
1324
- return;
1325
- }
1326
- theMap['mapOnMoveBeginHandler'] = MapPanHandlerImpl.initWithOwnerAndListenerForMap(new WeakRef(this), listener, theMap);
1327
- theMap['mapOnMoveBeginHandler'].setOnMoveBegin();
1328
- for (let i = 0; i < theMap.gestureRecognizers.count; i++) {
1329
- const recognizer = theMap.gestureRecognizers.objectAtIndex(i);
1330
- if (recognizer instanceof UIPanGestureRecognizer) {
1331
- recognizer.addTargetAction(theMap['mapOnMoveBeginHandler'], 'pan');
1332
- break;
1333
- }
1334
- }
1335
1395
  resolve();
1336
1396
  }
1337
1397
  catch (ex) {
1338
1398
  if (Trace.isEnabled()) {
1339
- CLog(CLogTypes.info, 'Error in mapbox.setOnScrollListener: ' + ex);
1399
+ CLog(CLogTypes.info, 'Error in mapbox.getUserLocation: ' + ex);
1340
1400
  }
1341
1401
  reject(ex);
1342
1402
  }
1343
1403
  });
1344
1404
  }
1345
- setOnFlingListener(listener, nativeMap) {
1346
- return Promise.reject("'setOnFlingListener' is not supported on iOS");
1347
- }
1348
- async setOnCameraMoveListener(listener, nativeMap) {
1349
- const theMap = nativeMap || this._mapboxViewInstance;
1350
- if (theMap) {
1351
- theMap.delegate.setCameraChangedListener(listener);
1352
- }
1353
- else {
1354
- return Promise.reject('No map has been loaded');
1355
- }
1356
- }
1357
- setOnCameraMoveCancelListener(listener, nativeMap) {
1358
- return Promise.reject("'setOnCameraMoveCancelListener' not currently supported on iOS");
1359
- }
1360
- async setOnCameraIdleListener(listener, nativeMap) {
1361
- const theMap = nativeMap || this._mapboxViewInstance;
1362
- if (theMap) {
1363
- theMap.delegate.setCameraIdledListener(listener);
1364
- }
1365
- else {
1366
- return Promise.reject('No map has been loaded');
1367
- }
1368
- }
1369
- getViewport(nativeMap) {
1405
+ changeUserLocationMarkerMode(renderModeString, cameraModeString, nativeMap) {
1370
1406
  return new Promise((resolve, reject) => {
1371
1407
  try {
1372
1408
  const theMap = nativeMap || this._mapboxViewInstance;
1373
- if (!theMap) {
1374
- reject('No map has been loaded');
1375
- return;
1409
+ if (Trace.isEnabled()) {
1410
+ CLog(CLogTypes.info, "Mapbox::changeUserLocationMarkerMode(): changing renderMode to '" + renderModeString + "' cameraMode '" + cameraModeString + "'");
1376
1411
  }
1377
- const visibleBounds = theMap.visibleCoordinateBounds;
1378
- const bounds = {
1379
- north: visibleBounds.ne.latitude,
1380
- east: visibleBounds.ne.longitude,
1381
- south: visibleBounds.sw.latitude,
1382
- west: visibleBounds.sw.longitude
1383
- };
1384
- resolve({
1385
- bounds,
1386
- zoomLevel: theMap.zoomLevel
1387
- });
1412
+ theMap.userTrackingMode = this._stringToCameraMode(cameraModeString);
1413
+ const delegate = theMap.delegate;
1414
+ const renderMode = this._stringToRenderMode(renderModeString);
1415
+ delegate.changeUserLocationRenderMode(renderMode);
1388
1416
  }
1389
1417
  catch (ex) {
1390
1418
  if (Trace.isEnabled()) {
1391
- CLog(CLogTypes.info, 'Error in mapbox.getViewport: ' + ex);
1419
+ CLog(CLogTypes.info, 'Error in mapbox.showUserLocationMarker: ' + ex);
1392
1420
  }
1393
1421
  reject(ex);
1394
1422
  }
1395
1423
  });
1396
1424
  }
1397
- setViewport(options, nativeMap) {
1425
+ forceUserLocationUpdate(location, nativeMap) { }
1426
+ queryRenderedFeatures(options, nativeMap) {
1398
1427
  return new Promise((resolve, reject) => {
1399
1428
  try {
1400
1429
  const theMap = nativeMap || this._mapboxViewInstance;
1401
- if (!theMap) {
1402
- reject('No map has been loaded');
1430
+ if (options.point === undefined) {
1431
+ reject("Please set the 'point' parameter");
1403
1432
  return;
1404
1433
  }
1405
- const bounds = {
1406
- sw: CLLocationCoordinate2DMake(options.bounds.south, options.bounds.west),
1407
- ne: CLLocationCoordinate2DMake(options.bounds.north, options.bounds.east)
1408
- };
1409
- const animated = options.animated === undefined || options.animated;
1410
- const padding = Mapbox.merge(options.padding === undefined ? {} : options.padding, {
1411
- top: 25,
1412
- left: 25,
1413
- bottom: 25,
1414
- right: 25
1415
- });
1416
- theMap.setVisibleCoordinateBoundsEdgePaddingAnimated(bounds, padding, animated);
1417
- resolve();
1434
+ if (!options) {
1435
+ options = {};
1436
+ }
1437
+ const { x, y } = theMap.convertCoordinateToPointToView({ latitude: options.point.lat, longitude: options.point.lng }, theMap);
1438
+ const queryLayerIds = options.layers ? NSSet.setWithArray(Utils.ios.collections.jsArrayToNSArray(options.layers)) : null;
1439
+ const queryFilter = options.filter ? FilterParser.parseJson(options.filter) : null;
1440
+ const features = theMap.visibleFeaturesAtPointInStyleLayersWithIdentifiersPredicate({ x, y }, queryLayerIds, queryFilter);
1441
+ const result = [];
1442
+ for (let i = 0; i < features.count; i++) {
1443
+ const feature = features.objectAtIndex(i);
1444
+ const featureJson = NSJSONSerialization.dataWithJSONObjectOptionsError(feature.geoJSONDictionary(), 0);
1445
+ result.push(JSON.parse(NSString.alloc().initWithDataEncoding(featureJson, NSUTF8StringEncoding)));
1446
+ }
1447
+ resolve(result);
1418
1448
  }
1419
1449
  catch (ex) {
1420
1450
  if (Trace.isEnabled()) {
1421
- CLog(CLogTypes.info, 'Error in mapbox.setViewport: ' + ex);
1451
+ CLog(CLogTypes.info, 'Error in mapbox.queryRenderedFeatures: ' + ex);
1422
1452
  }
1423
1453
  reject(ex);
1424
1454
  }
1425
1455
  });
1426
1456
  }
1427
- downloadOfflineRegion(options) {
1457
+ querySourceFeatures(sourceId, options, nativeMap) {
1428
1458
  return new Promise((resolve, reject) => {
1429
1459
  try {
1430
- const styleURL = _getMapStyle(options.style);
1431
- const swCoordinate = CLLocationCoordinate2DMake(options.bounds.south, options.bounds.west);
1432
- const neCoordinate = CLLocationCoordinate2DMake(options.bounds.north, options.bounds.east);
1433
- const bounds = {
1434
- sw: swCoordinate,
1435
- ne: neCoordinate
1436
- };
1437
- const region = MGLTilePyramidOfflineRegion.alloc().initWithStyleURLBoundsFromZoomLevelToZoomLevel(styleURL, bounds, options.minZoom, options.maxZoom);
1438
- if (options.accessToken) {
1439
- MGLAccountManager.accessToken = options.accessToken;
1460
+ const theMap = nativeMap || this._mapboxViewInstance;
1461
+ if (!options) {
1462
+ options = {};
1440
1463
  }
1441
- if (options.onProgress) {
1442
- _addObserver(MGLOfflinePackProgressChangedNotification, (notification) => {
1443
- const offlinePack = notification.object;
1444
- const offlinePackProgress = offlinePack.progress;
1445
- const userInfo = NSKeyedUnarchiver.unarchiveObjectWithData(offlinePack.context);
1446
- const complete = offlinePackProgress.countOfResourcesCompleted === offlinePackProgress.countOfResourcesExpected;
1447
- options.onProgress({
1448
- name: userInfo.objectForKey('name'),
1449
- completed: offlinePackProgress.countOfResourcesCompleted,
1450
- expected: offlinePackProgress.countOfResourcesExpected,
1451
- percentage: Math.round((offlinePackProgress.countOfResourcesCompleted / offlinePackProgress.countOfResourcesExpected) * 10000) / 100,
1452
- complete
1453
- });
1454
- if (complete) {
1455
- resolve();
1456
- }
1457
- });
1464
+ const source = theMap.style.sourceWithIdentifier(sourceId);
1465
+ if (!source) {
1466
+ throw new Error(`Source with id "${sourceId}" not found.`);
1458
1467
  }
1459
- _addObserver(MGLOfflinePackErrorNotification, (notification) => {
1460
- const offlinePack = notification.object;
1461
- const userInfo = NSKeyedUnarchiver.unarchiveObjectWithData(offlinePack.context);
1462
- const error = notification.userInfo[MGLOfflinePackUserInfoKeyError];
1463
- reject({
1464
- name: userInfo.objectForKey('name'),
1465
- error: 'Download error. ' + error
1466
- });
1467
- });
1468
- _addObserver(MGLOfflinePackMaximumMapboxTilesReachedNotification, (notification) => {
1469
- const offlinePack = notification.object;
1470
- const userInfo = NSKeyedUnarchiver.unarchiveObjectWithData(offlinePack.context);
1471
- const maximumCount = notification.userInfo[MGLOfflinePackUserInfoKeyMaximumCount];
1472
- console.log(`Offline region '${userInfo.objectForKey('name')}' reached the tile limit of ${maximumCount}`);
1473
- });
1474
- const userInfo = { name: options.name };
1475
- const context = NSKeyedArchiver.archivedDataWithRootObject(userInfo);
1476
- MGLOfflineStorage.sharedOfflineStorage.addPackForRegionWithContextCompletionHandler(region, context, (pack, error) => {
1477
- if (error) {
1478
- reject(error.localizedFailureReason);
1479
- }
1480
- else {
1481
- pack.resume();
1468
+ let features;
1469
+ const queryFilter = options.filter ? FilterParser.parseJson(options.filter) : null;
1470
+ if (source instanceof MGLShapeSource) {
1471
+ features = source.featuresMatchingPredicate(queryFilter);
1472
+ }
1473
+ else if (source instanceof MGLVectorTileSource) {
1474
+ if (!options.sourceLayer) {
1475
+ throw new Error('The option "sourceLayer" is required for vector sources.');
1482
1476
  }
1483
- });
1477
+ const sourceLayerIds = options.sourceLayer ? NSSet.setWithArray(Utils.ios.collections.jsArrayToNSArray([options.sourceLayer])) : null;
1478
+ features = source.featuresInSourceLayersWithIdentifiersPredicate(sourceLayerIds, queryFilter);
1479
+ }
1480
+ else {
1481
+ throw new Error('Only sources from type "vector" or "geojson" are supported.');
1482
+ }
1483
+ const result = [];
1484
+ for (let i = 0; i < features.count; i++) {
1485
+ const feature = features.objectAtIndex(i);
1486
+ const featureJson = NSJSONSerialization.dataWithJSONObjectOptionsError(feature.geoJSONDictionary(), 0);
1487
+ result.push(JSON.parse(NSString.alloc().initWithDataEncoding(featureJson, NSUTF8StringEncoding)));
1488
+ }
1489
+ resolve(result);
1484
1490
  }
1485
1491
  catch (ex) {
1486
1492
  if (Trace.isEnabled()) {
1487
- CLog(CLogTypes.info, 'Error in mapbox.downloadOfflineRegion: ' + ex);
1493
+ CLog(CLogTypes.info, 'Error in mapbox.querySourceFeatures: ' + ex);
1488
1494
  }
1489
1495
  reject(ex);
1490
1496
  }
1491
1497
  });
1492
1498
  }
1493
- listOfflineRegions(options) {
1499
+ addPolygon(options, nativeMap) {
1494
1500
  return new Promise((resolve, reject) => {
1495
- try {
1496
- const packs = MGLOfflineStorage.sharedOfflineStorage.packs;
1497
- if (!packs) {
1498
- reject('No packs found or Mapbox not ready yet');
1499
- return;
1500
- }
1501
- const regions = [];
1502
- for (let i = 0; i < packs.count; i++) {
1503
- const pack = packs.objectAtIndex(i);
1504
- const region = pack.region;
1505
- const userInfo = NSKeyedUnarchiver.unarchiveObjectWithData(pack.context);
1506
- regions.push({
1507
- name: userInfo.objectForKey('name'),
1508
- style: '' + region.styleURL,
1509
- minZoom: region.minimumZoomLevel,
1510
- maxZoom: region.maximumZoomLevel,
1511
- bounds: {
1512
- north: region.bounds.ne.latitude,
1513
- east: region.bounds.ne.longitude,
1514
- south: region.bounds.sw.latitude,
1515
- west: region.bounds.sw.longitude
1516
- }
1517
- });
1501
+ const theMap = nativeMap || this._mapboxViewInstance;
1502
+ const points = options.points;
1503
+ if (points === undefined) {
1504
+ reject("Please set the 'points' parameter");
1505
+ return;
1506
+ }
1507
+ const coordinateArray = [];
1508
+ points.forEach((point) => coordinateArray.push([point.lng, point.lat]));
1509
+ const polygonID = `polygon_${options.id || new Date().getTime()}`;
1510
+ if (theMap.style.sourceWithIdentifier(polygonID)) {
1511
+ reject("Remove the polygon with this id first with 'removePolygons': " + polygonID);
1512
+ return;
1513
+ }
1514
+ const geoJSON = `{
1515
+ "type": "FeatureCollection",
1516
+ "features": [
1517
+ {
1518
+ "id": ${JSON.stringify(polygonID)},
1519
+ "type": "Feature",
1520
+ "properties": {
1521
+ },
1522
+ "geometry": {
1523
+ "type": "Polygon",
1524
+ "coordinates": [${JSON.stringify(coordinateArray)}]
1525
+ }
1518
1526
  }
1519
- resolve(regions);
1527
+ ]
1528
+ }`;
1529
+ const geoDataStr = NSString.stringWithString(geoJSON);
1530
+ const geoData = geoDataStr.dataUsingEncoding(NSUTF8StringEncoding);
1531
+ const geoDataBase64Enc = geoData.base64EncodedStringWithOptions(0);
1532
+ const geo = NSData.alloc().initWithBase64EncodedStringOptions(geoDataBase64Enc, null);
1533
+ const shape = MGLShape.shapeWithDataEncodingError(geo, NSUTF8StringEncoding);
1534
+ const source = MGLShapeSource.alloc().initWithIdentifierShapeOptions(polygonID, shape, null);
1535
+ theMap.style.addSource(source);
1536
+ if (options.strokeColor || options.strokeWidth || options.strokeOpacity) {
1537
+ const strokeLayer = MGLLineStyleLayer.alloc().initWithIdentifierSource(polygonID + '_stroke', source);
1538
+ strokeLayer.lineColor = NSExpression.expressionForConstantValue(!options.strokeColor ? UIColor.blackColor : options.strokeColor instanceof Color ? options.strokeColor.ios : new Color(options.strokeColor).ios);
1539
+ strokeLayer.lineWidth = NSExpression.expressionForConstantValue(options.strokeWidth || 5);
1540
+ strokeLayer.lineOpacity = NSExpression.expressionForConstantValue(options.strokeOpacity === undefined ? 1 : options.strokeOpacity);
1541
+ theMap.style.addLayer(strokeLayer);
1542
+ }
1543
+ const layer = MGLFillStyleLayer.alloc().initWithIdentifierSource(polygonID, source);
1544
+ layer.fillColor = NSExpression.expressionForConstantValue(!options.fillColor ? UIColor.blackColor : options.fillColor instanceof Color ? options.fillColor.ios : new Color(options.fillColor).ios);
1545
+ layer.fillOpacity = NSExpression.expressionForConstantValue(options.fillOpacity === undefined ? 1 : options.fillOpacity);
1546
+ theMap.style.addLayer(layer);
1547
+ resolve();
1548
+ });
1549
+ }
1550
+ addPolyline(options, nativeMap) {
1551
+ return new Promise((resolve, reject) => {
1552
+ const theMap = nativeMap || this._mapboxViewInstance;
1553
+ const points = options.points;
1554
+ if (points === undefined) {
1555
+ reject("Please set the 'points' parameter");
1556
+ return;
1520
1557
  }
1521
- catch (ex) {
1522
- if (Trace.isEnabled()) {
1523
- CLog(CLogTypes.info, 'Error in mapbox.listOfflineRegions: ' + ex);
1524
- }
1525
- reject(ex);
1558
+ const coordinateArray = [];
1559
+ points.forEach((point) => coordinateArray.push([point.lng, point.lat]));
1560
+ const polylineID = 'polyline_' + (options.id || new Date().getTime());
1561
+ if (theMap.style.sourceWithIdentifier(polylineID)) {
1562
+ reject("Remove the polyline with this id first with 'removePolylines': " + polylineID);
1563
+ return;
1526
1564
  }
1565
+ const geoJSON = `{"type": "FeatureCollection", "features": [{"type": "Feature","properties": {},"geometry": {"type": "LineString", "coordinates": ${JSON.stringify(coordinateArray)}}}]}`;
1566
+ const geoDataStr = NSString.stringWithString(geoJSON);
1567
+ const geoData = geoDataStr.dataUsingEncoding(NSUTF8StringEncoding);
1568
+ const geoDataBase64Enc = geoData.base64EncodedStringWithOptions(0);
1569
+ const geo = NSData.alloc().initWithBase64EncodedStringOptions(geoDataBase64Enc, null);
1570
+ const shape = MGLShape.shapeWithDataEncodingError(geo, NSUTF8StringEncoding);
1571
+ const source = MGLShapeSource.alloc().initWithIdentifierShapeOptions(polylineID, shape, null);
1572
+ theMap.style.addSource(source);
1573
+ const layer = MGLLineStyleLayer.alloc().initWithIdentifierSource(polylineID, source);
1574
+ layer.lineColor = NSExpression.expressionForConstantValue(!options.color ? UIColor.blackColor : options.color instanceof Color ? options.color.ios : new Color(options.color).ios);
1575
+ layer.lineWidth = NSExpression.expressionForConstantValue(options.width || 5);
1576
+ layer.lineOpacity = NSExpression.expressionForConstantValue(options.opacity === undefined ? 1 : options.opacity);
1577
+ theMap.style.addLayer(layer);
1578
+ resolve();
1527
1579
  });
1528
1580
  }
1529
- deleteOfflineRegion(options) {
1581
+ removePolyById(theMap, id) {
1582
+ let layer = theMap.style.layerWithIdentifier(id);
1583
+ if (layer !== null) {
1584
+ theMap.style.removeLayer(layer);
1585
+ }
1586
+ layer = theMap.style.layerWithIdentifier(id + '_stroke');
1587
+ if (layer !== null) {
1588
+ theMap.style.removeLayer(layer);
1589
+ }
1590
+ const source = theMap.style.sourceWithIdentifier(id);
1591
+ if (source !== null) {
1592
+ theMap.style.removeSource(source);
1593
+ }
1594
+ }
1595
+ removePolys(polyType, ids, nativeMap) {
1596
+ return new Promise((resolve) => {
1597
+ const theMap = nativeMap || this._mapboxViewInstance;
1598
+ ids.forEach((id) => this.removePolyById(theMap, polyType + id));
1599
+ resolve();
1600
+ });
1601
+ }
1602
+ removePolygons(ids, nativeMap) {
1603
+ return this.removePolys('polygon_', ids, nativeMap);
1604
+ }
1605
+ removePolylines(ids, nativeMap) {
1606
+ return this.removePolys('polyline_', ids, nativeMap);
1607
+ }
1608
+ animateCamera(options, nativeMap) {
1530
1609
  return new Promise((resolve, reject) => {
1531
1610
  try {
1532
- if (!options || !options.name) {
1533
- reject("Pass in the 'name' param");
1534
- return;
1611
+ const theMap = nativeMap || this._mapboxViewInstance;
1612
+ let cam;
1613
+ if (options.bounds) {
1614
+ const padding = options.padding || 0;
1615
+ const insets = {
1616
+ top: padding,
1617
+ left: padding,
1618
+ bottom: padding,
1619
+ right: padding
1620
+ };
1621
+ const bounds = {
1622
+ sw: CLLocationCoordinate2DMake(options.bounds.south, options.bounds.west),
1623
+ ne: CLLocationCoordinate2DMake(options.bounds.north, options.bounds.east)
1624
+ };
1625
+ cam = theMap.cameraThatFitsCoordinateBoundsEdgePadding(bounds, insets);
1535
1626
  }
1536
- const packs = MGLOfflineStorage.sharedOfflineStorage.packs;
1537
- let found = false;
1538
- for (let i = 0; i < packs.count; i++) {
1539
- const pack = packs.objectAtIndex(i);
1540
- const userInfo = NSKeyedUnarchiver.unarchiveObjectWithData(pack.context);
1541
- const name = userInfo.objectForKey('name');
1542
- if (name === options.name) {
1543
- found = true;
1544
- MGLOfflineStorage.sharedOfflineStorage.removePackWithCompletionHandler(pack, (error) => {
1545
- if (error) {
1546
- reject(error.localizedFailureReason);
1547
- }
1548
- else {
1549
- resolve();
1550
- }
1551
- });
1627
+ else {
1628
+ const target = options.target;
1629
+ if (target === undefined) {
1630
+ reject("Please set the 'target' parameter");
1631
+ return;
1552
1632
  }
1633
+ cam = theMap.camera;
1634
+ cam.centerCoordinate = CLLocationCoordinate2DMake(target.lat, target.lng);
1553
1635
  }
1554
- if (!found) {
1555
- reject('Region not found');
1636
+ if (options.altitude) {
1637
+ cam.altitude = options.altitude;
1638
+ }
1639
+ if (options.bearing) {
1640
+ cam.heading = options.bearing;
1641
+ }
1642
+ if (options.tilt) {
1643
+ cam.pitch = options.tilt;
1644
+ }
1645
+ if (options.zoomLevel && options.target) {
1646
+ cam.altitude = MGLAltitudeForZoomLevel(options.zoomLevel, cam.pitch, options.target.lat, theMap.frame.size);
1556
1647
  }
1648
+ const durationMs = options.duration ? options.duration : 10000;
1649
+ theMap.setCameraWithDurationAnimationTimingFunction(cam, durationMs / 1000, CAMediaTimingFunction.functionWithName(kCAMediaTimingFunctionEaseInEaseOut));
1650
+ setTimeout(() => {
1651
+ resolve();
1652
+ }, durationMs);
1557
1653
  }
1558
1654
  catch (ex) {
1559
1655
  if (Trace.isEnabled()) {
1560
- CLog(CLogTypes.info, 'Error in mapbox.deleteOfflineRegion: ' + ex);
1656
+ CLog(CLogTypes.info, 'Error in mapbox.animateCamera: ' + ex);
1561
1657
  }
1562
1658
  reject(ex);
1563
1659
  }
1564
1660
  });
1565
1661
  }
1566
- addExtrusion(options, nativeMap) {
1662
+ setOnMapClickListener(listener, nativeMap) {
1567
1663
  return new Promise((resolve, reject) => {
1568
1664
  try {
1569
1665
  const theMap = nativeMap || this._mapboxViewInstance;
@@ -1571,17 +1667,26 @@ export class Mapbox extends MapboxCommon {
1571
1667
  reject('No map has been loaded');
1572
1668
  return;
1573
1669
  }
1670
+ theMap['mapTapHandler'] = MapTapHandlerImpl.initWithOwnerAndListenerForMap(new WeakRef(this), listener, theMap);
1671
+ const tapGestureRecognizer = UITapGestureRecognizer.alloc().initWithTargetAction(theMap['mapTapHandler'], 'tap');
1672
+ for (let i = 0; i < theMap.gestureRecognizers.count; i++) {
1673
+ const recognizer = theMap.gestureRecognizers.objectAtIndex(i);
1674
+ if (recognizer instanceof UITapGestureRecognizer) {
1675
+ tapGestureRecognizer.requireGestureRecognizerToFail(recognizer);
1676
+ }
1677
+ }
1678
+ theMap.addGestureRecognizer(tapGestureRecognizer);
1574
1679
  resolve();
1575
1680
  }
1576
1681
  catch (ex) {
1577
1682
  if (Trace.isEnabled()) {
1578
- CLog(CLogTypes.info, 'Error in mapbox.deleteOfflineRegion: ' + ex);
1683
+ CLog(CLogTypes.info, 'Error in mapbox.setOnMapClickListener: ' + ex);
1579
1684
  }
1580
1685
  reject(ex);
1581
1686
  }
1582
1687
  });
1583
1688
  }
1584
- updateSource(id, options, nativeMap) {
1689
+ setOnMapLongClickListener(listener, nativeMap) {
1585
1690
  return new Promise((resolve, reject) => {
1586
1691
  try {
1587
1692
  const theMap = nativeMap || this._mapboxViewInstance;
@@ -1589,159 +1694,88 @@ export class Mapbox extends MapboxCommon {
1589
1694
  reject('No map has been loaded');
1590
1695
  return;
1591
1696
  }
1592
- const source = theMap.style.sourceWithIdentifier(id);
1593
- if (!source) {
1594
- reject('Source does not exists: ' + id);
1595
- return;
1596
- }
1597
- switch (options.type) {
1598
- case 'geojson':
1599
- const content = NSString.stringWithString(JSON.stringify(options.data));
1600
- const nsData = content.dataUsingEncoding(NSUTF8StringEncoding);
1601
- const geoJsonShape = MGLShape.shapeWithDataEncodingError(nsData, NSUTF8StringEncoding);
1602
- source.shape = geoJsonShape;
1603
- break;
1604
- default:
1605
- reject('Invalid source type: ' + options['type']);
1606
- return;
1697
+ theMap['mapLongPressHandler'] = MapLongPressHandlerImpl.initWithOwnerAndListenerForMap(new WeakRef(this), listener, theMap);
1698
+ const longPressGestureRecognizer = UILongPressGestureRecognizer.alloc().initWithTargetAction(theMap['mapLongPressHandler'], 'longPress');
1699
+ for (let i = 0; i < theMap.gestureRecognizers.count; i++) {
1700
+ const recognizer = theMap.gestureRecognizers.objectAtIndex(i);
1701
+ if (recognizer instanceof UILongPressGestureRecognizer) {
1702
+ longPressGestureRecognizer.requireGestureRecognizerToFail(recognizer);
1703
+ }
1607
1704
  }
1705
+ theMap.addGestureRecognizer(longPressGestureRecognizer);
1706
+ resolve();
1608
1707
  }
1609
1708
  catch (ex) {
1610
1709
  if (Trace.isEnabled()) {
1611
- CLog(CLogTypes.info, 'Error in mapbox.addSource: ' + ex);
1710
+ CLog(CLogTypes.info, 'Error in mapbox.setOnMapClickListener: ' + ex);
1612
1711
  }
1613
1712
  reject(ex);
1614
1713
  }
1615
- });
1616
- }
1617
- addSource(id, options, nativeMap) {
1618
- return new Promise((resolve, reject) => {
1619
- try {
1620
- const theMap = nativeMap || this._mapboxViewInstance;
1621
- let source;
1622
- if (!theMap) {
1623
- reject('No map has been loaded');
1624
- return;
1625
- }
1626
- if (theMap.style.sourceWithIdentifier(id)) {
1627
- reject('Source exists: ' + id);
1628
- return;
1629
- }
1630
- switch (options.type) {
1631
- case 'vector': {
1632
- if (options.url) {
1633
- source = MGLVectorTileSource.alloc().initWithIdentifierConfigurationURL(id, NSURL.URLWithString(options.url));
1634
- }
1635
- else {
1636
- const sourceOptions = {};
1637
- if (options.minzoom !== undefined) {
1638
- sourceOptions[MGLTileSourceOptionMinimumZoomLevel] = options.minzoom;
1639
- }
1640
- if (options.maxzoom !== undefined) {
1641
- sourceOptions[MGLTileSourceOptionMaximumZoomLevel] = options.maxzoom;
1642
- }
1643
- if (options.scheme) {
1644
- switch (options.scheme) {
1645
- case 'xyz':
1646
- sourceOptions[MGLTileSourceOptionTileCoordinateSystem] = 0;
1647
- break;
1648
- case 'tms':
1649
- sourceOptions[MGLTileSourceOptionTileCoordinateSystem] = 1;
1650
- break;
1651
- default:
1652
- throw new Error('Unknown raster tile scheme.');
1653
- }
1654
- }
1655
- if (options.bounds) {
1656
- sourceOptions[MGLTileSourceOptionCoordinateBounds] = NSValue.valueWithMGLCoordinateBounds({
1657
- sw: CLLocationCoordinate2DMake(options.bounds[1], options.bounds[0]),
1658
- ne: CLLocationCoordinate2DMake(options.bounds[3], options.bounds[2])
1659
- });
1660
- }
1661
- source = MGLVectorTileSource.alloc().initWithIdentifierTileURLTemplatesOptions(id, options.tiles, sourceOptions);
1662
- }
1663
- break;
1664
- }
1665
- case 'geojson':
1666
- if (theMap.style.sourceWithIdentifier(id)) {
1667
- reject("Remove the layer with this id first with 'removeLayer': " + id);
1668
- return;
1669
- }
1670
- let geoJsonShape;
1671
- if (options.data) {
1672
- const content = NSString.stringWithString(JSON.stringify(options.data));
1673
- const nsData = content.dataUsingEncoding(NSUTF8StringEncoding);
1674
- geoJsonShape = MGLShape.shapeWithDataEncodingError(nsData, NSUTF8StringEncoding);
1675
- }
1676
- const sourceOptions = {};
1677
- if (options.minzoom !== undefined) {
1678
- sourceOptions[MGLShapeSourceOptionMinimumZoomLevel] = options.minzoom;
1679
- }
1680
- if (options.maxzoom !== undefined) {
1681
- sourceOptions[MGLShapeSourceOptionMaximumZoomLevel] = options.maxzoom;
1682
- }
1683
- if (options.cluster) {
1684
- sourceOptions[MGLShapeSourceOptionClustered] = true;
1685
- sourceOptions[MGLShapeSourceOptionClusterRadius] = options.cluster.radius || 40;
1686
- sourceOptions[MGLShapeSourceOptionMaximumZoomLevelForClustering] = options.cluster.maxZoom || 13;
1687
- }
1688
- source = MGLShapeSource.alloc().initWithIdentifierShapeOptions(id, geoJsonShape, sourceOptions);
1689
- break;
1690
- case 'raster': {
1691
- const sourceOptions = {
1692
- [MGLTileSourceOptionTileSize]: options.tileSize || 256
1693
- };
1694
- if (options.minzoom !== undefined) {
1695
- sourceOptions[MGLTileSourceOptionMinimumZoomLevel] = options.minzoom;
1696
- }
1697
- if (options.maxzoom !== undefined) {
1698
- sourceOptions[MGLTileSourceOptionMaximumZoomLevel] = options.maxzoom;
1699
- }
1700
- if (options.scheme) {
1701
- switch (options.scheme || 'xyz') {
1702
- case 'xyz':
1703
- sourceOptions[MGLTileSourceOptionTileCoordinateSystem] = 0;
1704
- break;
1705
- case 'tms':
1706
- sourceOptions[MGLTileSourceOptionTileCoordinateSystem] = 1;
1707
- break;
1708
- default:
1709
- throw new Error('Unknown raster tile scheme.');
1710
- }
1711
- }
1712
- if (options.bounds) {
1713
- sourceOptions[MGLTileSourceOptionCoordinateBounds] = NSValue.valueWithMGLCoordinateBounds({
1714
- sw: CLLocationCoordinate2DMake(options.bounds[1], options.bounds[0]),
1715
- ne: CLLocationCoordinate2DMake(options.bounds[3], options.bounds[2])
1716
- });
1717
- }
1718
- source = MGLRasterTileSource.alloc().initWithIdentifierTileURLTemplatesOptions(id, options.tiles, sourceOptions);
1714
+ });
1715
+ }
1716
+ setOnScrollListener(listener, nativeMap) {
1717
+ return new Promise((resolve, reject) => {
1718
+ try {
1719
+ const theMap = nativeMap || this._mapboxViewInstance;
1720
+ if (!theMap) {
1721
+ reject('No map has been loaded');
1722
+ return;
1723
+ }
1724
+ if (theMap['mapPanHandler'] === undefined) {
1725
+ theMap['mapPanHandler'] = MapPanHandlerImpl.initWithOwnerAndListenerForMap(new WeakRef(this), listener, 2, theMap);
1726
+ }
1727
+ else {
1728
+ theMap['mapPanHandler'].addListener(2, listener);
1729
+ }
1730
+ for (let i = 0; i < theMap.gestureRecognizers.count; i++) {
1731
+ const recognizer = theMap.gestureRecognizers.objectAtIndex(i);
1732
+ if (recognizer instanceof UIPanGestureRecognizer) {
1733
+ recognizer.addTargetAction(theMap['mapPanHandler'], 'pan');
1719
1734
  break;
1720
1735
  }
1721
- default:
1722
- reject('Invalid source type: ' + options['type']);
1723
- return;
1724
1736
  }
1725
- if (!source) {
1726
- const ex = 'No source to add';
1727
- if (Trace.isEnabled()) {
1728
- CLog(CLogTypes.info, 'Error in mapbox.addSource: ' + ex);
1729
- }
1730
- reject(ex);
1737
+ resolve();
1738
+ }
1739
+ catch (ex) {
1740
+ if (Trace.isEnabled()) {
1741
+ CLog(CLogTypes.info, 'Error in mapbox.setOnScrollListener: ' + ex);
1742
+ }
1743
+ reject(ex);
1744
+ }
1745
+ });
1746
+ }
1747
+ setOnMoveBeginListener(listener, nativeMap) {
1748
+ return new Promise((resolve, reject) => {
1749
+ try {
1750
+ const theMap = nativeMap || this._mapboxViewInstance;
1751
+ if (!theMap) {
1752
+ reject('No map has been loaded');
1731
1753
  return;
1732
1754
  }
1733
- theMap.style.addSource(source);
1755
+ if (theMap['mapPanHandler'] === undefined) {
1756
+ theMap['mapPanHandler'] = MapPanHandlerImpl.initWithOwnerAndListenerForMap(new WeakRef(this), listener, 1, theMap);
1757
+ }
1758
+ else {
1759
+ theMap['mapPanHandler'].addListener(1, listener);
1760
+ }
1761
+ for (let i = 0; i < theMap.gestureRecognizers.count; i++) {
1762
+ const recognizer = theMap.gestureRecognizers.objectAtIndex(i);
1763
+ if (recognizer instanceof UIPanGestureRecognizer) {
1764
+ recognizer.addTargetAction(theMap['mapPanHandler'], 'panBegin');
1765
+ break;
1766
+ }
1767
+ }
1734
1768
  resolve();
1735
1769
  }
1736
1770
  catch (ex) {
1737
1771
  if (Trace.isEnabled()) {
1738
- CLog(CLogTypes.info, 'Error in mapbox.addSource: ' + ex);
1772
+ CLog(CLogTypes.info, 'Error in mapbox.setOnMoveBeginListener: ' + ex);
1739
1773
  }
1740
1774
  reject(ex);
1741
1775
  }
1742
1776
  });
1743
1777
  }
1744
- removeSource(id, nativeMap) {
1778
+ setOnMoveEndListener(listener, nativeMap) {
1745
1779
  return new Promise((resolve, reject) => {
1746
1780
  try {
1747
1781
  const theMap = nativeMap || this._mapboxViewInstance;
@@ -1749,86 +1783,82 @@ export class Mapbox extends MapboxCommon {
1749
1783
  reject('No map has been loaded');
1750
1784
  return;
1751
1785
  }
1752
- const source = theMap.style.sourceWithIdentifier(id);
1753
- if (!source) {
1754
- reject('Source does not exist');
1755
- return;
1786
+ if (theMap['mapPanHandler'] === undefined) {
1787
+ theMap['mapPanHandler'] = MapPanHandlerImpl.initWithOwnerAndListenerForMap(new WeakRef(this), listener, 3, theMap);
1788
+ }
1789
+ else {
1790
+ theMap['mapPanHandler'].addListener(3, listener);
1791
+ }
1792
+ for (let i = 0; i < theMap.gestureRecognizers.count; i++) {
1793
+ const recognizer = theMap.gestureRecognizers.objectAtIndex(i);
1794
+ if (recognizer instanceof UIPanGestureRecognizer) {
1795
+ recognizer.addTargetAction(theMap['mapPanHandler'], 'panEnd');
1796
+ break;
1797
+ }
1756
1798
  }
1757
- theMap.style.removeSource(source);
1758
1799
  resolve();
1759
1800
  }
1760
1801
  catch (ex) {
1761
1802
  if (Trace.isEnabled()) {
1762
- CLog(CLogTypes.info, 'Error in mapbox.removeSource: ' + ex);
1803
+ CLog(CLogTypes.info, 'Error in mapbox.setOnMoveEndListener: ' + ex);
1763
1804
  }
1764
1805
  reject(ex);
1765
1806
  }
1766
1807
  });
1767
1808
  }
1768
- async addLayer(style, belowLayerId, nativeMapView) {
1769
- const theMap = nativeMapView || this._mapboxViewInstance;
1770
- let source = null;
1771
- if (typeof style.source != 'string') {
1772
- await this.addSource(style.id + '_source', style.source);
1773
- source = theMap.style.sourceWithIdentifier(style.id + '_source');
1809
+ setOnFlingListener(listener, nativeMap) {
1810
+ return Promise.reject("'setOnFlingListener' is not supported on iOS");
1811
+ }
1812
+ async setOnCameraMoveListener(listener, nativeMap) {
1813
+ const theMap = nativeMap || this._mapboxViewInstance;
1814
+ if (theMap) {
1815
+ theMap.delegate.setCameraChangedListener(listener);
1774
1816
  }
1775
1817
  else {
1776
- source = theMap.style.sourceWithIdentifier(style.source);
1777
- }
1778
- const layer = await LayerFactory.createLayer(style, source);
1779
- if (belowLayerId) {
1780
- const belowlayer = theMap.style.layerWithIdentifier(belowLayerId);
1781
- if (belowlayer) {
1782
- theMap.style.insertLayerBelowLayer(layer.getNativeInstance(), belowlayer);
1783
- return;
1784
- }
1818
+ return Promise.reject('No map has been loaded');
1785
1819
  }
1786
- theMap.style.addLayer(layer.getNativeInstance());
1787
1820
  }
1788
- async removeLayer(id, nativeMapViewInstance) {
1789
- const theMap = nativeMapViewInstance || this._mapboxViewInstance;
1790
- if (Trace.isEnabled()) {
1791
- CLog(CLogTypes.info, "Mapbox::removeLayer(): attempting to remove layer '" + id + "'");
1792
- }
1793
- const layer = theMap.style.layerWithIdentifier(id);
1794
- if (Trace.isEnabled()) {
1795
- CLog(CLogTypes.info, 'Mapbox:removeLayer(): got layer object: ', layer);
1796
- }
1797
- if (!layer) {
1798
- throw new Error("Layer '" + id + "' not found when attempting to remove it.");
1799
- }
1800
- theMap.style.removeLayer(layer);
1801
- if (Trace.isEnabled()) {
1802
- CLog(CLogTypes.info, 'Mapbox:removeLayer(): after removing layer ' + id);
1803
- }
1821
+ setOnCameraMoveCancelListener(listener, nativeMap) {
1822
+ return Promise.reject("'setOnCameraMoveCancelListener' not currently supported on iOS");
1804
1823
  }
1805
- async addLinePoint(id, lnglat, sourceId, nativeMapView) {
1806
- const theMap = nativeMapView || this._mapboxViewInstance;
1807
- const sId = !!sourceId ? sourceId : id + '_source';
1808
- const lineSource = theMap.style.sourceWithIdentifier(sId);
1809
- if (!lineSource) {
1810
- throw new Error(`no source found with id: ${sId}`);
1811
- }
1812
- try {
1813
- const lineFeatures = lineSource.featuresMatchingPredicate(FilterParser.parseJson(['==', '$type', 'LineString']));
1814
- if (lineFeatures.count === 0) {
1815
- throw new Error('no line string feature found');
1816
- }
1817
- const lineFeature = lineFeatures.objectAtIndex(0);
1818
- const newCoord = CLLocationCoordinate2DMake(lnglat[1], lnglat[0]);
1819
- const newCoordPointer = new interop.Reference(newCoord);
1820
- lineFeature.appendCoordinatesCount(newCoordPointer, 1);
1821
- lineSource.shape = lineFeature;
1824
+ async setOnCameraIdleListener(listener, nativeMap) {
1825
+ const theMap = nativeMap || this._mapboxViewInstance;
1826
+ if (theMap) {
1827
+ theMap.delegate.setCameraIdledListener(listener);
1822
1828
  }
1823
- catch (error) {
1824
- console.log(error);
1825
- throw error;
1829
+ else {
1830
+ return Promise.reject('No map has been loaded');
1826
1831
  }
1827
1832
  }
1828
- addGeoJsonClustered(options, nativeMapViewInstance) {
1829
- throw new Error('Method not implemented.');
1833
+ getViewport(nativeMap) {
1834
+ return new Promise((resolve, reject) => {
1835
+ try {
1836
+ const theMap = nativeMap || this._mapboxViewInstance;
1837
+ if (!theMap) {
1838
+ reject('No map has been loaded');
1839
+ return;
1840
+ }
1841
+ const visibleBounds = theMap.visibleCoordinateBounds;
1842
+ const bounds = {
1843
+ north: visibleBounds.ne.latitude,
1844
+ east: visibleBounds.ne.longitude,
1845
+ south: visibleBounds.sw.latitude,
1846
+ west: visibleBounds.sw.longitude
1847
+ };
1848
+ resolve({
1849
+ bounds,
1850
+ zoomLevel: theMap.zoomLevel
1851
+ });
1852
+ }
1853
+ catch (ex) {
1854
+ if (Trace.isEnabled()) {
1855
+ CLog(CLogTypes.info, 'Error in mapbox.getViewport: ' + ex);
1856
+ }
1857
+ reject(ex);
1858
+ }
1859
+ });
1830
1860
  }
1831
- trackUser(options, nativeMap) {
1861
+ setViewport(options, nativeMap) {
1832
1862
  return new Promise((resolve, reject) => {
1833
1863
  try {
1834
1864
  const theMap = nativeMap || this._mapboxViewInstance;
@@ -1836,41 +1866,163 @@ export class Mapbox extends MapboxCommon {
1836
1866
  reject('No map has been loaded');
1837
1867
  return;
1838
1868
  }
1839
- if (!theMap.showsUserLocation) {
1840
- reject('The map is not currently showing the user location');
1841
- return;
1869
+ const bounds = {
1870
+ sw: CLLocationCoordinate2DMake(options.bounds.south, options.bounds.west),
1871
+ ne: CLLocationCoordinate2DMake(options.bounds.north, options.bounds.east)
1872
+ };
1873
+ const animated = options.animated === undefined || options.animated;
1874
+ const padding = options.padding !== undefined ? { top: options.padding, left: options.padding, bottom: options.padding, right: options.padding } : { top: 25, left: 25, bottom: 25, right: 25 };
1875
+ theMap.setVisibleCoordinateBoundsEdgePaddingAnimated(bounds, padding, animated);
1876
+ resolve();
1877
+ }
1878
+ catch (ex) {
1879
+ if (Trace.isEnabled()) {
1880
+ CLog(CLogTypes.info, 'Error in mapbox.setViewport: ' + ex);
1881
+ }
1882
+ reject(ex);
1883
+ }
1884
+ });
1885
+ }
1886
+ downloadOfflineRegion(options) {
1887
+ return new Promise((resolve, reject) => {
1888
+ try {
1889
+ const styleURL = _getMapStyle(options.style);
1890
+ const swCoordinate = CLLocationCoordinate2DMake(options.bounds.south, options.bounds.west);
1891
+ const neCoordinate = CLLocationCoordinate2DMake(options.bounds.north, options.bounds.east);
1892
+ const bounds = {
1893
+ sw: swCoordinate,
1894
+ ne: neCoordinate
1895
+ };
1896
+ const region = MGLTilePyramidOfflineRegion.alloc().initWithStyleURLBoundsFromZoomLevelToZoomLevel(styleURL, bounds, options.minZoom, options.maxZoom);
1897
+ if (options.accessToken) {
1898
+ MGLAccountManager.accessToken = options.accessToken;
1899
+ }
1900
+ if (options.onProgress) {
1901
+ _addObserver(MGLOfflinePackProgressChangedNotification, (notification) => {
1902
+ const offlinePack = notification.object;
1903
+ const offlinePackProgress = offlinePack.progress;
1904
+ const userInfo = NSKeyedUnarchiver.unarchiveObjectWithData(offlinePack.context);
1905
+ const complete = offlinePackProgress.countOfResourcesCompleted === offlinePackProgress.countOfResourcesExpected;
1906
+ options.onProgress({
1907
+ name: userInfo.objectForKey('name'),
1908
+ completed: offlinePackProgress.countOfResourcesCompleted,
1909
+ expected: offlinePackProgress.countOfResourcesExpected,
1910
+ percentage: Math.round((offlinePackProgress.countOfResourcesCompleted / offlinePackProgress.countOfResourcesExpected) * 10000) / 100,
1911
+ complete
1912
+ });
1913
+ if (complete) {
1914
+ resolve();
1915
+ }
1916
+ });
1917
+ }
1918
+ _addObserver(MGLOfflinePackErrorNotification, (notification) => {
1919
+ const offlinePack = notification.object;
1920
+ const userInfo = NSKeyedUnarchiver.unarchiveObjectWithData(offlinePack.context);
1921
+ const error = notification.userInfo[MGLOfflinePackUserInfoKeyError];
1922
+ reject({
1923
+ name: userInfo.objectForKey('name'),
1924
+ error: 'Download error. ' + error
1925
+ });
1926
+ });
1927
+ _addObserver(MGLOfflinePackMaximumMapboxTilesReachedNotification, (notification) => {
1928
+ const offlinePack = notification.object;
1929
+ const userInfo = NSKeyedUnarchiver.unarchiveObjectWithData(offlinePack.context);
1930
+ const maximumCount = notification.userInfo[MGLOfflinePackUserInfoKeyMaximumCount];
1931
+ console.log(`Offline region '${userInfo.objectForKey('name')}' reached the tile limit of ${maximumCount}`);
1932
+ });
1933
+ const userInfo = { name: options.name };
1934
+ const context = NSKeyedArchiver.archivedDataWithRootObject(userInfo);
1935
+ MGLOfflineStorage.sharedOfflineStorage.addPackForRegionWithContextCompletionHandler(region, context, (pack, error) => {
1936
+ if (error) {
1937
+ reject(error.localizedFailureReason);
1938
+ }
1939
+ else {
1940
+ pack.resume();
1941
+ }
1942
+ });
1943
+ }
1944
+ catch (ex) {
1945
+ if (Trace.isEnabled()) {
1946
+ CLog(CLogTypes.info, 'Error in mapbox.downloadOfflineRegion: ' + ex);
1947
+ }
1948
+ reject(ex);
1949
+ }
1950
+ });
1951
+ }
1952
+ listOfflineRegions(options) {
1953
+ return new Promise((resolve, reject) => {
1954
+ try {
1955
+ const packs = MGLOfflineStorage.sharedOfflineStorage.packs;
1956
+ if (!packs) {
1957
+ reject('No packs found or Mapbox not ready yet');
1958
+ return;
1959
+ }
1960
+ const regions = [];
1961
+ for (let i = 0; i < packs.count; i++) {
1962
+ const pack = packs.objectAtIndex(i);
1963
+ const region = pack.region;
1964
+ const userInfo = NSKeyedUnarchiver.unarchiveObjectWithData(pack.context);
1965
+ regions.push({
1966
+ name: userInfo.objectForKey('name'),
1967
+ style: '' + region.styleURL,
1968
+ minZoom: region.minimumZoomLevel,
1969
+ maxZoom: region.maximumZoomLevel,
1970
+ bounds: {
1971
+ north: region.bounds.ne.latitude,
1972
+ east: region.bounds.ne.longitude,
1973
+ south: region.bounds.sw.latitude,
1974
+ west: region.bounds.sw.longitude
1975
+ }
1976
+ });
1842
1977
  }
1843
- theMap.setUserTrackingModeAnimated(_getTrackingMode(options.mode), options.animated !== false);
1844
- resolve();
1978
+ resolve(regions);
1845
1979
  }
1846
1980
  catch (ex) {
1847
1981
  if (Trace.isEnabled()) {
1848
- CLog(CLogTypes.info, 'Error in mapbox.trackUser: ' + ex);
1982
+ CLog(CLogTypes.info, 'Error in mapbox.listOfflineRegions: ' + ex);
1849
1983
  }
1850
1984
  reject(ex);
1851
1985
  }
1852
1986
  });
1853
1987
  }
1854
- getLayer(name, nativeMap) {
1988
+ deleteOfflineRegion(options) {
1855
1989
  return new Promise((resolve, reject) => {
1856
1990
  try {
1857
- const theMap = nativeMap || this._mapboxViewInstance;
1858
- if (!theMap) {
1859
- reject('No map has been loaded');
1991
+ if (!options || (!options.id && !options.name)) {
1992
+ reject("Pass in the 'id' or 'name' param");
1860
1993
  return;
1861
1994
  }
1862
- const layer = theMap.style.layerWithIdentifier(name);
1863
- resolve(new Layer(layer));
1995
+ const packs = MGLOfflineStorage.sharedOfflineStorage.packs;
1996
+ let found = false;
1997
+ for (let i = 0; i < packs.count; i++) {
1998
+ const pack = packs.objectAtIndex(i);
1999
+ const userInfo = NSKeyedUnarchiver.unarchiveObjectWithData(pack.context);
2000
+ const regionId = options.id ? userInfo.objectForKey('id') : userInfo.objectForKey('name');
2001
+ if (regionId === (options.id || options.name)) {
2002
+ found = true;
2003
+ MGLOfflineStorage.sharedOfflineStorage.removePackWithCompletionHandler(pack, (error) => {
2004
+ if (error) {
2005
+ reject(error.localizedFailureReason);
2006
+ }
2007
+ else {
2008
+ resolve();
2009
+ }
2010
+ });
2011
+ }
2012
+ }
2013
+ if (!found) {
2014
+ reject('Region not found');
2015
+ }
1864
2016
  }
1865
2017
  catch (ex) {
1866
2018
  if (Trace.isEnabled()) {
1867
- CLog(CLogTypes.info, 'Error in mapbox.getLayer: ' + ex);
2019
+ CLog(CLogTypes.info, 'Error in mapbox.deleteOfflineRegion: ' + ex);
1868
2020
  }
1869
2021
  reject(ex);
1870
2022
  }
1871
2023
  });
1872
2024
  }
1873
- getLayers(nativeMap) {
2025
+ addExtrusion(options, nativeMap) {
1874
2026
  return new Promise((resolve, reject) => {
1875
2027
  try {
1876
2028
  const theMap = nativeMap || this._mapboxViewInstance;
@@ -1878,489 +2030,370 @@ export class Mapbox extends MapboxCommon {
1878
2030
  reject('No map has been loaded');
1879
2031
  return;
1880
2032
  }
1881
- const layers = theMap.style.layers;
1882
- const result = [];
1883
- for (let i = 0; i < layers.count; i++) {
1884
- result.push(new Layer(layers[i]));
1885
- }
1886
- resolve(result);
2033
+ resolve();
1887
2034
  }
1888
2035
  catch (ex) {
1889
2036
  if (Trace.isEnabled()) {
1890
- CLog(CLogTypes.info, 'Error in mapbox.getLayers: ' + ex);
2037
+ CLog(CLogTypes.info, 'Error in mapbox.deleteOfflineRegion: ' + ex);
1891
2038
  }
1892
2039
  reject(ex);
1893
2040
  }
1894
2041
  });
1895
2042
  }
1896
- project(data) {
1897
- const theMap = this._mapboxViewInstance;
1898
- const { x, y } = theMap.convertCoordinateToPointToView({ latitude: data.lat, longitude: data.lng }, theMap);
1899
- return { x, y };
1900
- }
1901
- }
1902
- const _addObserver = (eventName, callback) => NSNotificationCenter.defaultCenter.addObserverForNameObjectQueueUsingBlock(eventName, null, NSOperationQueue.mainQueue, callback);
1903
- function _downloadImage(marker) {
1904
- return new Promise((resolve, reject) => {
1905
- if (Trace.isEnabled()) {
1906
- CLog(CLogTypes.info, '>> _downloadImage');
1907
- }
1908
- if (_markerIconDownloadCache[marker.icon]) {
1909
- marker.iconDownloaded = _markerIconDownloadCache[marker.icon];
1910
- if (Trace.isEnabled()) {
1911
- CLog(CLogTypes.info, '>> marker.iconDownloaded: ' + marker.iconDownloaded);
1912
- }
1913
- resolve(marker);
1914
- return;
1915
- }
1916
- getImage(marker.icon).then((output) => {
1917
- marker.iconDownloaded = output.ios;
1918
- _markerIconDownloadCache[marker.icon] = marker.iconDownloaded;
1919
- resolve(marker);
1920
- }, (ignoredError) => {
1921
- console.log(`Download failed for ${marker.icon} with error: ${ignoredError}`);
1922
- resolve(marker);
1923
- });
1924
- });
1925
- }
1926
- const _downloadMarkerImages = (markers) => {
1927
- const iterations = [];
1928
- const result = [];
1929
- markers.forEach((marker) => {
1930
- if (marker.icon && marker.icon.startsWith('http')) {
1931
- const p = _downloadImage(marker).then((mark) => result.push(mark));
1932
- iterations.push(p);
1933
- }
1934
- else {
1935
- result.push(marker);
1936
- }
1937
- });
1938
- return Promise.all(iterations).then(() => result);
1939
- };
1940
- var MGLMapViewDelegateImpl = /** @class */ (function (_super) {
1941
- __extends(MGLMapViewDelegateImpl, _super);
1942
- function MGLMapViewDelegateImpl() {
1943
- return _super !== null && _super.apply(this, arguments) || this;
1944
- }
1945
- MGLMapViewDelegateImpl.new = function () {
1946
- return _super.new.call(this);
1947
- };
1948
- /**
1949
- * initialize with the mapReady callback
1950
- */
1951
- MGLMapViewDelegateImpl.prototype.initWithCallback = function (mapLoadedCallback) {
1952
- if (Trace.isEnabled()) {
1953
- CLog(CLogTypes.info, 'MGLMapViewDelegateImpl::initWithCallback()');
1954
- }
1955
- this.mapLoadedCallback = mapLoadedCallback;
1956
- return this;
1957
- };
1958
- /**
1959
- * set a reference to the mapboxAPI instance
1960
- */
1961
- MGLMapViewDelegateImpl.prototype.setMapboxApi = function (api) {
1962
- this.mapboxApi = api;
1963
- };
1964
- /**
1965
- * set the user location click listener callback
1966
- */
1967
- MGLMapViewDelegateImpl.prototype.setUserLocationClickListener = function (callback) {
1968
- this.userLocationClickListener = callback;
1969
- };
1970
- /**
1971
- * set the user location click listener callback
1972
- */
1973
- MGLMapViewDelegateImpl.prototype.setUserLocationChangedistener = function (callback) {
1974
- this.userLocationChangedListener = callback;
1975
- };
1976
- /**
1977
- * set user location marker modes
1978
- */
1979
- MGLMapViewDelegateImpl.prototype.changeUserLocationRenderMode = function (userLocationRenderMode) {
1980
- this.userLocationAnnotationView.changeUserLocationRenderMode(userLocationRenderMode);
1981
- };
1982
- /**
1983
- * set the camera changd listener callback
1984
- */
1985
- MGLMapViewDelegateImpl.prototype.setCameraChangedListener = function (callback) {
1986
- this.cameraChangedListener = callback;
1987
- };
1988
- /**
1989
- * set the camera idled listener callback
1990
- */
1991
- MGLMapViewDelegateImpl.prototype.setCameraIdledListener = function (callback) {
1992
- this.cameraIdledListener = callback;
1993
- };
1994
- /**
1995
- * set style loaded callback.
1996
- *
1997
- * set an optional callback to be invoked when a style set with
1998
- * setMapStyle() is finished loading
1999
- *
2000
- * @param {function} callback function with loaded style as parameter.
2001
- *
2002
- * @see Mapbox:setMapStyle()
2003
- */
2004
- MGLMapViewDelegateImpl.prototype.setStyleLoadedCallback = function (callback) {
2005
- this.styleLoadedCallback = callback;
2006
- };
2007
- /**
2008
- * map ready callback
2009
- */
2010
- MGLMapViewDelegateImpl.prototype.mapViewDidFinishLoadingMap = function (mapView) {
2011
- if (Trace.isEnabled()) {
2012
- CLog(CLogTypes.info, 'MGLMapViewDelegateImpl:mapViewDidFinishLoadingMap(): top');
2013
- }
2014
- if (this.mapLoadedCallback !== undefined) {
2015
- this.mapLoadedCallback(mapView);
2016
- // this should be fired only once, but it's also fired when the style changes, so just remove the callback
2017
- this.mapLoadedCallback = undefined;
2018
- }
2019
- };
2020
- MGLMapViewDelegateImpl.prototype.mapViewDidFinishRenderingMapFullyRendered = function (mapView, fullyRendered) {
2021
- if (Trace.isEnabled()) {
2022
- CLog(CLogTypes.info, 'MGLMapViewDelegateImpl:mapViewDidFinishRenderingMapFullyRendered(): rendered is:', fullyRendered);
2023
- }
2024
- };
2025
- /**
2026
- * Callback when the style has been loaded.
2027
- *
2028
- * Based on my testing, it looks like this callback is invoked multiple times.
2029
- *
2030
- * @see Mapbox:setMapStyle()
2031
- *
2032
- * @link https://mapbox.github.io/mapbox-gl-native/macos/0.3.0/Protocols/MGLMapViewDelegate.html#/c:objc(pl)MGLMapViewDelegate(im)mapView:didFinishLoadingStyle:
2033
- */
2034
- MGLMapViewDelegateImpl.prototype.mapViewDidFinishLoadingStyle = function (mapView, style) {
2035
- if (Trace.isEnabled()) {
2036
- CLog(CLogTypes.info, 'MGLMapViewDelegateImpl:mapViewDidFinishLoadingStyle(): callback called.');
2037
- }
2038
- if (this.styleLoadedCallback !== undefined) {
2039
- this.styleLoadedCallback(mapView, style);
2040
- // to avoid multiple calls. This is only invoked from setMapStyle().
2041
- this.styleLoadedCallback = undefined;
2042
- }
2043
- };
2044
- /**
2045
- * disable the default user location callout
2046
- *
2047
- * This took forever to find. The default iOS click handler for the user location
2048
- * marker is about useless. It just displays "You Are Here". The examples do not
2049
- * show how to disable it.
2050
- */
2051
- MGLMapViewDelegateImpl.prototype.mapViewAnnotationCanShowCallout = function (mapView, annotation) {
2052
- if (annotation.isKindOfClass(MGLUserLocation.class())) {
2053
- return false;
2054
- }
2055
- else {
2056
- return true;
2057
- }
2058
- };
2059
- MGLMapViewDelegateImpl.prototype.mapViewDidFailLoadingMapWithError = function (mapView, error) {
2060
- if (Trace.isEnabled()) {
2061
- CLog(CLogTypes.info, 'mapViewDidFailLoadingMapWithError: ' + error);
2062
- }
2063
- };
2064
- MGLMapViewDelegateImpl.prototype.mapViewDidChangeUserTrackingModeAnimated = function (mapView, mode, animated) {
2065
- if (Trace.isEnabled()) {
2066
- CLog(CLogTypes.info, 'mapViewDidChangeUserTrackingModeAnimated: ' + mode);
2067
- }
2068
- };
2069
- /**
2070
- * fired when the marker icon is about to be rendered - return null for the default icon
2071
- */
2072
- MGLMapViewDelegateImpl.prototype.mapViewImageForAnnotation = function (mapView, annotation) {
2073
- var cachedMarker = this.getTappedMarkerDetails(annotation);
2074
- if (cachedMarker) {
2075
- if (cachedMarker.reuseIdentifier) {
2076
- var reusedImage = mapView.dequeueReusableAnnotationImageWithIdentifier(cachedMarker.reuseIdentifier);
2077
- if (reusedImage) {
2078
- return reusedImage;
2043
+ updateSource(id, options, nativeMap) {
2044
+ return new Promise((resolve, reject) => {
2045
+ try {
2046
+ const theMap = nativeMap || this._mapboxViewInstance;
2047
+ if (!theMap) {
2048
+ reject('No map has been loaded');
2049
+ return;
2050
+ }
2051
+ const source = theMap.style.sourceWithIdentifier(id);
2052
+ if (!source) {
2053
+ reject('Source does not exists: ' + id);
2054
+ return;
2055
+ }
2056
+ switch (options.type) {
2057
+ case 'geojson':
2058
+ const content = NSString.stringWithString(JSON.stringify(options.data));
2059
+ const nsData = content.dataUsingEncoding(NSUTF8StringEncoding);
2060
+ const geoJsonShape = MGLShape.shapeWithDataEncodingError(nsData, NSUTF8StringEncoding);
2061
+ source.shape = geoJsonShape;
2062
+ break;
2063
+ default:
2064
+ reject('Invalid source type: ' + options['type']);
2065
+ return;
2079
2066
  }
2080
2067
  }
2081
- // TODO try adding .rotatesToMatchCamera = true;
2082
- // .. for instance in the mapViewDidDeselectAnnotationView / mapViewDidSelectAnnotationView / mapViewViewForAnnotation delegate
2083
- if (cachedMarker.icon) {
2084
- if (cachedMarker.icon.startsWith('res://')) {
2085
- var resourceName = cachedMarker.icon.substring('res://'.length);
2086
- var imageSource = ImageSource.fromResourceSync(resourceName);
2087
- if (imageSource === null) {
2088
- console.log("Unable to locate " + resourceName);
2089
- }
2090
- else {
2091
- cachedMarker.reuseIdentifier = cachedMarker.icon;
2092
- return MGLAnnotationImage.annotationImageWithImageReuseIdentifier(imageSource.ios, cachedMarker.reuseIdentifier);
2093
- }
2068
+ catch (ex) {
2069
+ if (Trace.isEnabled()) {
2070
+ CLog(CLogTypes.info, 'Error in mapbox.addSource: ' + ex);
2094
2071
  }
2095
- else if (cachedMarker.icon.startsWith('http')) {
2096
- if (cachedMarker.iconDownloaded !== null) {
2097
- cachedMarker.reuseIdentifier = cachedMarker.icon;
2098
- return MGLAnnotationImage.annotationImageWithImageReuseIdentifier(cachedMarker.iconDownloaded, cachedMarker.reuseIdentifier);
2072
+ reject(ex);
2073
+ }
2074
+ });
2075
+ }
2076
+ addSource(id, options, nativeMap) {
2077
+ return new Promise((resolve, reject) => {
2078
+ try {
2079
+ const theMap = nativeMap || this._mapboxViewInstance;
2080
+ let source;
2081
+ if (!theMap) {
2082
+ reject('No map has been loaded');
2083
+ return;
2084
+ }
2085
+ if (theMap.style.sourceWithIdentifier(id)) {
2086
+ reject('Source exists: ' + id);
2087
+ return;
2088
+ }
2089
+ switch (options.type) {
2090
+ case 'vector': {
2091
+ if (options.url) {
2092
+ source = MGLVectorTileSource.alloc().initWithIdentifierConfigurationURL(id, NSURL.URLWithString(options.url));
2093
+ }
2094
+ else {
2095
+ const sourceOptions = {};
2096
+ if (options.minzoom !== undefined) {
2097
+ sourceOptions[MGLTileSourceOptionMinimumZoomLevel] = options.minzoom;
2098
+ }
2099
+ if (options.maxzoom !== undefined) {
2100
+ sourceOptions[MGLTileSourceOptionMaximumZoomLevel] = options.maxzoom;
2101
+ }
2102
+ if (options.scheme) {
2103
+ switch (options.scheme) {
2104
+ case 'xyz':
2105
+ sourceOptions[MGLTileSourceOptionTileCoordinateSystem] = 0;
2106
+ break;
2107
+ case 'tms':
2108
+ sourceOptions[MGLTileSourceOptionTileCoordinateSystem] = 1;
2109
+ break;
2110
+ default:
2111
+ throw new Error('Unknown raster tile scheme.');
2112
+ }
2113
+ }
2114
+ if (options.bounds) {
2115
+ sourceOptions[MGLTileSourceOptionCoordinateBounds] = NSValue.valueWithMGLCoordinateBounds({
2116
+ sw: CLLocationCoordinate2DMake(options.bounds[1], options.bounds[0]),
2117
+ ne: CLLocationCoordinate2DMake(options.bounds[3], options.bounds[2])
2118
+ });
2119
+ }
2120
+ source = MGLVectorTileSource.alloc().initWithIdentifierTileURLTemplatesOptions(id, options.tiles, sourceOptions);
2121
+ }
2122
+ break;
2123
+ }
2124
+ case 'geojson':
2125
+ if (theMap.style.sourceWithIdentifier(id)) {
2126
+ reject("Remove the layer with this id first with 'removeLayer': " + id);
2127
+ return;
2128
+ }
2129
+ let geoJsonShape;
2130
+ if (options.data) {
2131
+ const content = NSString.stringWithString(JSON.stringify(options.data));
2132
+ const nsData = content.dataUsingEncoding(NSUTF8StringEncoding);
2133
+ geoJsonShape = MGLShape.shapeWithDataEncodingError(nsData, NSUTF8StringEncoding);
2134
+ }
2135
+ const sourceOptions = {};
2136
+ if (options.minzoom !== undefined) {
2137
+ sourceOptions[MGLShapeSourceOptionMinimumZoomLevel] = options.minzoom;
2138
+ }
2139
+ if (options.maxzoom !== undefined) {
2140
+ sourceOptions[MGLShapeSourceOptionMaximumZoomLevel] = options.maxzoom;
2141
+ }
2142
+ if (options.cluster) {
2143
+ sourceOptions[MGLShapeSourceOptionClustered] = true;
2144
+ sourceOptions[MGLShapeSourceOptionClusterRadius] = options.cluster.radius || 40;
2145
+ sourceOptions[MGLShapeSourceOptionMaximumZoomLevelForClustering] = options.cluster.maxZoom || 13;
2146
+ }
2147
+ source = MGLShapeSource.alloc().initWithIdentifierShapeOptions(id, geoJsonShape, sourceOptions);
2148
+ break;
2149
+ case 'raster': {
2150
+ const sourceOptions = {
2151
+ [MGLTileSourceOptionTileSize]: options.tileSize || 256
2152
+ };
2153
+ if (options.minzoom !== undefined) {
2154
+ sourceOptions[MGLTileSourceOptionMinimumZoomLevel] = options.minzoom;
2155
+ }
2156
+ if (options.maxzoom !== undefined) {
2157
+ sourceOptions[MGLTileSourceOptionMaximumZoomLevel] = options.maxzoom;
2158
+ }
2159
+ if (options.scheme) {
2160
+ switch (options.scheme || 'xyz') {
2161
+ case 'xyz':
2162
+ sourceOptions[MGLTileSourceOptionTileCoordinateSystem] = 0;
2163
+ break;
2164
+ case 'tms':
2165
+ sourceOptions[MGLTileSourceOptionTileCoordinateSystem] = 1;
2166
+ break;
2167
+ default:
2168
+ throw new Error('Unknown raster tile scheme.');
2169
+ }
2170
+ }
2171
+ if (options.bounds) {
2172
+ sourceOptions[MGLTileSourceOptionCoordinateBounds] = NSValue.valueWithMGLCoordinateBounds({
2173
+ sw: CLLocationCoordinate2DMake(options.bounds[1], options.bounds[0]),
2174
+ ne: CLLocationCoordinate2DMake(options.bounds[3], options.bounds[2])
2175
+ });
2176
+ }
2177
+ source = MGLRasterTileSource.alloc().initWithIdentifierTileURLTemplatesOptions(id, options.tiles, sourceOptions);
2178
+ break;
2099
2179
  }
2180
+ default:
2181
+ reject('Invalid source type: ' + options['type']);
2182
+ return;
2100
2183
  }
2101
- else {
2184
+ if (!source) {
2185
+ const ex = 'No source to add';
2102
2186
  if (Trace.isEnabled()) {
2103
- CLog(CLogTypes.info, 'Please use res://resourceName, http(s)://imageUrl or iconPath to use a local path');
2187
+ CLog(CLogTypes.info, 'Error in mapbox.addSource: ' + ex);
2104
2188
  }
2189
+ reject(ex);
2190
+ return;
2105
2191
  }
2192
+ theMap.style.addSource(source);
2193
+ resolve();
2106
2194
  }
2107
- else if (cachedMarker.iconPath) {
2108
- var appPath = knownFolders.currentApp().path;
2109
- var iconFullPath = appPath + '/' + cachedMarker.iconPath.replace('~/', '');
2110
- if (File.exists(iconFullPath)) {
2111
- var image = ImageSource.fromFileSync(iconFullPath).ios;
2112
- // perhaps add resize options for nice retina rendering (although you can now use the 'icon' param instead)
2113
- cachedMarker.reuseIdentifier = cachedMarker.iconPath;
2114
- return MGLAnnotationImage.annotationImageWithImageReuseIdentifier(image, cachedMarker.reuseIdentifier);
2195
+ catch (ex) {
2196
+ if (Trace.isEnabled()) {
2197
+ CLog(CLogTypes.info, 'Error in mapbox.addSource: ' + ex);
2115
2198
  }
2199
+ reject(ex);
2116
2200
  }
2117
- }
2118
- return null;
2119
- };
2120
- /**
2121
- * fired when one of the callout's accessoryviews is tapped (not currently used)
2122
- */
2123
- MGLMapViewDelegateImpl.prototype.mapViewAnnotationCalloutAccessoryControlTapped = function (mapView, annotation, control) { };
2124
- /**
2125
- * fired when a marker is tapped
2126
- */
2127
- MGLMapViewDelegateImpl.prototype.mapViewDidSelectAnnotation = function (mapView, annotation) {
2128
- if (Trace.isEnabled()) {
2129
- CLog(CLogTypes.info, 'MGLMapViewDelegateImpl::mapViewDidSelectAnntation()');
2130
- }
2131
- if (annotation.isKindOfClass(MGLUserLocation.class())) {
2132
- if (Trace.isEnabled()) {
2133
- CLog(CLogTypes.info, 'MGLMapViewDelegateImpl::mapViewDidSelectAnnotation(): tapped the user location button');
2201
+ });
2202
+ }
2203
+ removeSource(id, nativeMap) {
2204
+ return new Promise((resolve, reject) => {
2205
+ try {
2206
+ const theMap = nativeMap || this._mapboxViewInstance;
2207
+ if (!theMap) {
2208
+ reject('No map has been loaded');
2209
+ return;
2210
+ }
2211
+ const source = theMap.style.sourceWithIdentifier(id);
2212
+ if (!source) {
2213
+ reject('Source does not exist');
2214
+ return;
2215
+ }
2216
+ theMap.style.removeSource(source);
2217
+ resolve();
2134
2218
  }
2135
- if (typeof this.userLocationClickListener != 'undefined') {
2136
- this.userLocationClickListener(annotation);
2137
- return;
2219
+ catch (ex) {
2220
+ if (Trace.isEnabled()) {
2221
+ CLog(CLogTypes.info, 'Error in mapbox.removeSource: ' + ex);
2222
+ }
2223
+ reject(ex);
2138
2224
  }
2139
- mapView.deselectAnnotationAnimated(annotation, false);
2140
- }
2141
- var cachedMarker = this.getTappedMarkerDetails(annotation);
2142
- if (cachedMarker && cachedMarker.onTap) {
2143
- cachedMarker.onTap(cachedMarker);
2225
+ });
2226
+ }
2227
+ async addLayer(style, belowLayerId, nativeMapView) {
2228
+ const theMap = nativeMapView || this._mapboxViewInstance;
2229
+ let source = null;
2230
+ if (typeof style.source != 'string') {
2231
+ await this.addSource(style.id + '_source', style.source);
2232
+ source = theMap.style.sourceWithIdentifier(style.id + '_source');
2144
2233
  }
2145
- };
2146
- /**
2147
- * fired when a callout is tapped
2148
- */
2149
- MGLMapViewDelegateImpl.prototype.mapViewTapOnCalloutForAnnotation = function (mapView, annotation) {
2150
- var cachedMarker = this.getTappedMarkerDetails(annotation);
2151
- if (cachedMarker && cachedMarker.onCalloutTap) {
2152
- cachedMarker.onCalloutTap(cachedMarker);
2234
+ else {
2235
+ source = theMap.style.sourceWithIdentifier(style.source);
2153
2236
  }
2154
- };
2155
- MGLMapViewDelegateImpl.prototype.getTappedMarkerDetails = function (tapped) {
2156
- for (var m in _markers) {
2157
- var cached = _markers[m];
2158
- // don't compare lat/lng types as they're not the same (same for (sub)title, they may be null vs undefined)
2159
- if (
2160
- // eslint-disable-next-line eqeqeq
2161
- cached.lat == tapped.coordinate.latitude &&
2162
- // eslint-disable-next-line eqeqeq
2163
- cached.lng == tapped.coordinate.longitude &&
2164
- // eslint-disable-next-line eqeqeq
2165
- cached.title == tapped.title &&
2166
- // eslint-disable-next-line eqeqeq
2167
- cached.subtitle == tapped.subtitle) {
2168
- return cached;
2237
+ const layer = await LayerFactory.createLayer(style, source);
2238
+ if (belowLayerId) {
2239
+ const belowlayer = theMap.style.layerWithIdentifier(belowLayerId);
2240
+ if (belowlayer) {
2241
+ theMap.style.insertLayerBelowLayer(layer.getNativeInstance(), belowlayer);
2242
+ return;
2169
2243
  }
2170
2244
  }
2171
- };
2172
- /**
2173
- * override the standard location marker
2174
- */
2175
- MGLMapViewDelegateImpl.prototype.mapViewViewForAnnotation = function (mapView, annotation) {
2245
+ theMap.style.addLayer(layer.getNativeInstance());
2246
+ }
2247
+ async removeLayer(id, nativeMapViewInstance) {
2248
+ const theMap = nativeMapViewInstance || this._mapboxViewInstance;
2176
2249
  if (Trace.isEnabled()) {
2177
- CLog(CLogTypes.info, 'MGLMapViewDelegateImpl::mapViewViewForAnnotation() top');
2178
- }
2179
- if (annotation.isKindOfClass(MGLUserLocation.class())) {
2180
- this.userLocationAnnotationView = CustomUserLocationAnnotationView.alloc().init();
2181
- return this.userLocationAnnotationView;
2250
+ CLog(CLogTypes.info, "Mapbox::removeLayer(): attempting to remove layer '" + id + "'");
2182
2251
  }
2183
- return null;
2184
- };
2185
- MGLMapViewDelegateImpl.prototype.mapViewRegionIsChangingWithReason = function (mapView, reason) {
2252
+ const layer = theMap.style.layerWithIdentifier(id);
2186
2253
  if (Trace.isEnabled()) {
2187
- CLog(CLogTypes.info, 'MGLMapViewDelegateImpl::mapViewRegionIsChanging()');
2254
+ CLog(CLogTypes.info, 'Mapbox:removeLayer(): got layer object: ', layer);
2188
2255
  }
2189
- if (this.cameraChangedListener) {
2190
- this.cameraChangedListener(reason);
2256
+ if (!layer) {
2257
+ throw new Error("Layer '" + id + "' not found when attempting to remove it.");
2191
2258
  }
2192
- };
2193
- MGLMapViewDelegateImpl.prototype.mapViewRegionDidChangeWithReasonAnimated = function (mapView, reason, animated) {
2259
+ theMap.style.removeLayer(layer);
2194
2260
  if (Trace.isEnabled()) {
2195
- CLog(CLogTypes.info, 'MGLMapViewDelegateImpl::mapViewRegionDidChangeAnimated()');
2196
- }
2197
- if (this.cameraChangedListener) {
2198
- this.cameraChangedListener(reason, animated);
2261
+ CLog(CLogTypes.info, 'Mapbox:removeLayer(): after removing layer ' + id);
2199
2262
  }
2200
- if (this.cameraIdledListener) {
2201
- this.cameraIdledListener();
2263
+ }
2264
+ async addLinePoint(id, lnglat, sourceId, nativeMapView) {
2265
+ const theMap = nativeMapView || this._mapboxViewInstance;
2266
+ const sId = !!sourceId ? sourceId : id + '_source';
2267
+ const lineSource = theMap.style.sourceWithIdentifier(sId);
2268
+ if (!lineSource) {
2269
+ throw new Error(`no source found with id: ${sId}`);
2202
2270
  }
2203
- };
2204
- MGLMapViewDelegateImpl.prototype.mapViewDidUpdateUserLocation = function (mapView, userLocation) {
2205
- if (Trace.isEnabled()) {
2206
- CLog(CLogTypes.info, 'MGLMapViewDelegateImpl::mapViewDidUpdateUserLocation()');
2271
+ try {
2272
+ const lineFeatures = lineSource.featuresMatchingPredicate(FilterParser.parseJson(['==', '$type', 'LineString']));
2273
+ if (lineFeatures.count === 0) {
2274
+ throw new Error('no line string feature found');
2275
+ }
2276
+ const lineFeature = lineFeatures.objectAtIndex(0);
2277
+ const newCoord = CLLocationCoordinate2DMake(lnglat[1], lnglat[0]);
2278
+ const newCoordPointer = new interop.Reference(newCoord);
2279
+ lineFeature.appendCoordinatesCount(newCoordPointer, 1);
2280
+ lineSource.shape = lineFeature;
2207
2281
  }
2208
- if (this.userLocationChangedListener) {
2209
- this.userLocationChangedListener(_getLocation(userLocation));
2282
+ catch (error) {
2283
+ console.log(error);
2284
+ throw error;
2210
2285
  }
2211
- };
2212
- MGLMapViewDelegateImpl.ObjCProtocols = [MGLMapViewDelegate];
2213
- return MGLMapViewDelegateImpl;
2214
- }(NSObject));
2215
- var MapTapHandlerImpl = /** @class */ (function (_super) {
2216
- __extends(MapTapHandlerImpl, _super);
2217
- function MapTapHandlerImpl() {
2218
- return _super !== null && _super.apply(this, arguments) || this;
2219
2286
  }
2220
- MapTapHandlerImpl.initWithOwnerAndListenerForMap = function (owner, listener, mapView) {
2221
- var handler = MapTapHandlerImpl.new();
2222
- handler._owner = owner;
2223
- handler._listener = listener;
2224
- handler._mapView = mapView;
2225
- return handler;
2226
- };
2227
- MapTapHandlerImpl.prototype.tap = function (recognizer) {
2228
- var tapPoint = recognizer.locationInView(this._mapView);
2229
- var tapCoordinate = this._mapView.convertPointToCoordinateFromView(tapPoint, this._mapView);
2230
- this._listener({
2231
- lat: tapCoordinate.latitude,
2232
- lng: tapCoordinate.longitude
2233
- });
2234
- };
2235
- MapTapHandlerImpl.ObjCExposedMethods = {
2236
- tap: { returns: interop.types.void, params: [interop.types.id] }
2237
- };
2238
- return MapTapHandlerImpl;
2239
- }(NSObject));
2240
- var MapLongPressHandlerImpl = /** @class */ (function (_super) {
2241
- __extends(MapLongPressHandlerImpl, _super);
2242
- function MapLongPressHandlerImpl() {
2243
- return _super !== null && _super.apply(this, arguments) || this;
2287
+ addGeoJsonClustered(options, nativeMapViewInstance) {
2288
+ throw new Error('Method not implemented.');
2244
2289
  }
2245
- MapLongPressHandlerImpl.initWithOwnerAndListenerForMap = function (owner, listener, mapView) {
2246
- var handler = MapLongPressHandlerImpl.new();
2247
- handler._owner = owner;
2248
- handler._listener = listener;
2249
- handler._mapView = mapView;
2250
- return handler;
2251
- };
2252
- MapLongPressHandlerImpl.prototype.longPress = function (recognizer) {
2253
- var longPressPoint = recognizer.locationInView(this._mapView);
2254
- var longPressCoordinate = this._mapView.convertPointToCoordinateFromView(longPressPoint, this._mapView);
2255
- this._listener({
2256
- lat: longPressCoordinate.latitude,
2257
- lng: longPressCoordinate.longitude
2290
+ trackUser(options, nativeMap) {
2291
+ return new Promise((resolve, reject) => {
2292
+ try {
2293
+ const theMap = nativeMap || this._mapboxViewInstance;
2294
+ if (!theMap) {
2295
+ reject('No map has been loaded');
2296
+ return;
2297
+ }
2298
+ if (!theMap.showsUserLocation) {
2299
+ reject('The map is not currently showing the user location');
2300
+ return;
2301
+ }
2302
+ theMap.setUserTrackingModeAnimated(_getTrackingMode(options.cameraMode), options.animated !== false);
2303
+ resolve();
2304
+ }
2305
+ catch (ex) {
2306
+ if (Trace.isEnabled()) {
2307
+ CLog(CLogTypes.info, 'Error in mapbox.trackUser: ' + ex);
2308
+ }
2309
+ reject(ex);
2310
+ }
2258
2311
  });
2259
- };
2260
- MapLongPressHandlerImpl.ObjCExposedMethods = {
2261
- longPress: { returns: interop.types.void, params: [interop.types.id] }
2262
- };
2263
- return MapLongPressHandlerImpl;
2264
- }(NSObject));
2265
- var MapPanHandlerImpl = /** @class */ (function (_super) {
2266
- __extends(MapPanHandlerImpl, _super);
2267
- function MapPanHandlerImpl() {
2268
- return _super !== null && _super.apply(this, arguments) || this;
2269
2312
  }
2270
- MapPanHandlerImpl.initWithOwnerAndListenerForMap = function (owner, listener, mapView) {
2271
- var handler = MapPanHandlerImpl.new();
2272
- handler._owner = owner;
2273
- handler._listener = listener;
2274
- handler._mapView = mapView;
2275
- handler.onMoveBegin = false;
2276
- return handler;
2277
- };
2278
- MapPanHandlerImpl.prototype.setOnMoveBegin = function () {
2279
- this.onMoveBegin = true;
2280
- };
2281
- MapPanHandlerImpl.prototype.pan = function (recognizer) {
2282
- var panPoint = recognizer.locationInView(this._mapView);
2283
- var panCoordinate = this._mapView.convertPointToCoordinateFromView(panPoint, this._mapView);
2284
- if (Trace.isEnabled()) {
2285
- CLog(CLogTypes.info, 'MapPanHandlerImpl::pan(): top with state:', recognizer.state);
2286
- }
2287
- // if this is the beginning of the pan simulate the Android onMoveBegin
2288
- //
2289
- // See the objc platform declarations in objc!UIKit.d.ts. It doesn't quite match the apple documention
2290
- if (this.onMoveBegin) {
2291
- if (recognizer.state === UIGestureRecognizerState.Began) {
2313
+ getLayer(name, nativeMap) {
2314
+ return new Promise((resolve, reject) => {
2315
+ try {
2316
+ const theMap = nativeMap || this._mapboxViewInstance;
2317
+ if (!theMap) {
2318
+ reject('No map has been loaded');
2319
+ return;
2320
+ }
2321
+ const layer = theMap.style.layerWithIdentifier(name);
2322
+ resolve(new Layer(layer));
2323
+ }
2324
+ catch (ex) {
2292
2325
  if (Trace.isEnabled()) {
2293
- CLog(CLogTypes.info, 'MapPanHandlerImpl::pan(): calling onMoveBegin listener');
2326
+ CLog(CLogTypes.info, 'Error in mapbox.getLayer: ' + ex);
2294
2327
  }
2295
- this._listener({
2296
- lat: panCoordinate.latitude,
2297
- lng: panCoordinate.longitude
2298
- });
2328
+ reject(ex);
2299
2329
  }
2300
- return;
2301
- }
2302
- this._listener({
2303
- lat: panCoordinate.latitude,
2304
- lng: panCoordinate.longitude
2305
2330
  });
2306
- };
2307
- MapPanHandlerImpl.ObjCExposedMethods = {
2308
- pan: { returns: interop.types.void, params: [interop.types.id] }
2309
- };
2310
- return MapPanHandlerImpl;
2311
- }(NSObject));
2312
- var MapSwipeHandlerImpl = /** @class */ (function (_super) {
2313
- __extends(MapSwipeHandlerImpl, _super);
2314
- function MapSwipeHandlerImpl() {
2315
- return _super !== null && _super.apply(this, arguments) || this;
2316
2331
  }
2317
- MapSwipeHandlerImpl.initWithOwnerAndListenerForMap = function (owner, listener, mapView) {
2318
- var handler = MapSwipeHandlerImpl.new();
2319
- handler._owner = owner;
2320
- handler._listener = listener;
2321
- handler._mapView = mapView;
2322
- return handler;
2323
- };
2324
- MapSwipeHandlerImpl.prototype.swipe = function (recognizer) {
2325
- var swipePoint = recognizer.locationInView(this._mapView);
2326
- var swipeCoordinate = this._mapView.convertPointToCoordinateFromView(swipePoint, this._mapView);
2327
- this._listener({
2328
- lat: swipeCoordinate.latitude,
2329
- lng: swipeCoordinate.longitude
2332
+ getLayers(nativeMap) {
2333
+ return new Promise((resolve, reject) => {
2334
+ try {
2335
+ const theMap = nativeMap || this._mapboxViewInstance;
2336
+ if (!theMap) {
2337
+ reject('No map has been loaded');
2338
+ return;
2339
+ }
2340
+ const layers = theMap.style.layers;
2341
+ const result = [];
2342
+ for (let i = 0; i < layers.count; i++) {
2343
+ result.push(new Layer(layers[i]));
2344
+ }
2345
+ resolve(result);
2346
+ }
2347
+ catch (ex) {
2348
+ if (Trace.isEnabled()) {
2349
+ CLog(CLogTypes.info, 'Error in mapbox.getLayers: ' + ex);
2350
+ }
2351
+ reject(ex);
2352
+ }
2330
2353
  });
2331
- };
2332
- MapSwipeHandlerImpl.ObjCExposedMethods = {
2333
- swipe: { returns: interop.types.void, params: [interop.types.id] }
2334
- };
2335
- return MapSwipeHandlerImpl;
2336
- }(NSObject));
2337
- export class Layer {
2338
- constructor(instance) {
2339
- this.instance = instance;
2340
- this.id = instance.identifier;
2341
- }
2342
- visibility() {
2343
- return this.instance.visible;
2344
- }
2345
- show() {
2346
- this.instance.visible = true;
2347
2354
  }
2348
- hide() {
2349
- this.instance.visible = false;
2350
- }
2351
- getNativeInstance() {
2352
- return this.instance;
2355
+ project(data) {
2356
+ const theMap = this._mapboxViewInstance;
2357
+ const { x, y } = theMap.convertCoordinateToPointToView({ latitude: data.lat, longitude: data.lng }, theMap);
2358
+ return { x, y };
2353
2359
  }
2354
- setFilter(filter) {
2355
- if (this.instance instanceof MGLVectorStyleLayer) {
2356
- this.instance.predicate = FilterParser.parseJson(filter);
2360
+ }
2361
+ const _addObserver = (eventName, callback) => NSNotificationCenter.defaultCenter.addObserverForNameObjectQueueUsingBlock(eventName, null, NSOperationQueue.mainQueue, callback);
2362
+ function _downloadImage(marker) {
2363
+ return new Promise((resolve, reject) => {
2364
+ if (Trace.isEnabled()) {
2365
+ CLog(CLogTypes.info, '>> _downloadImage');
2357
2366
  }
2358
- else {
2359
- throw new Error('Set filter only support for vector layer.');
2367
+ if (_markerIconDownloadCache[marker.icon]) {
2368
+ marker.iconDownloaded = _markerIconDownloadCache[marker.icon];
2369
+ if (Trace.isEnabled()) {
2370
+ CLog(CLogTypes.info, '>> marker.iconDownloaded: ' + marker.iconDownloaded);
2371
+ }
2372
+ resolve(marker);
2373
+ return;
2360
2374
  }
2361
- }
2362
- getFilter() {
2363
- return FilterParser.toJson(this.instance.predicate);
2364
- }
2375
+ Http.getImage(marker.icon).then((output) => {
2376
+ marker.iconDownloaded = output.ios;
2377
+ _markerIconDownloadCache[marker.icon] = marker.iconDownloaded;
2378
+ resolve(marker);
2379
+ }, (ignoredError) => {
2380
+ console.log(`Download failed for ${marker.icon} with error: ${ignoredError}`);
2381
+ resolve(marker);
2382
+ });
2383
+ });
2365
2384
  }
2366
- //# sourceMappingURL=mapbox.ios.js.map
2385
+ const _downloadMarkerImages = (markers) => {
2386
+ const iterations = [];
2387
+ const result = [];
2388
+ markers.forEach((marker) => {
2389
+ if (marker.icon && marker.icon.startsWith('http')) {
2390
+ const p = _downloadImage(marker).then((mark) => result.push(mark));
2391
+ iterations.push(p);
2392
+ }
2393
+ else {
2394
+ result.push(marker);
2395
+ }
2396
+ });
2397
+ return Promise.all(iterations).then(() => result);
2398
+ };
2399
+ //# sourceMappingURL=index.ios.js.map