@nativescript-community/ui-mapbox 6.2.10 → 6.2.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/README.md +199 -99
  3. package/{mapbox.common.d.ts → common.d.ts} +42 -4
  4. package/{mapbox.common.js → common.js} +21 -1
  5. package/{filter/filter-parser.android.d.ts → expression/expression-parser.android.d.ts} +1 -1
  6. package/{filter/filter-parser.android.js → expression/expression-parser.android.js} +2 -2
  7. package/expression/expression-parser.d.ts +4 -0
  8. package/{filter/filter-parser.ios.d.ts → expression/expression-parser.ios.d.ts} +1 -1
  9. package/{filter/filter-parser.ios.js → expression/expression-parser.ios.js} +2 -2
  10. package/{mapbox.android.d.ts → index.android.d.ts} +9 -14
  11. package/{mapbox.android.js → index.android.js} +152 -65
  12. package/index.d.ts +99 -6
  13. package/{mapbox.ios.d.ts → index.ios.d.ts} +7 -30
  14. package/{mapbox.ios.js → index.ios.js} +1977 -1912
  15. package/layers/layer-factory.android.d.ts +15 -1
  16. package/layers/layer-factory.android.js +63 -2
  17. package/layers/layer-factory.d.ts +17 -2
  18. package/layers/layer-factory.ios.d.ts +15 -1
  19. package/layers/layer-factory.ios.js +72 -2
  20. package/layers/parser/property-parser.android.d.ts +1 -0
  21. package/layers/parser/property-parser.android.js +25 -0
  22. package/layers/parser/property-parser.d.ts +4 -0
  23. package/layers/parser/property-parser.ios.d.ts +1 -0
  24. package/layers/parser/property-parser.ios.js +21 -0
  25. package/package.json +55 -49
  26. package/platforms/android/include.gradle +3 -0
  27. package/platforms/android/ui_mapbox.aar +0 -0
  28. package/platforms/ios/Podfile +2 -2
  29. package/typings/Mapbox.ios.d.ts +2 -0
  30. package/LICENSE +0 -21
@@ -1,1564 +1,1665 @@
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 { ExpressionParser } from './expression/expression-parser';
5
+ var MGLMapViewDelegateImpl = /** @class */ (function (_super) {
6
+ __extends(MGLMapViewDelegateImpl, _super);
7
+ function MGLMapViewDelegateImpl() {
8
+ return _super !== null && _super.apply(this, arguments) || this;
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('~/', '');
706
- }
707
- const img = ImageSource.fromFileOrResourceSync(image);
708
- try {
709
- theMap.style.setImageForName(img.ios, imageId);
710
- resolve();
711
- }
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;
718
- }
719
- });
514
+ setConfig(settings) {
515
+ if (Trace.isEnabled()) {
516
+ CLog(CLogTypes.info, 'setConfig(): settings:', settings);
517
+ }
518
+ this.settings = settings;
720
519
  }
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
- });
520
+ getNativeMapView() {
521
+ return this.nativeMapView;
740
522
  }
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();
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?');
747
571
  }
748
- catch (ex) {
749
- if (Trace.isEnabled()) {
750
- CLog(CLogTypes.info, 'Error in mapbox.addMarkers: ' + ex);
751
- }
752
- reject(ex);
572
+ if (this.initCountHack > 50) {
573
+ return;
753
574
  }
754
- });
755
- }
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);
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()');
591
+ }
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');
764
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
+ });
765
613
  });
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();
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();
776
693
  }
777
- catch (ex) {
778
- if (Trace.isEnabled()) {
779
- CLog(CLogTypes.info, 'Error in mapbox.removeMarkers: ' + ex);
780
- }
781
- reject(ex);
694
+ if (this.userLocationRenderMode === 'GPS') {
695
+ this.updateHeading();
782
696
  }
783
- });
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 = {};
784
876
  }
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);
799
- }
800
- });
877
+ setMapboxViewInstance(mapboxViewInstance) {
878
+ this._mapboxViewInstance = mapboxViewInstance;
801
879
  }
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
- });
811
- }
812
- catch (ex) {
813
- if (Trace.isEnabled()) {
814
- CLog(CLogTypes.info, 'Error in mapbox.getCenter: ' + ex);
815
- }
816
- reject(ex);
817
- }
818
- });
880
+ initEventHandlerShim(settings, mapboxNativeViewInstance) {
881
+ if (Trace.isEnabled()) {
882
+ CLog(CLogTypes.info, 'Mapbox:initEventHandlerShim(): top');
883
+ }
884
+ this.setOnMapClickListener((point) => this.checkForClickEvent(point), mapboxNativeViewInstance);
819
885
  }
820
- setZoomLevel(options, nativeMap) {
821
- return new Promise((resolve, reject) => {
822
- 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);
837
- }
838
- reject(ex);
839
- }
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
840
893
  });
841
894
  }
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);
851
- }
852
- reject(ex);
853
- }
854
- });
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);
855
900
  }
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));
864
- setTimeout(() => {
865
- resolve();
866
- }, durationMs);
867
- }
868
- catch (ex) {
869
- if (Trace.isEnabled()) {
870
- CLog(CLogTypes.info, 'Error in mapbox.setTilt: ' + ex);
871
- }
872
- reject(ex);
873
- }
874
- });
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);
911
+ }
912
+ })
913
+ .catch((err) => {
914
+ console.error('click error ', eventListener.id, err);
915
+ });
916
+ });
917
+ this.view && this.view.notify({ eventName: 'mapClick', object: this.view, point });
918
+ return false;
875
919
  }
876
- getTilt(nativeMap) {
877
- return new Promise((resolve, reject) => {
878
- try {
879
- const theMap = nativeMap || this._mapboxViewInstance;
880
- resolve(theMap.camera.pitch);
881
- }
882
- catch (ex) {
883
- if (Trace.isEnabled()) {
884
- CLog(CLogTypes.info, 'Error in mapbox.getTilt: ' + ex);
885
- }
886
- reject(ex);
920
+ _addMarkers(markers, nativeMap) {
921
+ if (!markers) {
922
+ if (Trace.isEnabled()) {
923
+ CLog(CLogTypes.info, 'No markers passed');
887
924
  }
888
- });
889
- }
890
- getUserLocation(nativeMap) {
891
- return new Promise((resolve, reject) => {
892
- try {
893
- const theMap = nativeMap || this._mapboxViewInstance;
894
- const loc = theMap.userLocation;
895
- if (loc === null) {
896
- reject('Location not available');
897
- }
898
- else {
899
- resolve(_getLocation(loc));
900
- }
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'}]");
901
930
  }
902
- catch (ex) {
903
- if (Trace.isEnabled()) {
904
- CLog(CLogTypes.info, 'Error in mapbox.getUserLocation: ' + 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);
905
946
  }
906
- reject(ex);
907
- }
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
+ });
908
975
  });
909
976
  }
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
- }
933
- }
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';
977
+ show(options) {
978
+ if (Trace.isEnabled()) {
979
+ CLog(CLogTypes.info, 'show(): top with options:', options);
943
980
  }
944
- }
945
- showUserLocationMarker(options, nativeMap) {
946
981
  return new Promise((resolve, reject) => {
947
982
  try {
948
- 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
- const delegate = theMap.delegate;
954
- delegate.changeUserLocationRenderMode(this.userLocationRenderMode);
955
- if (typeof options.clickListener != 'undefined') {
956
- delegate.setUserLocationClickListener(options.clickListener);
983
+ const settings = Mapbox.merge(options, Mapbox.defaults);
984
+ if (settings.accessToken === undefined) {
985
+ reject("Please set the 'accessToken' parameter");
986
+ return;
957
987
  }
958
- resolve();
988
+ if (this._mapboxViewInstance) {
989
+ this._mapboxViewInstance.removeFromSuperview();
990
+ }
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);
1002
+ setTimeout(() => {
1003
+ view.addSubview(this._mapboxViewInstance);
1004
+ }, 500);
959
1005
  }
960
1006
  catch (ex) {
961
1007
  if (Trace.isEnabled()) {
962
- CLog(CLogTypes.info, 'Error in mapbox.getUserLocation: ' + ex);
1008
+ CLog(CLogTypes.info, 'Error in mapbox.show: ' + ex);
963
1009
  }
964
1010
  reject(ex);
965
1011
  }
966
1012
  });
967
1013
  }
968
- hideUserLocationMarker(nativeMap) {
1014
+ hide() {
969
1015
  return new Promise((resolve, reject) => {
970
1016
  try {
1017
+ if (this._mapboxViewInstance) {
1018
+ this._mapboxViewInstance.removeFromSuperview();
1019
+ }
971
1020
  resolve();
972
1021
  }
973
1022
  catch (ex) {
974
1023
  if (Trace.isEnabled()) {
975
- CLog(CLogTypes.info, 'Error in mapbox.getUserLocation: ' + ex);
1024
+ CLog(CLogTypes.info, 'Error in mapbox.hide: ' + ex);
976
1025
  }
977
1026
  reject(ex);
978
1027
  }
979
1028
  });
980
1029
  }
981
- changeUserLocationMarkerMode(renderModeString, cameraModeString, nativeMap) {
1030
+ unhide() {
982
1031
  return new Promise((resolve, reject) => {
983
1032
  try {
984
- const theMap = nativeMap || this._mapboxViewInstance;
985
- if (Trace.isEnabled()) {
986
- CLog(CLogTypes.info, "Mapbox::changeUserLocationMarkerMode(): changing renderMode to '" + renderModeString + "' cameraMode '" + cameraModeString + "'");
1033
+ if (this._mapboxViewInstance) {
1034
+ const view = UIApplication.sharedApplication.keyWindow.rootViewController.view;
1035
+ view.addSubview(this._mapboxViewInstance);
1036
+ resolve();
1037
+ }
1038
+ else {
1039
+ reject('No map found');
987
1040
  }
988
- theMap.userTrackingMode = this._stringToCameraMode(cameraModeString);
989
- const delegate = theMap.delegate;
990
- const renderMode = this._stringToRenderMode(renderModeString);
991
- delegate.changeUserLocationRenderMode(renderMode);
992
1041
  }
993
1042
  catch (ex) {
994
1043
  if (Trace.isEnabled()) {
995
- CLog(CLogTypes.info, 'Error in mapbox.showUserLocationMarker: ' + ex);
1044
+ CLog(CLogTypes.info, 'Error in mapbox.unhide: ' + ex);
996
1045
  }
997
1046
  reject(ex);
998
1047
  }
999
1048
  });
1000
1049
  }
1001
- forceUserLocationUpdate(location, nativeMap) { }
1002
- queryRenderedFeatures(options, nativeMap) {
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
+ });
1059
+ }
1060
+ onStart(nativeMap) {
1061
+ return Promise.resolve();
1062
+ }
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) {
1003
1079
  return new Promise((resolve, reject) => {
1004
1080
  try {
1005
1081
  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);
1082
+ const delegate = theMap.delegate;
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);
1024
1090
  }
1025
1091
  catch (ex) {
1026
1092
  if (Trace.isEnabled()) {
1027
- CLog(CLogTypes.info, 'Error in mapbox.queryRenderedFeatures: ' + ex);
1093
+ CLog(CLogTypes.info, 'Error in mapbox.setMapStyle: ' + ex);
1028
1094
  }
1029
1095
  reject(ex);
1030
1096
  }
1031
1097
  });
