@benedictstrube/ui-mapbox
Version:
Interactive, thoroughly customizable maps powered by vector tiles and OpenGL.
1,164 lines • 114 kB
JavaScript
import { request } from '@nativescript-community/perms';
import { AndroidApplication, Application, Color, File, Http, Image, ImageSource, Trace, Utils, knownFolders, path } from '@nativescript/core';
import { ExpressionParser } from './expression/expression-parser';
import { Layer, LayerFactory } from './layers/layer-factory';
import { CLog, CLogTypes, MapStyle, MapboxCommon, MapboxTraceCategory, MapboxViewBase, telemetryProperty } from './common';
export * from './common';
function _getLocation(loc) {
if (loc === null) {
return null;
}
else {
return {
location: {
lat: loc.getLatitude(),
lng: loc.getLongitude()
},
speed: loc.getSpeed()
};
}
}
export function setLogLevel(level) {
const Logger = com.mapbox.mapboxsdk.log.Logger;
let loggingLevel;
switch (level) {
case 'none':
loggingLevel = Logger.NONE;
break;
case 'info':
loggingLevel = Logger.INFO;
break;
case 'debug':
loggingLevel = Logger.DEBUG;
break;
case 'verbose':
loggingLevel = Logger.VERBOSE;
break;
case 'fault':
case 'error':
loggingLevel = Logger.ERROR;
break;
}
Logger.setVerbosity(loggingLevel);
}
export class MapboxView extends MapboxViewBase {
constructor() {
super();
this.settings = null;
this.initialized = false;
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'constructor(): building new MapboxView object.');
}
}
setConfig(settings) {
if (settings.zoomLevel && !settings.center) {
settings.center = {
lat: 48.858093,
lng: 2.294694
};
}
this.settings = settings;
}
getNativeMapView() {
return this.nativeMapView;
}
getMapboxApi() {
return this.mapbox;
}
createNativeView() {
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'createNativeView(): top');
}
const nativeView = new android.widget.FrameLayout(this._context);
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'createNativeView(): bottom');
}
return nativeView;
}
onLoaded() {
super.onLoaded();
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'onLoaded()');
}
if (!this.initialized) {
this.initMap();
this.initialized = true;
}
}
initNativeView() {
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'initNativeView(): top');
}
this.nativeView.owner = this;
Application.android.on(AndroidApplication.activityPausedEvent, this.onPause, this);
Application.android.on(AndroidApplication.activityResumedEvent, this.onResume, this);
super.initNativeView();
}
disposeNativeView() {
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'disposeNativeView(): top');
}
this.nativeView.owner = null;
Application.android.off(AndroidApplication.activityPausedEvent, this.onPause, this);
Application.android.off(AndroidApplication.activityResumedEvent, this.onResume, this);
if (this.mapbox) {
this.mapbox.destroy();
}
super.disposeNativeView();
}
initMap() {
if (Trace.isEnabled()) {
CLog(CLogTypes.info, "MapboxView:initMap(): top - accessToken is '" + this.config.accessToken + "'", this.config);
}
if (!this.nativeMapView && ((this.config && this.config.accessToken) || (this.settings && this.settings.accessToken))) {
this.mapbox = new Mapbox(this);
const options = {
context: this._context,
parentView: this.nativeView,
onLocationPermissionGranted: (event) => {
this.notify({
eventName: MapboxViewBase.locationPermissionGrantedEvent,
object: this,
map: this,
android: this.nativeMapView
});
},
onLocationPermissionDenied: (event) => {
this.notify({
eventName: MapboxViewBase.locationPermissionDeniedEvent,
object: this,
map: this,
android: this.nativeMapView
});
},
onMapReady: (map) => {
if (this.telemetry === false) {
try {
com.mapbox.mapboxsdk.Mapbox.getTelemetry().setUserTelemetryRequestState(false);
console.error('telemtry disabled!');
}
catch (err) {
console.error('telemtry', err);
}
}
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'initMap(): onMapReady event - calling notify with the MapboxViewBase.mapReadyEvent');
}
if (this.hasListeners(MapboxViewBase.mapReadyEvent)) {
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'initMap(): onMapReady has listeners.');
}
}
else {
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'initMap(): onMapReady DOES NOT HAVE listeners.');
}
}
this.notify({
eventName: MapboxViewBase.mapReadyEvent,
object: this,
map: this,
android: this.nativeMapView
});
},
onScrollEvent: (event) => {
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'initMap(): onScrollEvent event');
}
this.notify({
eventName: MapboxViewBase.scrollEvent,
object: this,
event,
map: this,
android: this.nativeMapView
});
},
onMoveBeginEvent: (event) => {
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'initMap(): onMoveBeginEvent event');
}
this.notify({
eventName: MapboxViewBase.moveBeginEvent,
object: this,
event,
map: this,
android: this.nativeMapView
});
},
onMoveEndEvent: (event) => {
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'initMap(): onMoveEndEvent event');
}
this.notify({
eventName: MapboxViewBase.moveEndEvent,
object: this,
event,
map: this,
android: this.nativeMapView
});
}
};
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'initMap(): this.config is:', this.config);
}
if (!this.settings) {
this.settings = Mapbox.merge(this.config, Mapbox.defaults);
}
else {
this.settings = Mapbox.merge(this.settings, Mapbox.defaults);
}
this.settings = Mapbox.merge(this.settings, options);
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'initMap(): before show.');
}
this.mapbox.show(this.settings);
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'initMap(): bottom.');
}
}
}
[telemetryProperty.setNative](value) {
if (com.mapbox.mapboxsdk.Mapbox.getTelemetry()) {
com.mapbox.mapboxsdk.Mapbox.getTelemetry().setUserTelemetryRequestState(value);
}
}
}
export class Mapbox extends MapboxCommon {
constructor(view) {
super(view);
this._accessToken = '';
this.circleManager = null;
this.lineManager = null;
this.symbolManager = null;
this._markers = [];
this._polylines = [];
this._polygons = [];
this.lines = [];
this.eventCallbacks = {};
this._markerIconDownloadCache = [];
this.iconCache = {};
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'constructor(): building new Mapbox object.');
}
this.eventCallbacks['click'] = [];
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'constructor(): end of Mapbox constructor.');
}
}
setMapboxViewInstance(mapboxViewInstance) { }
show(options) {
return new Promise((resolve, reject) => {
try {
const settings = Mapbox.merge(options, Mapbox.defaults);
const showIt = () => {
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'show()');
}
if (settings.accessToken === undefined) {
reject('mapbox_accesstoken_missing');
return;
}
if (this._mapboxViewInstance) {
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'show(): view already created. Removing it.');
}
const viewGroup = this._mapboxViewInstance.getParent();
if (viewGroup !== null) {
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'show(): view already created. Removing _mapboxViewInstance child of view parent.');
}
viewGroup.removeView(this._mapboxViewInstance);
}
}
this._accessToken = settings.accessToken;
let context = Application.android.context;
if (settings.context) {
context = settings.context;
}
com.mapbox.mapboxsdk.Mapbox.getInstance(context, this._accessToken);
const mapboxMapOptions = this._getMapboxMapOptions(settings);
this._mapboxViewInstance = new com.mapbox.mapboxsdk.maps.MapView(context, mapboxMapOptions);
this._mapboxViewInstance.onCreate(null);
if (Trace.isEnabled()) {
this.onDidFailLoadingMapListener = new com.mapbox.mapboxsdk.maps.MapView.OnDidFailLoadingMapListener({
onDidFailLoadingMap: (error) => CLog(CLogTypes.error, 'Mapbox::show(): failed to load map:', error)
});
this._mapboxViewInstance.addOnDidFailLoadingMapListener(this.onDidFailLoadingMapListener);
}
if (Trace.isEnabled()) {
this.onDidFinishLoadingMapListener = new com.mapbox.mapboxsdk.maps.MapView.OnDidFinishLoadingMapListener({
onDidFinishLoadingMap: () => CLog(CLogTypes.info, 'show(): finished loading map')
});
this._mapboxViewInstance.addOnDidFinishLoadingMapListener(this.onDidFinishLoadingMapListener);
}
this.onMapReadyCallback = new com.mapbox.mapboxsdk.maps.OnMapReadyCallback({
onMapReady: (mbMap) => {
this._mapboxMapInstance = mbMap;
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'show(): onMapReady() with instance:', this._mapboxMapInstance);
}
this.setMapStyle(settings.style).then((style) => {
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'show(): style loaded.');
}
this.initEventHandlerShim(settings, this._mapboxViewInstance);
this._addMarkers(settings.markers, this._mapboxViewInstance);
if (settings.showUserLocation) {
this.requestFineLocationPermission()
.then(() => {
this.showUserLocationMarker(settings.locationComponentOptions);
if (settings.onLocationPermissionGranted) {
settings.onLocationPermissionGranted(this._mapboxMapInstance);
}
})
.catch((err) => {
if (settings.onLocationPermissionDenied) {
settings.onLocationPermissionDenied(this._mapboxMapInstance);
}
});
}
if (settings.onMapReady) {
settings.onMapReady(this._mapboxMapInstance);
}
resolve({
android: this._mapboxViewInstance
});
});
}
});
this._mapboxViewInstance.getMapAsync(this.onMapReadyCallback);
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'show(): after getMapAsync()');
}
if (settings.parentView) {
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'show(): adding map to passed in view');
}
settings.parentView.addView(this._mapboxViewInstance);
}
else if (settings.container) {
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'show(): adding map to passed in container');
}
context = Application.android.foregroundActivity;
if (!context) {
context = Application.android.startActivity;
}
const mapViewLayout = new android.widget.FrameLayout(context);
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'show(): before adding mapboxViewInstance to FrameLayout');
}
mapViewLayout.addView(this._mapboxViewInstance);
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'show(): before adding FrameLayout to container');
}
settings.container.addChild(mapViewLayout);
}
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'show(): showIt() bottom');
}
};
setTimeout(showIt, settings.delay ? settings.delay : 200);
}
catch (ex) {
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'Error in mapbox.show: ' + ex);
}
reject(ex);
}
});
}
hide() {
return new Promise((resolve, reject) => {
try {
if (this._mapboxViewInstance) {
const viewGroup = this._mapboxViewInstance.getParent();
if (viewGroup !== null) {
viewGroup.setVisibility(android.view.View.INVISIBLE);
}
}
resolve();
}
catch (ex) {
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'Error in mapbox.hide: ' + ex);
}
reject(ex);
}
});
}
unhide() {
return new Promise((resolve, reject) => {
try {
if (this._mapboxViewInstance) {
this._mapboxViewInstance.getParent().setVisibility(android.view.View.VISIBLE);
resolve();
}
else {
reject('No map found');
}
}
catch (ex) {
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'Error in mapbox.unhide: ' + ex);
}
reject(ex);
}
});
}
destroy(nativeMap) {
return new Promise(async (resolve, reject) => {
this.clearEventListeners();
this.iconFactory = null;
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'destroy(): destroying mapbox view.');
}
if (this.lineManager) {
this.lineManager.onDestroy();
this.lineManager = null;
}
if (this.circleManager) {
this.circleManager.onDestroy();
this.circleManager = null;
}
if (this.symbolManager) {
this.symbolManager.onDestroy();
this.symbolManager = null;
}
if (this._locationComponent) {
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'destroy(): Location marker not disabled before destroy() called.');
}
await this.hideUserLocationMarker();
}
if (this._mapboxViewInstance) {
const viewGroup = this._mapboxViewInstance.getParent();
if (viewGroup !== null) {
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'destroy(): removing _mapboxViewInstance view.');
}
viewGroup.removeView(this._mapboxViewInstance);
}
this._mapboxViewInstance.onPause();
this._mapboxViewInstance.onStop();
this._mapboxViewInstance.destroyDrawingCache();
this._mapboxViewInstance.onDestroy();
this._mapboxViewInstance = null;
this._mapboxMapInstance = null;
}
resolve();
});
}
clearEventListeners() {
if (this.onDidFailLoadingMapListener) {
this._mapboxViewInstance.removeOnDidFailLoadingMapListener(this.onDidFailLoadingMapListener);
this.onDidFailLoadingMapListener = null;
}
if (this.onDidFinishLoadingMapListener) {
this._mapboxViewInstance.removeOnDidFinishLoadingMapListener(this.onDidFinishLoadingMapListener);
this.onDidFinishLoadingMapListener = null;
}
if (this.onDidFinishLoadingStyleListener) {
this._mapboxViewInstance.removeOnDidFinishLoadingStyleListener(this.onDidFinishLoadingStyleListener);
this.onDidFinishLoadingStyleListener = null;
}
if (this.onAnnotationClickListener) {
this.lineManager.removeClickListener(this.onAnnotationClickListener);
this.onAnnotationClickListener = null;
}
if (this.onMarkerClickListener) {
this._mapboxMapInstance.setOnMarkerClickListener(null);
this.onMarkerClickListener = null;
}
if (this.onInfoWindowClickListener) {
this._mapboxMapInstance.setOnInfoWindowClickListener(null);
this.onInfoWindowClickListener = null;
}
if (this.onDidFailLoadingMapListener) {
this._mapboxViewInstance.removeOnDidFailLoadingMapListener(this.onDidFailLoadingMapListener);
this.onDidFailLoadingMapListener = null;
}
if (this.onMapClickListener) {
this._mapboxMapInstance.removeOnMapClickListener(this.onMapClickListener);
this.onMapClickListener = null;
}
if (this.onMapLongClickListener) {
this._mapboxMapInstance.removeOnMapLongClickListener(this.onMapLongClickListener);
this.onMapLongClickListener = null;
}
if (this.onMoveListener) {
this._mapboxMapInstance.removeOnMoveListener(this.onMoveListener);
this.onMoveListener = null;
}
if (this.onScrollListener) {
this._mapboxMapInstance.removeOnMoveListener(this.onScrollListener);
this.onScrollListener = null;
}
if (this.onFlingListener) {
this._mapboxMapInstance.removeOnFlingListener(this.onFlingListener);
this.onFlingListener = null;
}
if (this.onCameraMoveListener) {
this._mapboxMapInstance.removeOnCameraMoveListener(this.onCameraMoveListener);
this.onCameraMoveListener = null;
}
if (this.onCameraMoveCancelListener) {
this._mapboxMapInstance.removeOnCameraMoveCancelListener(this.onCameraMoveCancelListener);
this.onCameraMoveCancelListener = null;
}
if (this.onCameraIdleListener) {
this._mapboxMapInstance.removeOnCameraIdleListener(this.onCameraIdleListener);
this.onCameraIdleListener = null;
}
if (this.onLocationClickListener) {
this._locationComponent.removeOnLocationClickListener(this.onLocationClickListener);
this.onLocationClickListener = null;
}
}
async onStart(nativeMap) {
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'onStart()');
}
this._mapboxViewInstance.onStart();
}
async onResume(nativeMapViewInstance) {
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'onResume()');
}
this._mapboxViewInstance.onResume();
}
async onPause(nativeMapViewInstance) {
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'onPause()');
}
this._mapboxViewInstance.onPause();
}
async onStop(nativeMap) {
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'onStop()');
}
this._mapboxViewInstance.onStop();
}
async onLowMemory(nativeMap) {
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'onLowMemory()');
}
this._mapboxViewInstance.onLowMemory();
}
async onDestroy(nativeMap) {
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'onDestroy()');
}
this._mapboxViewInstance.onDestroy();
}
initEventHandlerShim(settings, mapboxNativeViewInstance) {
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'Mapbox:initEventHandlerShim(): top');
}
this.setOnMapClickListener((point) => this.checkForClickEvent(point), mapboxNativeViewInstance);
this.setOnMoveBeginListener((point) => {
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'Mapbox:initEventHandlerShim(): moveBegin:', point);
}
if (typeof settings.onMoveBeginEvent != 'undefined') {
settings.onMoveBeginEvent(point);
}
}, mapboxNativeViewInstance);
this.setOnMoveEndListener((point) => {
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'Mapbox:initEventHandlerShim(): moveEnd:', point);
}
if (typeof settings.onMoveEndEvent != 'undefined') {
settings.onMoveEndEvent(point);
}
}, mapboxNativeViewInstance);
this.setOnScrollListener((point) => {
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'Mapbox:initEventHandlerShim(): move:', point);
}
if (typeof settings.onScrollEvent != 'undefined') {
settings.onScrollEvent(point);
}
}, mapboxNativeViewInstance);
}
onMapEvent(eventName, id, callback, nativeMapView) {
if (typeof this.eventCallbacks[eventName] == 'undefined') {
this.eventCallbacks[eventName] = [];
}
this.eventCallbacks[eventName].push({
id,
callback
});
}
offMapEvent(eventName, id, nativeMapView) {
if (typeof this.eventCallbacks[eventName] == 'undefined') {
return;
}
this.eventCallbacks[eventName] = this.eventCallbacks[eventName].filter((entry) => entry.id !== id);
}
checkForClickEvent(point, nativeMap) {
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'Mapbox:checkForClickEvent(): got click event with point:', JSON.stringify(point));
}
this.eventCallbacks['click'] &&
this.eventCallbacks['click'].forEach((eventListener) => {
this.queryRenderedFeatures({ point, layers: [eventListener.id] }).then((response) => {
if (response.length > 0) {
eventListener.callback(response);
}
});
});
this.view && this.view.notify({ eventName: 'mapClick', object: this.view, point });
return false;
}
handleLineClickEvent(clickOverlay) {
const lineEntry = this.lines.find((entry) => {
if (Trace.isEnabled()) {
CLog(CLogTypes.info, "Mapbox:handleLineClickEvent(): checking lineEntry clickOverlay id '" + entry.clickOverlay + "' against clickOverlay '" + clickOverlay + "'");
}
return entry.clickOverlay === clickOverlay;
});
if (!lineEntry) {
console.error('Mapbox:handleLineClick(): click on overlay without an underlying line layer');
return false;
}
for (let x = 0; x < this.eventCallbacks['click'].length; x++) {
const entry = this.eventCallbacks['click'][x];
if (Trace.isEnabled()) {
CLog(CLogTypes.info, "Mapbox:handleLineClickEvent(): checking entry id '" + entry.id + "' against lineEnty id '" + lineEntry.id + "'");
}
if (entry.id === lineEntry.id) {
if (Trace.isEnabled()) {
CLog(CLogTypes.info, "Mapbox:handleLineClickEvent(): calling callback for '" + entry.id + "'");
}
return entry.callback(lineEntry);
}
}
return false;
}
hasFineLocationPermission() {
return new Promise((resolve, reject) => {
try {
resolve(this._fineLocationPermissionGranted());
}
catch (ex) {
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'Error in mapbox.hasFineLocationPermission: ' + ex);
}
reject(ex);
}
});
}
async requestFineLocationPermission() {
return request('location');
}
setMapStyle(style, nativeMapViewInstance) {
return new Promise((resolve, reject) => {
try {
const mapStyle = this._getMapStyle(style);
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'setMapStyle(): with style:', style);
}
this.onDidFinishLoadingStyleListener = new com.mapbox.mapboxsdk.maps.MapView.OnDidFinishLoadingStyleListener({
onDidFinishLoadingStyle: () => {
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'Mapbox:setMapStyle(): style loaded');
}
const nMapbox = this._mapboxMapInstance;
const nMapView = this._mapboxViewInstance;
const nStyle = nMapbox.getStyle();
this.lineManager = new com.mapbox.mapboxsdk.plugins.annotation.LineManager(nMapView, nMapbox, nStyle);
this.onAnnotationClickListener = new com.mapbox.mapboxsdk.plugins.annotation.OnAnnotationClickListener({
onAnnotationClick: (line) => {
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'Mapbox:setMapStyle(): click on line:', line);
}
this.handleLineClickEvent(line);
return true;
}
});
this.lineManager.addClickListener(this.onAnnotationClickListener);
resolve();
}
});
this._mapboxViewInstance.addOnDidFinishLoadingStyleListener(this.onDidFinishLoadingStyleListener);
this.onDidFailLoadingMapListener = new com.mapbox.mapboxsdk.maps.MapView.OnDidFailLoadingMapListener({
onDidFailLoadingMap: (error) => {
if (Trace.isEnabled()) {
CLog(CLogTypes.error, 'Mapbox:setMapStyle(): style failed', mapStyle, error);
}
reject(error);
}
});
this._mapboxViewInstance.addOnDidFailLoadingMapListener(this.onDidFailLoadingMapListener);
const builder = new com.mapbox.mapboxsdk.maps.Style.Builder();
this._mapboxMapInstance.setStyle(builder.fromUri(mapStyle));
}
catch (ex) {
if (Trace.isEnabled()) {
CLog(CLogTypes.error, 'Error in mapbox.setMapStyle', style, ex);
}
reject(ex);
}
});
}
async getImage(imageId, nativeMap) {
return new Promise((resolve, reject) => {
const theMap = nativeMap || this._mapboxMapInstance;
if (!theMap) {
reject('No map has been loaded');
return;
}
try {
const nativeImage = theMap.getStyle().getImage(imageId);
const img = new ImageSource(nativeImage);
resolve(img);
}
catch (ex) {
reject('Error during getImage: ' + ex);
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'Error in mapbox.getImage: ' + ex);
}
throw ex;
}
});
}
async addImage(imageId, image, nativeMap) {
return new Promise((resolve, reject) => {
const theMap = nativeMap || this._mapboxMapInstance;
if (!theMap) {
reject('No map has been loaded');
return;
}
if (!image.startsWith('res://')) {
image = path.join(knownFolders.currentApp().path, image.replace('~/', ''));
}
const img = ImageSource.fromFileOrResourceSync(image);
try {
theMap.getStyle().addImage(imageId, img.android);
resolve();
}
catch (ex) {
reject('Error during addImage: ' + ex);
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'Error in mapbox.addImage: ' + ex);
}
throw ex;
}
});
}
async removeImage(imageId, nativeMap) {
return new Promise((resolve, reject) => {
const theMap = nativeMap || this._mapboxMapInstance;
if (!theMap) {
reject('No map has been loaded');
return;
}
try {
theMap.getStyle().removeImage(imageId);
resolve();
}
catch (ex) {
reject('Error during removeImage: ' + ex);
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'Error in mapbox.removeImage: ' + ex);
}
throw ex;
}
});
}
async addMarkers(markers, nativeMap) {
try {
this._addMarkers(markers, this._mapboxViewInstance);
}
catch (ex) {
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'Error in mapbox.addMarkers: ' + ex);
}
throw ex;
}
}
async removeMarkers(ids, nativeMap) {
try {
this._removeMarkers(ids, this._mapboxViewInstance);
}
catch (ex) {
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'Error in mapbox.removeMarkers: ' + ex);
}
throw ex;
}
}
_addMarkers(markers, nativeMap) {
if (!markers) {
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'No markers passed');
}
return;
}
if (!Array.isArray(markers)) {
if (Trace.isEnabled()) {
CLog(CLogTypes.info, "markers must be passed as an Array: [{title:'foo'}]");
}
return;
}
if (!this._mapboxMapInstance) {
return;
}
if (!this.onMarkerClickListener) {
this.onMarkerClickListener = new com.mapbox.mapboxsdk.maps.MapboxMap.OnMarkerClickListener({
onMarkerClick: (marker) => {
const cachedMarker = this._getClickedMarkerDetails(marker);
if (cachedMarker && cachedMarker.onTap) {
cachedMarker.onTap(cachedMarker);
}
return false;
}
});
this._mapboxMapInstance.setOnMarkerClickListener(this.onMarkerClickListener);
}
if (!this.onInfoWindowClickListener) {
this.onInfoWindowClickListener = new com.mapbox.mapboxsdk.maps.MapboxMap.OnInfoWindowClickListener({
onInfoWindowClick: (marker) => {
const cachedMarker = this._getClickedMarkerDetails(marker);
if (cachedMarker && cachedMarker.onCalloutTap) {
cachedMarker.onCalloutTap(cachedMarker);
}
return true;
}
});
this._mapboxMapInstance.setOnInfoWindowClickListener(this.onInfoWindowClickListener);
}
if (!this.iconFactory) {
this.iconFactory = com.mapbox.mapboxsdk.annotations.IconFactory.getInstance(Application.android.context);
}
const iconFactory = this.iconFactory;
this._downloadMarkerImages(markers).then((updatedMarkers) => {
for (const m in updatedMarkers) {
const marker = updatedMarkers[m];
this._markers.push(marker);
const markerOptions = new com.mapbox.mapboxsdk.annotations.MarkerOptions();
markerOptions.setTitle(marker.title);
markerOptions.setSnippet(marker.subtitle);
markerOptions.setPosition(new com.mapbox.mapboxsdk.geometry.LatLng(parseFloat(marker.lat), parseFloat(marker.lng)));
if (marker.icon) {
if (marker.icon.startsWith('res://')) {
let cached = this.iconCache[marker.iconPath];
if (!cached) {
const resourcename = marker.icon.substring(6);
const res = Utils.ad.getApplicationContext().getResources();
const identifier = res.getIdentifier(resourcename, 'drawable', Utils.ad.getApplication().getPackageName());
if (identifier !== 0) {
cached = this.iconCache[marker.iconPath] = iconFactory.fromResource(identifier);
}
}
if (cached) {
markerOptions.setIcon(cached);
}
else {
console.log(`No icon found for this device density for icon ' ${marker.icon}'. Falling back to the default icon.`);
}
}
else if (marker.icon.startsWith('http')) {
if (marker.iconDownloaded !== null) {
markerOptions.setIcon(iconFactory.fromBitmap(marker.iconDownloaded));
}
}
else {
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'Please use res://resourcename, http(s)://imageurl or iconPath to use a local path');
}
}
}
else if (marker.iconPath) {
let cached = this.iconCache[marker.iconPath];
if (!cached) {
const iconFullPath = path.join(knownFolders.currentApp().path, marker.iconPath.replace('~/', ''));
if (File.exists(iconFullPath)) {
cached = this.iconCache[marker.iconPath] = iconFactory.fromPath(iconFullPath);
}
}
if (cached) {
markerOptions.setIcon(cached);
}
else {
console.log(`Marker icon not found, using the default instead. Requested path: '" + ${marker.iconPath}'.`);
}
}
marker.android = this._mapboxMapInstance.addMarker(markerOptions);
if (marker.selected) {
this._mapboxMapInstance.selectMarker(marker.android);
}
marker.update = (newSettings) => {
for (const m in this._markers) {
const _marker = this._markers[m];
if (marker.id === _marker.id) {
if (newSettings.onTap !== undefined) {
_marker.onTap = newSettings.onTap;
}
if (newSettings.onCalloutTap !== undefined) {
_marker.onCalloutTap = newSettings.onCalloutTap;
}
if (newSettings.title !== undefined) {
_marker.title = newSettings.title;
_marker.android.setTitle(newSettings.title);
}
if (newSettings.subtitle !== undefined) {
_marker.subtitle = newSettings.title;
_marker.android.setSnippet(newSettings.subtitle);
}
if (newSettings.lat && newSettings.lng) {
_marker.lat = newSettings.lat;
_marker.lng = newSettings.lng;
_marker.android.setPosition(new com.mapbox.mapboxsdk.geometry.LatLng(parseFloat(newSettings.lat), parseFloat(newSettings.lng)));
}
if (newSettings.selected) {
this._mapboxMapInstance.selectMarker(_marker.android);
}
}
}
};
}
});
}
_removeMarkers(ids, nativeMap) {
if (!this._mapboxMapInstance) {
return;
}
for (const m in this._markers) {
const marker = this._markers[m];
if (!ids || (marker && marker.id && ids.indexOf(marker.id) > -1)) {
if (marker && marker.android) {
this._mapboxMapInstance.removeAnnotation(marker.android);
}
}
}
if (ids) {
this._markers = this._markers.filter((marker) => ids.indexOf(marker.id) === -1);
}
else {
this._markers = [];
}
}
setCenter(options, nativeMap) {
return new Promise((resolve, reject) => {
try {
const cameraPosition = new com.mapbox.mapboxsdk.camera.CameraPosition.Builder().target(new com.mapbox.mapboxsdk.geometry.LatLng(options.lat, options.lng)).build();
if (options.animated === true) {
const newCameraPosition = com.mapbox.mapboxsdk.camera.CameraUpdateFactory.newCameraPosition(cameraPosition);
this._mapboxMapInstance.animateCamera(newCameraPosition, 1000, null);
}
else {
this._mapboxMapInstance.setCameraPosition(cameraPosition);
}
resolve();
}
catch (ex) {
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'Error in mapbox.setCenter: ' + ex);
}
reject(ex);
}
});
}
getCenter(nativeMap) {
return new Promise((resolve, reject) => {
try {
const coordinate = this._mapboxMapInstance.getCameraPosition().target;
resolve({
lat: coordinate.getLatitude(),
lng: coordinate.getLongitude()
});
}
catch (ex) {
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'Error in mapbox.getCenter: ' + ex);
}
reject(ex);
}
});
}
setZoomLevel(options, nativeMap) {
return new Promise((resolve, reject) => {
try {
const animated = options.animated === undefined || options.animated;
const level = options.level;
if (level >= 0 && level <= 20) {
const cameraUpdate = com.mapbox.mapboxsdk.camera.CameraUpdateFactory.zoomTo(level);
if (animated) {
this._mapboxMapInstance.easeCamera(cameraUpdate);
}
else {
this._mapboxMapInstance.moveCamera(cameraUpdate);
}
resolve();
}
else {
reject('invalid zoomlevel, use any double value from 0 to 20 (like 8.3)');
}
}
catch (ex) {
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'Error in mapbox.setZoomLevel: ' + ex);
}
reject(ex);
}
});
}
getZoomLevel(nativeMap) {
return new Promise((resolve, reject) => {
try {
const level = this._mapboxMapInstance.getCameraPosition().zoom;
resolve(level);
}
catch (ex) {
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'Error in mapbox.getZoomLevel: ' + ex);
}
reject(ex);
}
});
}
setTilt(options, nativeMap) {
return new Promise((resolve, reject) => {
try {
const tilt = options.tilt ? options.tilt : 30;
const cameraPositionBuilder = new com.mapbox.mapboxsdk.camera.CameraPosition.Builder().tilt(tilt);
const cameraUpdate = com.mapbox.mapboxsdk.camera.CameraUpdateFactory.newCameraPosition(cameraPositionBuilder.build());
const durationMs = options.duration ? options.duration : 5000;
this._mapboxMapInstance.easeCamera(cameraUpdate, durationMs);
setTimeout(() => {
resolve();
}, durationMs);
}
catch (ex) {
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'Error in mapbox.setTilt: ' + ex);
}
reject(ex);
}
});
}
getTilt(nativeMap) {
return new Promise((resolve, reject) => {
try {
const tilt = this._mapboxMapInstance.getCameraPosition().tilt;
resolve(tilt);
}
catch (ex) {
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'Error in mapbox.getTilt: ' + ex);
}
reject(ex);
}
});
}
getUserLocation() {
return new Promise((resolve, reject) => {
try {
const loc = this._locationComponent ? this._locationComponent.getLastKnownLocation() : null;
if (loc === null) {
reject('Location not available');
}
else {
resolve(_getLocation(loc));
}
}
catch (ex) {
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'Error in mapbox.getUserLocation: ' + ex);
}
reject(ex);
}
});
}
queryRenderedFeatures(options) {
return new Promise((resolve, reject) => {
try {
if (options.point === undefined) {
reject("Please set the 'point' parameter");
return;
}
if (!options) {
options = {};
}
const mapboxPoint = new com.mapbox.mapboxsdk.geometry.LatLng(options.point.lat, options.point.lng);
const screenLocation = this._mapboxMapInstance.getProjection().toScreenLocation(mapboxPoint);
if (this._mapboxMapInstance.queryRenderedFeatures) {
const queryFilter = options.filter ? ExpressionParser.parseJson(options.filter) : null;
const features = this._mapboxMapInstance.queryRenderedFeatures(screenLocation, queryFilter, options.layers);
const result = [];
for (let i = 0; i < features.size(); i++) {
const feature = features.get(i);
result.push(JSON.parse(feature.toJson()));
}
resolve(result);
}
else {
reject('Feature not supported by this Mapbox version');
}
}
catch (ex) {
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'Error in mapbox.queryRenderedFeatures: ' + ex);
}
reject(ex);
}
});
}
querySourceFeatures(sourceId, options) {
return new Promise((resolve, reject) => {
try {
if (!options) {
options = {};
}
const source = this._mapboxMapInstance.getStyle().getSource(sourceId);
if (!source) {
throw new Error(`Source with id "${sourceId}" not found.`);
}
let features;
const queryFilter = options.filter ? ExpressionParser.parseJson(options.filter) : null;
if (source instanceof com.mapbox.mapboxsdk.style.sources.GeoJsonSource) {
features = source.querySourceFeatures(queryFilter);
}
else if (source instanceof com.mapbox.mapboxsdk.style.sources.VectorSource) {
if (!options.sourceLayer) {
throw new Error('The option "sourceLayer" is required for vector sources.');
}
features = source.querySourceFeatures([options.sourceLayer], queryFilter);
}
else {
throw new Error('Only sources from type "vector" or "geojson" are supported.');
}
const result = [];
for (let i = 0; i < features.size(); i++) {
const feature = features.get(i);
result.push(JSON.parse(feature.toJson()));
}
resolve(result);
}
catch (ex) {
if (Trace.isEnabled()) {
CLog(CLogTypes.info, 'Error in mapbox.querySourceFeatures: ' + ex);
}
reject(ex);
}
});
}
addPolygon(options, nativeMap) {
return new Promise((resolve, reject) => {
try {
const points = options.points;
if (points === undefined) {
reject("Please set the 'points' parameter");
return;
}
const polygonOptions = new com.mapbox.mapboxsdk.annotations.PolygonOptions();
for (const p in points) {
const point = points[p];
polygonOptions.add(new com.mapbox.mapboxsdk.geometry.LatLng(point.lat, point.lng));
}
polygonOptions.fillColor(Mapbox.getAndroidColor(options.fillColor));
polygonOptions.alpha(options.fillOpacity === undefined ? 1 : options.fillOpacity);
if (options.strokeColor) {
polygonOptions.strokeColor(Mapbox.getAnd