Skip to content

Commit 05a3659

Browse files
committed
feat: implement #50
1 parent 6b3a804 commit 05a3659

File tree

3 files changed

+199
-45
lines changed

3 files changed

+199
-45
lines changed

src/ui-mapbox/common.ts

+6
Original file line numberDiff line numberDiff line change
@@ -657,6 +657,8 @@ export interface MapboxApi {
657657

658658
setOnMoveBeginListener(listener: (data?: LatLng) => void, nativeMap?: any): Promise<void>;
659659

660+
setOnMoveEndListener(listener: (data?: LatLng) => void, nativeMap?: any): Promise<void>;
661+
660662
setOnFlingListener(listener: () => void, nativeMap?: any): Promise<any>;
661663

662664
setOnCameraMoveListener(listener: (reason, animated?: boolean) => void, nativeMap?: any): Promise<any>;
@@ -910,6 +912,9 @@ export abstract class MapboxViewCommonBase extends ContentView implements Mapbox
910912
setOnMoveBeginListener(listener: (data?: LatLng) => void, nativeMap?: any): Promise<void> {
911913
return this.mapbox.setOnMoveBeginListener(listener, this.getNativeMapView());
912914
}
915+
setOnMoveEndListener(listener: (data?: LatLng) => void, nativeMap?: any): Promise<void> {
916+
return this.mapbox.setOnMoveEndListener(listener, this.getNativeMapView());
917+
}
913918
setOnFlingListener(listener: () => void, nativeMap?: any): Promise<any> {
914919
return this.mapbox.setOnFlingListener(listener, this.getNativeMapView());
915920
}
@@ -1159,6 +1164,7 @@ export abstract class MapboxViewBase extends MapboxViewCommonBase {
11591164
public static mapReadyEvent: string = 'mapReady';
11601165
public static scrollEvent: string = 'scrollEvent';
11611166
public static moveBeginEvent: string = 'moveBeginEvent';
1167+
public static moveEndEvent: string = 'moveEndEvent';
11621168

11631169
public static locationPermissionGrantedEvent: string = 'locationPermissionGranted';
11641170
public static locationPermissionDeniedEvent: string = 'locationPermissionDenied';

src/ui-mapbox/index.android.ts

+72-3
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
*/
66

77
import { request } from '@nativescript-community/perms';
8-
import { AndroidApplication, Application, Color, File, Image, ImageSource, Trace, Utils, knownFolders, path, Http } from '@nativescript/core';
8+
import { AndroidApplication, Application, Color, File, Http, Image, ImageSource, Trace, Utils, knownFolders, path } from '@nativescript/core';
99
import { FilterParser } from './filter/filter-parser';
10-
import { LayerFactory, Layer } from './layers/layer-factory';
10+
import { Layer, LayerFactory } from './layers/layer-factory';
1111
import {
1212
AddExtrusionOptions,
1313
AddGeoJsonClusteredOptions,
@@ -336,6 +336,19 @@ export class MapboxView extends MapboxViewBase {
336336
map: this,
337337
android: this.nativeMapView
338338
});
339+
},
340+
onMoveEndEvent: (event) => {
341+
if (Trace.isEnabled()) {
342+
CLog(CLogTypes.info, 'initMap(): onMoveEndEvent event');
343+
}
344+
345+
this.notify({
346+
eventName: MapboxViewBase.moveEndEvent,
347+
object: this,
348+
event,
349+
map: this,
350+
android: this.nativeMapView
351+
});
339352
}
340353
};
341354

@@ -923,6 +936,26 @@ export class Mapbox extends MapboxCommon implements MapboxApi {
923936
settings.onMoveBeginEvent(point);
924937
}
925938
}, mapboxNativeViewInstance);
939+
940+
this.setOnMoveEndListener((point: LatLng) => {
941+
if (Trace.isEnabled()) {
942+
CLog(CLogTypes.info, 'Mapbox:initEventHandlerShim(): moveEnd:', point);
943+
}
944+
945+
if (typeof settings.onMoveEndEvent != 'undefined') {
946+
settings.onMoveEndEvent(point);
947+
}
948+
}, mapboxNativeViewInstance);
949+
950+
this.setOnScrollListener((point: LatLng) => {
951+
if (Trace.isEnabled()) {
952+
CLog(CLogTypes.info, 'Mapbox:initEventHandlerShim(): move:', point);
953+
}
954+
955+
if (typeof settings.onScrollEvent != 'undefined') {
956+
settings.onScrollEvent(point);
957+
}
958+
}, mapboxNativeViewInstance);
926959
}
927960