1032
1098
  }
1033
- querySourceFeatures(sourceId, options, nativeMap) {
1099
+ async getImage(imageId, nativeMap) {
1034
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
+ }
1035
1106
  try {
1036
- 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);
1107
+ const nativeImage = theMap.style.imageForName(imageId);
1108
+ const img = new ImageSource(nativeImage);
1109
+ resolve(img);
1066
1110
  }
1067
1111
  catch (ex) {
1112
+ reject('Error during getImage: ' + ex);
1068
1113
  if (Trace.isEnabled()) {
1069
- CLog(CLogTypes.info, 'Error in mapbox.querySourceFeatures: ' + ex);
1114
+ CLog(CLogTypes.info, 'Error in mapbox.getImage: ' + ex);
1070
1115
  }
1071
- reject(ex);
1116
+ throw ex;
1072
1117
  }
1073
1118
  });
1074
1119
  }
1075
- addPolygon(options, nativeMap) {
1120
+ async addImage(imageId, image, nativeMap) {
1076
1121
  return new Promise((resolve, reject) => {
1077
1122
  const theMap = nativeMap || this._mapboxViewInstance;
1078
- const points = options.points;
1079
- if (points === undefined) {
1080
- reject("Please set the 'points' parameter");
1123
+ if (!theMap) {
1124
+ reject('No map has been loaded');
1081
1125
  return;
1082
1126
  }
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;
1127
+ if (!image.startsWith('res://')) {
1128
+ const appPath = knownFolders.currentApp().path;
1129
+ image = appPath + '/' + image.replace('~/', '');
1089
1130
  }
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)}]
1101
- }
1131
+ const img = ImageSource.fromFileOrResourceSync(image);
1132
+ try {
1133
+ theMap.style.setImageForName(img.ios, imageId);
1134
+ resolve();
1135
+ }
1136
+ catch (ex) {
1137
+ reject('Error during addImage: ' + ex);
1138
+ if (Trace.isEnabled()) {
1139
+ CLog(CLogTypes.info, 'Error in mapbox.addImage: ' + ex);
1102
1140
  }
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);
1141
+ throw ex;
1118
1142
  }
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
1143
  });
1125
1144
  }
1126
- addPolyline(options, nativeMap) {
1145
+ async removeImage(imageId, nativeMap) {
1127
1146
  return new Promise((resolve, reject) => {
1128
1147
  const theMap = nativeMap || this._mapboxViewInstance;
1129
- const points = options.points;
1130
- if (points === undefined) {
1131
- reject("Please set the 'points' parameter");
1148
+ if (!theMap) {
1149
+ reject('No map has been loaded');
1132
1150
  return;
1133
1151
  }
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;
1152
+ try {
1153
+ theMap.style.removeImageForName(imageId);
1154
+ resolve();
1155
+ }
1156
+ catch (ex) {
1157
+ reject('Error during removeImage: ' + ex);
1158
+ if (Trace.isEnabled()) {
1159
+ CLog(CLogTypes.info, 'Error in mapbox.removeImage: ' + ex);
1160
+ }
1161
+ throw ex;
1140
1162
  }
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
- });
1156
- }
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();
1176
1163
  });
1177
1164
  }
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) {
1165
+ addMarkers(markers, nativeMap) {
1185
1166
  return new Promise((resolve, reject) => {
1186
1167
  try {
1187
1168
  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);
1169
+ this._addMarkers(markers, theMap);
1170
+ resolve();
1171
+ }
1172
+ catch (ex) {
1173
+ if (Trace.isEnabled()) {
1174
+ CLog(CLogTypes.info, 'Error in mapbox.addMarkers: ' + ex);
1202
1175
  }
1203
- else {
1204
- const target = options.target;
1205
- if (target === undefined) {
1206
- reject("Please set the 'target' parameter");
1207
- return;
1176
+ reject(ex);
1177
+ }
1178
+ });
1179
+ }
1180
+ removeMarkers(ids, nativeMap) {
1181
+ return new Promise((resolve, reject) => {
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);
1208
1188
  }
1209
- cam = theMap.camera;
1210
- cam.centerCoordinate = CLLocationCoordinate2DMake(target.lat, target.lng);
1189
+ });
1190
+ if (ids) {
1191
+ _markers = _markers.filter((marker) => ids.indexOf(marker.id) < 0);
1211
1192
  }
1212
- if (options.altitude) {
1213
- cam.altitude = options.altitude;
1193
+ else {
1194
+ _markers = [];
1214
1195
  }
1215
- if (options.bearing) {
1216
- cam.heading = options.bearing;
1196
+ if (markersToRemove.length > 0) {
1197
+ theMap.removeAnnotations(markersToRemove);
1217
1198
  }
1218
- if (options.tilt) {
1219
- cam.pitch = options.tilt;
1199
+ resolve();
1200
+ }
1201
+ catch (ex) {
1202
+ if (Trace.isEnabled()) {
1203
+ CLog(CLogTypes.info, 'Error in mapbox.removeMarkers: ' + ex);
1220
1204
  }
1221
- if (options.zoomLevel && options.target) {
1222
- cam.altitude = MGLAltitudeForZoomLevel(options.zoomLevel, cam.pitch, options.target.lat, theMap.frame.size);
1205
+ reject(ex);
1206
+ }
1207
+ });
1208
+ }
1209
+ setCenter(options, nativeMap) {
1210
+ return new Promise((resolve, reject) => {
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();
1217
+ }
1218
+ catch (ex) {
1219
+ if (Trace.isEnabled()) {
1220
+ CLog(CLogTypes.info, 'Error in mapbox.setCenter: ' + ex);
1223
1221
  }
1224
- const durationMs = options.duration ? options.duration : 10000;
1225
- theMap.setCameraWithDurationAnimationTimingFunction(cam, durationMs / 1000, CAMediaTimingFunction.functionWithName(kCAMediaTimingFunctionEaseInEaseOut));
1226
- setTimeout(() => {
1227
- resolve();
1228
- }, durationMs);
1222
+ reject(ex);
1223
+ }
1224
+ });
1225
+ }
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
+ });
1229
1235
  }
1230
1236
  catch (ex) {
1231
1237
  if (Trace.isEnabled()) {
1232
- CLog(CLogTypes.info, 'Error in mapbox.animateCamera: ' + ex);
1238
+ CLog(CLogTypes.info, 'Error in mapbox.getCenter: ' + ex);
1233
1239
  }
1234
1240
  reject(ex);
1235
1241
  }
1236
1242
  });
1237
1243
  }
1238
- setOnMapClickListener(listener, nativeMap) {
1244
+ setZoomLevel(options, nativeMap) {
1239
1245
  return new Promise((resolve, reject) => {
1240
1246
  try {
1241
1247
  const theMap = nativeMap || this._mapboxViewInstance;
1242
- if (!theMap) {
1243
- reject('No map has been loaded');
1244
- return;
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();
1245
1253
  }
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
- }
1254
+ else {
1255
+ reject('invalid ZoomLevel, use any double value from 0 to 20 (like 8.3)');
1253
1256
  }
1254
- theMap.addGestureRecognizer(tapGestureRecognizer);
1255
- resolve();
1256
1257
  }
1257
1258
  catch (ex) {
1258
1259
  if (Trace.isEnabled()) {
1259
- CLog(CLogTypes.info, 'Error in mapbox.setOnMapClickListener: ' + ex);
1260
+ CLog(CLogTypes.info, 'Error in mapbox.setZoomLevel: ' + ex);
1260
1261
  }
1261
1262
  reject(ex);
1262
1263
  }
1263
1264
  });
1264
1265
  }
1265
- setOnMapLongClickListener(listener, nativeMap) {
1266
+ getZoomLevel(nativeMap) {
1266
1267
  return new Promise((resolve, reject) => {
1267
1268
  try {
1268
1269
  const theMap = nativeMap || this._mapboxViewInstance;
1269
- if (!theMap) {
1270
- reject('No map has been loaded');
1271
- return;
1270
+ resolve(theMap.zoomLevel);
1271
+ }
1272
+ catch (ex) {
1273
+ if (Trace.isEnabled()) {
1274
+ CLog(CLogTypes.info, 'Error in mapbox.getZoomLevel: ' + ex);
1272
1275
  }
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
- }
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;
1287
+ theMap.setCameraWithDurationAnimationTimingFunction(cam, durationMs / 1000, CAMediaTimingFunction.functionWithName(kCAMediaTimingFunctionEaseInEaseOut));
1288
+ setTimeout(() => {
1289
+ resolve();
1290
+ }, durationMs);
1291
+ }
1292
+ catch (ex) {
1293
+ if (Trace.isEnabled()) {
1294
+ CLog(CLogTypes.info, 'Error in mapbox.setTilt: ' + ex);
1280
1295
  }
1281
- theMap.addGestureRecognizer(longPressGestureRecognizer);
1282
- resolve();
1296
+ reject(ex);
1297
+ }
1298
+ });
1299
+ }
1300
+ getTilt(nativeMap) {
1301
+ return new Promise((resolve, reject) => {
1302
+ try {
1303
+ const theMap = nativeMap || this._mapboxViewInstance;
1304
+ resolve(theMap.camera.pitch);
1283
1305
  }
1284
1306
  catch (ex) {
1285
1307
  if (Trace.isEnabled()) {
1286
- CLog(CLogTypes.info, 'Error in mapbox.setOnMapClickListener: ' + ex);
1308
+ CLog(CLogTypes.info, 'Error in mapbox.getTilt: ' + ex);
1287
1309
  }
1288
1310
  reject(ex);
1289
1311
  }
1290
1312
  });
1291
1313
  }
1292
- setOnScrollListener(listener, nativeMap) {
1314
+ getUserLocation(nativeMap) {
1293
1315
  return new Promise((resolve, reject) => {
1294
1316
  try {
1295
1317
  const theMap = nativeMap || this._mapboxViewInstance;
1296
- if (!theMap) {
1297
- reject('No map has been loaded');
1298
- return;
1318
+ const loc = theMap.userLocation;
1319
+ if (loc === null) {
1320
+ reject('Location not available');
1299
1321
  }
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
- }
1322
+ else {
1323
+ resolve(_getLocation(loc));
1307
1324
  }
1308
- resolve();
1309
1325
  }
1310
1326
  catch (ex) {
1311
1327
  if (Trace.isEnabled()) {
1312
- CLog(CLogTypes.info, 'Error in mapbox.setOnScrollListener: ' + ex);
1328
+ CLog(CLogTypes.info, 'Error in mapbox.getUserLocation: ' + ex);
1313
1329
  }
1314
1330
  reject(ex);
1315
1331
  }
1316
1332
  });
1317
1333
  }
1318
- setOnMoveBeginListener(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) {
1319
1370
  return new Promise((resolve, reject) => {
1320
1371
  try {
1321
1372
  const theMap = nativeMap || this._mapboxViewInstance;
1322
- if (!theMap) {
1323
- reject('No map has been loaded');
1324
- return;
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);
1325
1381
  }
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
- }
1382
+ resolve();
1383
+ }
1384
+ catch (ex) {
1385
+ if (Trace.isEnabled()) {
1386
+ CLog(CLogTypes.info, 'Error in mapbox.getUserLocation: ' + ex);
1334
1387
  }
1388
+ reject(ex);
1389
+ }
1390
+ });
1391
+ }
1392
+ hideUserLocationMarker(nativeMap) {
1393
+ return new Promise((resolve, reject) => {
1394
+ try {
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 = options.padding !== undefined ? { top: options.padding, left: options.padding, bottom: options.padding, right: options.padding } : { top: 25, left: 25, bottom: 25, right: 25 };
1411
- theMap.setVisibleCoordinateBoundsEdgePaddingAnimated(bounds, padding, animated);
1412
- 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 ? ExpressionParser.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);
1413
1448
  }
1414
1449
  catch (ex) {
1415
1450
  if (Trace.isEnabled()) {
1416
- CLog(CLogTypes.info, 'Error in mapbox.setViewport: ' + ex);
1451
+ CLog(CLogTypes.info, 'Error in mapbox.queryRenderedFeatures: ' + ex);
1417
1452
  }
1418
1453
  reject(ex);
1419
1454
  }
1420
1455
  });
