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