Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
311 changes: 1 addition & 310 deletions src/ui-mapbox/index.ios.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
}

/**
Expand Down Expand Up @@ -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()');
Expand Down Expand Up @@ -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

Expand Down