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