From cf9e189e9fc461b5e20f9c3c06aec3f9927e5153 Mon Sep 17 00:00:00 2001 From: Benedict Strube Date: Sun, 6 Feb 2022 22:47:55 +0100 Subject: [PATCH] fix(standard user location annotation view): restored standard user location annotation view The `CustomUserLocationAnnotationView` was very rudimentary and does not any functionality the standard annotation view does not offer. Besides, the custom implementation did not support the different camera modes. Therefore, it is best to use the standard annotation view. --- src/ui-mapbox/index.ios.ts | 311 +------------------------------------ 1 file changed, 1 insertion(+), 310 deletions(-) diff --git a/src/ui-mapbox/index.ios.ts b/src/ui-mapbox/index.ios.ts index c977515..5f61a90 100755 --- a/src/ui-mapbox/index.ios.ts +++ b/src/ui-mapbox/index.ios.ts @@ -61,7 +61,6 @@ class MGLMapViewDelegateImpl extends NSObject implements MGLMapViewDelegate { private cameraChangedListener: (reason, animated?: boolean) => void; private cameraIdledListener: () => void; private userLocationRenderMode: any; - private userLocationAnnotationView: CustomUserLocationAnnotationView; /** * initialize with the mapReady callback @@ -100,7 +99,7 @@ class MGLMapViewDelegateImpl extends NSObject implements MGLMapViewDelegate { * set user location marker modes */ changeUserLocationRenderMode(userLocationRenderMode) { - this.userLocationAnnotationView.changeUserLocationRenderMode(userLocationRenderMode); + // nothing to do here } /** @@ -315,23 +314,6 @@ class MGLMapViewDelegateImpl extends NSObject implements MGLMapViewDelegate { } } - /** - * override the standard location marker - */ - mapViewViewForAnnotation(mapView: MGLMapView, annotation: MGLAnnotation): MGLAnnotationView { - if (Trace.isEnabled()) { - CLog(CLogTypes.info, 'MGLMapViewDelegateImpl::mapViewViewForAnnotation() top'); - } - - if (annotation.isKindOfClass(MGLUserLocation.class())) { - this.userLocationAnnotationView = CustomUserLocationAnnotationView.alloc().init() as CustomUserLocationAnnotationView; - - return this.userLocationAnnotationView; - } - - return null; - } - mapViewRegionIsChangingWithReason(mapView: MGLMapView, reason: MGLCameraChangeReason) { if (Trace.isEnabled()) { CLog(CLogTypes.info, 'MGLMapViewDelegateImpl::mapViewRegionIsChanging()'); @@ -909,297 +891,6 @@ export class MapboxView extends MapboxViewBase { } } -/** - * a custom user location marker - * - * We want to add some behavior to the user location marker to visibly - * show the user when locations are being stored and when they are not. - * - * Sadly, it's not as easy under iOS as it is on Android. It involves - * creating a custom annotation view. - * - * @link https://docs.mapbox.com/ios/maps/examples/user-location-annotation/ - */ - -@NativeClass -class CustomUserLocationAnnotationView extends MGLUserLocationAnnotationView implements MGLUserLocationAnnotationView { - public size: number; - public dot: CALayer; - public arrow: CAShapeLayer; - - // may be NORMAL, COMPASS, or GPS. - - private userLocationRenderMode: string; - private renderModeChanged: boolean; - - /** - * init - * - * @link https://docs.nativescript.org/core-concepts/ios-runtime/HelloWorld - */ - - public init() { - this.size = 48; - super.initWithFrame(CGRectMake(0, 0, this.size, this.size)); - - this.renderModeChanged = true; - this.userLocationRenderMode = 'NORMAL'; - - return this; - } - - /** - * update - * - * The note from the Objective-C sample indicates this method may be called quite - * often so it needs to be kept lightweight. - */ - - update() { - if (CLLocationCoordinate2DIsValid(this.userLocation.coordinate)) { - // if it's the first time here, setup the layers that make up the - // location marker. - - if (!this.dot) { - this.drawNonTrackingLocationMarker(); - } - - if (this.userLocationRenderMode === 'GPS') { - this.updateHeading(); - } - } - } - - /** - * Draw the GPS tracking arrow. - * - * @link https://docs.nativescript.org/ns-framework-modules/color - */ - - drawTrackingLocationMarker() { - if (Trace.isEnabled()) { - CLog(CLogTypes.info, 'CustomerUserLocationAnnotatinView::drawTrackingLocationMarker()'); - } - - this.drawTrackingDot(); - this.drawArrow(); - } // end of setupLayers() - - /** - * draw the non-tracking marker - */ - - drawNonTrackingLocationMarker() { - if (Trace.isEnabled()) { - CLog(CLogTypes.info, 'CustomerUserLocationAnnotatinView::drawNonTrackingLocationMarker()'); - } - - this.drawNonTrackingDot(); - - if (this.arrow) { - this.arrow.removeFromSuperlayer(); - this.arrow = null; - } - } - - /** - * draw the tracking dot. - */ - - drawTrackingDot() { - this.size = 48; - - // we need to adjust the size of the bounds of the marker. The Tracking marker - // is larger than the non tracking marker. - - this.bounds = CGRectMake(0, 0, this.size, this.size); - - const dot = CALayer.layer(); - - dot.frame = this.bounds; - - // user corner radius to turn the layer into a circle - - dot.cornerRadius = this.size / 2; - dot.backgroundColor = this.tintColor.CGColor; - dot.borderWidth = 4; - - const whiteColor = new Color('#FFFFFF'); - dot.borderColor = whiteColor.ios.CGColor; - - if (!this.dot) { - this.layer.addSublayer(dot); - } else { - this.layer.replaceSublayerWith(this.dot, dot); - } - - // QUESTION: does GC catch this? - - this.dot = dot; - } - - /** - * draw the non-tracking dot. - */ - - drawNonTrackingDot() { - this.size = 24; - this.bounds = CGRectMake(0, 0, this.size, this.size); - const dot = CALayer.layer(); - - dot.frame = this.bounds; - - // user corner radius to turn the layer into a circle - - dot.cornerRadius = this.size / 2; - dot.backgroundColor = this.tintColor.CGColor; - - dot.borderWidth = 1; - - const whiteColor = new Color('#FFFFFF'); - dot.borderColor = whiteColor.ios.CGColor; - - if (!this.dot) { - this.layer.addSublayer(dot); - } else { - this.layer.replaceSublayerWith(this.dot, dot); - } - - // QUESTION: does GC catch this? - - this.dot = dot; - } - - /** - * draw an arrow - */ - - drawArrow() { - const arrow = CAShapeLayer.layer(); - - arrow.path = this.arrowPath(); - arrow.frame = CGRectMake(0, 0, this.size / 2, this.size / 2); - arrow.position = CGPointMake(CGRectGetMidX(this.dot.frame), CGRectGetMidY(this.dot.frame)); - arrow.fillColor = this.dot.borderColor; - - if (!this.arrow) { - this.layer.addSublayer(arrow); - } else { - this.layer.replaceSublayerWith(this.arrow, arrow); - } - - // QUESTION: Does GC catch this? - - this.arrow = arrow; - } - - /** - * update arrow heading - * - * @link https://docs.nativescript.org/core-concepts/ios-runtime/types/C-Functions - */ - - updateHeading() { - // just to avoid a possible race condition where the arrow isnt' drawn yet - - if (!this.arrow) { - return; - } - - if (typeof this.userLocation == 'undefined') { - return; - } - - if (typeof this.userLocation.heading == 'undefined' || this.userLocation.heading === null) { - return; - } - - if (typeof this.userLocation.heading.trueHeading == 'undefined' || this.userLocation.heading.trueHeading === null) { - return; - } - - if (this.userLocation.heading.trueHeading > 0) { - this.arrow.hidden = false; - - // get the difference between the map's current direction and the - // user's heading, then convert it from degrees to radians - // - // The original Objective-C example uses the inline C function MGLRadiansFromDegrees but because - // it's declared as inline it is not available for NativeScript. See linked article above. - - // let rotation : number = MGLRadiansFromDegrees( this.mapView.direction - this.userLocation.heading.trueHeading ); - - const degrees: number = this.mapView.direction - this.userLocation.heading.trueHeading; - - // in radians - - let rotation: number = (degrees * Math.PI) / 180; - - rotation = -rotation; - - // if the difference would be perceptible, rotate the arrow. - - if (fabs(rotation) > 0.01) { - // Disable implicit animations of this rotation, which reduces lag between updates - - CATransaction.begin(); - CATransaction.setDisableActions(true); - - this.arrow.setAffineTransform(CGAffineTransformRotate(CGAffineTransformIdentity, rotation)); - - CATransaction.commit(); - } - } else { - this.arrow.hidden = true; - } - } - - /** - * Calculate the vector path for an arrow - */ - - arrowPath() { - const max: number = this.size / 2; - const pad: number = 3; - - const top: CGPoint = CGPointMake(max * 0.5, 0); - const left: CGPoint = CGPointMake(0 + pad, max - pad); - const right: CGPoint = CGPointMake(max - pad, max - pad); - const center: CGPoint = CGPointMake(max * 0.5, max * 0.6); - - const bezierPath = UIBezierPath.bezierPath(); - bezierPath.moveToPoint(top); - bezierPath.addLineToPoint(left); - bezierPath.addLineToPoint(center); - - bezierPath.addLineToPoint(right); - bezierPath.addLineToPoint(top); - bezierPath.closePath(); - - return bezierPath.CGPath; - } - - /** - * change Render mode - * - * @param {string} renderMode - */ - - changeUserLocationRenderMode(renderMode) { - if (Trace.isEnabled()) { - CLog(CLogTypes.info, "CustomUserLocationAnnotatinView::changeUserLocationRenderMode(): changing mode to '" + renderMode + "'"); - } - - this.userLocationRenderMode = renderMode; - - if (renderMode === 'GPS') { - this.drawTrackingLocationMarker(); - } else { - this.drawNonTrackingLocationMarker(); - } - } -} // end of class CustomUserLocationAnnotationView - export class Mapbox extends MapboxCommon implements MapboxApi { // reference to the native mapbox API