1421
1456
  }
1422
- downloadOfflineRegion(options) {
1457
+ querySourceFeatures(sourceId, options, nativeMap) {
1423
1458
  return new Promise((resolve, reject) => {
1424
1459
  try {
1425
- const styleURL = _getMapStyle(options.style);
1426
- const swCoordinate = CLLocationCoordinate2DMake(options.bounds.south, options.bounds.west);
1427
- const neCoordinate = CLLocationCoordinate2DMake(options.bounds.north, options.bounds.east);
1428
- const bounds = {
1429
- sw: swCoordinate,
1430
- ne: neCoordinate
1431
- };
1432
- const region = MGLTilePyramidOfflineRegion.alloc().initWithStyleURLBoundsFromZoomLevelToZoomLevel(styleURL, bounds, options.minZoom, options.maxZoom);
1433
- if (options.accessToken) {
1434
- MGLAccountManager.accessToken = options.accessToken;
1460
+ const theMap = nativeMap || this._mapboxViewInstance;
1461
+ if (!options) {
1462
+ options = {};
1435
1463
  }
1436
- if (options.onProgress) {
1437
- _addObserver(MGLOfflinePackProgressChangedNotification, (notification) => {
1438
- const offlinePack = notification.object;
1439
- const offlinePackProgress = offlinePack.progress;
1440
- const userInfo = NSKeyedUnarchiver.unarchiveObjectWithData(offlinePack.context);
1441
- const complete = offlinePackProgress.countOfResourcesCompleted === offlinePackProgress.countOfResourcesExpected;
1442
- options.onProgress({
1443
- name: userInfo.objectForKey('name'),
1444
- completed: offlinePackProgress.countOfResourcesCompleted,
1445
- expected: offlinePackProgress.countOfResourcesExpected,
1446
- percentage: Math.round((offlinePackProgress.countOfResourcesCompleted / offlinePackProgress.countOfResourcesExpected) * 10000) / 100,
1447
- complete
1448
- });
1449
- if (complete) {
1450
- resolve();
1451
- }
1452
- });
1464
+ const source = theMap.style.sourceWithIdentifier(sourceId);
1465
+ if (!source) {
1466
+ throw new Error(`Source with id "${sourceId}" not found.`);
1453
1467
  }
1454
- _addObserver(MGLOfflinePackErrorNotification, (notification) => {
1455
- const offlinePack = notification.object;
1456
- const userInfo = NSKeyedUnarchiver.unarchiveObjectWithData(offlinePack.context);
1457
- const error = notification.userInfo[MGLOfflinePackUserInfoKeyError];
1458
- reject({
1459
- name: userInfo.objectForKey('name'),
1460
- error: 'Download error. ' + error
1461
- });
1462
- });
1463
- _addObserver(MGLOfflinePackMaximumMapboxTilesReachedNotification, (notification) => {
1464
- const offlinePack = notification.object;
1465
- const userInfo = NSKeyedUnarchiver.unarchiveObjectWithData(offlinePack.context);
1466
- const maximumCount = notification.userInfo[MGLOfflinePackUserInfoKeyMaximumCount];
1467
- console.log(`Offline region '${userInfo.objectForKey('name')}' reached the tile limit of ${maximumCount}`);
1468
- });
1469
- const userInfo = { name: options.name };
1470
- const context = NSKeyedArchiver.archivedDataWithRootObject(userInfo);
1471
- MGLOfflineStorage.sharedOfflineStorage.addPackForRegionWithContextCompletionHandler(region, context, (pack, error) => {
1472
- if (error) {
1473
- reject(error.localizedFailureReason);
1474
- }
1475
- else {
1476
- pack.resume();
1468
+ let features;
1469
+ const queryFilter = options.filter ? ExpressionParser.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.');
1477
1476
  }
1478
- });
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);
1479
1490
  }
1480
1491
  catch (ex) {
1481
1492
  if (Trace.isEnabled()) {
1482
- CLog(CLogTypes.info, 'Error in mapbox.downloadOfflineRegion: ' + ex);
1493
+ CLog(CLogTypes.info, 'Error in mapbox.querySourceFeatures: ' + ex);
1483
1494
  }
1484
1495
  reject(ex);
1485
1496
  }
1486
1497
  });
1487
1498
  }
1488
- listOfflineRegions(options) {
1499
+ addPolygon(options, nativeMap) {
1500
+ return new Promise((resolve, reject) => {
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
+ }
1526
+ }
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;
1557
+ }
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;
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();
1579
+ });
1580
+ }
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) {
1489
1609
  return new Promise((resolve, reject) => {
1490
1610
  try {
1491
- const packs = MGLOfflineStorage.sharedOfflineStorage.packs;
1492
- if (!packs) {
1493
- reject('No packs found or Mapbox not ready yet');
1494
- 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);
1495
1626
  }
1496
- const regions = [];
1497
- for (let i = 0; i < packs.count; i++) {
1498
- const pack = packs.objectAtIndex(i);
1499
- const region = pack.region;
1500
- const userInfo = NSKeyedUnarchiver.unarchiveObjectWithData(pack.context);
1501
- regions.push({
1502
- name: userInfo.objectForKey('name'),
1503
- style: '' + region.styleURL,
1504
- minZoom: region.minimumZoomLevel,
1505
- maxZoom: region.maximumZoomLevel,
1506
- bounds: {
1507
- north: region.bounds.ne.latitude,
1508
- east: region.bounds.ne.longitude,
1509
- south: region.bounds.sw.latitude,
1510
- west: region.bounds.sw.longitude
1511
- }
1512
- });
1627
+ else {
1628
+ const target = options.target;
1629
+ if (target === undefined) {
1630
+ reject("Please set the 'target' parameter");
1631
+ return;
1632
+ }
1633
+ cam = theMap.camera;
1634
+ cam.centerCoordinate = CLLocationCoordinate2DMake(target.lat, target.lng);
1513
1635
  }
1514
- resolve(regions);
1515
- }
1516
- catch (ex) {
1517
- if (Trace.isEnabled()) {
1518
- CLog(CLogTypes.info, 'Error in mapbox.listOfflineRegions: ' + ex);
1636
+ if (options.altitude) {
1637
+ cam.altitude = options.altitude;
1519
1638
  }
1520
- reject(ex);
1521
- }
1522
- });
1523
- }
1524
- deleteOfflineRegion(options) {
1525
- return new Promise((resolve, reject) => {
1526
- try {
1527
- if (!options || !options.name) {
1528
- reject("Pass in the 'name' param");
1529
- return;
1639
+ if (options.bearing) {
1640
+ cam.heading = options.bearing;
1530
1641
  }
1531
- const packs = MGLOfflineStorage.sharedOfflineStorage.packs;
1532
- let found = false;
1533
- for (let i = 0; i < packs.count; i++) {
1534
- const pack = packs.objectAtIndex(i);
1535
- const userInfo = NSKeyedUnarchiver.unarchiveObjectWithData(pack.context);
1536
- const name = userInfo.objectForKey('name');
1537
- if (name === options.name) {
1538
- found = true;
1539
- MGLOfflineStorage.sharedOfflineStorage.removePackWithCompletionHandler(pack, (error) => {
1540
- if (error) {
1541
- reject(error.localizedFailureReason);
1542
- }
1543
- else {
1544
- resolve();
1545
- }
1546
- });
1547
- }
1642
+ if (options.tilt) {
1643
+ cam.pitch = options.tilt;
1548
1644
  }
1549
- if (!found) {
1550
- reject('Region not found');
1645
+ if (options.zoomLevel && options.target) {
1646
+ cam.altitude = MGLAltitudeForZoomLevel(options.zoomLevel, cam.pitch, options.target.lat, theMap.frame.size);
1551
1647
  }
1648
+ const durationMs = options.duration ? options.duration : 10000;
1649
+ theMap.setCameraWithDurationAnimationTimingFunction(cam, durationMs / 1000, CAMediaTimingFunction.functionWithName(kCAMediaTimingFunctionEaseInEaseOut));
1650
+ setTimeout(() => {
1651
+ resolve();
1652
+ }, durationMs);
1552
1653
  }
1553
1654
  catch (ex) {
1554
1655
  if (Trace.isEnabled()) {
1555
- CLog(CLogTypes.info, 'Error in mapbox.deleteOfflineRegion: ' + ex);
1656
+ CLog(CLogTypes.info, 'Error in mapbox.animateCamera: ' + ex);
1556
1657
  }
1557
1658
  reject(ex);
1558
1659
  }
1559
1660
  });
1560
1661
  }
1561
- addExtrusion(options, nativeMap) {
1662
+ setOnMapClickListener(listener, nativeMap) {
1562
1663
  return new Promise((resolve, reject) => {
1563
1664
  try {
1564
1665
  const theMap = nativeMap || this._mapboxViewInstance;
@@ -1566,17 +1667,26 @@ export class Mapbox extends MapboxCommon {
1566
1667
  reject('No map has been loaded');
1567
1668
  return;
1568
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);
1569
1679
  resolve();
1570
1680
  }
1571
1681
  catch (ex) {
1572
1682
  if (Trace.isEnabled()) {
1573
- CLog(CLogTypes.info, 'Error in mapbox.deleteOfflineRegion: ' + ex);
1683
+ CLog(CLogTypes.info, 'Error in mapbox.setOnMapClickListener: ' + ex);
1574
1684
  }
1575
1685
  reject(ex);
1576
1686
  }
1577
1687
  });
1578
1688
  }
1579
- updateSource(id, options, nativeMap) {
1689
+ setOnMapLongClickListener(listener, nativeMap) {
1580
1690
  return new Promise((resolve, reject) => {
1581
1691
  try {
1582
1692
  const theMap = nativeMap || this._mapboxViewInstance;
@@ -1584,159 +1694,57 @@ export class Mapbox extends MapboxCommon {
1584
1694
  reject('No map has been loaded');
1585
1695
  return;
1586
1696
  }
1587
- const source = theMap.style.sourceWithIdentifier(id);
1588
- if (!source) {
1589
- reject('Source does not exists: ' + id);
1590
- return;
1591
- }
1592
- switch (options.type) {
1593
- case 'geojson':
1594
- const content = NSString.stringWithString(JSON.stringify(options.data));
1595
- const nsData = content.dataUsingEncoding(NSUTF8StringEncoding);
1596
- const geoJsonShape = MGLShape.shapeWithDataEncodingError(nsData, NSUTF8StringEncoding);
1597
- source.shape = geoJsonShape;
1598
- break;
1599
- default:
1600
- reject('Invalid source type: ' + options['type']);
1601
- 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
+ }
1602
1704
  }
1705
+ theMap.addGestureRecognizer(longPressGestureRecognizer);
1706
+ resolve();
1603
1707
  }
1604
1708
  catch (ex) {
1605
1709
  if (Trace.isEnabled()) {
1606
- CLog(CLogTypes.info, 'Error in mapbox.addSource: ' + ex);
1710
+ CLog(CLogTypes.info, 'Error in mapbox.setOnMapClickListener: ' + ex);
1607
1711
  }
1608
1712
  reject(ex);
1609
1713
  }
1610
1714
  });
1611
1715
  }
1612
- addSource(id, options, nativeMap) {
1716
+ setOnScrollListener(listener, nativeMap) {
1613
1717
  return new Promise((resolve, reject) => {
1614
1718
  try {
1615
1719
  const theMap = nativeMap || this._mapboxViewInstance;
1616
- let source;
1617
1720
  if (!theMap) {
1618
1721
  reject('No map has been loaded');
1619
1722
  return;
1620
1723
  }
1621
- if (theMap.style.sourceWithIdentifier(id)) {
1622
- reject('Source exists: ' + id);
1623
- return;
1724
+ if (theMap['mapPanHandler'] === undefined) {
1725
+ theMap['mapPanHandler'] = MapPanHandlerImpl.initWithOwnerAndListenerForMap(new WeakRef(this), listener, 2, theMap);
1624
1726
  }
1625
- switch (options.type) {
1626
- case 'vector': {
1627
- if (options.url) {
1628
- source = MGLVectorTileSource.alloc().initWithIdentifierConfigurationURL(id, NSURL.URLWithString(options.url));
1629
- }
1630
- else {
1631
- const sourceOptions = {};
1632
- if (options.minzoom !== undefined) {
1633
- sourceOptions[MGLTileSourceOptionMinimumZoomLevel] = options.minzoom;
1634
- }
1635
- if (options.maxzoom !== undefined) {
1636
- sourceOptions[MGLTileSourceOptionMaximumZoomLevel] = options.maxzoom;
1637
- }
1638
- if (options.scheme) {
1639
- switch (options.scheme) {
1640
- case 'xyz':
1641
- sourceOptions[MGLTileSourceOptionTileCoordinateSystem] = 0;
1642
- break;
1643
- case 'tms':
1644
- sourceOptions[MGLTileSourceOptionTileCoordinateSystem] = 1;
1645
- break;
1646
- default:
1647
- throw new Error('Unknown raster tile scheme.');
1648
- }
1649
- }
1650
- if (options.bounds) {
1651
- sourceOptions[MGLTileSourceOptionCoordinateBounds] = NSValue.valueWithMGLCoordinateBounds({
1652
- sw: CLLocationCoordinate2DMake(options.bounds[1], options.bounds[0]),
1653
- ne: CLLocationCoordinate2DMake(options.bounds[3], options.bounds[2])
1654
- });
1655
- }
1656
- source = MGLVectorTileSource.alloc().initWithIdentifierTileURLTemplatesOptions(id, options.tiles, sourceOptions);
1657
- }
1658
- break;
1659
- }
1660
- case 'geojson':
1661
- if (theMap.style.sourceWithIdentifier(id)) {
1662
- reject("Remove the layer with this id first with 'removeLayer': " + id);
1663
- return;
1664
- }
1665
- let geoJsonShape;
1666
- if (options.data) {
1667
- const content = NSString.stringWithString(JSON.stringify(options.data));
1668
- const nsData = content.dataUsingEncoding(NSUTF8StringEncoding);
1669
- geoJsonShape = MGLShape.shapeWithDataEncodingError(nsData, NSUTF8StringEncoding);
1670
- }
1671
- const sourceOptions = {};
1672
- if (options.minzoom !== undefined) {
1673
- sourceOptions[MGLShapeSourceOptionMinimumZoomLevel] = options.minzoom;
1674
- }
1675
- if (options.maxzoom !== undefined) {
1676
- sourceOptions[MGLShapeSourceOptionMaximumZoomLevel] = options.maxzoom;
1677
- }
1678
- if (options.cluster) {
1679
- sourceOptions[MGLShapeSourceOptionClustered] = true;
1680
- sourceOptions[MGLShapeSourceOptionClusterRadius] = options.cluster.radius || 40;
1681
- sourceOptions[MGLShapeSourceOptionMaximumZoomLevelForClustering] = options.cluster.maxZoom || 13;
1682
- }
1683
- source = MGLShapeSource.alloc().initWithIdentifierShapeOptions(id, geoJsonShape, sourceOptions);
1684
- break;
1685
- case 'raster': {
1686
- const sourceOptions = {
1687
- [MGLTileSourceOptionTileSize]: options.tileSize || 256
1688
- };
1689
- if (options.minzoom !== undefined) {
1690
- sourceOptions[MGLTileSourceOptionMinimumZoomLevel] = options.minzoom;
1691
- }
1692
- if (options.maxzoom !== undefined) {
1693
- sourceOptions[MGLTileSourceOptionMaximumZoomLevel] = options.maxzoom;
1694
- }
1695
- if (options.scheme) {
1696
- switch (options.scheme || 'xyz') {
1697
- case 'xyz':
1698
- sourceOptions[MGLTileSourceOptionTileCoordinateSystem] = 0;
1699
- break;
1700
- case 'tms':
1701
- sourceOptions[MGLTileSourceOptionTileCoordinateSystem] = 1;
1702
- break;
1703
- default:
1704
- throw new Error('Unknown raster tile scheme.');
1705
- }
1706
- }
1707
- if (options.bounds) {
1708
- sourceOptions[MGLTileSourceOptionCoordinateBounds] = NSValue.valueWithMGLCoordinateBounds({
1709
- sw: CLLocationCoordinate2DMake(options.bounds[1], options.bounds[0]),
1710
- ne: CLLocationCoordinate2DMake(options.bounds[3], options.bounds[2])
1711
- });
1712
- }
1713
- source = MGLRasterTileSource.alloc().initWithIdentifierTileURLTemplatesOptions(id, options.tiles, sourceOptions);
1714
- break;
1715
- }
1716
- default:
1717
- reject('Invalid source type: ' + options['type']);
1718
- return;
1727
+ else {
1728
+ theMap['mapPanHandler'].addListener(2, listener);
1719
1729
  }
1720
- if (!source) {
1721
- const ex = 'No source to add';
1722
- if (Trace.isEnabled()) {
1723
- CLog(CLogTypes.info, 'Error in mapbox.addSource: ' + ex);
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');
1734
+ break;
1724
1735
  }
1725
- reject(ex);
1726
- return;
1727
1736
  }
1728
- theMap.style.addSource(source);
1729
1737
  resolve();
1730
1738
  }
1731
1739
  catch (ex) {
1732
1740
  if (Trace.isEnabled()) {
1733
- CLog(CLogTypes.info, 'Error in mapbox.addSource: ' + ex);
1741
+ CLog(CLogTypes.info, 'Error in mapbox.setOnScrollListener: ' + ex);
1734
1742
  }
1735
1743
  reject(ex);
1736
1744
  }
1737
1745
  });
1738
1746
  }
1739
- removeSource(id, nativeMap) {
1747
+ setOnMoveBeginListener(listener, nativeMap) {
1740
1748
  return new Promise((resolve, reject) => {
1741
1749
  try {
1742
1750
  const theMap = nativeMap || this._mapboxViewInstance;
@@ -1744,109 +1752,277 @@ export class Mapbox extends MapboxCommon {
1744
1752
  reject('No map has been loaded');
1745
1753
  return;
1746
1754
  }
1747
- const source = theMap.style.sourceWithIdentifier(id);
1748
- if (!source) {
1749
- reject('Source does not exist');
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
+ }
1768
+ resolve();
1769
+ }
1770
+ catch (ex) {
1771
+ if (Trace.isEnabled()) {
1772
+ CLog(CLogTypes.info, 'Error in mapbox.setOnMoveBeginListener: ' + ex);
1773
+ }
1774
+ reject(ex);
1775
+ }
1776
+ });
1777
+ }
1778
+ setOnMoveEndListener(listener, nativeMap) {
1779
+ return new Promise((resolve, reject) => {
1780
+ try {
1781
+ const theMap = nativeMap || this._mapboxViewInstance;
1782
+ if (!theMap) {
1783
+ reject('No map has been loaded');
1750
1784
  return;
1751
1785
  }
1752
- theMap.style.removeSource(source);
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
+ }
1798
+ }
1753
1799
  resolve();
1754
1800
  }
1755
1801
  catch (ex) {
1756
1802
  if (Trace.isEnabled()) {
1757
- CLog(CLogTypes.info, 'Error in mapbox.removeSource: ' + ex);
1803
+ CLog(CLogTypes.info, 'Error in mapbox.setOnMoveEndListener: ' + ex);
1758
1804
  }
1759
1805
  reject(ex);
1760
1806
  }
1761
1807
  });
1762
1808
  }
1763
- async addLayer(style, belowLayerId, nativeMapView) {
1764
- const theMap = nativeMapView || this._mapboxViewInstance;
1765
- let source = null;
1766
- if (typeof style.source != 'string') {
1767
- await this.addSource(style.id + '_source', style.source);
1768
- 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);
1769
1816
  }
1770
1817
  else {
1771
- source = theMap.style.sourceWithIdentifier(style.source);
1772
- }
1773
- const layer = await LayerFactory.createLayer(style, source);
1774
- if (belowLayerId) {
1775
- const belowlayer = theMap.style.layerWithIdentifier(belowLayerId);
1776
- if (belowlayer) {
1777
- theMap.style.insertLayerBelowLayer(layer.getNativeInstance(), belowlayer);
1778
- return;
1779
- }
1818
+ return Promise.reject('No map has been loaded');
1780
1819
  }
1781
- theMap.style.addLayer(layer.getNativeInstance());
1782
1820
  }
1783
- async removeLayer(id, nativeMapViewInstance) {
1784
- const theMap = nativeMapViewInstance || this._mapboxViewInstance;
1785
- if (Trace.isEnabled()) {
1786
- CLog(CLogTypes.info, "Mapbox::removeLayer(): attempting to remove layer '" + id + "'");
1787
- }
1788
- const layer = theMap.style.layerWithIdentifier(id);
1789
- if (Trace.isEnabled()) {
1790
- CLog(CLogTypes.info, 'Mapbox:removeLayer(): got layer object: ', layer);
1791
- }
1792
- if (!layer) {
1793
- throw new Error("Layer '" + id + "' not found when attempting to remove it.");
1821
+ setOnCameraMoveCancelListener(listener, nativeMap) {
1822
+ return Promise.reject("'setOnCameraMoveCancelListener' not currently supported on iOS");
1823
+ }
1824
+ async setOnCameraIdleListener(listener, nativeMap) {
1825
+ const theMap = nativeMap || this._mapboxViewInstance;
1826
+ if (theMap) {
1827
+ theMap.delegate.setCameraIdledListener(listener);
1794
1828
  }
1795
- theMap.style.removeLayer(layer);
1796
- if (Trace.isEnabled()) {
1797
- CLog(CLogTypes.info, 'Mapbox:removeLayer(): after removing layer ' + id);
1829
+ else {
1830
+ return Promise.reject('No map has been loaded');
1798
1831
  }
1799
1832
  }
1800
- async addLinePoint(id, lnglat, sourceId, nativeMapView) {
1801
- const theMap = nativeMapView || this._mapboxViewInstance;
1802
- const sId = !!sourceId ? sourceId : id + '_source';
1803
- const lineSource = theMap.style.sourceWithIdentifier(sId);
1804
- if (!lineSource) {
1805
- throw new Error(`no source found with id: ${sId}`);
1806
- }
1807
- try {
1808
- const lineFeatures = lineSource.featuresMatchingPredicate(FilterParser.parseJson(['==', '$type', 'LineString']));
1809
- if (lineFeatures.count === 0) {
1810
- throw new Error('no line string feature found');
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
+ });
1860
+ }
1861
+ setViewport(options, nativeMap) {
1862
+ return new Promise((resolve, reject) => {
1863
+ try {
1864
+ const theMap = nativeMap || this._mapboxViewInstance;
1865
+ if (!theMap) {
1866
+ reject('No map has been loaded');
1867
+ return;
1868
+ }
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
+ });
1977
+ }
1978
+ resolve(regions);
1979
+ }
1980
+ catch (ex) {
1981
+ if (Trace.isEnabled()) {
1982
+ CLog(CLogTypes.info, 'Error in mapbox.listOfflineRegions: ' + ex);
1983
+ }
1984
+ reject(ex);
1811
1985
  }
1812
- const lineFeature = lineFeatures.objectAtIndex(0);
1813
- const newCoord = CLLocationCoordinate2DMake(lnglat[1], lnglat[0]);
1814
- const newCoordPointer = new interop.Reference(newCoord);
1815
- lineFeature.appendCoordinatesCount(newCoordPointer, 1);
1816
- lineSource.shape = lineFeature;
1817
- }
1818
- catch (error) {
1819
- console.log(error);
1820
- throw error;
1821
- }
1822
- }
1823
- addGeoJsonClustered(options, nativeMapViewInstance) {
1824
- throw new Error('Method not implemented.');
1986
+ });
1825
1987
  }
1826
- trackUser(options, nativeMap) {
1988
+ deleteOfflineRegion(options) {
1827
1989
  return new Promise((resolve, reject) => {
1828
1990
  try {
1829
- const theMap = nativeMap || this._mapboxViewInstance;
1830
- if (!theMap) {
1831
- reject('No map has been loaded');
1991
+ if (!options || (!options.id && !options.name)) {
1992
+ reject("Pass in the 'id' or 'name' param");
1832
1993
  return;
1833
1994
  }
1834
- if (!theMap.showsUserLocation) {
1835
- reject('The map is not currently showing the user location');
1836
- return;
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');
1837
2015
  }
1838
- theMap.setUserTrackingModeAnimated(_getTrackingMode(options.mode), options.animated !== false);
1839
- resolve();
1840
2016
  }
1841
2017
  catch (ex) {
1842
2018
  if (Trace.isEnabled()) {
1843
- CLog(CLogTypes.info, 'Error in mapbox.trackUser: ' + ex);
2019
+ CLog(CLogTypes.info, 'Error in mapbox.deleteOfflineRegion: ' + ex);
1844
2020
  }
1845
2021
  reject(ex);
1846
2022
  }
1847
2023
  });
1848
2024
  }
1849
- getLayer(name, nativeMap) {
2025
+ addExtrusion(options, nativeMap) {
1850
2026
  return new Promise((resolve, reject) => {
1851
2027
  try {
1852
2028
  const theMap = nativeMap || this._mapboxViewInstance;
@@ -1854,18 +2030,17 @@ export class Mapbox extends MapboxCommon {
1854
2030
  reject('No map has been loaded');
1855
2031
  return;
1856
2032
  }
1857
- const layer = theMap.style.layerWithIdentifier(name);
1858
- resolve(new Layer(layer));
2033
+ resolve();
1859
2034
  }
1860
2035
  catch (ex) {
1861
2036
  if (Trace.isEnabled()) {
1862
- CLog(CLogTypes.info, 'Error in mapbox.getLayer: ' + ex);
2037
+ CLog(CLogTypes.info, 'Error in mapbox.deleteOfflineRegion: ' + ex);
1863
2038
  }
1864
2039
  reject(ex);
1865
2040
  }
1866
2041
  });
1867
2042
  }
1868
- getLayers(nativeMap) {
2043
+ updateSource(id, options, nativeMap) {
1869
2044
  return new Promise((resolve, reject) => {
1870
2045
  try {
1871
2046
  const theMap = nativeMap || this._mapboxViewInstance;
@@ -1873,489 +2048,379 @@ export class Mapbox extends MapboxCommon {
1873
2048
  reject('No map has been loaded');
1874
2049
  return;
1875
2050
  }
1876
- const layers = theMap.style.layers;
1877
- const result = [];
1878
- for (let i = 0; i < layers.count; i++) {
1879
- result.push(new Layer(layers[i]));
1880
- }
1881
- resolve(result);
1882
- }
1883
- catch (ex) {
1884
- if (Trace.isEnabled()) {
1885
- CLog(CLogTypes.info, 'Error in mapbox.getLayers: ' + ex);
2051
+ const source = theMap.style.sourceWithIdentifier(id);
2052
+ if (!source) {
2053
+ reject('Source does not exists: ' + id);
2054
+ return;
1886
2055
  }
1887
- reject(ex);
1888
- }
1889
- });
1890
- }
1891
- project(data) {
1892
- const theMap = this._mapboxViewInstance;
1893
- const { x, y } = theMap.convertCoordinateToPointToView({ latitude: data.lat, longitude: data.lng }, theMap);
1894
- return { x, y };
1895
- }
1896
- }
1897
- const _addObserver = (eventName, callback) => NSNotificationCenter.defaultCenter.addObserverForNameObjectQueueUsingBlock(eventName, null, NSOperationQueue.mainQueue, callback);
1898
- function _downloadImage(marker) {
1899
- return new Promise((resolve, reject) => {
1900
- if (Trace.isEnabled()) {
1901
- CLog(CLogTypes.info, '>> _downloadImage');
1902
- }
1903
- if (_markerIconDownloadCache[marker.icon]) {
1904
- marker.iconDownloaded = _markerIconDownloadCache[marker.icon];
1905
- if (Trace.isEnabled()) {
1906
- CLog(CLogTypes.info, '>> marker.iconDownloaded: ' + marker.iconDownloaded);
1907
- }
1908
- resolve(marker);
1909
- return;
1910
- }
1911
- getImage(marker.icon).then((output) => {
1912
- marker.iconDownloaded = output.ios;
1913
- _markerIconDownloadCache[marker.icon] = marker.iconDownloaded;
1914
- resolve(marker);
1915
- }, (ignoredError) => {
1916
- console.log(`Download failed for ${marker.icon} with error: ${ignoredError}`);
1917
- resolve(marker);
1918
- });
1919
- });
1920
- }
1921
- const _downloadMarkerImages = (markers) => {
1922
- const iterations = [];
1923
- const result = [];
1924
- markers.forEach((marker) => {
1925
- if (marker.icon && marker.icon.startsWith('http')) {
1926
- const p = _downloadImage(marker).then((mark) => result.push(mark));
1927
- iterations.push(p);
1928
- }
1929
- else {
1930
- result.push(marker);
1931
- }
1932
- });
1933
- return Promise.all(iterations).then(() => result);
1934
- };
1935
- var MGLMapViewDelegateImpl = /** @class */ (function (_super) {
1936
- __extends(MGLMapViewDelegateImpl, _super);
1937
- function MGLMapViewDelegateImpl() {
1938
- return _super !== null && _super.apply(this, arguments) || this;
1939
- }
1940
- MGLMapViewDelegateImpl.new = function () {
1941
- return _super.new.call(this);
1942
- };
1943
- /**
1944
- * initialize with the mapReady callback
1945
- */
1946
- MGLMapViewDelegateImpl.prototype.initWithCallback = function (mapLoadedCallback) {
1947
- if (Trace.isEnabled()) {
1948
- CLog(CLogTypes.info, 'MGLMapViewDelegateImpl::initWithCallback()');
1949
- }
1950
- this.mapLoadedCallback = mapLoadedCallback;
1951
- return this;
1952
- };
1953
- /**
1954
- * set a reference to the mapboxAPI instance
1955
- */
1956
- MGLMapViewDelegateImpl.prototype.setMapboxApi = function (api) {
1957
- this.mapboxApi = api;
1958
- };
1959
- /**
1960
- * set the user location click listener callback
1961
- */
1962
- MGLMapViewDelegateImpl.prototype.setUserLocationClickListener = function (callback) {
1963
- this.userLocationClickListener = callback;
1964
- };
1965
- /**
1966
- * set the user location click listener callback
1967
- */
1968
- MGLMapViewDelegateImpl.prototype.setUserLocationChangedistener = function (callback) {
1969
- this.userLocationChangedListener = callback;
1970
- };
1971
- /**
1972
- * set user location marker modes
1973
- */
1974
- MGLMapViewDelegateImpl.prototype.changeUserLocationRenderMode = function (userLocationRenderMode) {
1975
- this.userLocationAnnotationView.changeUserLocationRenderMode(userLocationRenderMode);
1976
- };
1977
- /**
1978
- * set the camera changd listener callback
1979
- */
1980
- MGLMapViewDelegateImpl.prototype.setCameraChangedListener = function (callback) {
1981
- this.cameraChangedListener = callback;
1982
- };
1983
- /**
1984
- * set the camera idled listener callback
1985
- */
1986
- MGLMapViewDelegateImpl.prototype.setCameraIdledListener = function (callback) {
1987
- this.cameraIdledListener = callback;
1988
- };
1989
- /**
1990
- * set style loaded callback.
1991
- *
1992
- * set an optional callback to be invoked when a style set with
1993
- * setMapStyle() is finished loading
1994
- *
1995
- * @param {function} callback function with loaded style as parameter.
1996
- *
1997
- * @see Mapbox:setMapStyle()
1998
- */
1999
- MGLMapViewDelegateImpl.prototype.setStyleLoadedCallback = function (callback) {
2000
- this.styleLoadedCallback = callback;
2001
- };
2002
- /**
2003
- * map ready callback
2004
- */
2005
- MGLMapViewDelegateImpl.prototype.mapViewDidFinishLoadingMap = function (mapView) {
2006
- if (Trace.isEnabled()) {
2007
- CLog(CLogTypes.info, 'MGLMapViewDelegateImpl:mapViewDidFinishLoadingMap(): top');
2008
- }
2009
- if (this.mapLoadedCallback !== undefined) {
2010
- this.mapLoadedCallback(mapView);
2011
- // this should be fired only once, but it's also fired when the style changes, so just remove the callback
2012
- this.mapLoadedCallback = undefined;
2013
- }
2014
- };
2015
- MGLMapViewDelegateImpl.prototype.mapViewDidFinishRenderingMapFullyRendered = function (mapView, fullyRendered) {
2016
- if (Trace.isEnabled()) {
2017
- CLog(CLogTypes.info, 'MGLMapViewDelegateImpl:mapViewDidFinishRenderingMapFullyRendered(): rendered is:', fullyRendered);
2018
- }
2019
- };
2020
- /**
2021
- * Callback when the style has been loaded.
2022
- *
2023
- * Based on my testing, it looks like this callback is invoked multiple times.
2024
- *
2025
- * @see Mapbox:setMapStyle()
2026
- *
2027
- * @link https://mapbox.github.io/mapbox-gl-native/macos/0.3.0/Protocols/MGLMapViewDelegate.html#/c:objc(pl)MGLMapViewDelegate(im)mapView:didFinishLoadingStyle:
2028
- */
2029
- MGLMapViewDelegateImpl.prototype.mapViewDidFinishLoadingStyle = function (mapView, style) {
2030
- if (Trace.isEnabled()) {
2031
- CLog(CLogTypes.info, 'MGLMapViewDelegateImpl:mapViewDidFinishLoadingStyle(): callback called.');
2032
- }
2033
- if (this.styleLoadedCallback !== undefined) {
2034
- this.styleLoadedCallback(mapView, style);
2035
- // to avoid multiple calls. This is only invoked from setMapStyle().
2036
- this.styleLoadedCallback = undefined;
2037
- }
2038
- };
2039
- /**
2040
- * disable the default user location callout
2041
- *
2042
- * This took forever to find. The default iOS click handler for the user location
2043
- * marker is about useless. It just displays "You Are Here". The examples do not
2044
- * show how to disable it.
2045
- */
2046
- MGLMapViewDelegateImpl.prototype.mapViewAnnotationCanShowCallout = function (mapView, annotation) {
2047
- if (annotation.isKindOfClass(MGLUserLocation.class())) {
2048
- return false;
2049
- }
2050
- else {
2051
- return true;
2052
- }
2053
- };
2054
- MGLMapViewDelegateImpl.prototype.mapViewDidFailLoadingMapWithError = function (mapView, error) {
2055
- if (Trace.isEnabled()) {
2056
- CLog(CLogTypes.info, 'mapViewDidFailLoadingMapWithError: ' + error);
2057
- }
2058
- };
2059
- MGLMapViewDelegateImpl.prototype.mapViewDidChangeUserTrackingModeAnimated = function (mapView, mode, animated) {
2060
- if (Trace.isEnabled()) {
2061
- CLog(CLogTypes.info, 'mapViewDidChangeUserTrackingModeAnimated: ' + mode);
2062
- }
2063
- };
2064
- /**
2065
- * fired when the marker icon is about to be rendered - return null for the default icon
2066
- */
2067
- MGLMapViewDelegateImpl.prototype.mapViewImageForAnnotation = function (mapView, annotation) {
2068
- var cachedMarker = this.getTappedMarkerDetails(annotation);
2069
- if (cachedMarker) {
2070
- if (cachedMarker.reuseIdentifier) {
2071
- var reusedImage = mapView.dequeueReusableAnnotationImageWithIdentifier(cachedMarker.reuseIdentifier);
2072
- if (reusedImage) {
2073
- return reusedImage;
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;
2074
2066
  }
2075
2067
  }
2076
- // TODO try adding .rotatesToMatchCamera = true;
2077
- // .. for instance in the mapViewDidDeselectAnnotationView / mapViewDidSelectAnnotationView / mapViewViewForAnnotation delegate
2078
- if (cachedMarker.icon) {
2079
- if (cachedMarker.icon.startsWith('res://')) {
2080
- var resourceName = cachedMarker.icon.substring('res://'.length);
2081
- var imageSource = ImageSource.fromResourceSync(resourceName);
2082
- if (imageSource === null) {
2083
- console.log("Unable to locate " + resourceName);
2084
- }
2085
- else {
2086
- cachedMarker.reuseIdentifier = cachedMarker.icon;
2087
- return MGLAnnotationImage.annotationImageWithImageReuseIdentifier(imageSource.ios, cachedMarker.reuseIdentifier);
2088
- }
2068
+ catch (ex) {
2069
+ if (Trace.isEnabled()) {
2070
+ CLog(CLogTypes.info, 'Error in mapbox.addSource: ' + ex);
2089
2071
  }
2090
- else if (cachedMarker.icon.startsWith('http')) {
2091
- if (cachedMarker.iconDownloaded !== null) {
2092
- cachedMarker.reuseIdentifier = cachedMarker.icon;
2093
- 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.lineMetrics !== undefined) {
2143
+ sourceOptions[MGLShapeSourceOptionLineDistanceMetrics] = options.lineMetrics;
2144
+ }
2145
+ if (options.cluster) {
2146
+ sourceOptions[MGLShapeSourceOptionClustered] = true;
2147
+ sourceOptions[MGLShapeSourceOptionClusterRadius] = options.cluster.radius || 40;
2148
+ sourceOptions[MGLShapeSourceOptionMaximumZoomLevelForClustering] = options.cluster.maxZoom || 13;
2149
+ if (options.cluster.properties) {
2150
+ const clusterProperties = {};
2151
+ for (const property of Object.keys(options.cluster.properties)) {
2152
+ let [operator, operand] = options.cluster.properties[property];
2153
+ if (!Array.isArray(operator)) {
2154
+ operator = [operator];
2155
+ }
2156
+ const expressions = Utils.ios.collections.jsArrayToNSArray([ExpressionParser.parseJson(operator), ExpressionParser.parseJson(operand)]);
2157
+ clusterProperties[property] = expressions;
2158
+ }
2159
+ sourceOptions[MGLShapeSourceOptionClusterProperties] = clusterProperties;
2160
+ }
2161
+ }
2162
+ source = MGLShapeSource.alloc().initWithIdentifierShapeOptions(id, geoJsonShape, sourceOptions);
2163
+ break;
2164
+ case 'raster': {
2165
+ const sourceOptions = {
2166
+ [MGLTileSourceOptionTileSize]: options.tileSize || 256
2167
+ };
2168
+ if (options.minzoom !== undefined) {
2169
+ sourceOptions[MGLTileSourceOptionMinimumZoomLevel] = options.minzoom;
2170
+ }
2171
+ if (options.maxzoom !== undefined) {
2172
+ sourceOptions[MGLTileSourceOptionMaximumZoomLevel] = options.maxzoom;
2173
+ }
2174
+ if (options.scheme) {
2175
+ switch (options.scheme || 'xyz') {
2176
+ case 'xyz':
2177
+ sourceOptions[MGLTileSourceOptionTileCoordinateSystem] = 0;
2178
+ break;
2179
+ case 'tms':
2180
+ sourceOptions[MGLTileSourceOptionTileCoordinateSystem] = 1;
2181
+ break;
2182
+ default:
2183
+ throw new Error('Unknown raster tile scheme.');
2184
+ }
2185
+ }
2186
+ if (options.bounds) {
2187
+ sourceOptions[MGLTileSourceOptionCoordinateBounds] = NSValue.valueWithMGLCoordinateBounds({
2188
+ sw: CLLocationCoordinate2DMake(options.bounds[1], options.bounds[0]),
2189
+ ne: CLLocationCoordinate2DMake(options.bounds[3], options.bounds[2])
2190
+ });
2191
+ }
2192
+ source = MGLRasterTileSource.alloc().initWithIdentifierTileURLTemplatesOptions(id, options.tiles, sourceOptions);
2193
+ break;
2094
2194
  }
2195
+ default:
2196
+ reject('Invalid source type: ' + options['type']);
2197
+ return;
2095
2198
  }
2096
- else {
2199
+ if (!source) {
2200
+ const ex = 'No source to add';
2097
2201
  if (Trace.isEnabled()) {
2098
- CLog(CLogTypes.info, 'Please use res://resourceName, http(s)://imageUrl or iconPath to use a local path');
2202
+ CLog(CLogTypes.info, 'Error in mapbox.addSource: ' + ex);
2099
2203
  }
2204
+ reject(ex);
2205
+ return;
2100
2206
  }
2207
+ theMap.style.addSource(source);
2208
+ resolve();
2101
2209
  }
2102
- else if (cachedMarker.iconPath) {
2103
- var appPath = knownFolders.currentApp().path;
2104
- var iconFullPath = appPath + '/' + cachedMarker.iconPath.replace('~/', '');
2105
- if (File.exists(iconFullPath)) {
2106
- var image = ImageSource.fromFileSync(iconFullPath).ios;
2107
- // perhaps add resize options for nice retina rendering (although you can now use the 'icon' param instead)
2108
- cachedMarker.reuseIdentifier = cachedMarker.iconPath;
2109
- return MGLAnnotationImage.annotationImageWithImageReuseIdentifier(image, cachedMarker.reuseIdentifier);
2210
+ catch (ex) {
2211
+ if (Trace.isEnabled()) {
2212
+ CLog(CLogTypes.info, 'Error in mapbox.addSource: ' + ex);
2110
2213
  }
2214
+ reject(ex);
2111
2215
  }
2112
- }
2113
- return null;
2114
- };
2115
- /**
2116
- * fired when one of the callout's accessoryviews is tapped (not currently used)
2117
- */
2118
- MGLMapViewDelegateImpl.prototype.mapViewAnnotationCalloutAccessoryControlTapped = function (mapView, annotation, control) { };
2119
- /**
2120
- * fired when a marker is tapped
2121
- */
2122
- MGLMapViewDelegateImpl.prototype.mapViewDidSelectAnnotation = function (mapView, annotation) {
2123
- if (Trace.isEnabled()) {
2124
- CLog(CLogTypes.info, 'MGLMapViewDelegateImpl::mapViewDidSelectAnntation()');
2125
- }
2126
- if (annotation.isKindOfClass(MGLUserLocation.class())) {
2127
- if (Trace.isEnabled()) {
2128
- CLog(CLogTypes.info, 'MGLMapViewDelegateImpl::mapViewDidSelectAnnotation(): tapped the user location button');
2216
+ });
2217
+ }
2218
+ removeSource(id, nativeMap) {
2219
+ return new Promise((resolve, reject) => {
2220
+ try {
2221
+ const theMap = nativeMap || this._mapboxViewInstance;
2222
+ if (!theMap) {
2223
+ reject('No map has been loaded');
2224
+ return;
2225
+ }
2226
+ const source = theMap.style.sourceWithIdentifier(id);
2227
+ if (!source) {
2228
+ reject('Source does not exist');
2229
+ return;
2230
+ }
2231
+ theMap.style.removeSource(source);
2232
+ resolve();
2129
2233
  }
2130
- if (typeof this.userLocationClickListener != 'undefined') {
2131
- this.userLocationClickListener(annotation);
2132
- return;
2234
+ catch (ex) {
2235
+ if (Trace.isEnabled()) {
2236
+ CLog(CLogTypes.info, 'Error in mapbox.removeSource: ' + ex);
2237
+ }
2238
+ reject(ex);
2133
2239
  }
2134
- mapView.deselectAnnotationAnimated(annotation, false);
2135
- }
2136
- var cachedMarker = this.getTappedMarkerDetails(annotation);
2137
- if (cachedMarker && cachedMarker.onTap) {
2138
- cachedMarker.onTap(cachedMarker);
2240
+ });
2241
+ }
2242
+ async addLayer(style, belowLayerId, nativeMapView) {
2243
+ const theMap = nativeMapView || this._mapboxViewInstance;
2244
+ let source = null;
2245
+ if (typeof style.source != 'string') {
2246
+ await this.addSource(style.id + '_source', style.source);
2247
+ source = theMap.style.sourceWithIdentifier(style.id + '_source');
2139
2248
  }
2140
- };
2141
- /**
2142
- * fired when a callout is tapped
2143
- */
2144
- MGLMapViewDelegateImpl.prototype.mapViewTapOnCalloutForAnnotation = function (mapView, annotation) {
2145
- var cachedMarker = this.getTappedMarkerDetails(annotation);
2146
- if (cachedMarker && cachedMarker.onCalloutTap) {
2147
- cachedMarker.onCalloutTap(cachedMarker);
2249
+ else {
2250
+ source = theMap.style.sourceWithIdentifier(style.source);
2148
2251
  }
2149
- };
2150
- MGLMapViewDelegateImpl.prototype.getTappedMarkerDetails = function (tapped) {
2151
- for (var m in _markers) {
2152
- var cached = _markers[m];
2153
- // don't compare lat/lng types as they're not the same (same for (sub)title, they may be null vs undefined)
2154
- if (
2155
- // eslint-disable-next-line eqeqeq
2156
- cached.lat == tapped.coordinate.latitude &&
2157
- // eslint-disable-next-line eqeqeq
2158
- cached.lng == tapped.coordinate.longitude &&
2159
- // eslint-disable-next-line eqeqeq
2160
- cached.title == tapped.title &&
2161
- // eslint-disable-next-line eqeqeq
2162
- cached.subtitle == tapped.subtitle) {
2163
- return cached;
2252
+ const layer = await LayerFactory.createLayer(style, source);
2253
+ if (belowLayerId) {
2254
+ const belowlayer = theMap.style.layerWithIdentifier(belowLayerId);
2255
+ if (belowlayer) {
2256
+ theMap.style.insertLayerBelowLayer(layer.getNativeInstance(), belowlayer);
2257
+ return;
2164
2258
  }
2165
2259
  }
2166
- };
2167
- /**
2168
- * override the standard location marker
2169
- */
2170
- MGLMapViewDelegateImpl.prototype.mapViewViewForAnnotation = function (mapView, annotation) {
2260
+ theMap.style.addLayer(layer.getNativeInstance());
2261
+ }
2262
+ async removeLayer(id, nativeMapViewInstance) {
2263
+ const theMap = nativeMapViewInstance || this._mapboxViewInstance;
2171
2264
  if (Trace.isEnabled()) {
2172
- CLog(CLogTypes.info, 'MGLMapViewDelegateImpl::mapViewViewForAnnotation() top');
2173
- }
2174
- if (annotation.isKindOfClass(MGLUserLocation.class())) {
2175
- this.userLocationAnnotationView = CustomUserLocationAnnotationView.alloc().init();
2176
- return this.userLocationAnnotationView;
2265
+ CLog(CLogTypes.info, "Mapbox::removeLayer(): attempting to remove layer '" + id + "'");
2177
2266
  }
2178
- return null;
2179
- };
2180
- MGLMapViewDelegateImpl.prototype.mapViewRegionIsChangingWithReason = function (mapView, reason) {
2267
+ const layer = theMap.style.layerWithIdentifier(id);
2181
2268
  if (Trace.isEnabled()) {
2182
- CLog(CLogTypes.info, 'MGLMapViewDelegateImpl::mapViewRegionIsChanging()');
2269
+ CLog(CLogTypes.info, 'Mapbox:removeLayer(): got layer object: ', layer);
2183
2270
  }
2184
- if (this.cameraChangedListener) {
2185
- this.cameraChangedListener(reason);
2271
+ if (!layer) {
2272
+ throw new Error("Layer '" + id + "' not found when attempting to remove it.");
2186
2273
  }
2187
- };
2188
- MGLMapViewDelegateImpl.prototype.mapViewRegionDidChangeWithReasonAnimated = function (mapView, reason, animated) {
2274
+ theMap.style.removeLayer(layer);
2189
2275
  if (Trace.isEnabled()) {
2190
- CLog(CLogTypes.info, 'MGLMapViewDelegateImpl::mapViewRegionDidChangeAnimated()');
2191
- }
2192
- if (this.cameraChangedListener) {
2193
- this.cameraChangedListener(reason, animated);
2276
+ CLog(CLogTypes.info, 'Mapbox:removeLayer(): after removing layer ' + id);
2194
2277
  }
2195
- if (this.cameraIdledListener) {
2196
- this.cameraIdledListener();
2278
+ }
2279
+ async addLinePoint(id, lnglat, sourceId, nativeMapView) {
2280
+ const theMap = nativeMapView || this._mapboxViewInstance;
2281
+ const sId = !!sourceId ? sourceId : id + '_source';
2282
+ const lineSource = theMap.style.sourceWithIdentifier(sId);
2283
+ if (!lineSource) {
2284
+ throw new Error(`no source found with id: ${sId}`);
2197
2285
  }
2198
- };
2199
- MGLMapViewDelegateImpl.prototype.mapViewDidUpdateUserLocation = function (mapView, userLocation) {
2200
- if (Trace.isEnabled()) {
2201
- CLog(CLogTypes.info, 'MGLMapViewDelegateImpl::mapViewDidUpdateUserLocation()');
2286
+ try {
2287
+ const lineFeatures = lineSource.featuresMatchingPredicate(ExpressionParser.parseJson(['==', '$type', 'LineString']));
2288
+ if (lineFeatures.count === 0) {
2289
+ throw new Error('no line string feature found');
2290
+ }
2291
+ const lineFeature = lineFeatures.objectAtIndex(0);
2292
+ const newCoord = CLLocationCoordinate2DMake(lnglat[1], lnglat[0]);
2293
+ const newCoordPointer = new interop.Reference(newCoord);
2294
+ lineFeature.appendCoordinatesCount(newCoordPointer, 1);
2295
+ lineSource.shape = lineFeature;
2202
2296
  }
2203
- if (this.userLocationChangedListener) {
2204
- this.userLocationChangedListener(_getLocation(userLocation));
2297
+ catch (error) {
2298
+ console.log(error);
2299
+ throw error;
2205
2300
  }
2206
- };
2207
- MGLMapViewDelegateImpl.ObjCProtocols = [MGLMapViewDelegate];
2208
- return MGLMapViewDelegateImpl;
2209
- }(NSObject));
2210
- var MapTapHandlerImpl = /** @class */ (function (_super) {
2211
- __extends(MapTapHandlerImpl, _super);
2212
- function MapTapHandlerImpl() {
2213
- return _super !== null && _super.apply(this, arguments) || this;
2214
2301
  }
2215
- MapTapHandlerImpl.initWithOwnerAndListenerForMap = function (owner, listener, mapView) {
2216
- var handler = MapTapHandlerImpl.new();
2217
- handler._owner = owner;
2218
- handler._listener = listener;
2219
- handler._mapView = mapView;
2220
- return handler;
2221
- };
2222
- MapTapHandlerImpl.prototype.tap = function (recognizer) {
2223
- var tapPoint = recognizer.locationInView(this._mapView);
2224
- var tapCoordinate = this._mapView.convertPointToCoordinateFromView(tapPoint, this._mapView);
2225
- this._listener({
2226
- lat: tapCoordinate.latitude,
2227
- lng: tapCoordinate.longitude
2228
- });
2229
- };
2230
- MapTapHandlerImpl.ObjCExposedMethods = {
2231
- tap: { returns: interop.types.void, params: [interop.types.id] }
2232
- };
2233
- return MapTapHandlerImpl;
2234
- }(NSObject));
2235
- var MapLongPressHandlerImpl = /** @class */ (function (_super) {
2236
- __extends(MapLongPressHandlerImpl, _super);
2237
- function MapLongPressHandlerImpl() {
2238
- return _super !== null && _super.apply(this, arguments) || this;
2302
+ addGeoJsonClustered(options, nativeMapViewInstance) {
2303
+ throw new Error('Method not implemented.');
2239
2304
  }
2240
- MapLongPressHandlerImpl.initWithOwnerAndListenerForMap = function (owner, listener, mapView) {
2241
- var handler = MapLongPressHandlerImpl.new();
2242
- handler._owner = owner;
2243
- handler._listener = listener;
2244
- handler._mapView = mapView;
2245
- return handler;
2246
- };
2247
- MapLongPressHandlerImpl.prototype.longPress = function (recognizer) {
2248
- var longPressPoint = recognizer.locationInView(this._mapView);
2249
- var longPressCoordinate = this._mapView.convertPointToCoordinateFromView(longPressPoint, this._mapView);
2250
- this._listener({
2251
- lat: longPressCoordinate.latitude,
2252
- lng: longPressCoordinate.longitude
2305
+ trackUser(options, nativeMap) {
2306
+ return new Promise((resolve, reject) => {
2307
+ try {
2308
+ const theMap = nativeMap || this._mapboxViewInstance;
2309
+ if (!theMap) {
2310
+ reject('No map has been loaded');
2311
+ return;
2312
+ }
2313
+ if (!theMap.showsUserLocation) {
2314
+ reject('The map is not currently showing the user location');
2315
+ return;
2316
+ }
2317
+ theMap.setUserTrackingModeAnimated(_getTrackingMode(options.cameraMode), options.animated !== false);
2318
+ resolve();
2319
+ }
2320
+ catch (ex) {
2321
+ if (Trace.isEnabled()) {
2322
+ CLog(CLogTypes.info, 'Error in mapbox.trackUser: ' + ex);
2323
+ }
2324
+ reject(ex);
2325
+ }
2253
2326
  });
2254
- };
2255
- MapLongPressHandlerImpl.ObjCExposedMethods = {
2256
- longPress: { returns: interop.types.void, params: [interop.types.id] }
2257
- };
2258
- return MapLongPressHandlerImpl;
2259
- }(NSObject));
2260
- var MapPanHandlerImpl = /** @class */ (function (_super) {
2261
- __extends(MapPanHandlerImpl, _super);
2262
- function MapPanHandlerImpl() {
2263
- return _super !== null && _super.apply(this, arguments) || this;
2264
2327
  }
2265
- MapPanHandlerImpl.initWithOwnerAndListenerForMap = function (owner, listener, mapView) {
2266
- var handler = MapPanHandlerImpl.new();
2267
- handler._owner = owner;
2268
- handler._listener = listener;
2269
- handler._mapView = mapView;
2270
- handler.onMoveBegin = false;
2271
- return handler;
2272
- };
2273
- MapPanHandlerImpl.prototype.setOnMoveBegin = function () {
2274
- this.onMoveBegin = true;
2275
- };
2276
- MapPanHandlerImpl.prototype.pan = function (recognizer) {
2277
- var panPoint = recognizer.locationInView(this._mapView);
2278
- var panCoordinate = this._mapView.convertPointToCoordinateFromView(panPoint, this._mapView);
2279
- if (Trace.isEnabled()) {
2280
- CLog(CLogTypes.info, 'MapPanHandlerImpl::pan(): top with state:', recognizer.state);
2281
- }
2282
- // if this is the beginning of the pan simulate the Android onMoveBegin
2283
- //
2284
- // See the objc platform declarations in objc!UIKit.d.ts. It doesn't quite match the apple documention
2285
- if (this.onMoveBegin) {
2286
- if (recognizer.state === UIGestureRecognizerState.Began) {
2328
+ getLayer(name, nativeMap) {
2329
+ return new Promise((resolve, reject) => {
2330
+ try {
2331
+ const theMap = nativeMap || this._mapboxViewInstance;
2332
+ if (!theMap) {
2333
+ reject('No map has been loaded');
2334
+ return;
2335
+ }
2336
+ const layer = theMap.style.layerWithIdentifier(name);
2337
+ resolve(new Layer(layer));
2338
+ }
2339
+ catch (ex) {
2287
2340
  if (Trace.isEnabled()) {
2288
- CLog(CLogTypes.info, 'MapPanHandlerImpl::pan(): calling onMoveBegin listener');
2341
+ CLog(CLogTypes.info, 'Error in mapbox.getLayer: ' + ex);
2289
2342
  }
2290
- this._listener({
2291
- lat: panCoordinate.latitude,
2292
- lng: panCoordinate.longitude
2293
- });
2343
+ reject(ex);
2294
2344
  }
2295
- return;
2296
- }
2297
- this._listener({
2298
- lat: panCoordinate.latitude,
2299
- lng: panCoordinate.longitude
2300
2345
  });
2301
- };
2302
- MapPanHandlerImpl.ObjCExposedMethods = {
2303
- pan: { returns: interop.types.void, params: [interop.types.id] }
2304
- };
2305
- return MapPanHandlerImpl;
2306
- }(NSObject));
2307
- var MapSwipeHandlerImpl = /** @class */ (function (_super) {
2308
- __extends(MapSwipeHandlerImpl, _super);
2309
- function MapSwipeHandlerImpl() {
2310
- return _super !== null && _super.apply(this, arguments) || this;
2311
2346
  }
2312
- MapSwipeHandlerImpl.initWithOwnerAndListenerForMap = function (owner, listener, mapView) {
2313
- var handler = MapSwipeHandlerImpl.new();
2314
- handler._owner = owner;
2315
- handler._listener = listener;
2316
- handler._mapView = mapView;
2317
- return handler;
2318
- };
2319
- MapSwipeHandlerImpl.prototype.swipe = function (recognizer) {
2320
- var swipePoint = recognizer.locationInView(this._mapView);
2321
- var swipeCoordinate = this._mapView.convertPointToCoordinateFromView(swipePoint, this._mapView);
2322
- this._listener({
2323
- lat: swipeCoordinate.latitude,
2324
- lng: swipeCoordinate.longitude
2347
+ getLayers(nativeMap) {
2348
+ return new Promise((resolve, reject) => {
2349
+ try {
2350
+ const theMap = nativeMap || this._mapboxViewInstance;
2351
+ if (!theMap) {
2352
+ reject('No map has been loaded');
2353
+ return;
2354
+ }
2355
+ const layers = theMap.style.layers;
2356
+ const result = [];
2357
+ for (let i = 0; i < layers.count; i++) {
2358
+ result.push(new Layer(layers[i]));
2359
+ }
2360
+ resolve(result);
2361
+ }
2362
+ catch (ex) {
2363
+ if (Trace.isEnabled()) {
2364
+ CLog(CLogTypes.info, 'Error in mapbox.getLayers: ' + ex);
2365
+ }
2366
+ reject(ex);
2367
+ }
2325
2368
  });
2326
- };
2327
- MapSwipeHandlerImpl.ObjCExposedMethods = {
2328
- swipe: { returns: interop.types.void, params: [interop.types.id] }
2329
- };
2330
- return MapSwipeHandlerImpl;
2331
- }(NSObject));
2332
- export class Layer {
2333
- constructor(instance) {
2334
- this.instance = instance;
2335
- this.id = instance.identifier;
2336
- }
2337
- visibility() {
2338
- return this.instance.visible;
2339
2369
  }
2340
- show() {
2341
- this.instance.visible = true;
2342
- }
2343
- hide() {
2344
- this.instance.visible = false;
2370
+ project(data) {
2371
+ const theMap = this._mapboxViewInstance;
2372
+ const { x, y } = theMap.convertCoordinateToPointToView({ latitude: data.lat, longitude: data.lng }, theMap);
2373
+ return { x, y };
2345
2374
  }
2346
- getNativeInstance() {
2347
- return this.instance;
2375
+ projectBack(screenCoordinate) {
2376
+ const theMap = this._mapboxViewInstance;
2377
+ const cgPoint = {
2378
+ x: screenCoordinate.x,
2379
+ y: screenCoordinate.y
2380
+ };
2381
+ const coordinate = theMap.convertPointToCoordinateFromView(cgPoint, theMap);
2382
+ return {
2383
+ lat: coordinate.latitude,
2384
+ lng: coordinate.longitude
2385
+ };
2348
2386
  }
2349
- setFilter(filter) {
2350
- if (this.instance instanceof MGLVectorStyleLayer) {
2351
- this.instance.predicate = FilterParser.parseJson(filter);
2387
+ }
2388
+ const _addObserver = (eventName, callback) => NSNotificationCenter.defaultCenter.addObserverForNameObjectQueueUsingBlock(eventName, null, NSOperationQueue.mainQueue, callback);
2389
+ function _downloadImage(marker) {
2390
+ return new Promise((resolve, reject) => {
2391
+ if (Trace.isEnabled()) {
2392
+ CLog(CLogTypes.info, '>> _downloadImage');
2352
2393
  }
2353
- else {
2354
- throw new Error('Set filter only support for vector layer.');
2394
+ if (_markerIconDownloadCache[marker.icon]) {
2395
+ marker.iconDownloaded = _markerIconDownloadCache[marker.icon];
2396
+ if (Trace.isEnabled()) {
2397
+ CLog(CLogTypes.info, '>> marker.iconDownloaded: ' + marker.iconDownloaded);
2398
+ }
2399
+ resolve(marker);
2400
+ return;
2355
2401
  }
2356
- }
2357
- getFilter() {
2358
- return FilterParser.toJson(this.instance.predicate);
2359
- }
2402
+ Http.getImage(marker.icon).then((output) => {
2403
+ marker.iconDownloaded = output.ios;
2404
+ _markerIconDownloadCache[marker.icon] = marker.iconDownloaded;
2405
+ resolve(marker);
2406
+ }, (ignoredError) => {
2407
+ console.log(`Download failed for ${marker.icon} with error: ${ignoredError}`);
2408
+ resolve(marker);
2409
+ });
2410
+ });
2360
2411
  }
2361
- //# sourceMappingURL=mapbox.ios.js.map
2412
+ const _downloadMarkerImages = (markers) => {
2413
+ const iterations = [];
2414
+ const result = [];
2415
+ markers.forEach((marker) => {
2416
+ if (marker.icon && marker.icon.startsWith('http')) {
2417
+ const p = _downloadImage(marker).then((mark) => result.push(mark));
2418
+ iterations.push(p);
2419
+ }
2420
+ else {
2421
+ result.push(marker);
2422
+ }
2423
+ });
2424
+ return Promise.all(iterations).then(() => result);
2425
+ };
2426
+ //# sourceMappingURL=index.ios.js.map