Files
react-native-mapbox-gl/ios/RCTMapboxGL/RCTMapboxGL.m
T

772 lines
26 KiB
Objective-C

//
// RCTMapboxGL.m
// RCTMapboxGL
//
// Created by Bobby Sudekum on 4/30/15.
// Copyright (c) 2015 Mapbox. All rights reserved.
//
#import "RCTMapboxGL.h"
#import <React/RCTBridgeModule.h>
#import <React/RCTEventDispatcher.h>
#import <React/UIView+React.h>
#import <React/RCTLog.h>
#import "RCTMapboxGLConversions.h"
#import "RCTMapboxAnnotation.h"
@implementation RCTMapboxGL {
/* Required to publish events */
RCTEventDispatcher *_eventDispatcher;
/* Our map subview instance */
MGLMapView *_map;
/* Map properties */
NSMutableDictionary *_annotations;
CLLocationCoordinate2D _initialCenterCoordinate;
double _initialDirection;
double _initialZoomLevel;
BOOL _zoomEnabled;
double _minimumZoomLevel;
double _maximumZoomLevel;
BOOL _clipsToBounds;
BOOL _debugActive;
BOOL _finishedLoading;
BOOL _rotateEnabled;
BOOL _scrollEnabled;
BOOL _pitchEnabled;
BOOL _showsUserLocation;
NSURL *_styleURL;
int _userTrackingMode;
BOOL _attributionButton;
BOOL _logo;
BOOL _compass;
UIEdgeInsets _contentInset;
MGLAnnotationVerticalAlignment _userLocationVerticalAlignment;
/* So we don't fire onChangeUserTracking mode when triggered by props */
BOOL _isChangingUserTracking;
NSMutableDictionary<NSString *, UIView *> *_reactSubviews;
}
// View creation
- (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher
{
if (self = [super init]) {
_eventDispatcher = eventDispatcher;
_clipsToBounds = YES;
_finishedLoading = NO;
_annotations = [NSMutableDictionary dictionary];
_reactSubviews = [NSMutableDictionary dictionary];
}
return self;
}
- (void)createMapIfNeeded
{
CGRect bounds = self.bounds;
if (_map ||
!_styleURL ||
bounds.size.width <= 0 || bounds.size.height <= 0
) {
return;
}
_map = [[MGLMapView alloc] initWithFrame:self.bounds];
_map.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
_map.delegate = self;
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)];
[self addGestureRecognizer:longPress];
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingleTap:)];
singleTap.delegate = self;
[_map addGestureRecognizer:singleTap];
_map.centerCoordinate = _initialCenterCoordinate;
_map.clipsToBounds = _clipsToBounds;
_map.debugActive = _debugActive;
_map.direction = _initialDirection;
_map.rotateEnabled = _rotateEnabled;
_map.scrollEnabled = _scrollEnabled;
_map.zoomEnabled = _zoomEnabled;
_map.pitchEnabled = _pitchEnabled;
_map.minimumZoomLevel = _minimumZoomLevel;
_map.maximumZoomLevel = _maximumZoomLevel;
_map.showsUserLocation = _showsUserLocation;
_map.styleURL = _styleURL;
_map.zoomLevel = _initialZoomLevel;
_map.contentInset = _contentInset;
[_map.attributionButton setHidden:_attributionButton];
[_map.logoView setHidden:_logo];
[_map.compassView setHidden:_compass];
_map.userLocationVerticalAlignment = _userLocationVerticalAlignment;
_isChangingUserTracking = YES;
_map.userTrackingMode = _userTrackingMode;
_isChangingUserTracking = NO;
for (NSString * annotationId in _annotations) {
[_map addAnnotation:_annotations[annotationId]];
}
[self addSubview:_map];
for (NSString *key in [_reactSubviews allKeys]) {
[_map addAnnotation:_reactSubviews[key]];
}
[self layoutSubviews];
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}
- (void)layoutSubviews
{
if (!_map) {
[self createMapIfNeeded];
}
_map.frame = self.bounds;
[_map layoutSubviews];
}
// React subviews for custom annotation management
- (void)insertReactSubview:(id<RCTComponent>)subview atIndex:(NSInteger)atIndex {
// Our desired API is to pass up markers/overlays as children to the mapview component.
// This is where we intercept them and do the appropriate underlying mapview action.
if ([subview isKindOfClass:[RCTMapboxAnnotation class]]) {
RCTMapboxAnnotation * annotation = (RCTMapboxAnnotation *) subview;
annotation.map = self;
[_map addAnnotation:annotation];
NSString *key = annotation.reuseIdentifier;
_reactSubviews[key] = annotation;
}
}
- (void)removeReactSubview:(id<RCTComponent>)subview {
// similarly, when the children are being removed we have to do the appropriate
// underlying mapview action here.
if ([subview isKindOfClass:[RCTMapboxAnnotation class]]) {
RCTMapboxAnnotation * annotation = (RCTMapboxAnnotation *) subview;
[_reactSubviews removeObjectForKey:annotation.reuseIdentifier];
}
}
- (NSArray<id<RCTComponent>> *)reactSubviews {
return nil;
}
// Annotation management
- (void)upsertAnnotation:(RCTMGLAnnotation *) annotation {
NSString * identifier = [annotation id];
if (!identifier || [identifier length] == 0) {
RCTLogError(@"field `id` is required on all annotations");
return;
}
RCTMGLAnnotation * oldAnnotation = [_annotations objectForKey:identifier];
[_annotations setObject:annotation forKey:identifier];
[_map addAnnotation:annotation];
if (oldAnnotation) {
[_map removeAnnotation:oldAnnotation];
}
}
- (void)removeAnnotation:(NSString*)selectedIdentifier
{
RCTMGLAnnotation * annotation = [_annotations objectForKey:selectedIdentifier];
if (!annotation) { return; }
[_map removeAnnotation:annotation];
[_annotations removeObjectForKey:selectedIdentifier];
}
- (void)removeAllAnnotations
{
[_map removeAnnotations:_map.annotations];
[_annotations removeAllObjects];
}
- (void)deselectAnnotation
{
NSArray * annotations = [_map selectedAnnotations];
if (!annotations) { return; }
for (id annotation in annotations) {
[_map deselectAnnotation:annotation animated:YES];
}
}
- (void)restoreAnnotationPosition:(NSString *)annotationId {
if (_reactSubviews[annotationId] && [_reactSubviews[annotationId] isKindOfClass:[RCTMapboxAnnotation class]]){
RCTMapboxAnnotation *annotation = (RCTMapboxAnnotation *)_reactSubviews[annotationId];
CGPoint point = [_map convertCoordinate:annotation.coordinate toPointToView:_map];
annotation.center = point;
}
}
- (CGFloat)mapView:(MGLMapView *)mapView alphaForShapeAnnotation:(RCTMGLAnnotationPolyline *)shape
{
if ([shape isKindOfClass:[RCTMGLAnnotationPolyline class]]) {
return shape.strokeAlpha;
} else if ([shape isKindOfClass:[RCTMGLAnnotationPolygon class]]) {
return [(RCTMGLAnnotationPolygon *) shape fillAlpha];
} else {
return 1.0;
}
}
- (UIColor *)mapView:(MGLMapView *)mapView strokeColorForShapeAnnotation:(RCTMGLAnnotationPolyline *)shape
{
if ([shape isKindOfClass:[RCTMGLAnnotationPolyline class]]) {
return [self getUIColorObjectFromHexString:shape.strokeColor alpha:1];
} else if ([shape isKindOfClass:[RCTMGLAnnotationPolygon class]]) {
return [self getUIColorObjectFromHexString:[(RCTMGLAnnotationPolygon *) shape strokeColor] alpha:1];
} else {
return [UIColor blueColor];
}
}
- (CGFloat)mapView:(MGLMapView *)mapView lineWidthForPolylineAnnotation:(RCTMGLAnnotationPolyline *)shape
{
return shape.strokeWidth;
}
- (UIColor *)mapView:(MGLMapView *)mapView fillColorForPolygonAnnotation:(RCTMGLAnnotationPolygon *)shape
{
return [self getUIColorObjectFromHexString:shape.fillColor alpha:1];
}
- (BOOL)mapView:(RCTMapboxGL *)mapView annotationCanShowCallout:(id <MGLAnnotation>)annotation {
if (!_annotationsPopUpEnabled) { return NO; }
NSString *title = [(RCTMGLAnnotation *) annotation title];
NSString *subtitle = [(RCTMGLAnnotation *) annotation subtitle];
return ([title length] != 0 || [subtitle length] != 0);
}
- (nullable MGLAnnotationView *)mapView:(MGLMapView *)mapView viewForAnnotation:(id <MGLAnnotation>)annotation {
if ([annotation isKindOfClass:[RCTMapboxAnnotation class]] ){
RCTMapboxAnnotation *customAnnotation = (RCTMapboxAnnotation *)annotation;
MGLAnnotationView *annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:customAnnotation.reuseIdentifier];
if (!annotationView){
annotationView = _reactSubviews[customAnnotation.reuseIdentifier];
}
return annotationView;
}
return nil;
}
- (UIButton *)mapView:(MGLMapView *)mapView rightCalloutAccessoryViewForAnnotation:(id <MGLAnnotation>)annotation;
{
if ([annotation isKindOfClass:[RCTMGLAnnotation class]]) {
UIButton *accessoryButton = [(RCTMGLAnnotation *) annotation rightCalloutAccessory];
return accessoryButton;
}
return nil;
}
- (void)mapView:(MGLMapView *)mapView annotation:(id<MGLAnnotation>)annotation calloutAccessoryControlTapped:(UIControl *)control
{
if (annotation.title && annotation.subtitle) {
NSString *id = [(RCTMGLAnnotation *) annotation id];
NSDictionary *event = @{ @"target": self.reactTag,
@"src": @{ @"title": annotation.title,
@"subtitle": annotation.subtitle,
@"id": id,
@"latitude": @(annotation.coordinate.latitude),
@"longitude": @(annotation.coordinate.longitude)} };
[_eventDispatcher sendInputEventWithName:@"onRightAnnotationTapped" body:event];
}
}
- (MGLAnnotationImage *)mapView:(MGLMapView *)mapView imageForAnnotation:(id<MGLAnnotation>)annotation
{
NSDictionary *source = [(RCTMGLAnnotation *) annotation annotationImageSource];
if (!source) { return nil; }
CGSize imageSize = [(RCTMGLAnnotation *) annotation annotationImageSize];
NSString *reuseIdentifier = source[@"uri"];
MGLAnnotationImage *annotationImage = [mapView dequeueReusableAnnotationImageWithIdentifier:reuseIdentifier];
if (!annotationImage) {
UIImage *image = imageFromSource(source);
UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0.0);
[image drawInRect:CGRectMake(0, 0, imageSize.width, imageSize.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
annotationImage = [MGLAnnotationImage annotationImageWithImage:newImage reuseIdentifier:reuseIdentifier];
}
return annotationImage;
}
// React props
- (void)setInitialCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate
{
_initialCenterCoordinate = centerCoordinate;
}
- (void)setInitialZoomLevel:(double)zoomLevel
{
_initialZoomLevel = zoomLevel;
}
- (void)setInitialDirection:(double)direction
{
_initialDirection = direction;
}
- (void)setClipsToBounds:(BOOL)clipsToBounds
{
if (_clipsToBounds == clipsToBounds) { return; }
_clipsToBounds = clipsToBounds;
if (_map) { _map.clipsToBounds = clipsToBounds; }
}
- (void)setDebugActive:(BOOL)debugActive
{
if (_debugActive == debugActive) { return; }
_debugActive = debugActive;
if (_map) { _map.debugActive = debugActive; }
}
- (void)setRotateEnabled:(BOOL)rotateEnabled
{
if (_rotateEnabled == rotateEnabled) { return; }
_rotateEnabled = rotateEnabled;
if (_map) { _map.rotateEnabled = rotateEnabled; }
}
- (void)setScrollEnabled:(BOOL)scrollEnabled
{
if (_scrollEnabled == scrollEnabled) { return; }
_scrollEnabled = scrollEnabled;
if (_map) { _map.scrollEnabled = scrollEnabled; }
}
- (void)setZoomEnabled:(BOOL)zoomEnabled
{
if (_zoomEnabled == zoomEnabled) { return; }
_zoomEnabled = zoomEnabled;
if (_map) { _map.zoomEnabled = zoomEnabled; }
}
- (void)setMinimumZoomLevel:(double)minimumZoomLevel
{
if (_minimumZoomLevel == minimumZoomLevel) { return; }
_minimumZoomLevel = minimumZoomLevel;
if (_map) { _map.minimumZoomLevel = minimumZoomLevel; }
}
- (void)setMaximumZoomLevel:(double)maximumZoomLevel
{
if (_maximumZoomLevel == maximumZoomLevel) { return; }
_maximumZoomLevel = maximumZoomLevel;
if (_map) { _map.maximumZoomLevel = maximumZoomLevel; }
}
- (void)setPitchEnabled:(BOOL)pitchEnabled
{
if (_pitchEnabled == pitchEnabled) { return; }
_pitchEnabled = pitchEnabled;
if (_map) { _map.pitchEnabled = pitchEnabled; }
}
- (void)setShowsUserLocation:(BOOL)showsUserLocation
{
if (_showsUserLocation == showsUserLocation) { return; }
_showsUserLocation = showsUserLocation;
if (_map) { _map.showsUserLocation = showsUserLocation; }
}
- (void)setStyleURL:(NSURL *)styleURL
{
if (_styleURL && [styleURL isEqual:_styleURL]) { return; }
_styleURL = styleURL;
if (_map) {
_map.styleURL = styleURL;
} else {
[self createMapIfNeeded];
}
}
- (void)setUserTrackingMode:(int)userTrackingMode
{
if (_userTrackingMode == userTrackingMode) { return; }
if (userTrackingMode > 3 || userTrackingMode < 0) {
_userTrackingMode = 0;
} else {
_userTrackingMode = userTrackingMode;
}
if (_map) {
_isChangingUserTracking = YES;
_map.userTrackingMode = _userTrackingMode;
_isChangingUserTracking = NO;
}
}
- (void)setAttributionButtonIsHidden:(BOOL)isHidden
{
if (_attributionButton == isHidden) { return; }
_attributionButton = isHidden;
if (_map) { _map.attributionButton.hidden = isHidden; }
}
- (void)setLogoIsHidden:(BOOL)isHidden
{
if (_logo == isHidden) { return; }
_logo = isHidden;
if (_map) { _map.logoView.hidden = isHidden; }
}
- (void)setCompassIsHidden:(BOOL)isHidden
{
if (_compass == isHidden) { return; }
_compass = isHidden;
if (_map) { _map.compassView.hidden = isHidden; }
}
- (void)setContentInset:(UIEdgeInsets)inset
{
_contentInset = inset;
if (_map) { _map.contentInset = inset; }
}
- (void)setUserLocationVerticalAlignment:(MGLAnnotationVerticalAlignment)alignment
{
if (_userLocationVerticalAlignment == alignment) { return; }
_userLocationVerticalAlignment = alignment;
if (_map) { _map.userLocationVerticalAlignment = alignment; }
}
// Getters
- (MGLCoordinateBounds) visibleCoordinateBounds
{
return [_map visibleCoordinateBounds];
}
-(CLLocationCoordinate2D)centerCoordinate {
if (!_map) { return _initialCenterCoordinate; }
return _map.centerCoordinate;
}
-(double)direction {
if (!_map) { return _initialDirection; }
return _map.direction;
}
-(double)pitch {
if (!_map) { return 0; }
return _map.camera.pitch;
}
-(double)zoomLevel {
if (!_map) { return _initialZoomLevel; }
return _map.zoomLevel;
}
-(MGLMapCamera*)camera {
if (!_map) { return nil; }
return _map.camera;
}
// Imperative methods
- (void)setCenterCoordinate:(CLLocationCoordinate2D)coordinate zoomLevel:(double)zoomLevel direction:(double)direction animated:(BOOL)animated completionHandler:(void (^)())callback
{
if (!_map) {
_initialCenterCoordinate = coordinate;
_initialZoomLevel = zoomLevel;
_initialDirection = direction;
callback();
return;
}
[_map setCenterCoordinate:coordinate
zoomLevel:zoomLevel
direction:direction
animated:animated
completionHandler:callback];
}
- (void)setCamera:(MGLMapCamera *)camera withDuration:(NSTimeInterval)duration animationTimingFunction:(nullable CAMediaTimingFunction *)function completionHandler:(nullable void (^)(void))handler
{
[_map setCamera: camera withDuration:duration animationTimingFunction:function completionHandler:handler];
}
- (void)setVisibleCoordinateBounds:(MGLCoordinateBounds)bounds edgePadding:(UIEdgeInsets)padding animated:(BOOL)animated
{
[_map setVisibleCoordinateBounds:bounds edgePadding:padding animated:animated];
}
- (void)selectAnnotation:(NSString*)selectedId animated:(BOOL)animated;
{
RCTMGLAnnotation * annotation = [_annotations objectForKey:selectedId];
if (!annotation) { return; }
[_map selectAnnotation:annotation animated:animated];
}
// Events
-(void)mapView:(MGLMapView *)mapView didChangeUserTrackingMode:(MGLUserTrackingMode)mode animated:(BOOL)animated
{
if (_isChangingUserTracking) { return; }
if (!_onChangeUserTrackingMode) { return; }
_onChangeUserTrackingMode(@{ @"target": self.reactTag,
@"src": @(mode) });
}
- (void)mapView:(MGLMapView *)mapView didUpdateUserLocation:(MGLUserLocation *)userLocation;
{
if (!_onUpdateUserLocation) { return; }
_onUpdateUserLocation(@{ @"target": self.reactTag,
@"src": @{ @"latitude": @(userLocation.coordinate.latitude),
@"longitude": @(userLocation.coordinate.longitude),
@"verticalAccuracy": @(userLocation.location.verticalAccuracy),
@"horizontalAccuracy": @(userLocation.location.horizontalAccuracy),
@"headingAccuracy": @(userLocation.heading.headingAccuracy),
@"magneticHeading": @(userLocation.heading.magneticHeading),
@"trueHeading": @(userLocation.heading.trueHeading),
@"isUpdating": [NSNumber numberWithBool:userLocation.isUpdating]} });
}
- (void)mapView:(MGLMapView *)mapView didFailToLocateUserWithError:(NSError *)error
{
if (!_onLocateUserFailed) { return; }
_onLocateUserFailed(@{ @"target": self.reactTag,
@"src": @{ @"message": [error localizedDescription] } });
}
-(void)mapView:(MGLMapView *)mapView didSelectAnnotation:(id<MGLAnnotation>)annotation
{
if (!annotation.title || !annotation.subtitle) { return; }
if (!_onOpenAnnotation) { return; }
_onOpenAnnotation(@{ @"target": self.reactTag,
@"src": @{ @"title": annotation.title,
@"subtitle": annotation.subtitle,
@"id": [(RCTMGLAnnotation *) annotation id],
@"latitude": @(annotation.coordinate.latitude),
@"longitude": @(annotation.coordinate.longitude)} });
}
-(void)mapView:(MGLMapView *)mapView didDeselectAnnotation:(nonnull id<MGLAnnotation>)annotation
{
if (!annotation.title || !annotation.subtitle) { return; }
if (!_onCloseAnnotation) { return; }
_onCloseAnnotation(@{ @"target": self.reactTag,
@"src": @{ @"title": annotation.title,
@"subtitle": annotation.subtitle,
@"id": [(RCTMGLAnnotation *) annotation id],
@"latitude": @(annotation.coordinate.latitude),
@"longitude": @(annotation.coordinate.longitude)} });
}
- (void)mapView:(RCTMapboxGL *)mapView regionDidChangeAnimated:(BOOL)animated
{
if (!_onRegionDidChange) { return; }
CLLocationCoordinate2D region = _map.centerCoordinate;
_onRegionDidChange(@{ @"target": self.reactTag,
@"src": @{ @"latitude": @(region.latitude),
@"longitude": @(region.longitude),
@"zoomLevel": @(_map.zoomLevel),
@"direction": @(_map.direction),
@"pitch": @(_map.camera.pitch),
@"animated": @(animated) } });
}
- (void)mapView:(RCTMapboxGL *)mapView regionWillChangeAnimated:(BOOL)animated
{
if (!_onRegionWillChange) { return; }
CLLocationCoordinate2D region = _map.centerCoordinate;
_onRegionWillChange(@{ @"target": self.reactTag,
@"src": @{ @"latitude": @(region.latitude),
@"longitude": @(region.longitude),
@"zoomLevel": @(_map.zoomLevel),
@"direction": @(_map.direction),
@"pitch": @(_map.camera.pitch),
@"animated": @(animated) } });
}
- (void)handleSingleTap:(UITapGestureRecognizer *)sender
{
if (!_onTap) { return; }
CLLocationCoordinate2D location = [_map convertPoint:[sender locationInView:_map] toCoordinateFromView:_map];
CGPoint screenCoord = [sender locationInView:_map];
_onTap(@{ @"target": self.reactTag,
@"src": @{ @"latitude": @(location.latitude),
@"longitude": @(location.longitude),
@"screenCoordY": @(screenCoord.y),
@"screenCoordX": @(screenCoord.x) } });
}
- (void)handleLongPress:(UITapGestureRecognizer *)sender
{
if (!_onLongPress) { return; }
if (sender.state != UIGestureRecognizerStateBegan) { return; }
CLLocationCoordinate2D location = [_map convertPoint:[sender locationInView:_map] toCoordinateFromView:_map];
CGPoint screenCoord = [sender locationInView:_map];
_onLongPress(@{ @"target": self.reactTag,
@"src": @{ @"latitude": @(location.latitude),
@"longitude": @(location.longitude),
@"screenCoordY": @(screenCoord.y),
@"screenCoordX": @(screenCoord.x) } });
}
- (nonnull NSArray<id<MGLFeature>> *)visibleFeaturesAtPoint:(CGPoint)point
inStyleLayersWithIdentifiers:(nullable NSSet<NSString *> *)styleLayerIdentifiers
{
return [_map visibleFeaturesAtPoint:point inStyleLayersWithIdentifiers:styleLayerIdentifiers];
}
- (nonnull NSArray<id<MGLFeature>> *)visibleFeaturesInRect:(CGRect)rect inStyleLayersWithIdentifiers:(NSSet<NSString *> *)identifiers
{
return [_map visibleFeaturesInRect:rect inStyleLayersWithIdentifiers:identifiers];
}
- (void)mapViewDidFinishLoadingMap:(MGLMapView *)mapView
{
if (!_onFinishLoadingMap) { return; }
_onFinishLoadingMap(@{ @"target": self.reactTag });
}
- (void)mapViewWillStartLoadingMap:(MGLMapView *)mapView
{
if (!_onStartLoadingMap) { return; }
_onStartLoadingMap(@{ @"target": self.reactTag });
}
// Utils
- (unsigned int)intFromHexString:(NSString *)hexStr
{
unsigned int hexInt = 0;
// Create scanner
NSScanner *scanner = [NSScanner scannerWithString:hexStr];
// Tell scanner to skip the # character
[scanner setCharactersToBeSkipped:[NSCharacterSet characterSetWithCharactersInString:@"#"]];
// Scan hex value
[scanner scanHexInt:&hexInt];
return hexInt;
}
- (UIColor *)getUIColorObjectFromHexString:(NSString *)hexStr alpha:(CGFloat)alpha
{
// Convert hex string to an integer
unsigned int hexint = [self intFromHexString:hexStr];
// Create color object, specifying alpha as well
UIColor *color =
[UIColor colorWithRed:((CGFloat) ((hexint & 0xFF0000) >> 16))/255
green:((CGFloat) ((hexint & 0xFF00) >> 8))/255
blue:((CGFloat) (hexint & 0xFF))/255
alpha:alpha];
return color;
}
@end
@interface RCTMGLAnnotation ()
@property (nonatomic) CLLocationCoordinate2D coordinate;
@property (nonatomic) NSString *title;
@property (nonatomic) NSString *subtitle;
@end
@implementation RCTMGLAnnotation
+ (instancetype)annotationWithLocation:(CLLocationCoordinate2D)coordinate title:(NSString *)title subtitle:(NSString *)subtitle id:(NSString *)id
{
return [[self alloc] initWithLocation:coordinate title:title subtitle:subtitle id:id];
}
+ (instancetype)annotationWithLocationRightCallout:(CLLocationCoordinate2D)coordinate title:(NSString *)title subtitle:(NSString *)subtitle id:(NSString *)id rightCalloutAccessory:(UIButton *)rightCalloutAccessory
{
return [[self alloc] initWithLocationRightCallout:coordinate title:title subtitle:subtitle id:id rightCalloutAccessory:rightCalloutAccessory];
}
- (instancetype)initWithLocation:(CLLocationCoordinate2D)coordinate title:(NSString *)title subtitle:(NSString *)subtitle id:(NSString *)id
{
if (self = [super init]) {
_coordinate = coordinate;
_title = title;
_subtitle = subtitle;
_id = id;
}
return self;
}
- (instancetype)initWithLocationRightCallout:(CLLocationCoordinate2D)coordinate title:(NSString *)title subtitle:(NSString *)subtitle id:(NSString *)id rightCalloutAccessory:(UIButton *)rightCalloutAccessory
{
if (self = [super init]) {
_rightCalloutAccessory = rightCalloutAccessory;
_coordinate = coordinate;
_title = title;
_subtitle = subtitle;
_id = id;
}
return self;
}
@end
@interface RCTMGLAnnotationPolyline ()
@end
@implementation RCTMGLAnnotationPolyline
+ (instancetype)polylineAnnotation:(CLLocationCoordinate2D *)coordinates strokeAlpha:(double)strokeAlpha strokeColor:(NSString *)strokeColor strokeWidth:(double)strokeWidth id:(NSString *)id type:(NSString *)type count:(NSUInteger)count
{
RCTMGLAnnotationPolyline *polyline = [self polylineWithCoordinates:coordinates count:count];
polyline.strokeAlpha = strokeAlpha;
polyline.strokeColor = strokeColor;
polyline.strokeWidth = strokeWidth;
polyline.id = id;
return polyline;
}
@end
@interface RCTMGLAnnotationPolygon ()
@end
@implementation RCTMGLAnnotationPolygon
+ (instancetype)polygonAnnotation:(CLLocationCoordinate2D *)coordinates fillAlpha:(double)fillAlpha fillColor:(NSString *)fillColor strokeColor:(NSString *)strokeColor strokeAlpha:(double)strokeAlpha id:(NSString *)id type:(NSString *)type count:(NSUInteger)count
{
RCTMGLAnnotationPolygon *polygon = [self polygonWithCoordinates:coordinates count:count];
polygon.fillAlpha = fillAlpha;
polygon.fillColor = fillColor;
polygon.strokeAlpha = strokeAlpha;
polygon.strokeColor = strokeColor;
polygon.id = id;
return polygon;
}
@end