928961
/**
@@ -1901,6 +1934,42 @@ export class Mapbox extends MapboxCommon implements MapboxApi {
19011934
});
19021935
}
19031936

1937+
setOnMoveEndListener(listener: (data?: LatLng) => void, nativeMap?): Promise<void> {
1938+
return new Promise((resolve, reject) => {
1939+
try {
1940+
if (!this._mapboxMapInstance) {
1941+
reject('No map has been loaded');
1942+
return;
1943+
}
1944+
1945+
if (Trace.isEnabled()) {
1946+
CLog(CLogTypes.info, 'setOnMoveEndListener():');
1947+
}
1948+
1949+
this.onMoveListener = new com.mapbox.mapboxsdk.maps.MapboxMap.OnMoveListener({
1950+
onMoveBegin: (detector: any /* MoveGestureDetector */) => {},
1951+
onMove: (detector: any /* MoveGestureDetector */) => {},
1952+
onMoveEnd: (detector: any /* MoveGestureDetector */) => {
1953+
const coordinate = this._mapboxMapInstance.getCameraPosition().target;
1954+
return listener({
1955+
lat: coordinate.getLatitude(),
1956+
lng: coordinate.getLongitude()
1957+
});
1958+
}
1959+
});
1960+
1961+
this._mapboxMapInstance.addOnMoveListener(this.onMoveListener);
1962+
1963+
resolve();
1964+
} catch (ex) {
1965+
if (Trace.isEnabled()) {
1966+
CLog(CLogTypes.info, 'Error in mapbox.setOnMoveEndListener: ' + ex);
1967+
}
1968+
reject(ex);
1969+
}
1970+
});
1971+
}
1972+
19041973
setOnScrollListener(listener: (data?: LatLng) => void, nativeMap?): Promise<void> {
19051974
return new Promise((resolve, reject) => {
19061975
try {
@@ -2884,7 +2953,7 @@ export class Mapbox extends MapboxCommon implements MapboxApi {
28842953
_getRegionName(offlineRegion: com.mapbox.mapboxsdk.offline.OfflineRegion) {
28852954
const metadata = offlineRegion.getMetadata();
28862955
const jsonStr = new java.lang.String(metadata, 'UTF-8');
2887-
const jsonObj = new org.json.JSONObject((jsonStr as any) as string);
2956+
const jsonObj = new org.json.JSONObject(jsonStr as any as string);
28882957
return jsonObj.getString('name');
28892958
}
28902959

src/ui-mapbox/index.ios.ts

+121-42
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Color, File, ImageSource, Trace, knownFolders, path, Http, Utils } from '@nativescript/core';
1+
import { Color, File, Http, ImageSource, Trace, Utils, knownFolders, path } from '@nativescript/core';
22
import {
33
AddExtrusionOptions,
44
AddGeoJsonClusteredOptions,
@@ -35,7 +35,7 @@ import {
3535
Viewport,
3636
telemetryProperty
3737
} from './common';
38-
import { LayerFactory, Layer } from './layers/layer-factory';
38+
import { Layer, LayerFactory } from './layers/layer-factory';
3939
import { FilterParser } from './filter/filter-parser';
4040

4141
/**
@@ -422,66 +422,79 @@ class MapLongPressHandlerImpl extends NSObject {
422422
/**
423423
* pan handler
424424
*
425-
* This is used by the OnScrollListener
425+
* This is used by scroll listeners
426426
*/
427427
@NativeClass
428428
class MapPanHandlerImpl extends NSObject {
429429
private _owner: WeakRef<Mapbox>;
430-
private _listener: (data?: LatLng) => void;
431-
private onMoveBegin: boolean;
430+
private _listener: Map<UIGestureRecognizerState, (data?: LatLng) => void>;
432431
private _mapView: MGLMapView;
433432

434-
public static initWithOwnerAndListenerForMap(owner: WeakRef<Mapbox>, listener: (data?: LatLng) => void, mapView: MGLMapView): MapPanHandlerImpl {
433+
public static initWithOwnerAndListenerForMap(owner: WeakRef<Mapbox>, listener: (data?: LatLng) => void, panState: UIGestureRecognizerState, mapView: MGLMapView): MapPanHandlerImpl {
435434
const handler = MapPanHandlerImpl.new() as MapPanHandlerImpl;
436435
handler._owner = owner;
437-
handler._listener = listener;
436+
handler._listener = new Map([[panState, listener]]);
438437
handler._mapView = mapView;
439438

440-
handler.onMoveBegin = false;
441-
442439
return handler;
443440
}
444441

445-
public setOnMoveBegin() {
446-
this.onMoveBegin = true;
442+
public static ObjCExposedMethods = {
443+
pan: { returns: interop.types.void, params: [interop.types.id] },
444+
panEnd: { returns: interop.types.void, params: [interop.types.id] },
445+
panBegin: { returns: interop.types.void, params: [interop.types.id] }
446+
};
447+
448+
public addListener(panState: UIGestureRecognizerState, listener: (data?: LatLng) => void) {
449+
this._listener.set(panState, listener);
447450
}
448451

449452
public pan(recognizer: UIPanGestureRecognizer): void {
450-
const panPoint = recognizer.locationInView(this._mapView);
451-
const panCoordinate = this._mapView.convertPointToCoordinateFromView(panPoint, this._mapView);
453+
const panCoordinate = this.getCoordinates(recognizer);
452454

453455
if (Trace.isEnabled()) {
454456
CLog(CLogTypes.info, 'MapPanHandlerImpl::pan(): top with state:', recognizer.state);
455457
}
456458

457-
// if this is the beginning of the pan simulate the Android onMoveBegin
458-
//
459-
// See the objc platform declarations in objc!UIKit.d.ts. It doesn't quite match the apple documention
459+
if (recognizer.state === UIGestureRecognizerState.Changed) {
460+
this.notifyListener(recognizer.state, panCoordinate.latitude, panCoordinate.longitude);
461+
}
462+
}
460463

461-
if (this.onMoveBegin) {
462-
if (recognizer.state === UIGestureRecognizerState.Began) {
463-
if (Trace.isEnabled()) {
464-
CLog(CLogTypes.info, 'MapPanHandlerImpl::pan(): calling onMoveBegin listener');
465-
}
464+
public panEnd(recognizer: UIPanGestureRecognizer): void {
465+
const panCoordinate = this.getCoordinates(recognizer);
466466

467-
this._listener({
468-
lat: panCoordinate.latitude,
469-
lng: panCoordinate.longitude
470-
});
471-
}
467+
if (Trace.isEnabled()) {
468+
CLog(CLogTypes.info, 'MapPanHandlerImpl::panEnd(): top with state:', recognizer.state);
469+
}
472470

473-
return;
471+
if (recognizer.state === UIGestureRecognizerState.Ended) {
472+
this.notifyListener(recognizer.state, panCoordinate.latitude, panCoordinate.longitude);
474473
}
474+
}
475475

476-
this._listener({
477-
lat: panCoordinate.latitude,
478-
lng: panCoordinate.longitude
479-
});
476+
public panBegin(recognizer: UIPanGestureRecognizer): void {
477+
const panCoordinate = this.getCoordinates(recognizer);
478+
479+
if (Trace.isEnabled()) {
480+
CLog(CLogTypes.info, 'MapPanHandlerImpl::panBegin(): top with state:', recognizer.state);
481+
}
482+
483+
if (recognizer.state === UIGestureRecognizerState.Began) {
484+
this.notifyListener(recognizer.state, panCoordinate.latitude, panCoordinate.longitude);
485+
}
480486
}
481487

482-
public static ObjCExposedMethods = {
483-
pan: { returns: interop.types.void, params: [interop.types.id] }
484-
};
488+
private getCoordinates(recognizer: UIPanGestureRecognizer) {
489+
const panPoint = recognizer.locationInView(this._mapView);
490+
return this._mapView.convertPointToCoordinateFromView(panPoint, this._mapView);
491+
}
492+
493+
private notifyListener(panState: UIGestureRecognizerState, latitude: number, longitude: number) {
494+
if (this._listener.has(panState)) {
495+
this._listener.get(panState)({ lat: latitude, lng: longitude });
496+
}
497+
}
485498
}
486499

487500
/**
@@ -850,6 +863,32 @@ export class MapboxView extends MapboxViewBase {
850863
ios: this.nativeMapView
851864
});
852865
}, this.nativeMapView);
866+
867+
this.mapbox.setOnMoveEndListener((data?: LatLng) => {
868+
if (Trace.isEnabled()) {
869+
CLog(CLogTypes.info, 'initMap(): onMoveEnd listener');
870+
}
871+
872+
this.notify({
873+
eventName: MapboxViewBase.moveEndEvent,
874+
object: this,
875+
map: this,
876+
ios: this.nativeMapView
877+
});
878+
}, this.nativeMapView);
879+
880+
this.mapbox.setOnScrollListener((data?: LatLng) => {
881+
if (Trace.isEnabled()) {
882+
CLog(CLogTypes.info, 'initMap(): onScroll listener');
883+
}
884+
885+
this.notify({
886+
eventName: MapboxViewBase.scrollEvent,
887+
object: this,
888+
map: this,
889+
ios: this.nativeMapView
890+
});
891+
}, this.nativeMapView);
853892
};
854893

855894
// draw the map after a timeout
@@ -2247,7 +2286,11 @@ export class Mapbox extends MapboxCommon implements MapboxApi {
22472286
}
22482287

22492288
// adding the pan handler to the map oject so it's not GC'd
2250-
theMap['mapPanHandler'] = MapPanHandlerImpl.initWithOwnerAndListenerForMap(new WeakRef(this), listener, theMap);
2289+
if (theMap['mapPanHandler'] === undefined) {
2290+
theMap['mapPanHandler'] = MapPanHandlerImpl.initWithOwnerAndListenerForMap(new WeakRef(this), listener, UIGestureRecognizerState.Changed, theMap);
2291+
} else {
2292+
(theMap['mapPanHandler'] as MapPanHandlerImpl).addListener(UIGestureRecognizerState.Changed, listener);
2293+
}
22512294

22522295
// there's already a pan recognizer, so find it and attach a target action
22532296
for (let i = 0; i < theMap.gestureRecognizers.count; i++) {
@@ -2286,27 +2329,63 @@ export class Mapbox extends MapboxCommon implements MapboxApi {
22862329
}
22872330

22882331
// adding the pan handler to the map oject so it's not GC'd
2289-
theMap['mapOnMoveBeginHandler'] = MapPanHandlerImpl.initWithOwnerAndListenerForMap(new WeakRef(this), listener, theMap);
2332+
if (theMap['mapPanHandler'] === undefined) {
2333+
theMap['mapPanHandler'] = MapPanHandlerImpl.initWithOwnerAndListenerForMap(new WeakRef(this), listener, UIGestureRecognizerState.Began, theMap);
2334+
} else {
2335+
(theMap['mapPanHandler'] as MapPanHandlerImpl).addListener(UIGestureRecognizerState.Began, listener);
2336+
}
22902337

2291-
// tell the panHandler that we're only interested in the first pan per pan gesture
2338+
// there's already a pan recognizer, so find it and attach a target action
22922339

2293-
theMap['mapOnMoveBeginHandler'].setOnMoveBegin();
2340+
for (let i = 0; i < theMap.gestureRecognizers.count; i++) {
2341+
const recognizer: UIGestureRecognizer = theMap.gestureRecognizers.objectAtIndex(i);
22942342

2295-
// there's already a pan recognizer, so find it and attach a target action
2343+
if (recognizer instanceof UIPanGestureRecognizer) {
2344+
recognizer.addTargetAction(theMap['mapPanHandler'], 'panBegin');
2345+
break;
2346+
}
2347+
}
2348+
2349+
resolve();
2350+
} catch (ex) {
2351+
if (Trace.isEnabled()) {
2352+
CLog(CLogTypes.info, 'Error in mapbox.setOnMoveBeginListener: ' + ex);
2353+
}
2354+
reject(ex);
2355+
}
2356+
});
2357+
}
2358+
2359+
setOnMoveEndListener(listener: () => void, nativeMap?: any): Promise<void> {
2360+
return new Promise((resolve, reject) => {
2361+
try {
2362+
const theMap: MGLMapView = nativeMap || this._mapboxViewInstance;
22962363

2364+
if (!theMap) {
2365+
reject('No map has been loaded');
2366+
return;
2367+
}
2368+
2369+
if (theMap['mapPanHandler'] === undefined) {
2370+
theMap['mapPanHandler'] = MapPanHandlerImpl.initWithOwnerAndListenerForMap(new WeakRef(this), listener, UIGestureRecognizerState.Ended, theMap);
2371+
} else {
2372+
(theMap['mapPanHandler'] as MapPanHandlerImpl).addListener(UIGestureRecognizerState.Ended, listener);
2373+
}
2374+
2375+
// there's already a pan recognizer, so find it and attach a target action
22972376
for (let i = 0; i < theMap.gestureRecognizers.count; i++) {
22982377
const recognizer: UIGestureRecognizer = theMap.gestureRecognizers.objectAtIndex(i);
22992378

23002379
if (recognizer instanceof UIPanGestureRecognizer) {
2301-
recognizer.addTargetAction(theMap['mapOnMoveBeginHandler'], 'pan');
2380+
recognizer.addTargetAction(theMap['mapPanHandler'], 'panEnd');
23022381
break;
23032382
}
23042383
}
23052384

23062385
resolve();
23072386
} catch (ex) {
23082387
if (Trace.isEnabled()) {
2309-
CLog(CLogTypes.info, 'Error in mapbox.setOnScrollListener: ' + ex);
2388+
CLog(CLogTypes.info, 'Error in mapbox.setOnMoveEndListener: ' + ex);
23102389
}
23112390
reject(ex);
23122391
}
@@ -3113,4 +3192,4 @@ const _downloadMarkerImages = (markers: MapboxMarker[]) => {
31133192
});
31143193

31153194
return Promise.all(iterations).then(() => result);
3116-
};
3195+
};

0 commit comments

Comments
 (0)