chore: add mobile app

This commit is contained in:
2026-02-07 22:33:02 +01:00
parent db34640acc
commit e89384ad4e
29327 changed files with 3886944 additions and 12 deletions
@@ -0,0 +1,18 @@
//
// AIRDummyView.h
// AirMapsExplorer
//
// Created by Gil Birman on 10/4/16.
//
#ifdef HAVE_GOOGLE_MAPS
#import <UIKit/UIKit.h>
@interface AIRDummyView : UIView
@property (nonatomic, weak) UIView *view;
- (instancetype)initWithView:(UIView*)view;
@end
#endif
@@ -0,0 +1,23 @@
//
// AIRDummyView.m
// AirMapsExplorer
//
// Created by Gil Birman on 10/4/16.
//
#ifdef HAVE_GOOGLE_MAPS
#import <Foundation/Foundation.h>
#import "AIRDummyView.h"
@implementation AIRDummyView
- (instancetype)initWithView:(UIView*)view
{
if ((self = [super init])) {
self.view = view;
}
return self;
}
@end
#endif
@@ -0,0 +1,29 @@
//
// AIRGMSMarker.h
// AirMaps
//
// Created by Gil Birman on 9/5/16.
//
#ifdef HAVE_GOOGLE_MAPS
#import <GoogleMaps/GoogleMaps.h>
#import <React/UIView+React.h>
@class AIRGoogleMapMarker;
@interface AIRGMSMarker : GMSMarker
@property (nonatomic, strong) NSString *identifier;
@property (nonatomic, weak) AIRGoogleMapMarker *fakeMarker;
@property (nonatomic, copy) RCTBubblingEventBlock onPress;
@property (nonatomic, copy) RCTDirectEventBlock onSelect;
@property (nonatomic, copy) RCTDirectEventBlock onDeselect;
@end
@protocol AIRGMSMarkerDelegate <NSObject>
@required
-(void)didTapMarker;
@end
#endif
@@ -0,0 +1,16 @@
//
// AIRGMSMarker.m
// AirMaps
//
// Created by Gil Birman on 9/5/16.
//
#ifdef HAVE_GOOGLE_MAPS
#import "AIRGMSMarker.h"
@implementation AIRGMSMarker
@end
#endif
@@ -0,0 +1,20 @@
//
// AIRGMSPolygon.h
// AirMaps
//
// Created by Gerardo Pacheco 02/05/2017.
//
#ifdef HAVE_GOOGLE_MAPS
#import <GoogleMaps/GoogleMaps.h>
#import <React/UIView+React.h>
@class AIRGoogleMapPolygon;
@interface AIRGMSPolygon : GMSPolygon
@property (nonatomic, strong) NSString *identifier;
@property (nonatomic, copy) RCTBubblingEventBlock onPress;
@end
#endif
@@ -0,0 +1,16 @@
//
// AIRGMSPolygon.m
// AirMaps
//
// Created by Gerardo Pacheco 02/05/2017.
//
#ifdef HAVE_GOOGLE_MAPS
#import "AIRGMSPolygon.h"
@implementation AIRGMSPolygon
@end
#endif
@@ -0,0 +1,20 @@
//
// AIRGMSPolyline.h
// AirMaps
//
// Created by Guilherme Pontes 04/05/2017.
//
#ifdef HAVE_GOOGLE_MAPS
#import <GoogleMaps/GoogleMaps.h>
#import <React/UIView+React.h>
@class AIRGoogleMapPolyline;
@interface AIRGMSPolyline : GMSPolyline
@property (nonatomic, strong) NSString *identifier;
@property (nonatomic, copy) RCTBubblingEventBlock onPress;
@end
#endif
@@ -0,0 +1,15 @@
//
// AIRGMSPolyline.m
// AirMaps
//
// Created by Guilherme Pontes 04/05/2017.
//
#ifdef HAVE_GOOGLE_MAPS
#import "AIRGMSPolyline.h"
@implementation AIRGMSPolyline
@end
#endif
@@ -0,0 +1,89 @@
//
// AIRGoogleMap.h
// AirMaps
//
// Created by Gil Birman on 9/1/16.
//
#ifdef HAVE_GOOGLE_MAPS
#import <UIKit/UIKit.h>
#import <React/RCTComponent.h>
#import <React/RCTBridge.h>
#import <GoogleMaps/GoogleMaps.h>
#import <MapKit/MapKit.h>
#import "AIRGMSMarker.h"
#import "RCTConvert+AirMap.h"
@interface AIRGoogleMap : GMSMapView
// TODO: don't use MK region?
@property (nonatomic, weak) RCTBridge *bridge;
@property (nonatomic, assign) MKCoordinateRegion initialRegion;
@property (nonatomic, assign) MKCoordinateRegion region;
@property (nonatomic, assign) GMSCameraPosition *cameraProp; // Because the base class already has a "camera" prop.
@property (nonatomic, strong) GMSCameraPosition *initialCamera;
@property (nonatomic, assign) NSString *customMapStyleString;
@property (nonatomic, assign) UIEdgeInsets mapPadding;
@property (nonatomic, assign) NSString *paddingAdjustmentBehaviorString;
@property (nonatomic, copy) RCTBubblingEventBlock onMapReady;
@property (nonatomic, copy) RCTBubblingEventBlock onMapLoaded;
@property (nonatomic, copy) RCTBubblingEventBlock onKmlReady;
@property (nonatomic, copy) RCTBubblingEventBlock onPress;
@property (nonatomic, copy) RCTBubblingEventBlock onLongPress;
@property (nonatomic, copy) RCTBubblingEventBlock onPanDrag;
@property (nonatomic, copy) RCTBubblingEventBlock onUserLocationChange;
@property (nonatomic, copy) RCTBubblingEventBlock onMarkerPress;
@property (nonatomic, copy) RCTBubblingEventBlock onMarkerSelect;
@property (nonatomic, copy) RCTBubblingEventBlock onMarkerDeselect;
@property (nonatomic, copy) RCTBubblingEventBlock onChange;
@property (nonatomic, copy) RCTBubblingEventBlock onPoiClick;
@property (nonatomic, copy) RCTDirectEventBlock onRegionChangeStart;
@property (nonatomic, copy) RCTDirectEventBlock onRegionChange;
@property (nonatomic, copy) RCTDirectEventBlock onRegionChangeComplete;
@property (nonatomic, copy) RCTDirectEventBlock onIndoorLevelActivated;
@property (nonatomic, copy) RCTDirectEventBlock onIndoorBuildingFocused;
@property (nonatomic, strong) NSMutableArray *markers;
@property (nonatomic, strong) NSMutableArray *polygons;
@property (nonatomic, strong) NSMutableArray *polylines;
@property (nonatomic, strong) NSMutableArray *circles;
@property (nonatomic, strong) NSMutableArray *heatmaps;
@property (nonatomic, strong) NSMutableArray *tiles;
@property (nonatomic, strong) NSMutableArray *overlays;
@property (nonatomic, assign) BOOL showsBuildings;
@property (nonatomic, assign) BOOL showsTraffic;
@property (nonatomic, assign) BOOL showsCompass;
@property (nonatomic, assign) BOOL scrollEnabled;
@property (nonatomic, assign) BOOL zoomEnabled;
@property (nonatomic, assign) BOOL rotateEnabled;
@property (nonatomic, assign) BOOL scrollDuringRotateOrZoomEnabled;
@property (nonatomic, assign) BOOL pitchEnabled;
@property (nonatomic, assign) BOOL zoomTapEnabled;
@property (nonatomic, assign) BOOL showsUserLocation;
@property (nonatomic, assign) BOOL showsMyLocationButton;
@property (nonatomic, assign) BOOL showsIndoors;
@property (nonatomic, assign) BOOL showsIndoorLevelPicker;
@property (nonatomic, assign) NSString *kmlSrc;
- (void)didPrepareMap;
- (void)mapViewDidFinishTileRendering;
- (BOOL)didTapMarker:(GMSMarker *)marker;
- (void)didTapPolyline:(GMSPolyline *)polyline;
- (void)didTapPolygon:(GMSPolygon *)polygon;
- (void)didTapAtCoordinate:(CLLocationCoordinate2D)coordinate;
- (void)didLongPressAtCoordinate:(CLLocationCoordinate2D)coordinate;
- (void)willMove:(BOOL)gesture;
- (void)didChangeCameraPosition:(GMSCameraPosition *)position isGesture:(BOOL)isGesture;
- (void)idleAtCameraPosition:(GMSCameraPosition *)position isGesture:(BOOL)isGesture;
- (void)didTapPOIWithPlaceID:(NSString *)placeID name:(NSString *) name location:(CLLocationCoordinate2D) location;
- (NSArray *)getMapBoundaries;
+ (MKCoordinateRegion)makeGMSCameraPositionFromMap:(GMSMapView *)map andGMSCameraPosition:(GMSCameraPosition *)position;
+ (GMSCameraPosition*)makeGMSCameraPositionFromMap:(GMSMapView *)map andMKCoordinateRegion:(MKCoordinateRegion)region;
- (NSDictionary*) getMarkersFramesWithOnlyVisible:(BOOL)onlyVisible;
- (instancetype)initWithMapId:(NSString *)mapId initialCamera:(GMSCameraPosition*) camera backgroundColor:(UIColor *) backgroundColor andZoomTapEnabled:(BOOL)zoomTapEnabled;
@end
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,23 @@
//
// AIRGoogleMapCallout.h
// AirMaps
//
// Created by Gil Birman on 9/6/16.
//
//
#ifdef HAVE_GOOGLE_MAPS
#import <UIKit/UIKit.h>
#import <React/RCTView.h>
@interface AIRGoogleMapCallout : UIView
@property (nonatomic, assign) BOOL tooltip;
@property (nonatomic, copy) RCTBubblingEventBlock onPress;
@property (nonatomic, assign) BOOL alphaHitTest;
- (BOOL) isPointInside:(CGPoint)pointInCallout;
@end
#endif
@@ -0,0 +1,39 @@
//
// AIRGoogleMapCallout.m
// AirMaps
//
// Created by Gil Birman on 9/6/16.
//
//
#ifdef HAVE_GOOGLE_MAPS
#import "AIRGoogleMapCallout.h"
#import <React/RCTUtils.h>
#import <React/RCTView.h>
#import <React/RCTBridge.h>
@implementation AIRGoogleMapCallout
- (BOOL) isPointInside:(CGPoint)pointInCallout {
if (!self.alphaHitTest)
return TRUE;
CGFloat alpha = [self alphaOfPoint:pointInCallout];
return alpha >= 0.01;
}
- (CGFloat) alphaOfPoint:(CGPoint)point {
unsigned char pixel[4] = {0};
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(pixel, 1, 1, 8, 4, colorSpace, kCGBitmapAlphaInfoMask & kCGImageAlphaPremultipliedLast);
CGContextTranslateCTM(context, -point.x, -point.y);
[self.layer renderInContext:context];
CGContextRelease(context);
CGColorSpaceRelease(colorSpace);
return pixel[3]/255.0;
}
@end
#endif
@@ -0,0 +1,17 @@
//
// AIRGoogleMapCalloutManager.h
// AirMaps
//
// Created by Gil Birman on 9/6/16.
//
//
#ifdef HAVE_GOOGLE_MAPS
#import <React/RCTViewManager.h>
@interface AIRGoogleMapCalloutManager : RCTViewManager
@end
#endif
@@ -0,0 +1,30 @@
//
// AIRGoogleMapCalloutManager.m
// AirMaps
//
// Created by Gil Birman on 9/6/16.
//
//
#ifdef HAVE_GOOGLE_MAPS
#import "AIRGoogleMapCalloutManager.h"
#import "AIRGoogleMapCallout.h"
#import <React/RCTView.h>
@implementation AIRGoogleMapCalloutManager
RCT_EXPORT_MODULE()
- (UIView *)view
{
AIRGoogleMapCallout *callout = [AIRGoogleMapCallout new];
return callout;
}
RCT_EXPORT_VIEW_PROPERTY(tooltip, BOOL)
RCT_EXPORT_VIEW_PROPERTY(onPress, RCTBubblingEventBlock)
RCT_EXPORT_VIEW_PROPERTY(alphaHitTest, BOOL)
@end
#endif
@@ -0,0 +1,18 @@
//
// AIRGoogleMapCalloutSubview.h
// AirMaps
//
// Created by Denis Oblogin on 10/8/18.
//
//
#ifdef HAVE_GOOGLE_MAPS
#import <UIKit/UIKit.h>
#import <React/RCTView.h>
@interface AIRGoogleMapCalloutSubview : UIView
@property (nonatomic, copy) RCTBubblingEventBlock onPress;
@end
#endif
@@ -0,0 +1,19 @@
//
// AIRGoogleMapCalloutSubview.m
// AirMaps
//
// Created by Denis Oblogin on 10/8/18.
//
//
#ifdef HAVE_GOOGLE_MAPS
#import "AIRGoogleMapCalloutSubview.h"
#import <React/RCTUtils.h>
#import <React/RCTView.h>
#import <React/RCTBridge.h>
@implementation AIRGoogleMapCalloutSubview
@end
#endif
@@ -0,0 +1,17 @@
//
// AIRGoogleMapCalloutSubviewManager.h
// AirMaps
//
// Created by Denis Oblogin on 10/8/18.
//
//
#ifdef HAVE_GOOGLE_MAPS
#import <React/RCTViewManager.h>
@interface AIRGoogleMapCalloutSubviewManager : RCTViewManager
@end
#endif
@@ -0,0 +1,28 @@
//
// AIRGoogleMapCalloutSubviewManager.m
// AirMaps
//
// Created by Denis Oblogin on 10/8/18.
//
//
#ifdef HAVE_GOOGLE_MAPS
#import "AIRGoogleMapCalloutSubviewManager.h"
#import "AIRGoogleMapCalloutSubview.h"
#import <React/RCTView.h>
@implementation AIRGoogleMapCalloutSubviewManager
RCT_EXPORT_MODULE()
- (UIView *)view
{
AIRGoogleMapCalloutSubview *calloutSubview = [AIRGoogleMapCalloutSubview new];
return calloutSubview;
}
RCT_EXPORT_VIEW_PROPERTY(onPress, RCTBubblingEventBlock)
@end
#endif
@@ -0,0 +1,24 @@
//
// AIRGoogleMapsCircle.h
//
// Created by Nick Italiano on 10/24/16.
//
#ifdef HAVE_GOOGLE_MAPS
#import <GoogleMaps/GoogleMaps.h>
#import "AIRMapCoordinate.h"
@interface AIRGoogleMapCircle : UIView
@property (nonatomic, strong) GMSCircle *circle;
@property (nonatomic, assign) double radius;
@property (nonatomic, assign) CLLocationCoordinate2D centerCoordinate;
@property (nonatomic, strong) UIColor *strokeColor;
@property (nonatomic, assign) double strokeWidth;
@property (nonatomic, strong) UIColor *fillColor;
@property (nonatomic, assign) int zIndex;
@end
#endif
@@ -0,0 +1,88 @@
//
// AIRGoogleMapsCircle.m
//
// Created by Nick Italiano on 10/24/16.
//
#ifdef HAVE_GOOGLE_MAPS
#import <UIKit/UIKit.h>
#import "AIRGoogleMapCircle.h"
#import <GoogleMaps/GoogleMaps.h>
#import <React/RCTUtils.h>
@implementation AIRGoogleMapCircle
{
BOOL _didMoveToWindow;
}
- (instancetype)init
{
if (self = [super init]) {
_didMoveToWindow = false;
_circle = [[GMSCircle alloc] init];
_circle.fillColor = _fillColor;
_circle.strokeColor = _strokeColor;
}
return self;
}
- (void)didMoveToWindow {
[super didMoveToWindow];
if(_didMoveToWindow) return;
_didMoveToWindow = true;
if(_fillColor) {
_circle.fillColor = _fillColor;
}
if(_strokeColor) {
_circle.strokeColor = _strokeColor;
}
if(_strokeWidth) {
_circle.strokeWidth = _strokeWidth;
}
}
- (void)setRadius:(double)radius
{
_radius = radius;
_circle.radius = radius;
}
- (void)setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate
{
_centerCoordinate = centerCoordinate;
_circle.position = centerCoordinate;
}
-(void)setStrokeColor:(UIColor *)strokeColor
{
_strokeColor = strokeColor;
if(_didMoveToWindow) {
_circle.strokeColor = strokeColor;
}
}
-(void)setStrokeWidth:(double)strokeWidth
{
_strokeWidth = strokeWidth;
if(_didMoveToWindow) {
_circle.strokeWidth = strokeWidth;
}
}
-(void)setFillColor:(UIColor *)fillColor
{
_fillColor = fillColor;
if(_didMoveToWindow) {
_circle.fillColor = fillColor;
}
}
-(void)setZIndex:(int)zIndex
{
_zIndex = zIndex;
_circle.zIndex = zIndex;
}
@end
#endif
@@ -0,0 +1,15 @@
//
// AIRGoogleMapCircleManager.h
//
// Created by Nick Italiano on 10/24/16.
//
#ifdef HAVE_GOOGLE_MAPS
#import <React/RCTViewManager.h>
@interface AIRGoogleMapCircleManager : RCTViewManager
@end
#endif
@@ -0,0 +1,37 @@
//
// AIRGoogleMapCircleManager.m
//
// Created by Nick Italiano on 10/24/16.
//
#ifdef HAVE_GOOGLE_MAPS
#import "AIRGoogleMapCircleManager.h"
#import "AIRGoogleMapCircle.h"
#import <React/RCTBridge.h>
#import <React/UIView+React.h>
@interface AIRGoogleMapCircleManager()
@end
@implementation AIRGoogleMapCircleManager
RCT_EXPORT_MODULE()
- (UIView *)view
{
AIRGoogleMapCircle *circle = [AIRGoogleMapCircle new];
return circle;
}
RCT_EXPORT_VIEW_PROPERTY(radius, double)
RCT_REMAP_VIEW_PROPERTY(center, centerCoordinate, CLLocationCoordinate2D)
RCT_EXPORT_VIEW_PROPERTY(strokeColor, UIColor)
RCT_EXPORT_VIEW_PROPERTY(strokeWidth, double)
RCT_EXPORT_VIEW_PROPERTY(fillColor, UIColor)
RCT_EXPORT_VIEW_PROPERTY(zIndex, int)
@end
#endif
@@ -0,0 +1,17 @@
//
// AIRGoogleMapHeatmap.h
//
// Created by David Cako on 29 April 2018.
//
#import "GMUHeatmapTileLayer.h"
@interface AIRGoogleMapHeatmap : UIView
@property (nonatomic, strong) GMUHeatmapTileLayer *heatmap;
@property (nonatomic, strong) NSMutableArray<GMUWeightedLatLng *> *points;
@property (nonatomic, assign) NSUInteger radius;
@property (nonatomic, assign) float opacity;
@property (nonatomic, assign) GMUGradient *gradient;
@end
@@ -0,0 +1,64 @@
//
// AIRGoogleMapHeatmap.m
//
// Created by David Cako on 29 April 2018.
//
#import <UIKit/UIKit.h>
#import "AIRGoogleMapHeatmap.h"
#import <GoogleMaps/GoogleMaps.h>
#import <React/RCTConvert.h>
#import <React/RCTConvert+CoreLocation.h>
@implementation AIRGoogleMapHeatmap
- (instancetype)init
{
if (self = [super init]) {
_heatmap = [[GMUHeatmapTileLayer alloc] init];
}
return self;
}
- (void)setPoints:(NSArray<NSDictionary *> *)points
{
NSMutableArray<GMUWeightedLatLng *> *w = [NSMutableArray arrayWithCapacity:points.count];
for (int i = 0; i < points.count; i++) {
CLLocationCoordinate2D coord = [RCTConvert CLLocationCoordinate2D:points[i]];
float intensity = 1.0;
if (points[i][@"weight"] != nil) {
intensity = [RCTConvert float:points[i][@"weight"]];
}
[w addObject:[[GMUWeightedLatLng alloc] initWithCoordinate:coord intensity:intensity]];
}
_points = w;
[self.heatmap setWeightedData:w];
[self.heatmap clearTileCache];
[self.heatmap setMap:self.heatmap.map];
}
- (void)setRadius:(NSUInteger)radius
{
_radius = radius;
[self.heatmap setRadius:radius];
}
- (void)setOpacity:(float)opacity
{
_opacity = opacity;
[self.heatmap setOpacity:opacity];
}
- (void)setGradient:(NSDictionary *)gradient
{
NSArray<UIColor *> *colors = [RCTConvert UIColorArray:gradient[@"colors"]];
NSArray<NSNumber *> *colorStartPoints = [RCTConvert NSNumberArray:gradient[@"startPoints"]];
NSUInteger colorMapSize = [RCTConvert NSUInteger:gradient[@"colorMapSize"]];
GMUGradient *gmuGradient = [[GMUGradient alloc] initWithColors:colors
startPoints:colorStartPoints
colorMapSize:colorMapSize];
_gradient = gmuGradient;
[self.heatmap setGradient:gmuGradient];
}
@end
@@ -0,0 +1,11 @@
//
// AIRGoogleMapHeatmapManager.h
//
// Created by David Cako on 29 April 2018.
//
#import <React/RCTViewManager.h>
@interface AIRGoogleMapHeatmapManager : RCTViewManager
@end
@@ -0,0 +1,32 @@
//
// AIRGoogleMapHeatmapManager.m
//
// Created by David Cako on 29 April 2018.
//
#import "AIRGoogleMapHeatmapManager.h"
#import "AIRGoogleMapHeatmap.h"
#import "AIRGoogleMap.h"
#import <React/RCTBridge.h>
#import <React/UIView+React.h>
@interface AIRGoogleMapHeatmapManager()
@end
@implementation AIRGoogleMapHeatmapManager
RCT_EXPORT_MODULE()
- (UIView *)view
{
AIRGoogleMapHeatmap *heatmap = [AIRGoogleMapHeatmap new];
return heatmap;
}
RCT_EXPORT_VIEW_PROPERTY(points, NSArray<NSDictionary *>)
RCT_EXPORT_VIEW_PROPERTY(radius, NSUInteger)
RCT_EXPORT_VIEW_PROPERTY(opacity, float)
RCT_EXPORT_VIEW_PROPERTY(gradient, NSDictionary *)
@end
@@ -0,0 +1,20 @@
//
// AIRGoogleMapManager.h
// AirMaps
//
// Created by Gil Birman on 9/1/16.
//
#ifdef HAVE_GOOGLE_MAPS
#import <React/RCTViewManager.h>
@interface AIRGoogleMapManager : RCTViewManager
@property (nonatomic, strong) NSDictionary *initialProps;
@property (nonatomic) BOOL isGesture;
@end
#endif
@@ -0,0 +1,622 @@
//
// AIRGoogleMapManager.m
// AirMaps
//
// Created by Gil Birman on 9/1/16.
//
#ifdef HAVE_GOOGLE_MAPS
#import "AIRGoogleMapManager.h"
#import <React/RCTViewManager.h>
#import <React/RCTBridge.h>
#import <React/RCTUIManager.h>
#import <React/RCTConvert+CoreLocation.h>
#import <React/RCTEventDispatcher.h>
#import <React/RCTViewManager.h>
#import <React/RCTConvert.h>
#import <React/UIView+React.h>
#import "RCTConvert+GMSMapViewType.h"
#import "AIRGoogleMap.h"
#import "AIRMapMarker.h"
#import "AIRMapPolyline.h"
#import "AIRMapPolygon.h"
#import "AIRMapCircle.h"
#import "SMCalloutView.h"
#import "AIRGoogleMapMarker.h"
#import "RCTConvert+AirMap.h"
#import <MapKit/MapKit.h>
#import <QuartzCore/QuartzCore.h>
static NSString *const RCTMapViewKey = @"MapView";
@interface AIRGoogleMapManager() <GMSMapViewDelegate>
{
BOOL didCallOnMapReady;
}
@end
@implementation AIRGoogleMapManager
RCT_EXPORT_MODULE()
- (UIView *)view
{
NSString* googleMapId = nil;
BOOL zoomTapEnabled = YES;
UIColor* backgroundColor = nil;
GMSCameraPosition* camera = nil;
if (self.initialProps){
if (self.initialProps[@"googleMapId"]){
googleMapId = self.initialProps[@"googleMapId"];
}
if (self.initialProps[@"zoomTapEnabled"]){
zoomTapEnabled = self.initialProps[@"zoomTapEnabled"];
}
if (self.initialProps[@"loadingBackgroundColor"]){
backgroundColor = [RCTConvert UIColor:self.initialProps[@"loadingBackgroundColor"]];
}
if (self.initialProps[@"initialCamera"]){
camera = [RCTConvert GMSCameraPositionWithDefaults:self.initialProps[@"initialCamera"] existingCamera:nil];
}
}
AIRGoogleMap *map = [[AIRGoogleMap alloc] initWithMapId:googleMapId initialCamera:camera backgroundColor:backgroundColor andZoomTapEnabled:zoomTapEnabled];
map.bridge = self.bridge;
map.delegate = self;
map.isAccessibilityElement = NO;
map.accessibilityElementsHidden = NO;
map.settings.consumesGesturesInView = NO;
UIPanGestureRecognizer *drag = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleMapDrag:)];
[drag setMinimumNumberOfTouches:1];
[drag setMaximumNumberOfTouches:1];
[map addGestureRecognizer:drag];
UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(handleMapDrag:)];
[map addGestureRecognizer:pinch];
return map;
}
RCT_EXPORT_VIEW_PROPERTY(isAccessibilityElement, BOOL)
RCT_REMAP_VIEW_PROPERTY(testID, accessibilityIdentifier, NSString)
RCT_EXPORT_VIEW_PROPERTY(googleMapId, NSString)
RCT_EXPORT_VIEW_PROPERTY(initialCamera, GMSCameraPosition)
RCT_REMAP_VIEW_PROPERTY(camera, cameraProp, GMSCameraPosition)
RCT_EXPORT_VIEW_PROPERTY(initialRegion, MKCoordinateRegion)
RCT_EXPORT_VIEW_PROPERTY(region, MKCoordinateRegion)
RCT_EXPORT_VIEW_PROPERTY(showsBuildings, BOOL)
RCT_EXPORT_VIEW_PROPERTY(showsCompass, BOOL)
//RCT_EXPORT_VIEW_PROPERTY(showsScale, BOOL) // Not supported by GoogleMaps
RCT_EXPORT_VIEW_PROPERTY(showsTraffic, BOOL)
RCT_EXPORT_VIEW_PROPERTY(zoomEnabled, BOOL)
RCT_EXPORT_VIEW_PROPERTY(rotateEnabled, BOOL)
RCT_EXPORT_VIEW_PROPERTY(scrollEnabled, BOOL)
RCT_EXPORT_VIEW_PROPERTY(scrollDuringRotateOrZoomEnabled, BOOL)
RCT_EXPORT_VIEW_PROPERTY(pitchEnabled, BOOL)
RCT_EXPORT_VIEW_PROPERTY(zoomTapEnabled, BOOL)
RCT_EXPORT_VIEW_PROPERTY(showsUserLocation, BOOL)
RCT_EXPORT_VIEW_PROPERTY(showsMyLocationButton, BOOL)
RCT_EXPORT_VIEW_PROPERTY(showsIndoors, BOOL)
RCT_EXPORT_VIEW_PROPERTY(showsIndoorLevelPicker, BOOL)
RCT_EXPORT_VIEW_PROPERTY(customMapStyleString, NSString)
RCT_EXPORT_VIEW_PROPERTY(mapPadding, UIEdgeInsets)
RCT_REMAP_VIEW_PROPERTY(paddingAdjustmentBehavior, paddingAdjustmentBehaviorString, NSString)
RCT_EXPORT_VIEW_PROPERTY(onMapReady, RCTBubblingEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onMapLoaded, RCTBubblingEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onKmlReady, RCTBubblingEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onPress, RCTBubblingEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onLongPress, RCTBubblingEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onPanDrag, RCTBubblingEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onUserLocationChange, RCTBubblingEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onChange, RCTBubblingEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onMarkerPress, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onMarkerSelect, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onMarkerDeselect, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onRegionChangeStart, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onRegionChange, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onRegionChangeComplete, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onPoiClick, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onIndoorLevelActivated, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onIndoorBuildingFocused, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(mapType, GMSMapViewType)
RCT_EXPORT_VIEW_PROPERTY(minZoomLevel, CGFloat)
RCT_EXPORT_VIEW_PROPERTY(maxZoomLevel, CGFloat)
RCT_EXPORT_VIEW_PROPERTY(kmlSrc, NSString)
RCT_EXPORT_VIEW_PROPERTY(loadingBackgroundColor, UIColor)
RCT_EXPORT_METHOD(getCamera:(nonnull NSNumber *)reactTag
resolver: (RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
{
[self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
id view = viewRegistry[reactTag];
if (![view isKindOfClass:[AIRGoogleMap class]]) {
reject(@"Invalid argument", [NSString stringWithFormat:@"Invalid view returned from registry, expecting AIRGoogleMap, got: %@", view], NULL);
} else {
AIRGoogleMap *mapView = (AIRGoogleMap *)view;
resolve(@{
@"center": @{
@"latitude": @(mapView.camera.target.latitude),
@"longitude": @(mapView.camera.target.longitude),
},
@"pitch": @(mapView.camera.viewingAngle),
@"heading": @(mapView.camera.bearing),
@"zoom": @(mapView.camera.zoom),
});
}
}];
}
RCT_EXPORT_METHOD(setCamera:(nonnull NSNumber *)reactTag
camera:(id)json)
{
[self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
id view = viewRegistry[reactTag];
if (![view isKindOfClass:[AIRGoogleMap class]]) {
RCTLogError(@"Invalid view returned from registry, expecting AIRGoogleMap, got: %@", view);
} else {
AIRGoogleMap *mapView = (AIRGoogleMap *)view;
GMSCameraPosition *camera = [RCTConvert GMSCameraPositionWithDefaults:json existingCamera:[mapView cameraProp]];
[mapView setCameraProp:camera];
}
}];
}
RCT_EXPORT_METHOD(animateCamera:(nonnull NSNumber *)reactTag
withCamera:(id)json
withDuration:(CGFloat)duration)
{
[self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
id view = viewRegistry[reactTag];
if (![view isKindOfClass:[AIRGoogleMap class]]) {
RCTLogError(@"Invalid view returned from registry, expecting AIRGoogleMap, got: %@", view);
} else {
[CATransaction begin];
[CATransaction setAnimationDuration:duration/1000];
AIRGoogleMap *mapView = (AIRGoogleMap *)view;
GMSCameraPosition *camera = [RCTConvert GMSCameraPositionWithDefaults:json existingCamera:[mapView cameraProp]];
[mapView animateToCameraPosition:camera];
[CATransaction commit];
}
}];
}
RCT_EXPORT_METHOD(animateToRegion:(nonnull NSNumber *)reactTag
withRegion:(MKCoordinateRegion)region
withDuration:(CGFloat)duration)
{
[self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
id view = viewRegistry[reactTag];
if (![view isKindOfClass:[AIRGoogleMap class]]) {
RCTLogError(@"Invalid view returned from registry, expecting AIRGoogleMap, got: %@", view);
} else {
// Core Animation must be used to control the animation's duration
// See http://stackoverflow.com/a/15663039/171744
[CATransaction begin];
[CATransaction setAnimationDuration:duration/1000];
AIRGoogleMap *mapView = (AIRGoogleMap *)view;
GMSCameraPosition *camera = [AIRGoogleMap makeGMSCameraPositionFromMap:mapView andMKCoordinateRegion:region];
[mapView animateToCameraPosition:camera];
[CATransaction commit];
}
}];
}
RCT_EXPORT_METHOD(fitToElements:(nonnull NSNumber *)reactTag
edgePadding:(nonnull NSDictionary *)edgePadding
animated:(BOOL)animated)
{
[self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
id view = viewRegistry[reactTag];
if (![view isKindOfClass:[AIRGoogleMap class]]) {
RCTLogError(@"Invalid view returned from registry, expecting AIRGoogleMap, got: %@", view);
} else {
AIRGoogleMap *mapView = (AIRGoogleMap *)view;
CLLocationCoordinate2D myLocation = ((AIRGoogleMapMarker *)(mapView.markers.firstObject)).realMarker.position;
GMSCoordinateBounds *bounds = [[GMSCoordinateBounds alloc] initWithCoordinate:myLocation coordinate:myLocation];
for (AIRGoogleMapMarker *marker in mapView.markers)
bounds = [bounds includingCoordinate:marker.realMarker.position];
GMSCameraUpdate* cameraUpdate;
if ([edgePadding count] != 0) {
// Set Map viewport
CGFloat top = [RCTConvert CGFloat:edgePadding[@"top"]];
CGFloat right = [RCTConvert CGFloat:edgePadding[@"right"]];
CGFloat bottom = [RCTConvert CGFloat:edgePadding[@"bottom"]];
CGFloat left = [RCTConvert CGFloat:edgePadding[@"left"]];
cameraUpdate = [GMSCameraUpdate fitBounds:bounds withEdgeInsets:UIEdgeInsetsMake(top, left, bottom, right)];
} else {
cameraUpdate = [GMSCameraUpdate fitBounds:bounds withPadding:55.0f];
}
if (animated) {
[mapView animateWithCameraUpdate: cameraUpdate];
} else {
[mapView moveCamera: cameraUpdate];
}
}
}];
}
RCT_EXPORT_METHOD(fitToSuppliedMarkers:(nonnull NSNumber *)reactTag
markers:(nonnull NSArray *)markers
edgePadding:(nonnull NSDictionary *)edgePadding
animated:(BOOL)animated)
{
[self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
id view = viewRegistry[reactTag];
if (![view isKindOfClass:[AIRGoogleMap class]]) {
RCTLogError(@"Invalid view returned from registry, expecting AIRGoogleMap, got: %@", view);
} else {
AIRGoogleMap *mapView = (AIRGoogleMap *)view;
NSPredicate *filterMarkers = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
AIRGoogleMapMarker *marker = (AIRGoogleMapMarker *)evaluatedObject;
return [marker isKindOfClass:[AIRGoogleMapMarker class]] && [markers containsObject:marker.identifier];
}];
NSArray *filteredMarkers = [mapView.markers filteredArrayUsingPredicate:filterMarkers];
CLLocationCoordinate2D myLocation = ((AIRGoogleMapMarker *)(filteredMarkers.firstObject)).realMarker.position;
GMSCoordinateBounds *bounds = [[GMSCoordinateBounds alloc] initWithCoordinate:myLocation coordinate:myLocation];
for (AIRGoogleMapMarker *marker in filteredMarkers)
bounds = [bounds includingCoordinate:marker.realMarker.position];
// Set Map viewport
CGFloat top = [RCTConvert CGFloat:edgePadding[@"top"]];
CGFloat right = [RCTConvert CGFloat:edgePadding[@"right"]];
CGFloat bottom = [RCTConvert CGFloat:edgePadding[@"bottom"]];
CGFloat left = [RCTConvert CGFloat:edgePadding[@"left"]];
GMSCameraUpdate* cameraUpdate = [GMSCameraUpdate fitBounds:bounds withEdgeInsets:UIEdgeInsetsMake(top, left, bottom, right)];
if (animated) {
[mapView animateWithCameraUpdate:cameraUpdate
];
} else {
[mapView moveCamera: cameraUpdate];
}
}
}];
}
RCT_EXPORT_METHOD(fitToCoordinates:(nonnull NSNumber *)reactTag
coordinates:(nonnull NSArray<AIRMapCoordinate *> *)coordinates
edgePadding:(nonnull NSDictionary *)edgePadding
animated:(BOOL)animated)
{
[self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
id view = viewRegistry[reactTag];
if (![view isKindOfClass:[AIRGoogleMap class]]) {
RCTLogError(@"Invalid view returned from registry, expecting AIRGoogleMap, got: %@", view);
} else {
AIRGoogleMap *mapView = (AIRGoogleMap *)view;
CLLocationCoordinate2D myLocation = coordinates.firstObject.coordinate;
GMSCoordinateBounds *bounds = [[GMSCoordinateBounds alloc] initWithCoordinate:myLocation coordinate:myLocation];
for (AIRMapCoordinate *coordinate in coordinates)
bounds = [bounds includingCoordinate:coordinate.coordinate];
// Set Map viewport
CGFloat top = [RCTConvert CGFloat:edgePadding[@"top"]];
CGFloat right = [RCTConvert CGFloat:edgePadding[@"right"]];
CGFloat bottom = [RCTConvert CGFloat:edgePadding[@"bottom"]];
CGFloat left = [RCTConvert CGFloat:edgePadding[@"left"]];
GMSCameraUpdate *cameraUpdate = [GMSCameraUpdate fitBounds:bounds withEdgeInsets:UIEdgeInsetsMake(top, left, bottom, right)];
if (animated) {
[mapView animateWithCameraUpdate: cameraUpdate];
} else {
[mapView moveCamera: cameraUpdate];
}
}
}];
}
RCT_EXPORT_METHOD(takeSnapshot:(nonnull NSNumber *)reactTag
withWidth:(nonnull NSNumber *)width
withHeight:(nonnull NSNumber *)height
withRegion:(MKCoordinateRegion)region
format:(nonnull NSString *)format
quality:(nonnull NSNumber *)quality
result:(nonnull NSString *)result
withCallback:(RCTResponseSenderBlock)callback)
{
NSTimeInterval timeStamp = [[NSDate date] timeIntervalSince1970];
NSString *pathComponent = [NSString stringWithFormat:@"Documents/snapshot-%.20lf.%@", timeStamp, format];
NSString *filePath = [NSHomeDirectory() stringByAppendingPathComponent: pathComponent];
[self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
id view = viewRegistry[reactTag];
if (![view isKindOfClass:[AIRGoogleMap class]]) {
RCTLogError(@"Invalid view returned from registry, expecting AIRMap, got: %@", view);
} else {
AIRGoogleMap *mapView = (AIRGoogleMap *)view;
// TODO: currently we are ignoring width, height, region
UIGraphicsBeginImageContextWithOptions(mapView.frame.size, YES, 0.0f);
[mapView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
NSData *data;
if ([format isEqualToString:@"png"]) {
data = UIImagePNGRepresentation(image);
}
else if([format isEqualToString:@"jpg"]) {
data = UIImageJPEGRepresentation(image, quality.floatValue);
}
if ([result isEqualToString:@"file"]) {
[data writeToFile:filePath atomically:YES];
callback(@[[NSNull null], filePath]);
}
else if ([result isEqualToString:@"base64"]) {
callback(@[[NSNull null], [data base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithCarriageReturn]]);
}
}
UIGraphicsEndImageContext();
}];
}
RCT_EXPORT_METHOD(pointForCoordinate:(nonnull NSNumber *)reactTag
coordinate:(NSDictionary *)coordinate
resolver: (RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
{
CLLocationCoordinate2D coord =
CLLocationCoordinate2DMake(
[coordinate[@"latitude"] doubleValue],
[coordinate[@"longitude"] doubleValue]
);
[self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
id view = viewRegistry[reactTag];
if (![view isKindOfClass:[AIRGoogleMap class]]) {
RCTLogError(@"Invalid view returned from registry, expecting AIRMap, got: %@", view);
} else {
AIRGoogleMap *mapView = (AIRGoogleMap *)view;
CGPoint touchPoint = [mapView.projection pointForCoordinate:coord];
resolve(@{
@"x": @(touchPoint.x),
@"y": @(touchPoint.y),
});
}
}];
}
RCT_EXPORT_METHOD(coordinateForPoint:(nonnull NSNumber *)reactTag
point:(NSDictionary *)point
resolver: (RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
{
CGPoint pt = CGPointMake(
[point[@"x"] doubleValue],
[point[@"y"] doubleValue]
);
[self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
id view = viewRegistry[reactTag];
if (![view isKindOfClass:[AIRGoogleMap class]]) {
RCTLogError(@"Invalid view returned from registry, expecting AIRMap, got: %@", view);
} else {
AIRGoogleMap *mapView = (AIRGoogleMap *)view;
CLLocationCoordinate2D coordinate = [mapView.projection coordinateForPoint:pt];
resolve(@{
@"latitude": @(coordinate.latitude),
@"longitude": @(coordinate.longitude),
});
}
}];
}
RCT_EXPORT_METHOD(getMarkersFrames:(nonnull NSNumber *)reactTag
onlyVisible:(BOOL)onlyVisible
resolver: (RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
{
[self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
id view = viewRegistry[reactTag];
if (![view isKindOfClass:[AIRGoogleMap class]]) {
RCTLogError(@"Invalid view returned from registry, expecting AIRMap, got: %@", view);
} else {
AIRGoogleMap *mapView = (AIRGoogleMap *)view;
resolve([mapView getMarkersFramesWithOnlyVisible:onlyVisible]);
}
}];
}
RCT_EXPORT_METHOD(getMapBoundaries:(nonnull NSNumber *)reactTag
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
{
[self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
id view = viewRegistry[reactTag];
if (![view isKindOfClass:[AIRGoogleMap class]]) {
RCTLogError(@"Invalid view returned from registry, expecting AIRGoogleMap, got: %@", view);
} else {
NSArray *boundingBox = [view getMapBoundaries];
resolve(@{
@"northEast" : @{
@"longitude" : boundingBox[0][0],
@"latitude" : boundingBox[0][1]
},
@"southWest" : @{
@"longitude" : boundingBox[1][0],
@"latitude" : boundingBox[1][1]
}
});
}
}];
}
RCT_EXPORT_METHOD(setMapBoundaries:(nonnull NSNumber *)reactTag
northEast:(CLLocationCoordinate2D)northEast
southWest:(CLLocationCoordinate2D)southWest)
{
[self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
id view = viewRegistry[reactTag];
if (![view isKindOfClass:[AIRGoogleMap class]]) {
RCTLogError(@"Invalid view returned from registry, expecting AIRGoogleMap, got: %@", view);
} else {
AIRGoogleMap *mapView = (AIRGoogleMap *)view;
GMSCoordinateBounds *bounds = [[GMSCoordinateBounds alloc] initWithCoordinate:northEast coordinate:southWest];
mapView.cameraTargetBounds = bounds;
}
}];
}
RCT_EXPORT_METHOD(setIndoorActiveLevelIndex:(nonnull NSNumber *)reactTag
levelIndex:(NSInteger) levelIndex)
{
[self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
id view = viewRegistry[reactTag];
if (![view isKindOfClass:[AIRGoogleMap class]]) {
RCTLogError(@"Invalid view returned from registry, expecting AIRGoogleMap, got: %@", view);
} else {
AIRGoogleMap *mapView = (AIRGoogleMap *)view;
if (!mapView.indoorDisplay) {
return;
}
if ( levelIndex < [mapView.indoorDisplay.activeBuilding.levels count]) {
mapView.indoorDisplay.activeLevel = mapView.indoorDisplay.activeBuilding.levels[levelIndex];
}
}
}];
}
+ (BOOL)requiresMainQueueSetup {
return YES;
}
- (NSDictionary *)constantsToExport {
return @{ @"legalNotice": [GMSServices openSourceLicenseInfo] };
}
- (void)mapView:(GMSMapView *)mapView willMove:(BOOL)gesture {
self.isGesture = gesture;
AIRGoogleMap *googleMapView = (AIRGoogleMap *)mapView;
[googleMapView willMove:gesture];
}
- (void)mapViewDidStartTileRendering:(GMSMapView *)mapView {
AIRGoogleMap *googleMapView = (AIRGoogleMap *)mapView;
[googleMapView didPrepareMap];
}
- (void)mapViewDidFinishTileRendering:(GMSMapView *)mapView {
AIRGoogleMap *googleMapView = (AIRGoogleMap *)mapView;
[googleMapView mapViewDidFinishTileRendering];
}
- (BOOL)mapView:(GMSMapView *)mapView didTapMarker:(GMSMarker *)marker {
AIRGoogleMap *googleMapView = (AIRGoogleMap *)mapView;
return [googleMapView didTapMarker:marker];
}
- (void)mapView:(GMSMapView *)mapView didTapOverlay:(GMSPolygon *)polygon {
AIRGoogleMap *googleMapView = (AIRGoogleMap *)mapView;
[googleMapView didTapPolygon:polygon];
}
- (void)mapView:(GMSMapView *)mapView didTapAtCoordinate:(CLLocationCoordinate2D)coordinate {
AIRGoogleMap *googleMapView = (AIRGoogleMap *)mapView;
[googleMapView didTapAtCoordinate:coordinate];
}
- (void)mapView:(GMSMapView *)mapView didLongPressAtCoordinate:(CLLocationCoordinate2D)coordinate {
AIRGoogleMap *googleMapView = (AIRGoogleMap *)mapView;
[googleMapView didLongPressAtCoordinate:coordinate];
}
- (void)mapView:(GMSMapView *)mapView didChangeCameraPosition:(GMSCameraPosition *)position {
AIRGoogleMap *googleMapView = (AIRGoogleMap *)mapView;
[googleMapView didChangeCameraPosition:position isGesture:self.isGesture];
}
- (void)mapView:(GMSMapView *)mapView idleAtCameraPosition:(GMSCameraPosition *)position {
AIRGoogleMap *googleMapView = (AIRGoogleMap *)mapView;
[googleMapView idleAtCameraPosition:position isGesture:self.isGesture];
}
- (UIView *)mapView:(GMSMapView *)mapView markerInfoWindow:(GMSMarker *)marker {
AIRGMSMarker *aMarker = (AIRGMSMarker *)marker;
return [aMarker.fakeMarker markerInfoWindow];}
- (UIView *)mapView:(GMSMapView *)mapView markerInfoContents:(GMSMarker *)marker {
AIRGMSMarker *aMarker = (AIRGMSMarker *)marker;
return [aMarker.fakeMarker markerInfoContents];
}
- (void)mapView:(GMSMapView *)mapView didTapInfoWindowOfMarker:(GMSMarker *)marker {
AIRGMSMarker *aMarker = (AIRGMSMarker *)marker;
[aMarker.fakeMarker didTapInfoWindowOfMarker:aMarker];
}
- (void)mapView:(GMSMapView *)mapView didBeginDraggingMarker:(GMSMarker *)marker {
AIRGMSMarker *aMarker = (AIRGMSMarker *)marker;
[aMarker.fakeMarker didBeginDraggingMarker:aMarker];
}
- (void)mapView:(GMSMapView *)mapView didEndDraggingMarker:(GMSMarker *)marker {
AIRGMSMarker *aMarker = (AIRGMSMarker *)marker;
[aMarker.fakeMarker didEndDraggingMarker:aMarker];
}
- (void)mapView:(GMSMapView *)mapView didDragMarker:(GMSMarker *)marker {
AIRGMSMarker *aMarker = (AIRGMSMarker *)marker;
[aMarker.fakeMarker didDragMarker:aMarker];
}
- (void)mapView:(GMSMapView *)mapView
didTapPOIWithPlaceID:(NSString *)placeID
name:(NSString *)name
location:(CLLocationCoordinate2D)location {
AIRGoogleMap *googleMapView = (AIRGoogleMap *)mapView;
[googleMapView didTapPOIWithPlaceID:placeID name:name location:location];
}
#pragma mark Gesture Recognizer Handlers
- (void)handleMapDrag:(UIPanGestureRecognizer*)recognizer {
AIRGoogleMap *map = (AIRGoogleMap *)recognizer.view;
if (!map.onPanDrag) return;
CGPoint touchPoint = [recognizer locationInView:map];
CLLocationCoordinate2D coord = [map.projection coordinateForPoint:touchPoint];
map.onPanDrag(@{
@"coordinate": @{
@"latitude": @(coord.latitude),
@"longitude": @(coord.longitude),
},
@"position": @{
@"x": @(touchPoint.x),
@"y": @(touchPoint.y),
},
@"numberOfTouches": @(recognizer.numberOfTouches),
});
}
@end
#endif
@@ -0,0 +1,58 @@
//
// AIRGoogleMapMarker.h
// AirMaps
//
// Created by Gil Birman on 9/2/16.
//
#ifdef HAVE_GOOGLE_MAPS
#import <GoogleMaps/GoogleMaps.h>
#import <React/RCTBridge.h>
#import "AIRGMSMarker.h"
#import "AIRGoogleMap.h"
#import "AIRGoogleMapCallout.h"
#import "AIRGoogleMapCalloutSubview.h"
@interface AIRGoogleMapMarker : UIView
@property (nonatomic, weak) RCTBridge *bridge;
@property (nonatomic, strong) AIRGoogleMapCallout *calloutView;
@property (nonatomic, strong) NSString *identifier;
@property (nonatomic, assign) CLLocationCoordinate2D coordinate;
@property (nonatomic, assign) CLLocationDegrees rotation;
@property (nonatomic, strong) AIRGMSMarker* realMarker;
@property (nonatomic, copy) RCTBubblingEventBlock onPress;
@property (nonatomic, copy) RCTDirectEventBlock onDragStart;
@property (nonatomic, copy) RCTDirectEventBlock onDrag;
@property (nonatomic, copy) RCTDirectEventBlock onDragEnd;
@property (nonatomic, copy) NSString *imageSrc;
@property (nonatomic, copy) NSString *iconSrc;
@property (nonatomic, copy) NSString *title;
@property (nonatomic, copy) NSString *subtitle;
@property (nonatomic, strong) UIColor *pinColor;
@property (nonatomic, assign) CGPoint anchor;
@property (nonatomic, assign) CGPoint calloutAnchor;
@property (nonatomic, assign) NSInteger zIndex;
@property (nonatomic, assign) double opacity;
@property (nonatomic, assign) BOOL draggable;
@property (nonatomic, assign) BOOL tappable;
@property (nonatomic, assign) BOOL tracksViewChanges;
@property (nonatomic, assign) BOOL tracksInfoWindowChanges;
- (void)showCalloutView;
- (void)hideCalloutView;
- (void)redraw;
- (UIView *)markerInfoContents;
- (UIView *)markerInfoWindow;
- (void)didTapInfoWindowOfMarker:(AIRGMSMarker *)marker;
- (void)didTapInfoWindowOfMarker:(AIRGMSMarker *)marker point:(CGPoint)point frame:(CGRect)frame;
- (void)didTapInfoWindowOfMarker:(AIRGMSMarker *)marker subview:(AIRGoogleMapCalloutSubview*)subview point:(CGPoint)point frame:(CGRect)frame;
- (void)didBeginDraggingMarker:(AIRGMSMarker *)marker;
- (void)didEndDraggingMarker:(AIRGMSMarker *)marker;
- (void)didDragMarker:(AIRGMSMarker *)marker;
- (id)makeEventData;
- (id)makeEventData:(NSString *)action;
@end
#endif
@@ -0,0 +1,456 @@
//
// AIRGoogleMapMarker.m
// AirMaps
//
// Created by Gil Birman on 9/2/16.
//
#ifdef HAVE_GOOGLE_MAPS
#import "AIRGoogleMapMarker.h"
#import <GoogleMaps/GoogleMaps.h>
#import <React/RCTImageLoaderProtocol.h>
#import <React/RCTUtils.h>
#import "AIRGMSMarker.h"
#import "AIRGoogleMapCallout.h"
#import "AIRDummyView.h"
CGRect unionRect(CGRect a, CGRect b) {
return CGRectMake(
MIN(a.origin.x, b.origin.x),
MIN(a.origin.y, b.origin.y),
MAX(a.size.width, b.size.width),
MAX(a.size.height, b.size.height));
}
@interface AIRGoogleMapMarker ()
@end
@implementation AIRGoogleMapMarker {
RCTImageLoaderCancellationBlock _reloadImageCancellationBlock;
__weak UIImageView *_iconImageView;
UIView *_iconView;
}
- (instancetype)init
{
if ((self = [super init])) {
_realMarker = [[AIRGMSMarker alloc] init];
_realMarker.fakeMarker = self;
_realMarker.tracksViewChanges = true;
_realMarker.tracksInfoWindowChanges = false;
}
return self;
}
- (void)layoutSubviews {
float width = 0;
float height = 0;
for (UIView *v in [_iconView subviews]) {
float fw = v.frame.origin.x + v.frame.size.width;
float fh = v.frame.origin.y + v.frame.size.height;
width = MAX(fw, width);
height = MAX(fh, height);
}
[_iconView setFrame:CGRectMake(0, 0, width, height)];
}
- (void)iconViewInsertSubview:(UIView*)subview atIndex:(NSInteger)atIndex {
if (!_realMarker.iconView) {
_iconView = [[UIView alloc] init];
_realMarker.iconView = _iconView;
}
[_iconView insertSubview:subview atIndex:atIndex];
}
- (void)insertReactSubview:(id<RCTComponent>)subview atIndex:(NSInteger)atIndex {
if ([subview isKindOfClass:[AIRGoogleMapCallout class]]) {
self.calloutView = (AIRGoogleMapCallout *)subview;
} else { // a child view of the marker
[self iconViewInsertSubview:(UIView*)subview atIndex:atIndex+1];
}
AIRDummyView *dummySubview = [[AIRDummyView alloc] initWithView:(UIView *)subview];
[super insertReactSubview:(UIView*)dummySubview atIndex:atIndex];
}
- (void)removeReactSubview:(id<RCTComponent>)dummySubview {
UIView *subview = [dummySubview isKindOfClass:[AIRDummyView class]] ? ((AIRDummyView *)dummySubview).view : (UIView *)dummySubview;
if ([subview isKindOfClass:[AIRGoogleMapCallout class]]) {
self.calloutView = nil;
} else {
[subview removeFromSuperview];
}
[super removeReactSubview:(UIView*)dummySubview];
}
- (void)showCalloutView {
[_realMarker.map setSelectedMarker:_realMarker];
}
- (void)hideCalloutView {
[_realMarker.map setSelectedMarker:Nil];
}
- (void)redraw {
if (!_realMarker.iconView) return;
BOOL oldValue = _realMarker.tracksViewChanges;
if (oldValue == YES)
{
// Immediate refresh, like right now. Not waiting for next frame.
UIView *view = _realMarker.iconView;
_realMarker.iconView = nil;
_realMarker.iconView = view;
}
else
{
// Refresh according to docs
_realMarker.tracksViewChanges = YES;
_realMarker.tracksViewChanges = NO;
}
}
- (UIView *)markerInfoContents {
if (self.calloutView && !self.calloutView.tooltip) {
return self.calloutView;
}
return nil;
}
- (UIView *)markerInfoWindow {
if (self.calloutView && self.calloutView.tooltip) {
return self.calloutView;
}
return nil;
}
- (void)didTapInfoWindowOfMarker:(AIRGMSMarker *)marker point:(CGPoint)point frame:(CGRect)frame {
if (self.calloutView && self.calloutView.onPress) {
//todo: why not 'callout-press' ?
id event = @{
@"action": @"marker-overlay-press",
@"id": self.identifier ?: @"unknown",
@"point": @{
@"x": @(point.x),
@"y": @(point.y),
},
@"frame": @{
@"x": @(frame.origin.x),
@"y": @(frame.origin.y),
@"width": @(frame.size.width),
@"height": @(frame.size.height),
}
};
self.calloutView.onPress(event);
}
}
- (void)didTapInfoWindowOfMarker:(AIRGMSMarker *)marker {
[self didTapInfoWindowOfMarker:marker point:CGPointMake(-1, -1) frame:CGRectZero];
}
- (void)didTapInfoWindowOfMarker:(AIRGMSMarker *)marker subview:(AIRGoogleMapCalloutSubview*)subview point:(CGPoint)point frame:(CGRect)frame {
if (subview && subview.onPress) {
//todo: why not 'callout-inside-press' ?
id event = @{
@"action": @"marker-inside-overlay-press",
@"id": self.identifier ?: @"unknown",
@"point": @{
@"x": @(point.x),
@"y": @(point.y),
},
@"frame": @{
@"x": @(frame.origin.x),
@"y": @(frame.origin.y),
@"width": @(frame.size.width),
@"height": @(frame.size.height),
}
};
subview.onPress(event);
} else {
[self didTapInfoWindowOfMarker:marker point:point frame:frame];
}
}
- (void)didBeginDraggingMarker:(AIRGMSMarker *)marker {
if (!self.onDragStart) return;
self.onDragStart([self makeEventData]);
}
- (void)didEndDraggingMarker:(AIRGMSMarker *)marker {
if (!self.onDragEnd) return;
self.onDragEnd([self makeEventData]);
}
- (void)didDragMarker:(AIRGMSMarker *)marker {
if (!self.onDrag) return;
self.onDrag([self makeEventData]);
}
- (void)setCoordinate:(CLLocationCoordinate2D)coordinate {
_realMarker.position = coordinate;
}
- (CLLocationCoordinate2D)coordinate {
return _realMarker.position;
}
- (void)setRotation:(CLLocationDegrees)rotation {
_realMarker.rotation = rotation;
}
- (CLLocationDegrees)rotation {
return _realMarker.rotation;
}
- (void)setIdentifier:(NSString *)identifier {
_realMarker.identifier = identifier;
}
- (NSString *)identifier {
return _realMarker.identifier;
}
- (void)setOnPress:(RCTBubblingEventBlock)onPress {
_realMarker.onPress = onPress;
}
- (RCTBubblingEventBlock)onPress {
return _realMarker.onPress;
}
- (void)setOnSelect:(RCTDirectEventBlock)onSelect {
_realMarker.onSelect = onSelect;
}
- (RCTDirectEventBlock)onSelect {
return _realMarker.onSelect;
}
- (void)setOnDeselect:(RCTDirectEventBlock)onDeselect {
_realMarker.onDeselect = onDeselect;
}
- (RCTDirectEventBlock)onDeselect {
return _realMarker.onDeselect;
}
- (void)setOpacity:(double)opacity
{
_realMarker.opacity = opacity;
}
- (void)setImageSrc:(NSString *)imageSrc
{
_imageSrc = imageSrc;
if (_reloadImageCancellationBlock) {
_reloadImageCancellationBlock();
_reloadImageCancellationBlock = nil;
}
if (!_imageSrc) {
if (_iconImageView) [_iconImageView removeFromSuperview];
return;
}
if (!_iconImageView) {
// prevent glitch with marker (cf. https://github.com/react-native-maps/react-native-maps/issues/738)
UIImageView *empyImageView = [[UIImageView alloc] init];
_iconImageView = empyImageView;
[self iconViewInsertSubview:_iconImageView atIndex:0];
}
_reloadImageCancellationBlock = [[_bridge moduleForName:@"ImageLoader"] loadImageWithURLRequest:[RCTConvert NSURLRequest:_imageSrc]
size:self.bounds.size
scale:RCTScreenScale()
clipped:YES
resizeMode:RCTResizeModeCenter
progressBlock:nil
partialLoadBlock:nil
completionBlock:^(NSError *error, UIImage *image) {
if (error) {
// TODO(lmr): do something with the error?
NSLog(@"%@", error);
}
dispatch_async(dispatch_get_main_queue(), ^{
// TODO(gil): This way allows different image sizes
if (self->_iconImageView) [self->_iconImageView removeFromSuperview];
// ... but this way is more efficient?
// if (_iconImageView) {
// [_iconImageView setImage:image];
// return;
// }
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
// TODO: w,h or pixel density could be a prop.
float density = 1;
float w = image.size.width/density;
float h = image.size.height/density;
CGRect bounds = CGRectMake(0, 0, w, h);
imageView.contentMode = UIViewContentModeScaleAspectFit;
[imageView setFrame:bounds];
// NOTE: sizeToFit doesn't work instead. Not sure why.
// TODO: Doing it this way is not ideal because it causes things to reshuffle
// when the image loads IF the image is larger than the UIView.
// Shouldn't required images have size info automatically via RN?
CGRect selfBounds = unionRect(bounds, self.bounds);
[self setFrame:selfBounds];
self->_iconImageView = imageView;
[self iconViewInsertSubview:imageView atIndex:0];
});
}];
}
- (void)setIconSrc:(NSString *)iconSrc
{
_iconSrc = iconSrc;
if (_reloadImageCancellationBlock) {
_reloadImageCancellationBlock();
_reloadImageCancellationBlock = nil;
}
if (!_realMarker.icon) {
// prevent glitch with marker (cf. https://github.com/react-native-maps/react-native-maps/issues/3657)
UIImage *emptyImage = [[UIImage alloc] init];
_realMarker.icon = emptyImage;
}
_reloadImageCancellationBlock =
[[_bridge moduleForName:@"ImageLoader"] loadImageWithURLRequest:[RCTConvert NSURLRequest:_iconSrc]
size:self.bounds.size
scale:RCTScreenScale()
clipped:YES
resizeMode:RCTResizeModeCenter
progressBlock:nil
partialLoadBlock:nil
completionBlock:^(NSError *error, UIImage *image) {
if (error) {
// TODO(lmr): do something with the error?
NSLog(@"%@", error);
}
dispatch_async(dispatch_get_main_queue(), ^{
self->_realMarker.icon = image;
});
}];
}
- (void)setTitle:(NSString *)title {
_realMarker.title = [title copy];
}
- (NSString *)title {
return _realMarker.title;
}
- (void)setSubtitle:(NSString *)subtitle {
_realMarker.snippet = subtitle;
}
- (NSString *)subtitle {
return _realMarker.snippet;
}
- (void)setPinColor:(UIColor *)pinColor {
_pinColor = pinColor;
_realMarker.icon = [GMSMarker markerImageWithColor:pinColor];
}
- (void)setAnchor:(CGPoint)anchor {
_anchor = anchor;
_realMarker.groundAnchor = anchor;
}
- (void)setCalloutAnchor:(CGPoint)calloutAnchor {
_calloutAnchor = calloutAnchor;
_realMarker.infoWindowAnchor = calloutAnchor;
}
- (void)setZIndex:(NSInteger)zIndex
{
_zIndex = zIndex;
_realMarker.zIndex = (int)zIndex;
}
- (void)setDraggable:(BOOL)draggable {
_realMarker.draggable = draggable;
}
- (BOOL)draggable {
return _realMarker.draggable;
}
- (void)setTappable:(BOOL)tappable {
_realMarker.tappable = tappable;
}
- (BOOL)tappable {
return _realMarker.tappable;
}
- (void)setFlat:(BOOL)flat {
_realMarker.flat = flat;
}
- (BOOL)flat {
return _realMarker.flat;
}
- (void)setTracksViewChanges:(BOOL)tracksViewChanges {
_realMarker.tracksViewChanges = tracksViewChanges;
}
- (BOOL)tracksViewChanges {
return _realMarker.tracksViewChanges;
}
- (void)setTracksInfoWindowChanges:(BOOL)tracksInfoWindowChanges {
_realMarker.tracksInfoWindowChanges = tracksInfoWindowChanges;
}
- (BOOL)tracksInfoWindowChanges {
return _realMarker.tracksInfoWindowChanges;
}
- (id)makeEventData:(NSString *)action {
CLLocationCoordinate2D coordinate = self.realMarker.position;
CGPoint position = [self.realMarker.map.projection pointForCoordinate:coordinate];
return @{
@"id": self.identifier ?: @"unknown",
@"position": @{
@"x": @(position.x),
@"y": @(position.y),
},
@"coordinate": @{
@"latitude": @(coordinate.latitude),
@"longitude": @(coordinate.longitude),
},
@"action": action,
};
}
- (id)makeEventData {
return [self makeEventData:@"unknown"];
}
@end
#endif
@@ -0,0 +1,16 @@
//
// AIRGoogleMapMarkerManager.h
// AirMaps
//
// Created by Gil Birman on 9/2/16.
//
#ifdef HAVE_GOOGLE_MAPS
#import <React/RCTViewManager.h>
@interface AIRGoogleMapMarkerManager : RCTViewManager
@end
#endif
@@ -0,0 +1,117 @@
//
// AIRGoogleMapMarkerManager.m
// AirMaps
//
// Created by Gil Birman on 9/2/16.
//
#ifdef HAVE_GOOGLE_MAPS
#import "AIRGoogleMapMarkerManager.h"
#import "AIRGoogleMapMarker.h"
#import <MapKit/MapKit.h>
#import <React/RCTUIManager.h>
#import "RCTConvert+AirMap.h"
@implementation AIRGoogleMapMarkerManager
RCT_EXPORT_MODULE()
- (UIView *)view
{
AIRGoogleMapMarker *marker = [AIRGoogleMapMarker new];
// UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(_handleTap:)];
// // setting this to NO allows the parent MapView to continue receiving marker selection events
// tapGestureRecognizer.cancelsTouchesInView = NO;
// [marker addGestureRecognizer:tapGestureRecognizer];
marker.bridge = self.bridge;
marker.isAccessibilityElement = YES;
marker.accessibilityElementsHidden = NO;
return marker;
}
RCT_EXPORT_VIEW_PROPERTY(identifier, NSString)
RCT_EXPORT_VIEW_PROPERTY(coordinate, CLLocationCoordinate2D)
RCT_EXPORT_VIEW_PROPERTY(rotation, CLLocationDegrees)
RCT_EXPORT_VIEW_PROPERTY(onPress, RCTBubblingEventBlock)
RCT_REMAP_VIEW_PROPERTY(image, imageSrc, NSString)
RCT_REMAP_VIEW_PROPERTY(icon, iconSrc, NSString)
RCT_EXPORT_VIEW_PROPERTY(title, NSString)
RCT_REMAP_VIEW_PROPERTY(testID, accessibilityIdentifier, NSString)
RCT_REMAP_VIEW_PROPERTY(description, subtitle, NSString)
RCT_EXPORT_VIEW_PROPERTY(pinColor, UIColor)
RCT_EXPORT_VIEW_PROPERTY(anchor, CGPoint)
RCT_EXPORT_VIEW_PROPERTY(calloutAnchor, CGPoint)
RCT_EXPORT_VIEW_PROPERTY(zIndex, NSInteger)
RCT_EXPORT_VIEW_PROPERTY(draggable, BOOL)
RCT_EXPORT_VIEW_PROPERTY(tappable, BOOL)
RCT_EXPORT_VIEW_PROPERTY(flat, BOOL)
RCT_EXPORT_VIEW_PROPERTY(tracksViewChanges, BOOL)
RCT_EXPORT_VIEW_PROPERTY(tracksInfoWindowChanges, BOOL)
RCT_EXPORT_VIEW_PROPERTY(opacity, double)
RCT_EXPORT_VIEW_PROPERTY(onDragStart, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onDrag, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onDragEnd, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onSelect, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onDeselect, RCTDirectEventBlock)
RCT_EXPORT_METHOD(showCallout:(nonnull NSNumber *)reactTag)
{
[self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
id view = viewRegistry[reactTag];
if (![view isKindOfClass:[AIRGoogleMapMarker class]]) {
RCTLogError(@"Invalid view returned from registry, expecting AIRMap, got: %@", view);
} else {
[(AIRGoogleMapMarker *) view showCalloutView];
}
}];
}
RCT_EXPORT_METHOD(hideCallout:(nonnull NSNumber *)reactTag)
{
[self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
id view = viewRegistry[reactTag];
if (![view isKindOfClass:[AIRGoogleMapMarker class]]) {
RCTLogError(@"Invalid view returned from registry, expecting AIRMap, got: %@", view);
} else {
[(AIRGoogleMapMarker *) view hideCalloutView];
}
}];
}
RCT_EXPORT_METHOD(redrawCallout:(nonnull NSNumber *)reactTag)
{
[self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
id view = viewRegistry[reactTag];
if (![view isKindOfClass:[AIRGoogleMapMarker class]]) {
RCTLogError(@"Invalid view returned from registry, expecting AIRMap, got: %@", view);
} else {
AIRGoogleMapMarker* marker = (AIRGoogleMapMarker *) view;
[NSTimer scheduledTimerWithTimeInterval:0.0
target:[NSBlockOperation blockOperationWithBlock:^{
[marker hideCalloutView];
[marker showCalloutView];
}]
selector:@selector(main)
userInfo:nil
repeats:NO
];
}
}];
}
RCT_EXPORT_METHOD(redraw:(nonnull NSNumber *)reactTag)
{
[self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
id view = viewRegistry[reactTag];
if (![view isKindOfClass:[AIRGoogleMapMarker class]]) {
RCTLogError(@"Invalid view returned from registry, expecting AIRMap, got: %@", view);
} else {
[(AIRGoogleMapMarker *) view redraw];
}
}];
}
@end
#endif
@@ -0,0 +1,29 @@
//
// AIRGoogleMapOverlay.h
//
// Created by Taro Matsuzawa on 5/3/17.
//
#ifdef HAVE_GOOGLE_MAPS
#import <Foundation/Foundation.h>
#import <GoogleMaps/GoogleMaps.h>
#import <React/RCTBridge.h>
#import "AIRMapCoordinate.h"
#import "AIRGoogleMap.h"
@interface AIRGoogleMapOverlay : UIView
@property (nonatomic, strong) GMSGroundOverlay *overlay;
@property (nonatomic, copy) NSString *imageSrc;
@property (nonatomic, strong, readonly) UIImage *overlayImage;
@property (nonatomic, copy) NSArray *boundsRect;
@property (nonatomic, assign) CGFloat opacity;
@property (nonatomic, readonly) GMSCoordinateBounds *overlayBounds;
@property (nonatomic, readonly) double bearing;
@property (nonatomic, weak) RCTBridge *bridge;
@end
#endif
@@ -0,0 +1,92 @@
//
// AIRGoogleMapOverlay.m
// Created by Nick Italiano on 3/5/17.
//
#ifdef HAVE_GOOGLE_MAPS
#import "AIRGoogleMapOverlay.h"
#import <React/RCTEventDispatcher.h>
#import <React/RCTImageLoaderProtocol.h>
#import <React/RCTUtils.h>
#import <React/UIView+React.h>
@interface AIRGoogleMapOverlay()
@property (nonatomic, strong, readwrite) UIImage *overlayImage;
@property (nonatomic, readwrite) GMSCoordinateBounds *overlayBounds;
@property (nonatomic) CLLocationDirection bearing;
@end
@implementation AIRGoogleMapOverlay {
RCTImageLoaderCancellationBlock _reloadImageCancellationBlock;
CLLocationCoordinate2D _southWest;
CLLocationCoordinate2D _northEast;
}
- (instancetype)init
{
if ((self = [super init])) {
_overlay = [[GMSGroundOverlay alloc] init];
}
return self;
}
- (void)setImageSrc:(NSString *)imageSrc
{
NSLog(@">>> SET IMAGESRC: %@", imageSrc);
_imageSrc = imageSrc;
if (_reloadImageCancellationBlock) {
_reloadImageCancellationBlock();
_reloadImageCancellationBlock = nil;
}
__weak typeof(self) weakSelf = self;
_reloadImageCancellationBlock = [[_bridge moduleForName:@"ImageLoader"] loadImageWithURLRequest:[RCTConvert NSURLRequest:_imageSrc]
size:weakSelf.bounds.size
scale:RCTScreenScale()
clipped:YES
resizeMode:RCTResizeModeCenter
progressBlock:nil
partialLoadBlock:nil
completionBlock:^(NSError *error, UIImage *image) {
if (error) {
NSLog(@"%@", error);
}
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@">>> IMAGE: %@", image);
weakSelf.overlayImage = image;
weakSelf.overlay.icon = image;
});
}];
}
- (void)setBoundsRect:(NSArray *)boundsRect
{
_boundsRect = boundsRect;
_southWest = CLLocationCoordinate2DMake([boundsRect[1][0] doubleValue], [boundsRect[0][1] doubleValue]);
_northEast = CLLocationCoordinate2DMake([boundsRect[0][0] doubleValue], [boundsRect[1][1] doubleValue]);
_overlayBounds = [[GMSCoordinateBounds alloc] initWithCoordinate:_southWest
coordinate:_northEast];
_overlay.bounds = _overlayBounds;
}
- (void)setBearing:(double)bearing
{
_bearing = (double)bearing;
_overlay.bearing = _bearing;
}
- (void)setOpacity:(CGFloat)opacity
{
_overlay.opacity = opacity;
}
@end
#endif
@@ -0,0 +1,10 @@
//
// AIRGoogleMapOverlayManager.h
// Created by Taro Matsuzawa on 3/5/17.
//
#import <Foundation/Foundation.h>
#import <React/RCTViewManager.h>
@interface AIRGoogleMapOverlayManager : RCTViewManager
@end
@@ -0,0 +1,24 @@
#import "AIRGoogleMapOverlayManager.h"
#import "AIRGoogleMapOverlay.h"
@interface AIRGoogleMapOverlayManager()
@end
@implementation AIRGoogleMapOverlayManager
RCT_EXPORT_MODULE()
- (UIView *)view
{
AIRGoogleMapOverlay *overlay = [AIRGoogleMapOverlay new];
overlay.bridge = self.bridge;
return overlay;
}
RCT_REMAP_VIEW_PROPERTY(bounds, boundsRect, NSArray)
RCT_REMAP_VIEW_PROPERTY(bearing, bearing, double)
RCT_REMAP_VIEW_PROPERTY(image, imageSrc, NSString)
RCT_REMAP_VIEW_PROPERTY(opacity, opacity, CGFloat)
@end
@@ -0,0 +1,32 @@
//
// AIRGoogleMapPolygon.h
//
// Created by Nick Italiano on 10/22/16.
//
#ifdef HAVE_GOOGLE_MAPS
#import <GoogleMaps/GoogleMaps.h>
#import <React/RCTBridge.h>
#import "AIRGMSPolygon.h"
#import "AIRMapCoordinate.h"
@interface AIRGoogleMapPolygon : UIView
@property (nonatomic, weak) RCTBridge *bridge;
@property (nonatomic, strong) NSString *identifier;
@property (nonatomic, strong) AIRGMSPolygon *polygon;
@property (nonatomic, strong) NSArray<AIRMapCoordinate *> *coordinates;
@property (nonatomic, strong) NSArray<NSArray<AIRMapCoordinate *> *> *holes;
@property (nonatomic, copy) RCTBubblingEventBlock onPress;
@property (nonatomic, strong) UIColor *fillColor;
@property (nonatomic, assign) double strokeWidth;
@property (nonatomic, strong) UIColor *strokeColor;
@property (nonatomic, assign) BOOL geodesic;
@property (nonatomic, assign) int zIndex;
@property (nonatomic, assign) BOOL tappable;
@end
#endif
@@ -0,0 +1,127 @@
//
// AIRGoogleMapPolygon.m
//
// Created by Nick Italiano on 10/22/16.
//
#ifdef HAVE_GOOGLE_MAPS
#import "AIRGoogleMapPolygon.h"
#import "AIRGMSPolygon.h"
#import <GoogleMaps/GoogleMaps.h>
@implementation AIRGoogleMapPolygon
{
BOOL _didMoveToWindow;
}
- (instancetype)init
{
if (self = [super init]) {
_didMoveToWindow = false;
_polygon = [[AIRGMSPolygon alloc] init];
_polygon.fillColor = _fillColor;
_polygon.strokeColor = _strokeColor;
}
return self;
}
- (void)didMoveToWindow {
[super didMoveToWindow];
if(_didMoveToWindow) return;
_didMoveToWindow = true;
if(_fillColor) {
_polygon.fillColor = _fillColor;
}
if(_strokeColor) {
_polygon.strokeColor = _strokeColor;
}
if(_strokeWidth) {
_polygon.strokeWidth = _strokeWidth;
}
}
- (void)setCoordinates:(NSArray<AIRMapCoordinate *> *)coordinates
{
_coordinates = coordinates;
GMSMutablePath *path = [GMSMutablePath path];
for(int i = 0; i < coordinates.count; i++)
{
[path addCoordinate:coordinates[i].coordinate];
}
_polygon.path = path;
}
- (void)setHoles:(NSArray<NSArray<AIRMapCoordinate *> *> *)holes
{
_holes = holes;
if (holes.count)
{
NSMutableArray<GMSMutablePath *> *interiorPolygons = [NSMutableArray array];
for(int h = 0; h < holes.count; h++)
{
GMSMutablePath *path = [GMSMutablePath path];
for(int i = 0; i < holes[h].count; i++)
{
[path addCoordinate:holes[h][i].coordinate];
}
[interiorPolygons addObject:path];
}
_polygon.holes = interiorPolygons;
}
}
-(void)setFillColor:(UIColor *)fillColor
{
_fillColor = fillColor;
if(_didMoveToWindow) {
_polygon.fillColor = fillColor;
}
}
-(void)setStrokeWidth:(double)strokeWidth
{
_strokeWidth = strokeWidth;
if(_didMoveToWindow) {
_polygon.strokeWidth = strokeWidth;
}
}
-(void)setStrokeColor:(UIColor *) strokeColor
{
_strokeColor = strokeColor;
if(_didMoveToWindow) {
_polygon.strokeColor = strokeColor;
}
}
-(void)setGeodesic:(BOOL)geodesic
{
_geodesic = geodesic;
_polygon.geodesic = geodesic;
}
-(void)setZIndex:(int)zIndex
{
_zIndex = zIndex;
_polygon.zIndex = zIndex;
}
-(void)setTappable:(BOOL)tappable
{
_tappable = tappable;
_polygon.tappable = tappable;
}
- (void)setOnPress:(RCTBubblingEventBlock)onPress {
_polygon.onPress = onPress;
}
@end
#endif
@@ -0,0 +1,15 @@
//
// AIRGoogleMapPolylgoneManager.h
//
// Created by Nick Italiano on 10/22/16.
//
#ifdef HAVE_GOOGLE_MAPS
#import <React/RCTViewManager.h>
@interface AIRGoogleMapPolygonManager : RCTViewManager
@end
#endif
@@ -0,0 +1,46 @@
//
// AIRGoogleMapPolylgoneManager.m
//
// Created by Nick Italiano on 10/22/16.
//
#ifdef HAVE_GOOGLE_MAPS
#import "AIRGoogleMapPolygonManager.h"
#import <React/RCTBridge.h>
#import <React/RCTConvert.h>
#import <React/RCTConvert+CoreLocation.h>
#import <React/RCTEventDispatcher.h>
#import <React/RCTViewManager.h>
#import <React/UIView+React.h>
#import "RCTConvert+AirMap.h"
#import "AIRGoogleMapPolygon.h"
@interface AIRGoogleMapPolygonManager()
@end
@implementation AIRGoogleMapPolygonManager
RCT_EXPORT_MODULE()
- (UIView *)view
{
AIRGoogleMapPolygon *polygon = [AIRGoogleMapPolygon new];
polygon.bridge = self.bridge;
return polygon;
}
RCT_EXPORT_VIEW_PROPERTY(coordinates, AIRMapCoordinateArray)
RCT_EXPORT_VIEW_PROPERTY(holes, AIRMapCoordinateArrayArray)
RCT_EXPORT_VIEW_PROPERTY(fillColor, UIColor)
RCT_EXPORT_VIEW_PROPERTY(strokeWidth, double)
RCT_EXPORT_VIEW_PROPERTY(strokeColor, UIColor)
RCT_EXPORT_VIEW_PROPERTY(geodesic, BOOL)
RCT_EXPORT_VIEW_PROPERTY(zIndex, int)
RCT_EXPORT_VIEW_PROPERTY(tappable, BOOL)
RCT_EXPORT_VIEW_PROPERTY(onPress, RCTBubblingEventBlock)
@end
#endif
@@ -0,0 +1,36 @@
//
// AIRGoogleMapPolyline.h
//
// Created by Nick Italiano on 10/22/16.
//
#ifdef HAVE_GOOGLE_MAPS
#import <UIKit/UIKit.h>
#import <GoogleMaps/GoogleMaps.h>
#import <React/RCTBridge.h>
#import "AIRGMSPolyline.h"
#import "AIRMapCoordinate.h"
#import "AIRGoogleMapMarker.h"
@interface AIRGoogleMapPolyline : UIView
@property (nonatomic, weak) RCTBridge *bridge;
@property (nonatomic, strong) NSString *identifier;
@property (nonatomic, strong) AIRGMSPolyline *polyline;
@property (nonatomic, strong) NSArray<AIRMapCoordinate *> *coordinates;
@property (nonatomic, copy) RCTBubblingEventBlock onPress;
@property (nonatomic, strong) GMSMapView *originalMap;
@property (nonatomic, strong) UIColor *strokeColor;
@property (nonatomic, strong) NSArray<UIColor *> *strokeColors;
@property (nonatomic, assign) double strokeWidth;
@property (nonatomic, assign) UIColor *fillColor;
@property (nonatomic, strong) NSArray<NSNumber *> *lineDashPattern;
@property (nonatomic, assign) BOOL geodesic;
@property (nonatomic, assign) NSString *title;
@property (nonatomic, assign) int zIndex;
@property (nonatomic, assign) BOOL tappable;
@end
#endif
@@ -0,0 +1,143 @@
//
// AIRGoogleMapPolyline.m
//
// Created by Nick Italiano on 10/22/16.
//
#ifdef HAVE_GOOGLE_MAPS
#import <UIKit/UIKit.h>
#import "AIRGoogleMapPolyline.h"
#import "AIRGMSPolyline.h"
#import "AIRMapCoordinate.h"
#import "AIRGoogleMapMarker.h"
#import "AIRGoogleMapMarkerManager.h"
#import <GoogleMaps/GoogleMaps.h>
#import <React/RCTUtils.h>
@implementation AIRGoogleMapPolyline
- (instancetype)init
{
if (self = [super init]) {
_polyline = [[AIRGMSPolyline alloc] init];
_polyline.spans = @[[GMSStyleSpan spanWithColor:_strokeColor]];
_polyline.strokeColor = _strokeColor;
}
return self;
}
-(void)setCoordinates:(NSArray<AIRMapCoordinate *> *)coordinates
{
_coordinates = coordinates;
GMSMutablePath *path = [GMSMutablePath path];
if (!coordinates || coordinates.count == 0)
{
[path removeAllCoordinates];
return;
}
for (int i = 0; i < coordinates.count; i++) {
[path addCoordinate:coordinates[i].coordinate];
}
_polyline.path = path;
[self configureStyleSpansIfNeeded];
}
-(void)setStrokeColor:(UIColor *)strokeColor
{
_strokeColor = strokeColor;
_polyline.strokeColor = strokeColor;
[self configureStyleSpansIfNeeded];
}
-(void)setStrokeColors:(NSArray<UIColor *> *)strokeColors
{
NSMutableArray *spans = [NSMutableArray arrayWithCapacity:[strokeColors count]];
for (int i = 0; i < [strokeColors count]; i++)
{
GMSStrokeStyle *stroke;
if (i == 0) {
stroke = [GMSStrokeStyle solidColor:strokeColors[i]];
} else {
stroke = [GMSStrokeStyle gradientFromColor:strokeColors[i-1] toColor:strokeColors[i]];
}
[spans addObject:[GMSStyleSpan spanWithStyle:stroke]];
}
_strokeColors = strokeColors;
_polyline.spans = spans;
}
-(void)setStrokeWidth:(double)strokeWidth
{
_strokeWidth = strokeWidth;
_polyline.strokeWidth = strokeWidth;
}
-(void)setFillColor:(UIColor *)fillColor
{
_fillColor = fillColor;
_polyline.spans = @[[GMSStyleSpan spanWithColor:fillColor]];
}
- (void)setLineDashPattern:(NSArray<NSNumber *> *)lineDashPattern {
_lineDashPattern = lineDashPattern;
[self configureStyleSpansIfNeeded];
}
-(void)setGeodesic:(BOOL)geodesic
{
_geodesic = geodesic;
_polyline.geodesic = geodesic;
}
-(void)setTitle:(NSString *)title
{
_title = title;
_polyline.title = _title;
}
-(void) setZIndex:(int)zIndex
{
_zIndex = zIndex;
_polyline.zIndex = zIndex;
}
-(void)setTappable:(BOOL)tappable
{
_tappable = tappable;
_polyline.tappable = tappable;
}
- (void)setOnPress:(RCTBubblingEventBlock)onPress {
_polyline.onPress = onPress;
}
- (void)configureStyleSpansIfNeeded {
if (!_strokeColor || !_lineDashPattern || !_polyline.path) {
return;
}
BOOL isLine = YES;
NSMutableArray *styles = [[NSMutableArray alloc] init];
for (NSInteger i = 0; i < _lineDashPattern.count; i++) {
if (isLine) {
[styles addObject:[GMSStrokeStyle solidColor:_strokeColor]];
} else {
[styles addObject:[GMSStrokeStyle solidColor:[UIColor clearColor]]];
}
isLine = !isLine;
}
_polyline.spans = GMSStyleSpans(_polyline.path, styles, _lineDashPattern, kGMSLengthRhumb);
}
@end
#endif
@@ -0,0 +1,15 @@
//
// AIRGoogleMapPolylineManager.h
//
// Created by Nick Italiano on 10/22/16.
//
#ifdef HAVE_GOOGLE_MAPS
#import <React/RCTViewManager.h>
@interface AIRGoogleMapPolylineManager : RCTViewManager
@end
#endif
@@ -0,0 +1,48 @@
//
// AIRGoogleMapPolylineManager.m
//
// Created by Nick Italiano on 10/22/16.
//
#ifdef HAVE_GOOGLE_MAPS
#import "AIRGoogleMapPolylineManager.h"
#import <React/RCTBridge.h>
#import <React/RCTConvert.h>
#import <React/RCTConvert+CoreLocation.h>
#import <React/RCTEventDispatcher.h>
#import <React/RCTViewManager.h>
#import <React/UIView+React.h>
#import "RCTConvert+AirMap.h"
#import "AIRGoogleMapPolyline.h"
@interface AIRGoogleMapPolylineManager()
@end
@implementation AIRGoogleMapPolylineManager
RCT_EXPORT_MODULE()
- (UIView *)view
{
AIRGoogleMapPolyline *polyline = [AIRGoogleMapPolyline new];
polyline.bridge = self.bridge;
return polyline;
}
RCT_EXPORT_VIEW_PROPERTY(coordinates, AIRMapCoordinateArray)
RCT_EXPORT_VIEW_PROPERTY(fillColor, UIColor)
RCT_EXPORT_VIEW_PROPERTY(strokeColor, UIColor)
RCT_EXPORT_VIEW_PROPERTY(strokeColors, UIColorArray)
RCT_EXPORT_VIEW_PROPERTY(strokeWidth, double)
RCT_EXPORT_VIEW_PROPERTY(lineDashPattern, NSArray)
RCT_EXPORT_VIEW_PROPERTY(geodesic, BOOL)
RCT_EXPORT_VIEW_PROPERTY(zIndex, int)
RCT_EXPORT_VIEW_PROPERTY(tappable, BOOL)
RCT_EXPORT_VIEW_PROPERTY(onPress, RCTBubblingEventBlock)
@end
#endif
@@ -0,0 +1,33 @@
//
// AIRGoogleMapURLTileManager.m
// Created by Nick Italiano on 11/5/16.
//
#ifdef HAVE_GOOGLE_MAPS
#import "AIRGoogleMapUrlTileManager.h"
#import "AIRGoogleMapUrlTile.h"
@interface AIRGoogleMapUrlTileManager()
@end
@implementation AIRGoogleMapUrlTileManager
RCT_EXPORT_MODULE()
- (UIView *)view
{
AIRGoogleMapUrlTile *tileLayer = [AIRGoogleMapUrlTile new];
return tileLayer;
}
RCT_EXPORT_VIEW_PROPERTY(urlTemplate, NSString)
RCT_EXPORT_VIEW_PROPERTY(zIndex, int)
RCT_EXPORT_VIEW_PROPERTY(maximumZ, NSInteger)
RCT_EXPORT_VIEW_PROPERTY(minimumZ, NSInteger)
RCT_EXPORT_VIEW_PROPERTY(flipY, BOOL)
@end
#endif
@@ -0,0 +1,22 @@
//
// AIRGoogleMapURLTile.h
// Created by Nick Italiano on 11/5/16.
//
#ifdef HAVE_GOOGLE_MAPS
#import <Foundation/Foundation.h>
#import <GoogleMaps/GoogleMaps.h>
@interface AIRGoogleMapUrlTile : UIView
@property (nonatomic, strong) GMSURLTileLayer *tileLayer;
@property (nonatomic, assign) NSString *urlTemplate;
@property (nonatomic, assign) int zIndex;
@property NSInteger *maximumZ;
@property NSInteger *minimumZ;
@property BOOL flipY;
@end
#endif
@@ -0,0 +1,56 @@
//
// AIRGoogleMapURLTile.m
// Created by Nick Italiano on 11/5/16.
//
#ifdef HAVE_GOOGLE_MAPS
#import "AIRGoogleMapUrlTile.h"
@implementation AIRGoogleMapUrlTile
- (void)setZIndex:(int)zIndex
{
_zIndex = zIndex;
_tileLayer.zIndex = zIndex;
}
- (void)setUrlTemplate:(NSString *)urlTemplate
{
_urlTemplate = urlTemplate;
_tileLayer = [GMSURLTileLayer tileLayerWithURLConstructor:[self _getTileURLConstructor]];
_tileLayer.tileSize = [[UIScreen mainScreen] scale] * 256;
}
- (GMSTileURLConstructor)_getTileURLConstructor
{
NSString *urlTemplate = self.urlTemplate;
NSInteger *maximumZ = self.maximumZ;
NSInteger *minimumZ = self.minimumZ;
GMSTileURLConstructor urls = ^NSURL* _Nullable (NSUInteger x, NSUInteger y, NSUInteger zoom) {
if (self.flipY == YES) {
y = (1 << zoom) - y - 1;
}
NSString *url = urlTemplate;
url = [url stringByReplacingOccurrencesOfString:@"{x}" withString:[NSString stringWithFormat: @"%ld", (long)x]];
url = [url stringByReplacingOccurrencesOfString:@"{y}" withString:[NSString stringWithFormat: @"%ld", (long)y]];
url = [url stringByReplacingOccurrencesOfString:@"{z}" withString:[NSString stringWithFormat: @"%ld", (long)zoom]];
if(maximumZ && (long)zoom > (long)maximumZ) {
return nil;
}
if(minimumZ && (long)zoom < (long)minimumZ) {
return nil;
}
return [NSURL URLWithString:url];
};
return urls;
}
@end
#endif
@@ -0,0 +1,14 @@
//
// AIRGoogleMapURLTileManager.h
// Created by Nick Italiano on 11/5/16.
//
#ifdef HAVE_GOOGLE_MAPS
#import <Foundation/Foundation.h>
#import <React/RCTViewManager.h>
@interface AIRGoogleMapUrlTileManager : RCTViewManager
@end
#endif
@@ -0,0 +1,33 @@
//
// AIRGoogleMapWMSTile.h
// AirMaps
//
// Created by nizam on 10/28/18.
// Copyright © 2018. All rights reserved.
//
#ifdef HAVE_GOOGLE_MAPS
#import <Foundation/Foundation.h>
#import <GoogleMaps/GoogleMaps.h>
@interface WMSTileOverlay : GMSSyncTileLayer
@property (nonatomic) double MapX,MapY,FULL;
@property (nonatomic, strong) NSString *template;
@property (nonatomic, assign) NSInteger maximumZ;
@property (nonatomic, assign) NSInteger minimumZ;
@end
@interface AIRGoogleMapWMSTile : UIView
@property (nonatomic, strong) WMSTileOverlay *tileLayer;
@property (nonatomic, assign) NSString *urlTemplate;
@property (nonatomic, assign) int zIndex;
@property (nonatomic, assign) NSInteger maximumZ;
@property (nonatomic, assign) NSInteger minimumZ;
@property (nonatomic, assign) NSInteger tileSize;
@property (nonatomic, assign) float opacity;
@end
#endif
@@ -0,0 +1,125 @@
//
// AIRGoogleMapWMSTile.m
// AirMaps
//
// Created by nizam on 10/28/18.
// Copyright © 2018. All rights reserved.
//
#ifdef HAVE_GOOGLE_MAPS
#import "AIRGoogleMapWMSTile.h"
@implementation AIRGoogleMapWMSTile
-(id) init
{
self = [super init];
_opacity = 1;
return self ;
}
- (void)setZIndex:(int)zIndex
{
_zIndex = zIndex;
_tileLayer.zIndex = zIndex;
}
- (void)setTileSize:(NSInteger)tileSize
{
_tileSize = tileSize;
if(self.tileLayer) {
self.tileLayer.tileSize = tileSize;
[self.tileLayer clearTileCache];
}
}
- (void)setMinimumZ:(NSInteger)minimumZ
{
_minimumZ = minimumZ;
if(self.tileLayer && _minimumZ) {
[self.tileLayer setMinimumZ: _minimumZ ];
[self.tileLayer clearTileCache];
}
}
- (void)setMaximumZ:(NSInteger)maximumZ
{
_maximumZ = maximumZ;
if(self.tileLayer && maximumZ) {
[self.tileLayer setMaximumZ: _maximumZ ];
[self.tileLayer clearTileCache];
}
}
- (void)setOpacity:(float)opacity
{
_opacity = opacity;
if(self.tileLayer ) {
[self.tileLayer setOpacity:opacity];
[self.tileLayer clearTileCache];
}
}
- (void)setUrlTemplate:(NSString *)urlTemplate
{
_urlTemplate = urlTemplate;
WMSTileOverlay *tile = [[WMSTileOverlay alloc] init];
[tile setTemplate:urlTemplate];
[tile setMaximumZ: _maximumZ];
[tile setMinimumZ: _minimumZ];
[tile setOpacity: _opacity];
[tile setTileSize: _tileSize];
[tile setZIndex: _zIndex];
_tileLayer = tile;
}
@end
@implementation WMSTileOverlay
-(id) init
{
self = [super init];
_MapX = -20037508.34789244;
_MapY = 20037508.34789244;
_FULL = 20037508.34789244 * 2;
return self ;
}
-(NSArray *)getBoundBox:(NSInteger)x yAxis:(NSInteger)y zoom:(NSInteger)zoom
{
double tile = _FULL / pow(2.0, (double)zoom);
NSArray *result =[[NSArray alloc] initWithObjects:
[NSNumber numberWithDouble:_MapX + (double)x * tile ],
[NSNumber numberWithDouble:_MapY - (double)(y+1) * tile ],
[NSNumber numberWithDouble:_MapX + (double)(x+1) * tile ],
[NSNumber numberWithDouble:_MapY - (double)y * tile ],
nil];
return result;
}
- (UIImage *)tileForX:(NSUInteger)x y:(NSUInteger)y zoom:(NSUInteger)zoom
{
NSInteger maximumZ = self.maximumZ;
NSInteger minimumZ = self.minimumZ;
if(maximumZ && (long)zoom > (long)maximumZ) {
return nil;
}
if(minimumZ && (long)zoom < (long)minimumZ) {
return nil;
}
NSArray *bb = [self getBoundBox:x yAxis:y zoom:zoom];
NSMutableString *url = [self.template mutableCopy];
[url replaceOccurrencesOfString: @"{minX}" withString:[NSString stringWithFormat:@"%@", bb[0]] options:0 range:NSMakeRange(0, url.length)];
[url replaceOccurrencesOfString: @"{minY}" withString:[NSString stringWithFormat:@"%@", bb[1]] options:0 range:NSMakeRange(0, url.length)];
[url replaceOccurrencesOfString: @"{maxX}" withString:[NSString stringWithFormat:@"%@", bb[2]] options:0 range:NSMakeRange(0, url.length)];
[url replaceOccurrencesOfString: @"{maxY}" withString:[NSString stringWithFormat:@"%@", bb[3]] options:0 range:NSMakeRange(0, url.length)];
[url replaceOccurrencesOfString: @"{width}" withString:[NSString stringWithFormat:@"%d", (int)self.tileSize] options:0 range:NSMakeRange(0, url.length)];
[url replaceOccurrencesOfString: @"{height}" withString:[NSString stringWithFormat:@"%d", (int)self.tileSize] options:0 range:NSMakeRange(0, url.length)];
NSURL *uri = [NSURL URLWithString:url];
NSData *data = [NSData dataWithContentsOfURL:uri];
UIImage *img = [[UIImage alloc] initWithData:data];
return img;
}
@end
#endif
@@ -0,0 +1,17 @@
//
// AIRGoogleMapWMSTileManager.h
// AirMaps
//
// Created by nizam on 10/28/18.
// Copyright © 2018. All rights reserved.
//
#ifdef HAVE_GOOGLE_MAPS
#import <Foundation/Foundation.h>
#import <React/RCTViewManager.h>
@interface AIRGoogleMapWMSTileManager : RCTViewManager
@end
#endif
@@ -0,0 +1,37 @@
//
// AIRGoogleMapWMSTileManager.m
// AirMaps
//
// Created by nizam on 10/28/18.
// Copyright © 2018. All rights reserved.
//
#ifdef HAVE_GOOGLE_MAPS
#import "AIRGoogleMapWMSTileManager.h"
#import "AIRGoogleMapWMSTile.h"
@interface AIRGoogleMapWMSTileManager()
@end
@implementation AIRGoogleMapWMSTileManager
RCT_EXPORT_MODULE()
- (UIView *)view
{
AIRGoogleMapWMSTile *tileLayer = [AIRGoogleMapWMSTile new];
return tileLayer;
}
RCT_EXPORT_VIEW_PROPERTY(urlTemplate, NSString)
RCT_EXPORT_VIEW_PROPERTY(zIndex, int)
RCT_EXPORT_VIEW_PROPERTY(maximumZ, int)
RCT_EXPORT_VIEW_PROPERTY(minimumZ, int)
RCT_EXPORT_VIEW_PROPERTY(tileSize, int)
RCT_EXPORT_VIEW_PROPERTY(opacity, float)
@end
#endif
@@ -0,0 +1,17 @@
//
// RCTConvert+GMSMapViewType.h
//
// Created by Nick Italiano on 10/23/16.
//
#ifdef HAVE_GOOGLE_MAPS
#import <Foundation/Foundation.h>
#import <GoogleMaps/GoogleMaps.h>
#import <React/RCTConvert.h>
@interface RCTConvert (GMSMapViewType)
+ (GMSCameraPosition*)GMSCameraPositionWithDefaults:(id)json existingCamera:(GMSCameraPosition*)existingCamera;
@end
#endif
@@ -0,0 +1,79 @@
//
// RCTConvert+GMSMapViewType.m
//
// Created by Nick Italiano on 10/23/16.
//
#ifdef HAVE_GOOGLE_MAPS
#import "RCTConvert+GMSMapViewType.h"
#import <GoogleMaps/GoogleMaps.h>
#import <React/RCTConvert.h>
#import <React/RCTConvert+CoreLocation.h>
@implementation RCTConvert (GMSMapViewType)
RCT_ENUM_CONVERTER(GMSMapViewType,
(
@{
@"standard": @(kGMSTypeNormal),
@"satellite": @(kGMSTypeSatellite),
@"hybrid": @(kGMSTypeHybrid),
@"terrain": @(kGMSTypeTerrain),
@"none": @(kGMSTypeNone)
}
), kGMSTypeTerrain, intValue)
+ (GMSCameraPosition*)GMSCameraPosition:(id)json
{
json = [self NSDictionary:json];
return [RCTConvert GMSCameraPositionWithDefaults:json existingCamera:nil];
}
+ (GMSCameraPosition*)GMSCameraPositionWithDefaults:(id)json existingCamera:(GMSCameraPosition*)existingCamera
{
CLLocationDegrees latitude = 0;
CLLocationDegrees longitude = 0;
double viewingAngle = 0;
double zoom = 0;
double bearing = 0;
if (existingCamera != nil) {
viewingAngle = existingCamera.viewingAngle;
latitude = existingCamera.target.latitude;
longitude = existingCamera.target.longitude;
zoom = existingCamera.zoom;
bearing = existingCamera.bearing;
}
if (json[@"center"]) {
CLLocationCoordinate2D target = [self CLLocationCoordinate2D:json[@"center"]];
latitude = target.latitude;
longitude = target.longitude;
}
if (json[@"pitch"]) {
viewingAngle = [self double:json[@"pitch"]];
}
// zoomAtCoordinate:forMeters:perPoints is offered by the SDK, which would allow
// us to support the "altitude" property of the camera as an alternative to "zoom".
// However, I am not clear on what the "perPoints" argument does...
if (json[@"zoom"]) {
zoom = [self double:json[@"zoom"]];
}
if (json[@"heading"]) {
bearing = [self double:json[@"heading"]];
}
return [GMSCameraPosition cameraWithLatitude:latitude
longitude:longitude
zoom:zoom
bearing:bearing
viewingAngle:viewingAngle];
}
@end
#endif
@@ -0,0 +1,110 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSPrivacyTracking</key>
<false/>
<key>NSPrivacyTrackingDomains</key>
<array>
</array>
<key>NSPrivacyCollectedDataTypes</key>
<array>
<dict>
<key>NSPrivacyCollectedDataType</key>
<string>NSPrivacyCollectedDataTypeCrashData</string>
<key>NSPrivacyCollectedDataTypeLinked</key>
<false/>
<key>NSPrivacyCollectedDataTypeTracking</key>
<false/>
<key>NSPrivacyCollectedDataTypePurposes</key>
<array>
<string>NSPrivacyCollectedDataTypePurposeAnalytics</string>
</array>
</dict>
<dict>
<key>NSPrivacyCollectedDataType</key>
<string>NSPrivacyCollectedDataTypeDeviceID</string>
<key>NSPrivacyCollectedDataTypeLinked</key>
<false/>
<key>NSPrivacyCollectedDataTypeTracking</key>
<false/>
<key>NSPrivacyCollectedDataTypePurposes</key>
<array>
<string>NSPrivacyCollectedDataTypePurposeAnalytics</string>
<string>NSPrivacyCollectedDataTypePurposeAppFunctionality</string>
</array>
</dict>
<dict>
<key>NSPrivacyCollectedDataType</key>
<string>NSPrivacyCollectedDataTypePerformanceData</string>
<key>NSPrivacyCollectedDataTypeLinked</key>
<false/>
<key>NSPrivacyCollectedDataTypeTracking</key>
<false/>
<key>NSPrivacyCollectedDataTypePurposes</key>
<array>
<string>NSPrivacyCollectedDataTypePurposeAnalytics</string>
</array>
</dict>
<dict>
<key>NSPrivacyCollectedDataType</key>
<string>NSPrivacyCollectedDataTypeProductInteraction</string>
<key>NSPrivacyCollectedDataTypeLinked</key>
<false/>
<key>NSPrivacyCollectedDataTypeTracking</key>
<false/>
<key>NSPrivacyCollectedDataTypePurposes</key>
<array>
<string>NSPrivacyCollectedDataTypePurposeAnalytics</string>
</array>
</dict>
<dict>
<key>NSPrivacyCollectedDataType</key>
<string>NSPrivacyCollectedDataTypeUserID</string>
<key>NSPrivacyCollectedDataTypeLinked</key>
<true/>
<key>NSPrivacyCollectedDataTypeTracking</key>
<false/>
<key>NSPrivacyCollectedDataTypePurposes</key>
<array>
<string>NSPrivacyCollectedDataTypePurposeAnalytics</string>
</array>
</dict>
</array>
<key>NSPrivacyAccessedAPITypes</key>
<array>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryDiskSpace</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>85F4.1</string>
</array>
</dict>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryFileTimestamp</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>C617.1</string>
</array>
</dict>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategorySystemBootTime</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>35F9.1</string>
</array>
</dict>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryUserDefaults</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>1C8F.1</string>
</array>
</dict>
</array>
</dict>
</plist>
@@ -0,0 +1,597 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 63;
objects = {
/* Begin PBXBuildFile section */
1125B2DA1C4AD3DA007D0023 /* AIRMap.m in Sources */ = {isa = PBXBuildFile; fileRef = 1125B2BE1C4AD3DA007D0023 /* AIRMap.m */; };
1125B2DB1C4AD3DA007D0023 /* AIRMapCallout.m in Sources */ = {isa = PBXBuildFile; fileRef = 1125B2C01C4AD3DA007D0023 /* AIRMapCallout.m */; };
1125B2DC1C4AD3DA007D0023 /* AIRMapCalloutManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1125B2C21C4AD3DA007D0023 /* AIRMapCalloutManager.m */; };
1125B2DD1C4AD3DA007D0023 /* AIRMapCircle.m in Sources */ = {isa = PBXBuildFile; fileRef = 1125B2C41C4AD3DA007D0023 /* AIRMapCircle.m */; };
1125B2DE1C4AD3DA007D0023 /* AIRMapCircleManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1125B2C61C4AD3DA007D0023 /* AIRMapCircleManager.m */; };
1125B2DF1C4AD3DA007D0023 /* AIRMapCoordinate.m in Sources */ = {isa = PBXBuildFile; fileRef = 1125B2C81C4AD3DA007D0023 /* AIRMapCoordinate.m */; };
1125B2E01C4AD3DA007D0023 /* AIRMapManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1125B2CA1C4AD3DA007D0023 /* AIRMapManager.m */; };
1125B2E11C4AD3DA007D0023 /* AIRMapMarker.m in Sources */ = {isa = PBXBuildFile; fileRef = 1125B2CC1C4AD3DA007D0023 /* AIRMapMarker.m */; };
1125B2E21C4AD3DA007D0023 /* AIRMapMarkerManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1125B2CE1C4AD3DA007D0023 /* AIRMapMarkerManager.m */; };
1125B2E31C4AD3DA007D0023 /* AIRMapPolygon.m in Sources */ = {isa = PBXBuildFile; fileRef = 1125B2D01C4AD3DA007D0023 /* AIRMapPolygon.m */; };
1125B2E41C4AD3DA007D0023 /* AIRMapPolygonManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1125B2D21C4AD3DA007D0023 /* AIRMapPolygonManager.m */; };
1125B2E51C4AD3DA007D0023 /* AIRMapPolyline.m in Sources */ = {isa = PBXBuildFile; fileRef = 1125B2D41C4AD3DA007D0023 /* AIRMapPolyline.m */; };
1125B2E61C4AD3DA007D0023 /* AIRMapPolylineManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1125B2D61C4AD3DA007D0023 /* AIRMapPolylineManager.m */; };
1125B2F21C4AD445007D0023 /* SMCalloutView.m in Sources */ = {isa = PBXBuildFile; fileRef = 1125B2F11C4AD445007D0023 /* SMCalloutView.m */; };
19DABC7F1E7C9D3C00F41150 /* RCTConvert+AirMap.m in Sources */ = {isa = PBXBuildFile; fileRef = 19DABC7E1E7C9D3C00F41150 /* RCTConvert+AirMap.m */; };
2163AA501FEAEDD100BBEC95 /* AIRMapPolylineRenderer.m in Sources */ = {isa = PBXBuildFile; fileRef = 2163AA4F1FEAEDD100BBEC95 /* AIRMapPolylineRenderer.m */; };
4C99C9DE2226CF2800A8693E /* AIRWeakTimerReference.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C99C9DD2226CF2800A8693E /* AIRWeakTimerReference.m */; };
4C99C9E12226D8C400A8693E /* AIRWeakMapReference.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C99C9E02226D8C400A8693E /* AIRWeakMapReference.m */; };
4E0CFBDE2B388F2B0017E126 /* RCTComponentData+Maps.m in Sources */ = {isa = PBXBuildFile; fileRef = 4E0CFBDD2B388F2B0017E126 /* RCTComponentData+Maps.m */; };
53D31636202E723B00B55447 /* AIRMapOverlayManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 53D31635202E723B00B55447 /* AIRMapOverlayManager.m */; };
53D3163A202E72FC00B55447 /* AIRMapOverlay.m in Sources */ = {isa = PBXBuildFile; fileRef = 53D31639202E72FC00B55447 /* AIRMapOverlay.m */; };
53D3163D202E734F00B55447 /* AIRMapOverlayRenderer.m in Sources */ = {isa = PBXBuildFile; fileRef = 53D3163C202E734F00B55447 /* AIRMapOverlayRenderer.m */; };
628F81201FD16DF80058313A /* AIRMapLocalTile.m in Sources */ = {isa = PBXBuildFile; fileRef = 628F811F1FD16DF80058313A /* AIRMapLocalTile.m */; };
628F81231FD16EFA0058313A /* AIRMapLocalTileManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 628F81221FD16EFA0058313A /* AIRMapLocalTileManager.m */; };
62AEC4D41FD5A0AA003225E0 /* AIRMapLocalTileOverlay.m in Sources */ = {isa = PBXBuildFile; fileRef = 62AEC4D31FD5A0AA003225E0 /* AIRMapLocalTileOverlay.m */; };
8B19A3C82257BBDF00BB8735 /* AIRMapCalloutSubview.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B19A3C42257BBDE00BB8735 /* AIRMapCalloutSubview.m */; };
8B19A3C92257BBDF00BB8735 /* AIRMapCalloutSubviewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B19A3C72257BBDF00BB8735 /* AIRMapCalloutSubviewManager.m */; };
8BC85FB02107CFEC0006CEA5 /* AIRGoogleMapOverlay.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BC85FAF2107CFEC0006CEA5 /* AIRGoogleMapOverlay.m */; };
9B9498CA2017EFB800158761 /* AIRGoogleMapUrlTile.m in Sources */ = {isa = PBXBuildFile; fileRef = 9B9498A62017EFB400158761 /* AIRGoogleMapUrlTile.m */; };
9B9498CB2017EFB800158761 /* AIRGoogleMapURLTileManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 9B9498A72017EFB400158761 /* AIRGoogleMapURLTileManager.m */; };
9B9498CC2017EFB800158761 /* AIRGMSPolygon.m in Sources */ = {isa = PBXBuildFile; fileRef = 9B9498A82017EFB400158761 /* AIRGMSPolygon.m */; };
9B9498CD2017EFB800158761 /* AIRGoogleMapCallout.m in Sources */ = {isa = PBXBuildFile; fileRef = 9B9498AC2017EFB400158761 /* AIRGoogleMapCallout.m */; };
9B9498CE2017EFB800158761 /* AIRGMSMarker.m in Sources */ = {isa = PBXBuildFile; fileRef = 9B9498AE2017EFB500158761 /* AIRGMSMarker.m */; };
9B9498CF2017EFB800158761 /* AIRGMSPolyline.m in Sources */ = {isa = PBXBuildFile; fileRef = 9B9498AF2017EFB500158761 /* AIRGMSPolyline.m */; };
9B9498D02017EFB800158761 /* AIRGoogleMapPolylineManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 9B9498B12017EFB500158761 /* AIRGoogleMapPolylineManager.m */; };
9B9498D12017EFB800158761 /* AIRGoogleMapCircle.m in Sources */ = {isa = PBXBuildFile; fileRef = 9B9498B32017EFB500158761 /* AIRGoogleMapCircle.m */; };
9B9498D22017EFB800158761 /* AIRGoogleMapMarkerManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 9B9498B52017EFB500158761 /* AIRGoogleMapMarkerManager.m */; };
9B9498D32017EFB800158761 /* AIRGoogleMap.m in Sources */ = {isa = PBXBuildFile; fileRef = 9B9498B72017EFB500158761 /* AIRGoogleMap.m */; };
9B9498D42017EFB800158761 /* RCTConvert+GMSMapViewType.m in Sources */ = {isa = PBXBuildFile; fileRef = 9B9498B92017EFB600158761 /* RCTConvert+GMSMapViewType.m */; };
9B9498D52017EFB800158761 /* AIRGoogleMapPolyline.m in Sources */ = {isa = PBXBuildFile; fileRef = 9B9498BB2017EFB600158761 /* AIRGoogleMapPolyline.m */; };
9B9498D62017EFB800158761 /* AIRGoogleMapCircleManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 9B9498BC2017EFB600158761 /* AIRGoogleMapCircleManager.m */; };
9B9498D72017EFB800158761 /* AIRGoogleMapManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 9B9498BD2017EFB600158761 /* AIRGoogleMapManager.m */; };
9B9498D92017EFB800158761 /* AIRGoogleMapCalloutManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 9B9498C42017EFB700158761 /* AIRGoogleMapCalloutManager.m */; };
9B9498DA2017EFB800158761 /* AIRGoogleMapPolygon.m in Sources */ = {isa = PBXBuildFile; fileRef = 9B9498C62017EFB800158761 /* AIRGoogleMapPolygon.m */; };
9B9498DB2017EFB800158761 /* AIRGoogleMapMarker.m in Sources */ = {isa = PBXBuildFile; fileRef = 9B9498C72017EFB800158761 /* AIRGoogleMapMarker.m */; };
9B9498DC2017EFB800158761 /* AIRGoogleMapPolygonManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 9B9498C92017EFB800158761 /* AIRGoogleMapPolygonManager.m */; };
A8494E28218891020092506D /* AIRMapWMSTileManager.m in Sources */ = {isa = PBXBuildFile; fileRef = A8494E24218891020092506D /* AIRMapWMSTileManager.m */; };
A8494E29218891020092506D /* AIRMapWMSTile.m in Sources */ = {isa = PBXBuildFile; fileRef = A8494E27218891020092506D /* AIRMapWMSTile.m */; };
A8494E2E218891180092506D /* AIRGoogleMapWMSTileManager.m in Sources */ = {isa = PBXBuildFile; fileRef = A8494E2A218891180092506D /* AIRGoogleMapWMSTileManager.m */; };
A8494E2F218891180092506D /* AIRGoogleMapWMSTile.m in Sources */ = {isa = PBXBuildFile; fileRef = A8494E2D218891180092506D /* AIRGoogleMapWMSTile.m */; };
B5EA3BA92098E22B000E7AFD /* AIRDummyView.m in Sources */ = {isa = PBXBuildFile; fileRef = B5EA3BA72098E22B000E7AFD /* AIRDummyView.m */; };
BE2E4EC92621F63C00CC7F2E /* AIRMapUrlTileCachedOverlay.m in Sources */ = {isa = PBXBuildFile; fileRef = BE2E4EC82621F63C00CC7F2E /* AIRMapUrlTileCachedOverlay.m */; };
DA6C26381C9E2AFE0035349F /* AIRMapUrlTile.m in Sources */ = {isa = PBXBuildFile; fileRef = DA6C26371C9E2AFE0035349F /* AIRMapUrlTile.m */; };
DA6C263E1C9E324A0035349F /* AIRMapUrlTileManager.m in Sources */ = {isa = PBXBuildFile; fileRef = DA6C263D1C9E324A0035349F /* AIRMapUrlTileManager.m */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
11FA5C4F1C4A1296003AC2EE /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "include/$(PRODUCT_NAME)";
dstSubfolderSpec = 16;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
1125B2BD1C4AD3DA007D0023 /* AIRMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AIRMap.h; path = AirMaps/AIRMap.h; sourceTree = SOURCE_ROOT; };
1125B2BE1C4AD3DA007D0023 /* AIRMap.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AIRMap.m; path = AirMaps/AIRMap.m; sourceTree = SOURCE_ROOT; };
1125B2BF1C4AD3DA007D0023 /* AIRMapCallout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AIRMapCallout.h; path = AirMaps/AIRMapCallout.h; sourceTree = SOURCE_ROOT; };
1125B2C01C4AD3DA007D0023 /* AIRMapCallout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AIRMapCallout.m; path = AirMaps/AIRMapCallout.m; sourceTree = SOURCE_ROOT; };
1125B2C11C4AD3DA007D0023 /* AIRMapCalloutManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AIRMapCalloutManager.h; path = AirMaps/AIRMapCalloutManager.h; sourceTree = SOURCE_ROOT; };
1125B2C21C4AD3DA007D0023 /* AIRMapCalloutManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AIRMapCalloutManager.m; path = AirMaps/AIRMapCalloutManager.m; sourceTree = SOURCE_ROOT; };
1125B2C31C4AD3DA007D0023 /* AIRMapCircle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AIRMapCircle.h; path = AirMaps/AIRMapCircle.h; sourceTree = SOURCE_ROOT; };
1125B2C41C4AD3DA007D0023 /* AIRMapCircle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AIRMapCircle.m; path = AirMaps/AIRMapCircle.m; sourceTree = SOURCE_ROOT; };
1125B2C51C4AD3DA007D0023 /* AIRMapCircleManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AIRMapCircleManager.h; path = AirMaps/AIRMapCircleManager.h; sourceTree = SOURCE_ROOT; };
1125B2C61C4AD3DA007D0023 /* AIRMapCircleManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AIRMapCircleManager.m; path = AirMaps/AIRMapCircleManager.m; sourceTree = SOURCE_ROOT; };
1125B2C71C4AD3DA007D0023 /* AIRMapCoordinate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AIRMapCoordinate.h; path = AirMaps/AIRMapCoordinate.h; sourceTree = SOURCE_ROOT; };
1125B2C81C4AD3DA007D0023 /* AIRMapCoordinate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AIRMapCoordinate.m; path = AirMaps/AIRMapCoordinate.m; sourceTree = SOURCE_ROOT; };
1125B2C91C4AD3DA007D0023 /* AIRMapManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AIRMapManager.h; path = AirMaps/AIRMapManager.h; sourceTree = SOURCE_ROOT; };
1125B2CA1C4AD3DA007D0023 /* AIRMapManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AIRMapManager.m; path = AirMaps/AIRMapManager.m; sourceTree = SOURCE_ROOT; };
1125B2CB1C4AD3DA007D0023 /* AIRMapMarker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AIRMapMarker.h; path = AirMaps/AIRMapMarker.h; sourceTree = SOURCE_ROOT; };
1125B2CC1C4AD3DA007D0023 /* AIRMapMarker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AIRMapMarker.m; path = AirMaps/AIRMapMarker.m; sourceTree = SOURCE_ROOT; };
1125B2CD1C4AD3DA007D0023 /* AIRMapMarkerManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AIRMapMarkerManager.h; path = AirMaps/AIRMapMarkerManager.h; sourceTree = SOURCE_ROOT; };
1125B2CE1C4AD3DA007D0023 /* AIRMapMarkerManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AIRMapMarkerManager.m; path = AirMaps/AIRMapMarkerManager.m; sourceTree = SOURCE_ROOT; };
1125B2CF1C4AD3DA007D0023 /* AIRMapPolygon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AIRMapPolygon.h; path = AirMaps/AIRMapPolygon.h; sourceTree = SOURCE_ROOT; };
1125B2D01C4AD3DA007D0023 /* AIRMapPolygon.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AIRMapPolygon.m; path = AirMaps/AIRMapPolygon.m; sourceTree = SOURCE_ROOT; };
1125B2D11C4AD3DA007D0023 /* AIRMapPolygonManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AIRMapPolygonManager.h; path = AirMaps/AIRMapPolygonManager.h; sourceTree = SOURCE_ROOT; };
1125B2D21C4AD3DA007D0023 /* AIRMapPolygonManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AIRMapPolygonManager.m; path = AirMaps/AIRMapPolygonManager.m; sourceTree = SOURCE_ROOT; };
1125B2D31C4AD3DA007D0023 /* AIRMapPolyline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AIRMapPolyline.h; path = AirMaps/AIRMapPolyline.h; sourceTree = SOURCE_ROOT; };
1125B2D41C4AD3DA007D0023 /* AIRMapPolyline.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AIRMapPolyline.m; path = AirMaps/AIRMapPolyline.m; sourceTree = SOURCE_ROOT; };
1125B2D51C4AD3DA007D0023 /* AIRMapPolylineManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AIRMapPolylineManager.h; path = AirMaps/AIRMapPolylineManager.h; sourceTree = SOURCE_ROOT; };
1125B2D61C4AD3DA007D0023 /* AIRMapPolylineManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AIRMapPolylineManager.m; path = AirMaps/AIRMapPolylineManager.m; sourceTree = SOURCE_ROOT; };
1125B2F01C4AD445007D0023 /* SMCalloutView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SMCalloutView.h; path = AirMaps/Callout/SMCalloutView.h; sourceTree = SOURCE_ROOT; };
1125B2F11C4AD445007D0023 /* SMCalloutView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SMCalloutView.m; path = AirMaps/Callout/SMCalloutView.m; sourceTree = SOURCE_ROOT; };
11FA5C511C4A1296003AC2EE /* libAirMaps.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libAirMaps.a; sourceTree = BUILT_PRODUCTS_DIR; };
19DABC7D1E7C9D3C00F41150 /* RCTConvert+AirMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "RCTConvert+AirMap.h"; sourceTree = "<group>"; };
19DABC7E1E7C9D3C00F41150 /* RCTConvert+AirMap.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "RCTConvert+AirMap.m"; sourceTree = "<group>"; };
2163AA4E1FEAEDD100BBEC95 /* AIRMapPolylineRenderer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AIRMapPolylineRenderer.h; sourceTree = "<group>"; };
2163AA4F1FEAEDD100BBEC95 /* AIRMapPolylineRenderer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AIRMapPolylineRenderer.m; sourceTree = "<group>"; };
4C99C9DC2226CF2800A8693E /* AIRWeakTimerReference.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AIRWeakTimerReference.h; sourceTree = "<group>"; };
4C99C9DD2226CF2800A8693E /* AIRWeakTimerReference.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AIRWeakTimerReference.m; sourceTree = "<group>"; };
4C99C9DF2226D8C400A8693E /* AIRWeakMapReference.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AIRWeakMapReference.h; sourceTree = "<group>"; };
4C99C9E02226D8C400A8693E /* AIRWeakMapReference.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AIRWeakMapReference.m; sourceTree = "<group>"; };
4E0A36142BFB4CF3009FCCE4 /* Resources */ = {isa = PBXFileReference; lastKnownFileType = folder; name = Resources; path = AirGoogleMaps/Resources; sourceTree = "<group>"; };
4E0A36152BFB4E76009FCCE4 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
4E0CFBDC2B388F2B0017E126 /* RCTComponentData+Maps.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "RCTComponentData+Maps.h"; sourceTree = "<group>"; };
4E0CFBDD2B388F2B0017E126 /* RCTComponentData+Maps.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "RCTComponentData+Maps.m"; sourceTree = "<group>"; };
53D31635202E723B00B55447 /* AIRMapOverlayManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AIRMapOverlayManager.m; sourceTree = "<group>"; };
53D31637202E725E00B55447 /* AIRMapOverlayManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AIRMapOverlayManager.h; sourceTree = "<group>"; };
53D31638202E72D500B55447 /* AIRMapOverlay.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AIRMapOverlay.h; sourceTree = "<group>"; };
53D31639202E72FC00B55447 /* AIRMapOverlay.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AIRMapOverlay.m; sourceTree = "<group>"; };
53D3163B202E732300B55447 /* AIRMapOverlayRenderer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AIRMapOverlayRenderer.h; sourceTree = "<group>"; };
53D3163C202E734F00B55447 /* AIRMapOverlayRenderer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AIRMapOverlayRenderer.m; sourceTree = "<group>"; };
628F811E1FD16D780058313A /* AIRMapLocalTile.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AIRMapLocalTile.h; sourceTree = "<group>"; };
628F811F1FD16DF80058313A /* AIRMapLocalTile.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AIRMapLocalTile.m; sourceTree = "<group>"; };
628F81211FD16EAB0058313A /* AIRMapLocalTileManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AIRMapLocalTileManager.h; sourceTree = "<group>"; };
628F81221FD16EFA0058313A /* AIRMapLocalTileManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AIRMapLocalTileManager.m; sourceTree = "<group>"; };
62AEC4D31FD5A0AA003225E0 /* AIRMapLocalTileOverlay.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = AIRMapLocalTileOverlay.m; path = AirMaps/AIRMapLocalTileOverlay.m; sourceTree = "<group>"; };
8B19A3C42257BBDE00BB8735 /* AIRMapCalloutSubview.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AIRMapCalloutSubview.m; sourceTree = "<group>"; };
8B19A3C52257BBDE00BB8735 /* AIRMapCalloutSubviewManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AIRMapCalloutSubviewManager.h; sourceTree = "<group>"; };
8B19A3C62257BBDF00BB8735 /* AIRMapCalloutSubview.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AIRMapCalloutSubview.h; sourceTree = "<group>"; };
8B19A3C72257BBDF00BB8735 /* AIRMapCalloutSubviewManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AIRMapCalloutSubviewManager.m; sourceTree = "<group>"; };
8BC85FAD2107C0BD0006CEA5 /* User.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = User.xcconfig; sourceTree = "<group>"; };
8BC85FAE2107CFD80006CEA5 /* AIRGoogleMapOverlay.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AIRGoogleMapOverlay.h; path = AirGoogleMaps/AIRGoogleMapOverlay.h; sourceTree = "<group>"; };
8BC85FAF2107CFEC0006CEA5 /* AIRGoogleMapOverlay.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AIRGoogleMapOverlay.m; path = AirGoogleMaps/AIRGoogleMapOverlay.m; sourceTree = "<group>"; };
9B9498A42017EFB400158761 /* AIRGoogleMapCallout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AIRGoogleMapCallout.h; path = AirGoogleMaps/AIRGoogleMapCallout.h; sourceTree = "<group>"; };
9B9498A52017EFB400158761 /* AIRGoogleMapPolygonManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AIRGoogleMapPolygonManager.h; path = AirGoogleMaps/AIRGoogleMapPolygonManager.h; sourceTree = "<group>"; };
9B9498A62017EFB400158761 /* AIRGoogleMapUrlTile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AIRGoogleMapUrlTile.m; path = AirGoogleMaps/AIRGoogleMapUrlTile.m; sourceTree = "<group>"; };
9B9498A72017EFB400158761 /* AIRGoogleMapURLTileManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AIRGoogleMapURLTileManager.m; path = AirGoogleMaps/AIRGoogleMapURLTileManager.m; sourceTree = "<group>"; };
9B9498A82017EFB400158761 /* AIRGMSPolygon.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AIRGMSPolygon.m; path = AirGoogleMaps/AIRGMSPolygon.m; sourceTree = "<group>"; };
9B9498A92017EFB400158761 /* RCTConvert+GMSMapViewType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "RCTConvert+GMSMapViewType.h"; path = "AirGoogleMaps/RCTConvert+GMSMapViewType.h"; sourceTree = "<group>"; };
9B9498AA2017EFB400158761 /* AIRGoogleMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AIRGoogleMap.h; path = AirGoogleMaps/AIRGoogleMap.h; sourceTree = "<group>"; };
9B9498AB2017EFB400158761 /* AIRGoogleMapMarkerManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AIRGoogleMapMarkerManager.h; path = AirGoogleMaps/AIRGoogleMapMarkerManager.h; sourceTree = "<group>"; };
9B9498AC2017EFB400158761 /* AIRGoogleMapCallout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AIRGoogleMapCallout.m; path = AirGoogleMaps/AIRGoogleMapCallout.m; sourceTree = "<group>"; };
9B9498AD2017EFB400158761 /* AIRGoogleMapUrlTileManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AIRGoogleMapUrlTileManager.h; path = AirGoogleMaps/AIRGoogleMapUrlTileManager.h; sourceTree = "<group>"; };
9B9498AE2017EFB500158761 /* AIRGMSMarker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AIRGMSMarker.m; path = AirGoogleMaps/AIRGMSMarker.m; sourceTree = "<group>"; };
9B9498AF2017EFB500158761 /* AIRGMSPolyline.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AIRGMSPolyline.m; path = AirGoogleMaps/AIRGMSPolyline.m; sourceTree = "<group>"; };
9B9498B02017EFB500158761 /* AIRGoogleMapCircleManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AIRGoogleMapCircleManager.h; path = AirGoogleMaps/AIRGoogleMapCircleManager.h; sourceTree = "<group>"; };
9B9498B12017EFB500158761 /* AIRGoogleMapPolylineManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AIRGoogleMapPolylineManager.m; path = AirGoogleMaps/AIRGoogleMapPolylineManager.m; sourceTree = "<group>"; };
9B9498B32017EFB500158761 /* AIRGoogleMapCircle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AIRGoogleMapCircle.m; path = AirGoogleMaps/AIRGoogleMapCircle.m; sourceTree = "<group>"; };
9B9498B42017EFB500158761 /* AIRGMSPolyline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AIRGMSPolyline.h; path = AirGoogleMaps/AIRGMSPolyline.h; sourceTree = "<group>"; };
9B9498B52017EFB500158761 /* AIRGoogleMapMarkerManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AIRGoogleMapMarkerManager.m; path = AirGoogleMaps/AIRGoogleMapMarkerManager.m; sourceTree = "<group>"; };
9B9498B62017EFB500158761 /* AIRGoogleMapPolylineManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AIRGoogleMapPolylineManager.h; path = AirGoogleMaps/AIRGoogleMapPolylineManager.h; sourceTree = "<group>"; };
9B9498B72017EFB500158761 /* AIRGoogleMap.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AIRGoogleMap.m; path = AirGoogleMaps/AIRGoogleMap.m; sourceTree = "<group>"; };
9B9498B82017EFB600158761 /* AIRGoogleMapPolyline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AIRGoogleMapPolyline.h; path = AirGoogleMaps/AIRGoogleMapPolyline.h; sourceTree = "<group>"; };
9B9498B92017EFB600158761 /* RCTConvert+GMSMapViewType.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "RCTConvert+GMSMapViewType.m"; path = "AirGoogleMaps/RCTConvert+GMSMapViewType.m"; sourceTree = "<group>"; };
9B9498BA2017EFB600158761 /* AIRGMSPolygon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AIRGMSPolygon.h; path = AirGoogleMaps/AIRGMSPolygon.h; sourceTree = "<group>"; };
9B9498BB2017EFB600158761 /* AIRGoogleMapPolyline.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AIRGoogleMapPolyline.m; path = AirGoogleMaps/AIRGoogleMapPolyline.m; sourceTree = "<group>"; };
9B9498BC2017EFB600158761 /* AIRGoogleMapCircleManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AIRGoogleMapCircleManager.m; path = AirGoogleMaps/AIRGoogleMapCircleManager.m; sourceTree = "<group>"; };
9B9498BD2017EFB600158761 /* AIRGoogleMapManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AIRGoogleMapManager.m; path = AirGoogleMaps/AIRGoogleMapManager.m; sourceTree = "<group>"; };
9B9498BE2017EFB600158761 /* AIRGoogleMapManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AIRGoogleMapManager.h; path = AirGoogleMaps/AIRGoogleMapManager.h; sourceTree = "<group>"; };
9B9498C02017EFB700158761 /* AIRGoogleMapMarker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AIRGoogleMapMarker.h; path = AirGoogleMaps/AIRGoogleMapMarker.h; sourceTree = "<group>"; };
9B9498C12017EFB700158761 /* AIRGMSMarker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AIRGMSMarker.h; path = AirGoogleMaps/AIRGMSMarker.h; sourceTree = "<group>"; };
9B9498C22017EFB700158761 /* AIRGoogleMapCircle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AIRGoogleMapCircle.h; path = AirGoogleMaps/AIRGoogleMapCircle.h; sourceTree = "<group>"; };
9B9498C32017EFB700158761 /* AIRGoogleMapPolygon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AIRGoogleMapPolygon.h; path = AirGoogleMaps/AIRGoogleMapPolygon.h; sourceTree = "<group>"; };
9B9498C42017EFB700158761 /* AIRGoogleMapCalloutManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AIRGoogleMapCalloutManager.m; path = AirGoogleMaps/AIRGoogleMapCalloutManager.m; sourceTree = "<group>"; };
9B9498C52017EFB800158761 /* AIRGoogleMapCalloutManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AIRGoogleMapCalloutManager.h; path = AirGoogleMaps/AIRGoogleMapCalloutManager.h; sourceTree = "<group>"; };
9B9498C62017EFB800158761 /* AIRGoogleMapPolygon.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AIRGoogleMapPolygon.m; path = AirGoogleMaps/AIRGoogleMapPolygon.m; sourceTree = "<group>"; };
9B9498C72017EFB800158761 /* AIRGoogleMapMarker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AIRGoogleMapMarker.m; path = AirGoogleMaps/AIRGoogleMapMarker.m; sourceTree = "<group>"; };
9B9498C82017EFB800158761 /* AIRGoogleMapUrlTile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AIRGoogleMapUrlTile.h; path = AirGoogleMaps/AIRGoogleMapUrlTile.h; sourceTree = "<group>"; };
9B9498C92017EFB800158761 /* AIRGoogleMapPolygonManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AIRGoogleMapPolygonManager.m; path = AirGoogleMaps/AIRGoogleMapPolygonManager.m; sourceTree = "<group>"; };
A8494E24218891020092506D /* AIRMapWMSTileManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AIRMapWMSTileManager.m; sourceTree = "<group>"; };
A8494E25218891020092506D /* AIRMapWMSTile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AIRMapWMSTile.h; sourceTree = "<group>"; };
A8494E26218891020092506D /* AIRMapWMSTileManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AIRMapWMSTileManager.h; sourceTree = "<group>"; };
A8494E27218891020092506D /* AIRMapWMSTile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AIRMapWMSTile.m; sourceTree = "<group>"; };
A8494E2A218891180092506D /* AIRGoogleMapWMSTileManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AIRGoogleMapWMSTileManager.m; path = AirGoogleMaps/AIRGoogleMapWMSTileManager.m; sourceTree = "<group>"; };
A8494E2B218891180092506D /* AIRGoogleMapWMSTile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AIRGoogleMapWMSTile.h; path = AirGoogleMaps/AIRGoogleMapWMSTile.h; sourceTree = "<group>"; };
A8494E2C218891180092506D /* AIRGoogleMapWMSTileManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AIRGoogleMapWMSTileManager.h; path = AirGoogleMaps/AIRGoogleMapWMSTileManager.h; sourceTree = "<group>"; };
A8494E2D218891180092506D /* AIRGoogleMapWMSTile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AIRGoogleMapWMSTile.m; path = AirGoogleMaps/AIRGoogleMapWMSTile.m; sourceTree = "<group>"; };
B5EA3BA72098E22B000E7AFD /* AIRDummyView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AIRDummyView.m; path = AirGoogleMaps/AIRDummyView.m; sourceTree = "<group>"; };
B5EA3BA82098E22B000E7AFD /* AIRDummyView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AIRDummyView.h; path = AirGoogleMaps/AIRDummyView.h; sourceTree = "<group>"; };
BE2E4EC72621F63C00CC7F2E /* AIRMapUrlTileCachedOverlay.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AIRMapUrlTileCachedOverlay.h; path = AirMaps/AIRMapUrlTileCachedOverlay.h; sourceTree = SOURCE_ROOT; };
BE2E4EC82621F63C00CC7F2E /* AIRMapUrlTileCachedOverlay.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AIRMapUrlTileCachedOverlay.m; path = AirMaps/AIRMapUrlTileCachedOverlay.m; sourceTree = SOURCE_ROOT; };
DA6C26361C9E2AFE0035349F /* AIRMapUrlTile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AIRMapUrlTile.h; sourceTree = "<group>"; };
DA6C26371C9E2AFE0035349F /* AIRMapUrlTile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AIRMapUrlTile.m; sourceTree = "<group>"; };
DA6C263C1C9E324A0035349F /* AIRMapUrlTileManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AIRMapUrlTileManager.h; sourceTree = "<group>"; };
DA6C263D1C9E324A0035349F /* AIRMapUrlTileManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AIRMapUrlTileManager.m; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
11FA5C4E1C4A1296003AC2EE /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
11FA5C481C4A1296003AC2EE = {
isa = PBXGroup;
children = (
4E0A36152BFB4E76009FCCE4 /* PrivacyInfo.xcprivacy */,
9B9498A32017EF9D00158761 /* AirGoogleMaps */,
62AEC4D31FD5A0AA003225E0 /* AIRMapLocalTileOverlay.m */,
11FA5C531C4A1296003AC2EE /* AirMaps */,
11FA5C521C4A1296003AC2EE /* Products */,
8BC85FAD2107C0BD0006CEA5 /* User.xcconfig */,
);
sourceTree = "<group>";
};
11FA5C521C4A1296003AC2EE /* Products */ = {
isa = PBXGroup;
children = (
11FA5C511C4A1296003AC2EE /* libAirMaps.a */,
);
name = Products;
sourceTree = "<group>";
};
11FA5C531C4A1296003AC2EE /* AirMaps */ = {
isa = PBXGroup;
children = (
4E0CFBDC2B388F2B0017E126 /* RCTComponentData+Maps.h */,
4E0CFBDD2B388F2B0017E126 /* RCTComponentData+Maps.m */,
BE2E4EC72621F63C00CC7F2E /* AIRMapUrlTileCachedOverlay.h */,
BE2E4EC82621F63C00CC7F2E /* AIRMapUrlTileCachedOverlay.m */,
1125B2BD1C4AD3DA007D0023 /* AIRMap.h */,
1125B2BE1C4AD3DA007D0023 /* AIRMap.m */,
1125B2BF1C4AD3DA007D0023 /* AIRMapCallout.h */,
1125B2C01C4AD3DA007D0023 /* AIRMapCallout.m */,
1125B2C11C4AD3DA007D0023 /* AIRMapCalloutManager.h */,
1125B2C21C4AD3DA007D0023 /* AIRMapCalloutManager.m */,
8B19A3C62257BBDF00BB8735 /* AIRMapCalloutSubview.h */,
8B19A3C42257BBDE00BB8735 /* AIRMapCalloutSubview.m */,
8B19A3C52257BBDE00BB8735 /* AIRMapCalloutSubviewManager.h */,
8B19A3C72257BBDF00BB8735 /* AIRMapCalloutSubviewManager.m */,
1125B2C31C4AD3DA007D0023 /* AIRMapCircle.h */,
1125B2C41C4AD3DA007D0023 /* AIRMapCircle.m */,
1125B2C51C4AD3DA007D0023 /* AIRMapCircleManager.h */,
1125B2C61C4AD3DA007D0023 /* AIRMapCircleManager.m */,
1125B2D41C4AD3DA007D0023 /* AIRMapPolyline.m */,
1125B2C71C4AD3DA007D0023 /* AIRMapCoordinate.h */,
1125B2C81C4AD3DA007D0023 /* AIRMapCoordinate.m */,
1125B2C91C4AD3DA007D0023 /* AIRMapManager.h */,
1125B2CA1C4AD3DA007D0023 /* AIRMapManager.m */,
1125B2CB1C4AD3DA007D0023 /* AIRMapMarker.h */,
1125B2CD1C4AD3DA007D0023 /* AIRMapMarkerManager.h */,
1125B2CE1C4AD3DA007D0023 /* AIRMapMarkerManager.m */,
1125B2CF1C4AD3DA007D0023 /* AIRMapPolygon.h */,
1125B2D01C4AD3DA007D0023 /* AIRMapPolygon.m */,
1125B2D11C4AD3DA007D0023 /* AIRMapPolygonManager.h */,
1125B2D21C4AD3DA007D0023 /* AIRMapPolygonManager.m */,
1125B2D31C4AD3DA007D0023 /* AIRMapPolyline.h */,
1125B2D51C4AD3DA007D0023 /* AIRMapPolylineManager.h */,
1125B2D61C4AD3DA007D0023 /* AIRMapPolylineManager.m */,
2163AA4E1FEAEDD100BBEC95 /* AIRMapPolylineRenderer.h */,
2163AA4F1FEAEDD100BBEC95 /* AIRMapPolylineRenderer.m */,
1125B2F01C4AD445007D0023 /* SMCalloutView.h */,
1125B2F11C4AD445007D0023 /* SMCalloutView.m */,
19DABC7D1E7C9D3C00F41150 /* RCTConvert+AirMap.h */,
19DABC7E1E7C9D3C00F41150 /* RCTConvert+AirMap.m */,
DA6C26361C9E2AFE0035349F /* AIRMapUrlTile.h */,
DA6C26371C9E2AFE0035349F /* AIRMapUrlTile.m */,
DA6C263C1C9E324A0035349F /* AIRMapUrlTileManager.h */,
DA6C263D1C9E324A0035349F /* AIRMapUrlTileManager.m */,
A8494E25218891020092506D /* AIRMapWMSTile.h */,
A8494E27218891020092506D /* AIRMapWMSTile.m */,
A8494E26218891020092506D /* AIRMapWMSTileManager.h */,
A8494E24218891020092506D /* AIRMapWMSTileManager.m */,
1125B2CC1C4AD3DA007D0023 /* AIRMapMarker.m */,
628F811E1FD16D780058313A /* AIRMapLocalTile.h */,
628F811F1FD16DF80058313A /* AIRMapLocalTile.m */,
628F81211FD16EAB0058313A /* AIRMapLocalTileManager.h */,
628F81221FD16EFA0058313A /* AIRMapLocalTileManager.m */,
53D31638202E72D500B55447 /* AIRMapOverlay.h */,
53D31639202E72FC00B55447 /* AIRMapOverlay.m */,
53D31637202E725E00B55447 /* AIRMapOverlayManager.h */,
53D31635202E723B00B55447 /* AIRMapOverlayManager.m */,
53D3163B202E732300B55447 /* AIRMapOverlayRenderer.h */,
53D3163C202E734F00B55447 /* AIRMapOverlayRenderer.m */,
4C99C9DC2226CF2800A8693E /* AIRWeakTimerReference.h */,
4C99C9DD2226CF2800A8693E /* AIRWeakTimerReference.m */,
4C99C9DF2226D8C400A8693E /* AIRWeakMapReference.h */,
4C99C9E02226D8C400A8693E /* AIRWeakMapReference.m */,
);
path = AirMaps;
sourceTree = "<group>";
};
9B9498A32017EF9D00158761 /* AirGoogleMaps */ = {
isa = PBXGroup;
children = (
4E0A36142BFB4CF3009FCCE4 /* Resources */,
B5EA3BA82098E22B000E7AFD /* AIRDummyView.h */,
B5EA3BA72098E22B000E7AFD /* AIRDummyView.m */,
9B9498C12017EFB700158761 /* AIRGMSMarker.h */,
9B9498AE2017EFB500158761 /* AIRGMSMarker.m */,
9B9498BA2017EFB600158761 /* AIRGMSPolygon.h */,
9B9498A82017EFB400158761 /* AIRGMSPolygon.m */,
9B9498B42017EFB500158761 /* AIRGMSPolyline.h */,
9B9498AF2017EFB500158761 /* AIRGMSPolyline.m */,
9B9498AA2017EFB400158761 /* AIRGoogleMap.h */,
9B9498B72017EFB500158761 /* AIRGoogleMap.m */,
9B9498A42017EFB400158761 /* AIRGoogleMapCallout.h */,
9B9498AC2017EFB400158761 /* AIRGoogleMapCallout.m */,
9B9498C52017EFB800158761 /* AIRGoogleMapCalloutManager.h */,
9B9498C42017EFB700158761 /* AIRGoogleMapCalloutManager.m */,
9B9498C22017EFB700158761 /* AIRGoogleMapCircle.h */,
9B9498B32017EFB500158761 /* AIRGoogleMapCircle.m */,
9B9498B02017EFB500158761 /* AIRGoogleMapCircleManager.h */,
9B9498BC2017EFB600158761 /* AIRGoogleMapCircleManager.m */,
9B9498BE2017EFB600158761 /* AIRGoogleMapManager.h */,
9B9498BD2017EFB600158761 /* AIRGoogleMapManager.m */,
9B9498C02017EFB700158761 /* AIRGoogleMapMarker.h */,
9B9498C72017EFB800158761 /* AIRGoogleMapMarker.m */,
9B9498AB2017EFB400158761 /* AIRGoogleMapMarkerManager.h */,
9B9498B52017EFB500158761 /* AIRGoogleMapMarkerManager.m */,
9B9498C32017EFB700158761 /* AIRGoogleMapPolygon.h */,
9B9498C62017EFB800158761 /* AIRGoogleMapPolygon.m */,
9B9498A52017EFB400158761 /* AIRGoogleMapPolygonManager.h */,
9B9498C92017EFB800158761 /* AIRGoogleMapPolygonManager.m */,
9B9498B82017EFB600158761 /* AIRGoogleMapPolyline.h */,
9B9498BB2017EFB600158761 /* AIRGoogleMapPolyline.m */,
8BC85FAE2107CFD80006CEA5 /* AIRGoogleMapOverlay.h */,
8BC85FAF2107CFEC0006CEA5 /* AIRGoogleMapOverlay.m */,
9B9498B62017EFB500158761 /* AIRGoogleMapPolylineManager.h */,
9B9498B12017EFB500158761 /* AIRGoogleMapPolylineManager.m */,
9B9498C82017EFB800158761 /* AIRGoogleMapUrlTile.h */,
9B9498A62017EFB400158761 /* AIRGoogleMapUrlTile.m */,
9B9498AD2017EFB400158761 /* AIRGoogleMapUrlTileManager.h */,
9B9498A72017EFB400158761 /* AIRGoogleMapURLTileManager.m */,
A8494E2B218891180092506D /* AIRGoogleMapWMSTile.h */,
A8494E2D218891180092506D /* AIRGoogleMapWMSTile.m */,
A8494E2C218891180092506D /* AIRGoogleMapWMSTileManager.h */,
A8494E2A218891180092506D /* AIRGoogleMapWMSTileManager.m */,
9B9498A92017EFB400158761 /* RCTConvert+GMSMapViewType.h */,
9B9498B92017EFB600158761 /* RCTConvert+GMSMapViewType.m */,
);
name = AirGoogleMaps;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
11FA5C501C4A1296003AC2EE /* AirMaps */ = {
isa = PBXNativeTarget;
buildConfigurationList = 11FA5C5A1C4A1296003AC2EE /* Build configuration list for PBXNativeTarget "AirMaps" */;
buildPhases = (
11FA5C4D1C4A1296003AC2EE /* Sources */,
11FA5C4E1C4A1296003AC2EE /* Frameworks */,
11FA5C4F1C4A1296003AC2EE /* CopyFiles */,
);
buildRules = (
);
dependencies = (
);
name = AirMaps;
productName = AirMaps;
productReference = 11FA5C511C4A1296003AC2EE /* libAirMaps.a */;
productType = "com.apple.product-type.library.static";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
11FA5C491C4A1296003AC2EE /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0940;
ORGANIZATIONNAME = "react-native-maps";
TargetAttributes = {
11FA5C501C4A1296003AC2EE = {
CreatedOnToolsVersion = 7.2;
};
};
};
buildConfigurationList = 11FA5C4C1C4A1296003AC2EE /* Build configuration list for PBXProject "AirMaps" */;
compatibilityVersion = "Xcode 15.3";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
English,
en,
);
mainGroup = 11FA5C481C4A1296003AC2EE;
productRefGroup = 11FA5C521C4A1296003AC2EE /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
11FA5C501C4A1296003AC2EE /* AirMaps */,
);
};
/* End PBXProject section */
/* Begin PBXSourcesBuildPhase section */
11FA5C4D1C4A1296003AC2EE /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
62AEC4D41FD5A0AA003225E0 /* AIRMapLocalTileOverlay.m in Sources */,
9B9498DC2017EFB800158761 /* AIRGoogleMapPolygonManager.m in Sources */,
1125B2E31C4AD3DA007D0023 /* AIRMapPolygon.m in Sources */,
4C99C9DE2226CF2800A8693E /* AIRWeakTimerReference.m in Sources */,
1125B2E41C4AD3DA007D0023 /* AIRMapPolygonManager.m in Sources */,
A8494E2F218891180092506D /* AIRGoogleMapWMSTile.m in Sources */,
9B9498CB2017EFB800158761 /* AIRGoogleMapURLTileManager.m in Sources */,
A8494E28218891020092506D /* AIRMapWMSTileManager.m in Sources */,
1125B2DB1C4AD3DA007D0023 /* AIRMapCallout.m in Sources */,
53D31636202E723B00B55447 /* AIRMapOverlayManager.m in Sources */,
4E0CFBDE2B388F2B0017E126 /* RCTComponentData+Maps.m in Sources */,
1125B2E01C4AD3DA007D0023 /* AIRMapManager.m in Sources */,
1125B2E61C4AD3DA007D0023 /* AIRMapPolylineManager.m in Sources */,
9B9498DA2017EFB800158761 /* AIRGoogleMapPolygon.m in Sources */,
9B9498D12017EFB800158761 /* AIRGoogleMapCircle.m in Sources */,
1125B2DD1C4AD3DA007D0023 /* AIRMapCircle.m in Sources */,
9B9498CE2017EFB800158761 /* AIRGMSMarker.m in Sources */,
9B9498D72017EFB800158761 /* AIRGoogleMapManager.m in Sources */,
19DABC7F1E7C9D3C00F41150 /* RCTConvert+AirMap.m in Sources */,
A8494E2E218891180092506D /* AIRGoogleMapWMSTileManager.m in Sources */,
8B19A3C82257BBDF00BB8735 /* AIRMapCalloutSubview.m in Sources */,
1125B2E51C4AD3DA007D0023 /* AIRMapPolyline.m in Sources */,
4C99C9E12226D8C400A8693E /* AIRWeakMapReference.m in Sources */,
9B9498D52017EFB800158761 /* AIRGoogleMapPolyline.m in Sources */,
9B9498CF2017EFB800158761 /* AIRGMSPolyline.m in Sources */,
9B9498D42017EFB800158761 /* RCTConvert+GMSMapViewType.m in Sources */,
9B9498D32017EFB800158761 /* AIRGoogleMap.m in Sources */,
BE2E4EC92621F63C00CC7F2E /* AIRMapUrlTileCachedOverlay.m in Sources */,
DA6C263E1C9E324A0035349F /* AIRMapUrlTileManager.m in Sources */,
9B9498DB2017EFB800158761 /* AIRGoogleMapMarker.m in Sources */,
628F81201FD16DF80058313A /* AIRMapLocalTile.m in Sources */,
9B9498D92017EFB800158761 /* AIRGoogleMapCalloutManager.m in Sources */,
53D3163A202E72FC00B55447 /* AIRMapOverlay.m in Sources */,
53D3163D202E734F00B55447 /* AIRMapOverlayRenderer.m in Sources */,
1125B2DA1C4AD3DA007D0023 /* AIRMap.m in Sources */,
1125B2DF1C4AD3DA007D0023 /* AIRMapCoordinate.m in Sources */,
9B9498D62017EFB800158761 /* AIRGoogleMapCircleManager.m in Sources */,
8BC85FB02107CFEC0006CEA5 /* AIRGoogleMapOverlay.m in Sources */,
1125B2F21C4AD445007D0023 /* SMCalloutView.m in Sources */,
2163AA501FEAEDD100BBEC95 /* AIRMapPolylineRenderer.m in Sources */,
9B9498D02017EFB800158761 /* AIRGoogleMapPolylineManager.m in Sources */,
1125B2E11C4AD3DA007D0023 /* AIRMapMarker.m in Sources */,
A8494E29218891020092506D /* AIRMapWMSTile.m in Sources */,
9B9498CA2017EFB800158761 /* AIRGoogleMapUrlTile.m in Sources */,
8B19A3C92257BBDF00BB8735 /* AIRMapCalloutSubviewManager.m in Sources */,
B5EA3BA92098E22B000E7AFD /* AIRDummyView.m in Sources */,
9B9498CD2017EFB800158761 /* AIRGoogleMapCallout.m in Sources */,
1125B2E21C4AD3DA007D0023 /* AIRMapMarkerManager.m in Sources */,
DA6C26381C9E2AFE0035349F /* AIRMapUrlTile.m in Sources */,
628F81231FD16EFA0058313A /* AIRMapLocalTileManager.m in Sources */,
9B9498D22017EFB800158761 /* AIRGoogleMapMarkerManager.m in Sources */,
9B9498CC2017EFB800158761 /* AIRGMSPolygon.m in Sources */,
1125B2DE1C4AD3DA007D0023 /* AIRMapCircleManager.m in Sources */,
1125B2DC1C4AD3DA007D0023 /* AIRMapCalloutManager.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
11FA5C581C4A1296003AC2EE /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = "";
IPHONEOS_DEPLOYMENT_TARGET = 9.2;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
};
name = Debug;
};
11FA5C591C4A1296003AC2EE /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = "";
IPHONEOS_DEPLOYMENT_TARGET = 9.2;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
VALIDATE_PRODUCT = YES;
};
name = Release;
};
11FA5C5B1C4A1296003AC2EE /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 8BC85FAD2107C0BD0006CEA5 /* User.xcconfig */;
buildSettings = {
HEADER_SEARCH_PATHS = (
"$(SRCROOT)/../../react-native/React/**",
"$(SRCROOT)/../../react-native/Libraries/Image",
);
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
};
name = Debug;
};
11FA5C5C1C4A1296003AC2EE /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 8BC85FAD2107C0BD0006CEA5 /* User.xcconfig */;
buildSettings = {
HEADER_SEARCH_PATHS = (
"$(SRCROOT)/../../react-native/React/**",
"$(SRCROOT)/../../react-native/Libraries/Image",
);
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
11FA5C4C1C4A1296003AC2EE /* Build configuration list for PBXProject "AirMaps" */ = {
isa = XCConfigurationList;
buildConfigurations = (
11FA5C581C4A1296003AC2EE /* Debug */,
11FA5C591C4A1296003AC2EE /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
11FA5C5A1C4A1296003AC2EE /* Build configuration list for PBXNativeTarget "AirMaps" */ = {
isa = XCConfigurationList;
buildConfigurations = (
11FA5C5B1C4A1296003AC2EE /* Debug */,
11FA5C5C1C4A1296003AC2EE /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 11FA5C491C4A1296003AC2EE /* Project object */;
}
+83
View File
@@ -0,0 +1,83 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import <MapKit/MapKit.h>
#import <UIKit/UIKit.h>
#import <React/RCTComponent.h>
#import "SMCalloutView.h"
#import "RCTConvert+AirMap.h"
#import "AIRMapCalloutSubview.h"
@class AIRMapMarker;
extern const NSTimeInterval AIRMapRegionChangeObserveInterval;
extern const CGFloat AIRMapZoomBoundBuffer;
extern const NSInteger AIRMapMaxZoomLevel;
@interface AIRMap: MKMapView<SMCalloutViewDelegate>
@property (nonatomic, strong) SMCalloutView *calloutView;
@property (nonatomic, strong) UIImageView *cacheImageView;
@property (nonatomic, strong) UIView *loadingView;
@property (nonatomic, copy) NSString *userLocationAnnotationTitle;
@property (nonatomic, assign) BOOL followUserLocation;
@property (nonatomic, assign) BOOL userLocationCalloutEnabled;
@property (nonatomic, assign) BOOL hasStartedRendering;
@property (nonatomic, assign) BOOL cacheEnabled;
@property (nonatomic, assign) BOOL loadingEnabled;
@property (nonatomic, assign) BOOL legacyZoomConstraintsEnabled;
@property (nonatomic, strong) UIColor *loadingBackgroundColor;
@property (nonatomic, strong) UIColor *loadingIndicatorColor;
@property (nonatomic, assign) BOOL hasShownInitialLoading;
@property (nonatomic, assign) CGFloat minDelta;
@property (nonatomic, assign) CGFloat maxDelta;
@property (nonatomic, assign) UIEdgeInsets legalLabelInsets;
@property (nonatomic, assign) MKCoordinateRegion initialRegion;
@property (nonatomic, assign) MKMapCamera *initialCamera;
@property (nonatomic, assign) CGFloat minZoomLevel;
@property (nonatomic, assign) CGFloat maxZoomLevel;
@property (nonatomic, assign) CGPoint compassOffset;
@property (nonatomic, assign) UIEdgeInsets mapPadding;
@property (nonatomic, assign) CLLocationCoordinate2D pendingCenter;
@property (nonatomic, assign) MKCoordinateSpan pendingSpan;
@property (nonatomic, assign) BOOL ignoreRegionChanges;
@property (nonatomic, copy) RCTBubblingEventBlock onMapReady;
@property (nonatomic, copy) RCTBubblingEventBlock onChange;
@property (nonatomic, copy) RCTBubblingEventBlock onPress;
@property (nonatomic, copy) RCTBubblingEventBlock onPanDrag;
@property (nonatomic, copy) RCTBubblingEventBlock onDoublePress;
@property (nonatomic, copy) RCTBubblingEventBlock onLongPress;
@property (nonatomic, copy) RCTDirectEventBlock onMarkerPress;
@property (nonatomic, copy) RCTDirectEventBlock onMarkerSelect;
@property (nonatomic, copy) RCTDirectEventBlock onMarkerDeselect;
@property (nonatomic, copy) RCTDirectEventBlock onMarkerDragStart;
@property (nonatomic, copy) RCTDirectEventBlock onMarkerDrag;
@property (nonatomic, copy) RCTDirectEventBlock onMarkerDragEnd;
@property (nonatomic, copy) RCTDirectEventBlock onCalloutPress;
@property (nonatomic, copy) RCTDirectEventBlock onRegionChangeStart;
@property (nonatomic, copy) RCTDirectEventBlock onRegionChange;
@property (nonatomic, copy) RCTBubblingEventBlock onUserLocationChange;
- (void)cacheViewIfNeeded;
- (void)beginLoading;
- (void)finishLoading;
- (double)getZoomLevel;
- (NSArray *)getMapBoundaries;
- (AIRMapMarker*) markerAtPoint:(CGPoint)point;
- (NSDictionary*) getMarkersFramesWithOnlyVisible:(BOOL)onlyVisible;
@end
+756
View File
@@ -0,0 +1,756 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import "AIRMap.h"
#import <React/RCTEventDispatcher.h>
#import <React/UIView+React.h>
#import "AIRMapMarker.h"
#import "AIRMapPolyline.h"
#import "AIRMapPolygon.h"
#import "AIRMapCircle.h"
#import <QuartzCore/QuartzCore.h>
#import "AIRMapUrlTile.h"
#import "AIRMapWMSTile.h"
#import "AIRMapLocalTile.h"
#import "AIRMapOverlay.h"
const NSTimeInterval AIRMapRegionChangeObserveInterval = 0.1;
const CGFloat AIRMapZoomBoundBuffer = 0.01;
const NSInteger AIRMapMaxZoomLevel = 20;
@interface MKMapView (UIGestureRecognizer)
// this tells the compiler that MKMapView actually implements this method
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch;
@end
@interface AIRMap ()
@property (nonatomic, strong) UIActivityIndicatorView *activityIndicatorView;
@property (nonatomic, assign) NSNumber *shouldZoomEnabled;
@property (nonatomic, assign) NSNumber *shouldScrollEnabled;
@property (nonatomic, strong) MKCompassButton *defaultCompassButton;
@property (nonatomic, strong) MKCompassButton *overlayCompassButton;
- (void)updateScrollEnabled;
- (void)updateZoomEnabled;
@end
@implementation AIRMap
{
UIView *_legalLabel;
BOOL _initialRegionSet;
BOOL _initialCameraSet;
// Array to manually track RN subviews
//
// AIRMap implicitly creates subviews that aren't regular RN children
// (SMCalloutView injects an overlay subview), which otherwise confuses RN
// during component re-renders:
// https://github.com/facebook/react-native/blob/v0.16.0/React/Modules/RCTUIManager.m#L657
//
// Implementation based on RCTTextField, another component with indirect children
// https://github.com/facebook/react-native/blob/v0.16.0/Libraries/Text/RCTTextField.m#L20
NSMutableArray<UIView *> *_reactSubviews;
}
- (instancetype)init
{
if ((self = [super init])) {
_hasStartedRendering = NO;
_reactSubviews = [NSMutableArray new];
// Find Apple link label
for (UIView *subview in self.subviews) {
if ([NSStringFromClass(subview.class) isEqualToString:@"MKAttributionLabel"]) {
// This check is super hacky, but the whole premise of moving around
// Apple's internal subviews is super hacky
_legalLabel = subview;
break;
}
}
// 3rd-party callout view for MapKit that has more options than the built-in. It's painstakingly built to
// be identical to the built-in callout view (which has a private API)
self.calloutView = [SMCalloutView platformCalloutView];
self.calloutView.delegate = self;
self.minZoomLevel = 0;
self.maxZoomLevel = AIRMapMaxZoomLevel;
self.compassOffset = CGPointMake(0, 0);
self.legacyZoomConstraintsEnabled = YES;
}
return self;
}
-(void)addSubview:(UIView *)view {
if([view isKindOfClass:[AIRMapMarker class]]) {
[self addAnnotation:(id <MKAnnotation>)view];
} else {
[super addSubview:view];
}
}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-missing-super-calls"
- (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:[AIRMapMarker class]]) {
[self addAnnotation:(id <MKAnnotation>) subview];
} else if ([subview isKindOfClass:[AIRMapPolyline class]]) {
((AIRMapPolyline *)subview).map = self;
[self addOverlay:(id<MKOverlay>)subview];
} else if ([subview isKindOfClass:[AIRMapPolygon class]]) {
((AIRMapPolygon *)subview).map = self;
[self addOverlay:(id<MKOverlay>)subview];
} else if ([subview isKindOfClass:[AIRMapCircle class]]) {
((AIRMapCircle *)subview).map = self;
[self addOverlay:(id<MKOverlay>)subview];
} else if ([subview isKindOfClass:[AIRMapUrlTile class]]) {
((AIRMapUrlTile *)subview).map = self;
[self addOverlay:(id<MKOverlay>)subview];
}else if ([subview isKindOfClass:[AIRMapWMSTile class]]) {
((AIRMapWMSTile *)subview).map = self;
[self addOverlay:(id<MKOverlay>)subview];
} else if ([subview isKindOfClass:[AIRMapLocalTile class]]) {
((AIRMapLocalTile *)subview).map = self;
[self addOverlay:(id<MKOverlay>)subview];
} else if ([subview isKindOfClass:[AIRMapOverlay class]]) {
((AIRMapOverlay *)subview).map = self;
[self addOverlay:(id<MKOverlay>)subview];
} else {
NSArray<id<RCTComponent>> *childSubviews = [subview reactSubviews];
for (int i = 0; i < childSubviews.count; i++) {
[self insertReactSubview:(UIView *)childSubviews[i] atIndex:atIndex];
}
}
[_reactSubviews insertObject:(UIView *)subview atIndex:(NSUInteger) atIndex];
}
#pragma clang diagnostic pop
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-missing-super-calls"
- (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:[AIRMapMarker class]]) {
[self removeAnnotation:(id<MKAnnotation>)subview];
} else if ([subview isKindOfClass:[AIRMapPolyline class]]) {
[self removeOverlay:(id <MKOverlay>) subview];
} else if ([subview isKindOfClass:[AIRMapPolygon class]]) {
[self removeOverlay:(id <MKOverlay>) subview];
} else if ([subview isKindOfClass:[AIRMapCircle class]]) {
[self removeOverlay:(id <MKOverlay>) subview];
} else if ([subview isKindOfClass:[AIRMapUrlTile class]]) {
[self removeOverlay:(id <MKOverlay>) subview];
} else if ([subview isKindOfClass:[AIRMapWMSTile class]]) {
[self removeOverlay:(id <MKOverlay>) subview];
} else if ([subview isKindOfClass:[AIRMapLocalTile class]]) {
[self removeOverlay:(id <MKOverlay>) subview];
} else if ([subview isKindOfClass:[AIRMapOverlay class]]) {
[self removeOverlay:(id <MKOverlay>) subview];
} else {
NSArray<id<RCTComponent>> *childSubviews = [subview reactSubviews];
for (int i = 0; i < childSubviews.count; i++) {
[self removeReactSubview:(UIView *)childSubviews[i]];
}
}
[_reactSubviews removeObject:(UIView *)subview];
}
#pragma clang diagnostic pop
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-missing-super-calls"
- (NSArray<id<RCTComponent>> *)reactSubviews {
return _reactSubviews;
}
#pragma clang diagnostic pop
#pragma mark Utils
- (NSArray*) markers {
NSPredicate *filterMarkers = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
AIRMapMarker *marker = (AIRMapMarker *)evaluatedObject;
return [marker isKindOfClass:[AIRMapMarker class]];
}];
NSArray *filteredMarkers = [self.annotations filteredArrayUsingPredicate:filterMarkers];
return filteredMarkers;
}
- (AIRMapMarker*) markerForCallout:(AIRMapCallout*)callout {
AIRMapMarker* marker = nil;
NSArray* markers = [self markers];
for (AIRMapMarker* mrk in markers) {
if (mrk.calloutView == callout) {
marker = mrk;
break;
}
}
return marker;
}
- (CGRect) frameForMarker:(AIRMapMarker*) mrkAnn {
MKAnnotationView* mrkView = [self viewForAnnotation: mrkAnn];
CGRect mrkFrame = mrkView.frame;
return mrkFrame;
}
- (NSDictionary*) getMarkersFramesWithOnlyVisible:(BOOL)onlyVisible {
NSMutableDictionary* markersFrames = [NSMutableDictionary new];
for (AIRMapMarker* mrkAnn in self.markers) {
CGRect frame = [self frameForMarker:mrkAnn];
CGPoint point = [self convertCoordinate:mrkAnn.coordinate toPointToView:self];
NSDictionary* frameDict = @{
@"x": @(frame.origin.x),
@"y": @(frame.origin.y),
@"width": @(frame.size.width),
@"height": @(frame.size.height)
};
NSDictionary* pointDict = @{
@"x": @(point.x),
@"y": @(point.y)
};
NSString* k = mrkAnn.identifier;
BOOL isVisible = CGRectIntersectsRect(self.bounds, frame);
if (k != nil && (!onlyVisible || isVisible)) {
[markersFrames setObject:@{ @"frame": frameDict, @"point": pointDict } forKey:k];
}
}
return markersFrames;
}
- (AIRMapMarker*) markerAtPoint:(CGPoint)point {
AIRMapMarker* mrk = nil;
for (AIRMapMarker* mrkAnn in self.markers) {
CGRect frame = [self frameForMarker:mrkAnn];
if (CGRectContainsPoint(frame, point)) {
mrk = mrkAnn;
break;
}
}
return mrk;
}
#pragma mark Overrides for Callout behavior
// override UIGestureRecognizer's delegate method so we can prevent MKMapView's recognizer from firing
// when we interact with UIControl subclasses inside our callout view.
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
if ([touch.view isDescendantOfView:self.calloutView])
return NO;
else
return [super gestureRecognizer:gestureRecognizer shouldReceiveTouch:touch];
}
// Allow touches to be sent to our calloutview.
// See this for some discussion of why we need to override this: https://github.com/nfarina/calloutview/pull/9
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
CGPoint touchPoint = [self.calloutView convertPoint:point fromView:self];
UIView *touchedView = [self.calloutView hitTest:touchPoint withEvent:event];
if (touchedView) {
UIWindow* win = [[[UIApplication sharedApplication] windows] firstObject];
AIRMapCalloutSubview* calloutSubview = nil;
AIRMapCallout* callout = nil;
AIRMapMarker* marker = nil;
UIView* tmp = touchedView;
while (tmp && tmp != win && tmp != self.calloutView) {
if ([tmp respondsToSelector:@selector(onPress)]) {
calloutSubview = (AIRMapCalloutSubview*) tmp;
}
if ([tmp isKindOfClass:[AIRMapCallout class]]) {
callout = (AIRMapCallout*) tmp;
break;
}
tmp = tmp.superview;
}
if (callout) {
marker = [self markerForCallout:callout];
if (marker) {
CGPoint touchPointReal = [marker.calloutView convertPoint:point fromView:self];
if (![callout isPointInside:touchPointReal]) {
return [super hitTest:point withEvent:event];
}
}
}
return calloutSubview ? calloutSubview : touchedView;
}
return [super hitTest:point withEvent:event];
}
#pragma mark SMCalloutViewDelegate
- (NSTimeInterval)calloutView:(SMCalloutView *)calloutView delayForRepositionWithSize:(CGSize)offset {
// When the callout is being asked to present in a way where it or its target will be partially offscreen, it asks us
// if we'd like to reposition our surface first so the callout is completely visible. Here we scroll the map into view,
// but it takes some math because we have to deal in lon/lat instead of the given offset in pixels.
CLLocationCoordinate2D coordinate = self.region.center;
// where's the center coordinate in terms of our view?
CGPoint center = [self convertCoordinate:coordinate toPointToView:self];
// move it by the requested offset
center.x -= offset.width;
center.y -= offset.height;
// and translate it back into map coordinates
coordinate = [self convertPoint:center toCoordinateFromView:self];
// move the map!
[self setCenterCoordinate:coordinate animated:YES];
// tell the callout to wait for a while while we scroll (we assume the scroll delay for MKMapView matches UIScrollView)
return kSMCalloutViewRepositionDelayForUIScrollView;
}
#pragma mark Accessors
- (NSArray *)getMapBoundaries
{
MKMapRect mapRect = self.visibleMapRect;
CLLocationCoordinate2D northEast = MKCoordinateForMapPoint(MKMapPointMake(MKMapRectGetMaxX(mapRect), mapRect.origin.y));
CLLocationCoordinate2D southWest = MKCoordinateForMapPoint(MKMapPointMake(mapRect.origin.x, MKMapRectGetMaxY(mapRect)));
return @[
@[
[NSNumber numberWithDouble:northEast.longitude],
[NSNumber numberWithDouble:northEast.latitude]
],
@[
[NSNumber numberWithDouble:southWest.longitude],
[NSNumber numberWithDouble:southWest.latitude]
]
];
}
- (void)setShowsUserLocation:(BOOL)showsUserLocation
{
if (self.showsUserLocation != showsUserLocation) {
super.showsUserLocation = showsUserLocation;
}
}
- (void)setUserInterfaceStyle:(NSString*)userInterfaceStyle
{
if (@available(iOS 13.0, *)) {
if([userInterfaceStyle isEqualToString:@"light"]) {
self.overrideUserInterfaceStyle = UIUserInterfaceStyleLight;
} else if([userInterfaceStyle isEqualToString:@"dark"]) {
self.overrideUserInterfaceStyle = UIUserInterfaceStyleDark;
} else {
self.overrideUserInterfaceStyle = UIUserInterfaceStyleUnspecified;
}
} else {
NSLog(@"UserInterfaceStyle not supported below iOS 13");
}
}
- (void)setTintColor:(UIColor *)tintColor
{
super.tintColor = tintColor;
}
- (void)setFollowsUserLocation:(BOOL)followsUserLocation
{
_followUserLocation = followsUserLocation;
}
- (void)setUserLocationCalloutEnabled:(BOOL)calloutEnabled
{
_userLocationCalloutEnabled = calloutEnabled;
}
- (void)setHandlePanDrag:(BOOL)handleMapDrag {
for (UIGestureRecognizer *recognizer in [self gestureRecognizers]) {
if ([recognizer isKindOfClass:[UIPanGestureRecognizer class]]) {
recognizer.enabled = handleMapDrag;
break;
}
}
}
- (void)setRegion:(MKCoordinateRegion)region animated:(BOOL)animated
{
// If location is invalid, abort
if (!CLLocationCoordinate2DIsValid(region.center)) {
return;
}
// If new span values are nil, use old values instead
if (!region.span.latitudeDelta) {
region.span.latitudeDelta = self.region.span.latitudeDelta;
}
if (!region.span.longitudeDelta) {
region.span.longitudeDelta = self.region.span.longitudeDelta;
}
// Animate/move to new position
[super setRegion:region animated:animated];
}
- (void)setInitialRegion:(MKCoordinateRegion)initialRegion {
if (!_initialRegionSet) {
_initialRegionSet = YES;
[self setRegion:initialRegion animated:NO];
}
}
- (void)setCamera:(MKMapCamera*)camera animated:(BOOL)animated
{
[super setCamera:camera animated:animated];
}
- (void)setInitialCamera:(MKMapCamera*)initialCamera {
if (!_initialCameraSet) {
_initialCameraSet = YES;
[self setCamera:initialCamera animated:NO];
}
}
- (void)setCacheEnabled:(BOOL)cacheEnabled {
_cacheEnabled = cacheEnabled;
if (self.cacheEnabled && self.cacheImageView.image == nil) {
self.loadingView.hidden = NO;
[self.activityIndicatorView startAnimating];
}
else {
if (_loadingView != nil) {
self.loadingView.hidden = YES;
}
}
}
- (void)setLoadingEnabled:(BOOL)loadingEnabled {
_loadingEnabled = loadingEnabled;
if (!self.hasShownInitialLoading) {
self.loadingView.hidden = !self.loadingEnabled;
}
else {
if (_loadingView != nil) {
self.loadingView.hidden = YES;
}
}
}
- (UIColor *)loadingBackgroundColor {
return self.loadingView.backgroundColor;
}
- (void)setLoadingBackgroundColor:(UIColor *)loadingBackgroundColor {
self.loadingView.backgroundColor = loadingBackgroundColor;
}
- (UIColor *)loadingIndicatorColor {
return self.activityIndicatorView.color;
}
- (void)setLoadingIndicatorColor:(UIColor *)loadingIndicatorColor {
self.activityIndicatorView.color = loadingIndicatorColor;
}
- (void)setCameraZoomRange:(NSDictionary *)cameraZoomRange {
if (@available(iOS 13.0, *)) {
if (cameraZoomRange == nil) {
cameraZoomRange = @{};
}
NSNumber *minValue = cameraZoomRange[@"minCenterCoordinateDistance"];
NSNumber *maxValue = cameraZoomRange[@"maxCenterCoordinateDistance"];
if (minValue == nil && maxValue == nil) {
self.legacyZoomConstraintsEnabled = YES;
MKMapCameraZoomRange *defaultZoomRange = [[MKMapCameraZoomRange alloc] initWithMinCenterCoordinateDistance:MKMapCameraZoomDefault maxCenterCoordinateDistance:MKMapCameraZoomDefault];
[super setCameraZoomRange:defaultZoomRange animated:NO];
return;
}
MKMapCameraZoomRange *zoomRange = nil;
if (minValue != nil && maxValue != nil) {
zoomRange = [[MKMapCameraZoomRange alloc] initWithMinCenterCoordinateDistance:[minValue doubleValue] maxCenterCoordinateDistance:[maxValue doubleValue]];
} else if (minValue != nil) {
zoomRange = [[MKMapCameraZoomRange alloc] initWithMinCenterCoordinateDistance:[minValue doubleValue]];
} else if (maxValue != nil) {
zoomRange = [[MKMapCameraZoomRange alloc] initWithMaxCenterCoordinateDistance:[maxValue doubleValue]];
}
BOOL animated = [cameraZoomRange[@"animated"] boolValue];
self.legacyZoomConstraintsEnabled = NO;
[super setCameraZoomRange:zoomRange animated:animated];
}
}
// Include properties of MKMapView which are only available on iOS 9+
// and check if their selector is available before calling super method.
- (void)setShowsCompass:(BOOL)showsCompass {
if (self.overlayCompassButton != nil) {
self.overlayCompassButton.compassVisibility = showsCompass ? MKFeatureVisibilityAdaptive : MKFeatureVisibilityHidden;
}
if ([MKMapView instancesRespondToSelector:@selector(setShowsCompass:)]) {
[super setShowsCompass:showsCompass];
}
}
- (BOOL)showsCompass {
if ([MKMapView instancesRespondToSelector:@selector(showsCompass)]) {
return [super showsCompass];
} else {
return NO;
}
}
- (void)setShowsScale:(BOOL)showsScale {
if ([MKMapView instancesRespondToSelector:@selector(setShowsScale:)]) {
[super setShowsScale:showsScale];
}
}
- (BOOL)showsScale {
if ([MKMapView instancesRespondToSelector:@selector(showsScale)]) {
return [super showsScale];
} else {
return NO;
}
}
- (void)setShowsTraffic:(BOOL)showsTraffic {
if ([MKMapView instancesRespondToSelector:@selector(setShowsTraffic:)]) {
[super setShowsTraffic:showsTraffic];
}
}
- (BOOL)showsTraffic {
if ([MKMapView instancesRespondToSelector:@selector(showsTraffic)]) {
return [super showsTraffic];
} else {
return NO;
}
}
- (void)setScrollEnabled:(BOOL)scrollEnabled {
self.shouldScrollEnabled = [NSNumber numberWithBool:scrollEnabled];
[self updateScrollEnabled];
}
- (void)updateScrollEnabled {
if (self.cacheEnabled) {
[super setScrollEnabled:NO];
}
else if (self.shouldScrollEnabled != nil) {
[super setScrollEnabled:[self.shouldScrollEnabled boolValue]];
}
}
- (void)setZoomEnabled:(BOOL)zoomEnabled {
self.shouldZoomEnabled = [NSNumber numberWithBool:zoomEnabled];
[self updateZoomEnabled];
}
- (void)updateZoomEnabled {
if (self.cacheEnabled) {
[super setZoomEnabled: NO];
}
else if (self.shouldZoomEnabled != nil) {
[super setZoomEnabled:[self.shouldZoomEnabled boolValue]];
}
}
- (void)cacheViewIfNeeded {
// https://github.com/react-native-maps/react-native-maps/issues/3100
// Do nothing if app is not active
if ([[UIApplication sharedApplication] applicationState] != UIApplicationStateActive) {
return;
}
if (self.hasShownInitialLoading) {
if (!self.cacheEnabled) {
if (_cacheImageView != nil) {
self.cacheImageView.hidden = YES;
self.cacheImageView.image = nil;
}
}
else {
self.cacheImageView.image = nil;
self.cacheImageView.hidden = YES;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.01 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
self.cacheImageView.image = nil;
self.cacheImageView.hidden = YES;
UIGraphicsBeginImageContextWithOptions(self.bounds.size, self.opaque, 0.0);
[self.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
self.cacheImageView.image = image;
self.cacheImageView.hidden = NO;
});
}
[self updateScrollEnabled];
[self updateZoomEnabled];
[self updateLegalLabelInsets];
}
}
- (void)updateLegalLabelInsets {
if (_legalLabel) {
dispatch_async(dispatch_get_main_queue(), ^{
CGRect frame = self->_legalLabel.frame;
if (self->_legalLabelInsets.left) {
frame.origin.x = self->_legalLabelInsets.left;
} else if (self->_legalLabelInsets.right) {
frame.origin.x = self.frame.size.width - self->_legalLabelInsets.right - frame.size.width;
}
if (self->_legalLabelInsets.top) {
frame.origin.y = self->_legalLabelInsets.top;
} else if (self->_legalLabelInsets.bottom) {
frame.origin.y = self.frame.size.height - self->_legalLabelInsets.bottom - frame.size.height;
}
self->_legalLabel.frame = frame;
});
}
}
- (void)setLegalLabelInsets:(UIEdgeInsets)legalLabelInsets {
_legalLabelInsets = legalLabelInsets;
[self updateLegalLabelInsets];
}
- (void)setMapPadding:(UIEdgeInsets)mapPadding {
self.layoutMargins = mapPadding;
}
- (UIEdgeInsets)mapPadding {
return self.layoutMargins;
}
- (void)beginLoading {
if ((!self.hasShownInitialLoading && self.loadingEnabled) || (self.cacheEnabled && self.cacheImageView.image == nil)) {
self.loadingView.hidden = NO;
[self.activityIndicatorView startAnimating];
}
else {
if (_loadingView != nil) {
self.loadingView.hidden = YES;
}
}
}
- (void)finishLoading {
self.hasShownInitialLoading = YES;
if (_loadingView != nil) {
self.loadingView.hidden = YES;
}
[self cacheViewIfNeeded];
}
- (UIActivityIndicatorView *)activityIndicatorView {
if (_activityIndicatorView == nil) {
_activityIndicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
_activityIndicatorView.center = self.loadingView.center;
_activityIndicatorView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin;
_activityIndicatorView.color = [UIColor colorWithRed:96.f/255.f green:96.f/255.f blue:96.f/255.f alpha:1.f]; // defaults to #606060
}
[self.loadingView addSubview:_activityIndicatorView];
return _activityIndicatorView;
}
- (UIView *)loadingView {
if (_loadingView == nil) {
_loadingView = [[UIView alloc] initWithFrame:self.bounds];
_loadingView.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
_loadingView.backgroundColor = [UIColor whiteColor]; // defaults to #FFFFFF
[self addSubview:_loadingView];
_loadingView.hidden = NO;
}
return _loadingView;
}
- (UIImageView *)cacheImageView {
if (_cacheImageView == nil) {
_cacheImageView = [[UIImageView alloc] initWithFrame:self.bounds];
_cacheImageView.contentMode = UIViewContentModeCenter;
_cacheImageView.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
[self addSubview:self.cacheImageView];
_cacheImageView.hidden = YES;
}
return _cacheImageView;
}
- (void)layoutSubviews {
[super layoutSubviews];
[self cacheViewIfNeeded];
if (self.overlayCompassButton == nil) {
for (UIView *subview in self.subviews) {
if (![NSStringFromClass(subview.class) isEqualToString:@"MKPassThroughStackView"]) continue;
self.overlayCompassButton = [MKCompassButton compassButtonWithMapView:self];
[subview addSubview:self.overlayCompassButton];
self.overlayCompassButton.frame = CGRectMake(self.overlayCompassButton.frame.origin.x + _compassOffset.x, self.overlayCompassButton.frame.origin.y + _compassOffset.y, self.overlayCompassButton.frame.size.width, self.overlayCompassButton.frame.size.height);
break;
}
}
if (self.defaultCompassButton == nil) {
for (UIView *subview in self.subviews) {
if (![NSStringFromClass(subview.class) isEqualToString:@"MKPassThroughStackView"]) continue;
for (UIView *subview2 in subview.subviews) {
if (![NSStringFromClass(subview2.class) isEqualToString:@"MKCompassView"]) continue;
self.defaultCompassButton = subview2;
self.defaultCompassButton.hidden = YES;
}
break;
}
}
}
// based on https://medium.com/@dmytrobabych/getting-actual-rotation-and-zoom-level-for-mapkit-mkmapview-e7f03f430aa9
- (CGFloat)getZoomLevel {
CGFloat cameraAngle = self.camera.heading;
if (cameraAngle > 270) {
cameraAngle = 360 - cameraAngle;
} else if (cameraAngle > 90) {
cameraAngle = fabs(cameraAngle - 180);
}
CGFloat angleRad = M_PI * cameraAngle / 180; // map rotation in radians
CGFloat width = self.frame.size.width;
CGFloat height = self.frame.size.height;
CGFloat heightOffset = 20; // the offset (status bar height) which is taken by MapKit into consideration to calculate visible area height
// calculating Longitude span corresponding to normal (non-rotated) width
CGFloat spanStraight = width * self.region.span.longitudeDelta / (width * cos(angleRad) + (height - heightOffset) * sin(angleRad));
int normalizingFactor = 512;
return log2(360 * ((width / normalizingFactor) / spanStraight));
}
@end
@@ -0,0 +1,18 @@
//
// Created by Leland Richardson on 12/27/15.
// Copyright (c) 2015 Facebook. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <React/RCTView.h>
@interface AIRMapCallout : RCTView
@property (nonatomic, assign) BOOL tooltip;
@property (nonatomic, copy) RCTBubblingEventBlock onPress;
@property (nonatomic, assign) BOOL alphaHitTest;
- (BOOL) isPointInside:(CGPoint)pointInCallout;
@end
@@ -0,0 +1,30 @@
//
// Created by Leland Richardson on 12/27/15.
// Copyright (c) 2015 Facebook. All rights reserved.
//
#import "AIRMapCallout.h"
@implementation AIRMapCallout
- (BOOL) isPointInside:(CGPoint)pointInCallout {
if (!self.alphaHitTest)
return TRUE;
CGFloat alpha = [self alphaOfPoint:pointInCallout];
return alpha >= 0.01;
}
- (CGFloat) alphaOfPoint:(CGPoint)point {
unsigned char pixel[4] = {0};
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(pixel, 1, 1, 8, 4, colorSpace, kCGBitmapAlphaInfoMask & kCGImageAlphaPremultipliedLast);
CGContextTranslateCTM(context, -point.x, -point.y);
[self.layer renderInContext:context];
CGContextRelease(context);
CGColorSpaceRelease(colorSpace);
return pixel[3]/255.0;
}
@end
@@ -0,0 +1,10 @@
//
// Created by Leland Richardson on 12/27/15.
// Copyright (c) 2015 Facebook. All rights reserved.
//
#import <React/RCTViewManager.h>
@interface AIRMapCalloutManager : RCTViewManager
@end
@@ -0,0 +1,38 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import "AIRMapCalloutManager.h"
#import <React/RCTBridge.h>
#import <React/RCTConvert.h>
#import <React/RCTConvert+CoreLocation.h>
#import <React/RCTEventDispatcher.h>
#import <React/RCTViewManager.h>
#import <React/UIView+React.h>
#import "AIRMapMarker.h"
#import "AIRMapCallout.h"
@interface AIRMapCalloutManager()
@end
@implementation AIRMapCalloutManager
RCT_EXPORT_MODULE()
- (UIView *)view
{
return [AIRMapCallout new];
}
RCT_EXPORT_VIEW_PROPERTY(tooltip, BOOL)
RCT_EXPORT_VIEW_PROPERTY(onPress, RCTBubblingEventBlock)
RCT_EXPORT_VIEW_PROPERTY(alphaHitTest, BOOL)
@end
@@ -0,0 +1,15 @@
//
// AIRMapCalloutSubview.h
// AirMaps
//
// Created by Denis Oblogin on 10/8/18.
//
//
#import <UIKit/UIKit.h>
#import <React/RCTView.h>
@interface AIRMapCalloutSubview : UIView
@property (nonatomic, copy) RCTBubblingEventBlock onPress;
@end
@@ -0,0 +1,15 @@
//
// AIRMapCalloutSubview.m
// AirMaps
//
// Created by Denis Oblogin on 10/8/18.
//
//
#import "AIRMapCalloutSubview.h"
#import <React/RCTUtils.h>
#import <React/RCTView.h>
#import <React/RCTBridge.h>
@implementation AIRMapCalloutSubview
@end
@@ -0,0 +1,14 @@
//
// AIRMapCalloutSubviewManager.h
// AirMaps
//
// Created by Denis Oblogin on 10/8/18.
//
//
#import <React/RCTViewManager.h>
@interface AIRMapCalloutSubviewManager : RCTViewManager
@end
@@ -0,0 +1,24 @@
//
// AIRMapCalloutSubviewManager.m
// AirMaps
//
// Created by Denis Oblogin on 10/8/18.
//
//
#import "AIRMapCalloutSubviewManager.h"
#import "AIRMapCalloutSubview.h"
#import <React/RCTView.h>
@implementation AIRMapCalloutSubviewManager
RCT_EXPORT_MODULE()
- (UIView *)view
{
AIRMapCalloutSubview *calloutSubview = [AIRMapCalloutSubview new];
return calloutSubview;
}
RCT_EXPORT_VIEW_PROPERTY(onPress, RCTBubblingEventBlock)
@end
@@ -0,0 +1,44 @@
//
// Created by Leland Richardson on 12/27/15.
// Copyright (c) 2015 Facebook. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#import <UIKit/UIKit.h>
#import <React/RCTComponent.h>
#import <React/RCTView.h>
#import "AIRMapCoordinate.h"
#import "AIRMap.h"
#import "RCTConvert+AirMap.h"
@interface AIRMapCircle: MKAnnotationView <MKOverlay>
@property (nonatomic, weak) AIRMap *map;
@property (nonatomic, strong) MKCircle *circle;
@property (nonatomic, strong) MKCircleRenderer *renderer;
@property (nonatomic, assign) CLLocationCoordinate2D centerCoordinate;
@property (nonatomic, assign) CLLocationDistance radius;
@property (nonatomic, strong) UIColor *fillColor;
@property (nonatomic, strong) UIColor *strokeColor;
@property (nonatomic, assign) CGFloat strokeWidth;
@property (nonatomic, assign) CGFloat miterLimit;
@property (nonatomic, assign) CGLineCap lineCap;
@property (nonatomic, assign) CGLineJoin lineJoin;
@property (nonatomic, assign) CGFloat lineDashPhase;
@property (nonatomic, strong) NSArray <NSNumber *> *lineDashPattern;
#pragma mark MKOverlay protocol
@property(nonatomic, readonly) CLLocationCoordinate2D coordinate;
@property(nonatomic, readonly) MKMapRect boundingMapRect;
- (BOOL)intersectsMapRect:(MKMapRect)mapRect;
- (BOOL)canReplaceMapContent;
@end
@@ -0,0 +1,117 @@
//
// Created by Leland Richardson on 12/27/15.
// Copyright (c) 2015 Facebook. All rights reserved.
//
#import "AIRMapCircle.h"
#import <React/UIView+React.h>
@implementation AIRMapCircle {
BOOL _radiusSet;
BOOL _centerSet;
}
- (void)setFillColor:(UIColor *)fillColor {
_fillColor = fillColor;
[self update];
}
- (void)setStrokeColor:(UIColor *)strokeColor {
_strokeColor = strokeColor;
[self update];
}
- (void)setStrokeWidth:(CGFloat)strokeWidth {
_strokeWidth = strokeWidth;
[self update];
}
- (void)setLineJoin:(CGLineJoin)lineJoin {
_lineJoin = lineJoin;
[self update];
}
- (void)setLineCap:(CGLineCap)lineCap {
_lineCap = lineCap;
[self update];
}
- (void)setMiterLimit:(CGFloat)miterLimit {
_miterLimit = miterLimit;
[self update];
}
- (void)setLineDashPhase:(CGFloat)lineDashPhase {
_lineDashPhase = lineDashPhase;
[self update];
}
- (void)setLineDashPattern:(NSArray <NSNumber *> *)lineDashPattern {
_lineDashPattern = lineDashPattern;
[self update];
}
- (void)setRadius:(CLLocationDistance)radius {
_radius = radius;
_radiusSet = YES;
[self createCircleAndRendererIfPossible];
[self update];
}
- (void)setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate{
_centerCoordinate = centerCoordinate;
_centerSet = YES;
[self createCircleAndRendererIfPossible];
[self update];
}
- (void) createCircleAndRendererIfPossible
{
if (!_centerSet || !_radiusSet) return;
self.circle = [MKCircle circleWithCenterCoordinate:_centerCoordinate radius:_radius];
self.renderer = [[MKCircleRenderer alloc] initWithCircle:self.circle];
}
- (void) update
{
if (!_renderer) return;
_renderer.fillColor = _fillColor;
_renderer.strokeColor = _strokeColor;
_renderer.lineWidth = _strokeWidth;
_renderer.lineCap = _lineCap;
_renderer.lineJoin = _lineJoin;
_renderer.miterLimit = _miterLimit;
_renderer.lineDashPhase = _lineDashPhase;
_renderer.lineDashPattern = _lineDashPattern;
if (_map == nil) return;
[_map removeOverlay:self];
[_map addOverlay:self];
}
#pragma mark MKOverlay implementation
- (CLLocationCoordinate2D) coordinate
{
return self.circle.coordinate;
}
- (MKMapRect) boundingMapRect
{
return self.circle.boundingMapRect;
}
- (BOOL)intersectsMapRect:(MKMapRect)mapRect
{
BOOL answer = [self.circle intersectsMapRect:mapRect];
return answer;
}
- (BOOL)canReplaceMapContent
{
return NO;
}
@end
@@ -0,0 +1,10 @@
//
// Created by Leland Richardson on 12/27/15.
// Copyright (c) 2015 Facebook. All rights reserved.
//
#import <React/RCTViewManager.h>
@interface AIRMapCircleManager : RCTViewManager
@end
@@ -0,0 +1,51 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import "AIRMapCircleManager.h"
#import <React/RCTBridge.h>
#import <React/RCTConvert.h>
#import <React/RCTConvert+CoreLocation.h>
#import <React/RCTEventDispatcher.h>
#import <React/RCTViewManager.h>
#import <React/UIView+React.h>
#import "AIRMapMarker.h"
#import "AIRMapCircle.h"
@interface AIRMapCircleManager()
@end
@implementation AIRMapCircleManager
RCT_EXPORT_MODULE()
- (UIView *)view
{
AIRMapCircle *circle = [AIRMapCircle new];
return circle;
}
RCT_REMAP_VIEW_PROPERTY(center, centerCoordinate, CLLocationCoordinate2D)
RCT_EXPORT_VIEW_PROPERTY(radius, CLLocationDistance)
RCT_EXPORT_VIEW_PROPERTY(fillColor, UIColor)
RCT_EXPORT_VIEW_PROPERTY(strokeColor, UIColor)
RCT_EXPORT_VIEW_PROPERTY(strokeWidth, CGFloat)
RCT_EXPORT_VIEW_PROPERTY(lineCap, CGLineCap)
RCT_EXPORT_VIEW_PROPERTY(lineJoin, CGLineJoin)
RCT_EXPORT_VIEW_PROPERTY(miterLimit, CGFloat)
RCT_EXPORT_VIEW_PROPERTY(lineDashPhase, CGFloat)
RCT_EXPORT_VIEW_PROPERTY(lineDashPattern, NSArray)
// NOTE(lmr):
// for now, onPress events for overlays will be left unimplemented. Seems it is possible with some work, but
// it is difficult to achieve in both ios and android so I decided to leave it out.
//RCT_EXPORT_VIEW_PROPERTY(onPress, RCTBubblingEventBlock)
@end
@@ -0,0 +1,13 @@
//
// Created by Leland Richardson on 12/27/15.
// Copyright (c) 2015 Facebook. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
@interface AIRMapCoordinate : NSObject
@property (nonatomic, assign) CLLocationCoordinate2D coordinate;
@end
@@ -0,0 +1,10 @@
//
// Created by Leland Richardson on 12/27/15.
// Copyright (c) 2015 Facebook. All rights reserved.
//
#import "AIRMapCoordinate.h"
@implementation AIRMapCoordinate
@end
@@ -0,0 +1,36 @@
//
// AIRMapLocalTile.h
// AirMaps
//
// Created by Peter Zavadsky on 01/12/2017.
// Copyright © 2017 Christopher. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#import <UIKit/UIKit.h>
#import <React/RCTComponent.h>
#import <React/RCTView.h>
#import "AIRMapCoordinate.h"
#import "AIRMap.h"
#import "RCTConvert+AirMap.h"
@interface AIRMapLocalTile : MKAnnotationView <MKOverlay>
@property (nonatomic, weak) AIRMap *map;
@property (nonatomic, strong) MKTileOverlay *tileOverlay;
@property (nonatomic, strong) MKTileOverlayRenderer *renderer;
@property (nonatomic, copy) NSString *pathTemplate;
@property (nonatomic, assign) CGFloat tileSize;
#pragma mark MKOverlay protocol
@property(nonatomic, readonly) CLLocationCoordinate2D coordinate;
@property(nonatomic, readonly) MKMapRect boundingMapRect;
//- (BOOL)intersectsMapRect:(MKMapRect)mapRect;
- (BOOL)canReplaceMapContent;
@end
@@ -0,0 +1,68 @@
//
// AIRMapLocalTile.m
// AirMaps
//
// Created by Peter Zavadsky on 01/12/2017.
// Copyright © 2017 Christopher. All rights reserved.
//
#import "AIRMapLocalTile.h"
#import <React/UIView+React.h>
#import "AIRMapLocalTileOverlay.h"
@implementation AIRMapLocalTile {
BOOL _pathTemplateSet;
BOOL _tileSizeSet;
}
- (void)setPathTemplate:(NSString *)pathTemplate{
_pathTemplate = pathTemplate;
_pathTemplateSet = YES;
[self createTileOverlayAndRendererIfPossible];
[self update];
}
- (void)setTileSize:(CGFloat)tileSize{
_tileSize = tileSize;
_tileSizeSet = YES;
[self createTileOverlayAndRendererIfPossible];
[self update];
}
- (void) createTileOverlayAndRendererIfPossible
{
if (!_pathTemplateSet || !_tileSizeSet) return;
self.tileOverlay = [[AIRMapLocalTileOverlay alloc] initWithURLTemplate:self.pathTemplate];
self.tileOverlay.canReplaceMapContent = YES;
self.tileOverlay.tileSize = CGSizeMake(_tileSize, _tileSize);
self.renderer = [[MKTileOverlayRenderer alloc] initWithTileOverlay:self.tileOverlay];
}
- (void) update
{
if (!_renderer) return;
if (_map == nil) return;
[_map removeOverlay:self];
[_map addOverlay:self level:MKOverlayLevelAboveLabels];
}
#pragma mark MKOverlay implementation
- (CLLocationCoordinate2D) coordinate
{
return self.tileOverlay.coordinate;
}
- (MKMapRect) boundingMapRect
{
return self.tileOverlay.boundingMapRect;
}
- (BOOL)canReplaceMapContent
{
return self.tileOverlay.canReplaceMapContent;
}
@end
@@ -0,0 +1,13 @@
//
// AIRMapLocalTileManager.h
// AirMaps
//
// Created by Peter Zavadsky on 01/12/2017.
// Copyright © 2017 Christopher. All rights reserved.
//
#import <React/RCTViewManager.h>
@interface AIRMapLocalTileManager : RCTViewManager
@end
@@ -0,0 +1,38 @@
//
// AIRMapLocalTileManager.m
// AirMaps
//
// Created by Peter Zavadsky on 01/12/2017.
// Copyright © 2017 Christopher. All rights reserved.
//
#import <React/RCTBridge.h>
#import <React/RCTConvert.h>
#import <React/RCTConvert+CoreLocation.h>
#import <React/RCTEventDispatcher.h>
#import <React/RCTViewManager.h>
#import <React/UIView+React.h>
#import "AIRMapMarker.h"
#import "AIRMapLocalTile.h"
#import "AIRMapLocalTileManager.h"
@interface AIRMapLocalTileManager()
@end
@implementation AIRMapLocalTileManager
RCT_EXPORT_MODULE()
- (UIView *)view
{
AIRMapLocalTile *tile = [AIRMapLocalTile new];
return tile;
}
RCT_EXPORT_VIEW_PROPERTY(pathTemplate, NSString)
RCT_EXPORT_VIEW_PROPERTY(tileSize, CGFloat)
@end
@@ -0,0 +1,12 @@
//
// AIRMapLocalTileOverlay.h
// Pods
//
// Created by Peter Zavadsky on 04/12/2017.
//
#import <MapKit/MapKit.h>
@interface AIRMapLocalTileOverlay : MKTileOverlay
@end
@@ -0,0 +1,31 @@
//
// AIRMapLocalTileOverlay.m
// Pods-AirMapsExplorer
//
// Created by Peter Zavadsky on 04/12/2017.
//
#import "AIRMapLocalTileOverlay.h"
@interface AIRMapLocalTileOverlay ()
@end
@implementation AIRMapLocalTileOverlay
-(void)loadTileAtPath:(MKTileOverlayPath)path result:(void (^)(NSData *, NSError *))result {
NSMutableString *tileFilePath = [self.URLTemplate mutableCopy];
[tileFilePath replaceOccurrencesOfString: @"{x}" withString:[NSString stringWithFormat:@"%li", (long)path.x] options:0 range:NSMakeRange(0, tileFilePath.length)];
[tileFilePath replaceOccurrencesOfString:@"{y}" withString:[NSString stringWithFormat:@"%li", (long)path.y] options:0 range:NSMakeRange(0, tileFilePath.length)];
[tileFilePath replaceOccurrencesOfString:@"{z}" withString:[NSString stringWithFormat:@"%li", (long)path.z] options:0 range:NSMakeRange(0, tileFilePath.length)];
if ([[NSFileManager defaultManager] fileExistsAtPath:tileFilePath]) {
NSData* tile = [NSData dataWithContentsOfFile:tileFilePath];
result(tile,nil);
} else {
result(nil, nil);
}
}
@end
@@ -0,0 +1,29 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import <React/RCTViewManager.h>
#import "AIRMap.h"
#define MERCATOR_RADIUS 85445659.44705395
#define MERCATOR_OFFSET 268435456
@interface AIRMapManager : RCTViewManager
- (void)setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate
zoomLevel:(double)zoomLevel
animated:(BOOL)animated
mapView:(AIRMap *)mapView;
- (MKCoordinateRegion)coordinateRegionWithMapView:(AIRMap *)mapView
centerCoordinate:(CLLocationCoordinate2D)centerCoordinate
andZoomLevel:(double)zoomLevel;
- (double) zoomLevel:(AIRMap *)mapView;
@end
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,63 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import "AIRMapMarker.h"
#import "AIRMapCallout.h"
#import <MapKit/MapKit.h>
#import <UIKit/UIKit.h>
#import <React/RCTComponent.h>
#import "AIRMap.h"
#import "SMCalloutView.h"
#import "RCTConvert+AirMap.h"
@class RCTBridge;
@interface AIRMapMarker : MKAnnotationView <MKAnnotation>
@property (nonatomic, strong) AIRMapCallout *calloutView;
@property (nonatomic, weak) AIRMap *map;
@property (nonatomic, weak) RCTBridge *bridge;
@property (nonatomic, strong) NSString *identifier;
@property (nonatomic, copy) NSString *imageSrc;
@property (nonatomic, copy) NSString *title;
@property (nonatomic, copy) NSString *subtitle;
@property (nonatomic, assign) CLLocationCoordinate2D coordinate;
@property (nonatomic, strong) UIColor *pinColor;
@property (nonatomic, assign) NSInteger zIndex;
@property (nonatomic, assign) double opacity;
@property (nonatomic, assign) BOOL isPreselected;
@property (nonatomic, assign) MKFeatureVisibility titleVisibility;
@property (nonatomic, assign) MKFeatureVisibility subtitleVisibility;
@property (nonatomic, assign) BOOL useLegacyPinView;
@property (nonatomic, copy) RCTBubblingEventBlock onPress;
@property (nonatomic, copy) RCTDirectEventBlock onSelect;
@property (nonatomic, copy) RCTDirectEventBlock onDeselect;
@property (nonatomic, copy) RCTDirectEventBlock onCalloutPress;
@property (nonatomic, copy) RCTDirectEventBlock onDragStart;
@property (nonatomic, copy) RCTDirectEventBlock onDrag;
@property (nonatomic, copy) RCTDirectEventBlock onDragEnd;
- (MKAnnotationView *)getAnnotationView;
- (void)fillCalloutView:(SMCalloutView *)calloutView;
- (BOOL)shouldShowCalloutView;
- (void)showCalloutView;
- (void)hideCalloutView;
- (void)addTapGestureRecognizer;
- (void)setUseLegacyPinView:(BOOL)value;
@end
@interface AIREmptyCalloutBackgroundView : SMCalloutBackgroundView
@end
@@ -0,0 +1,393 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import "AIRMapMarker.h"
#import <React/RCTBridge.h>
#import <React/RCTEventDispatcher.h>
#import <React/RCTImageLoaderProtocol.h>
#import <React/RCTUtils.h>
#import <React/UIView+React.h>
NSInteger const AIR_CALLOUT_OPEN_ZINDEX_BASELINE = 999;
@implementation AIREmptyCalloutBackgroundView
@end
@implementation AIRMapMarker {
BOOL _hasSetCalloutOffset;
RCTImageLoaderCancellationBlock _reloadImageCancellationBlock;
MKMarkerAnnotationView *_markerView;
MKPinAnnotationView *_pinView;
BOOL _calloutIsOpen;
NSInteger _zIndexBeforeOpen;
BOOL _useLegacyPinView;
}
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self.layer addObserver:self forKeyPath:@"zPosition" options:NSKeyValueObservingOptionNew context:nil];
}
return self;
}
- (void)reactSetFrame:(CGRect)frame
{
// Make sure we use the image size when available
CGSize size = self.image ? self.image.size : frame.size;
CGRect bounds = {CGPointZero, size};
// The MapView is basically in charge of figuring out the center position of the marker view. If the view changed in
// height though, we need to compensate in such a way that the bottom of the marker stays at the same spot on the
// map.
CGFloat dy = (bounds.size.height - self.bounds.size.height) / 2;
CGPoint center = (CGPoint){ self.center.x, self.center.y - dy };
// Avoid crashes due to nan coords
if (isnan(center.x) || isnan(center.y) ||
isnan(bounds.origin.x) || isnan(bounds.origin.y) ||
isnan(bounds.size.width) || isnan(bounds.size.height)) {
RCTLogError(@"Invalid layout for (%@)%@. position: %@. bounds: %@",
self.reactTag, self, NSStringFromCGPoint(center), NSStringFromCGRect(bounds));
return;
}
self.center = center;
self.bounds = bounds;
}
- (void)insertReactSubview:(id<RCTComponent>)subview atIndex:(NSInteger)atIndex {
if ([subview isKindOfClass:[AIRMapCallout class]]) {
self.calloutView = (AIRMapCallout *)subview;
} else {
[super insertReactSubview:(UIView *)subview atIndex:atIndex];
}
}
- (void)removeReactSubview:(id<RCTComponent>)subview {
if ([subview isKindOfClass:[AIRMapCallout class]] && self.calloutView == subview) {
self.calloutView = nil;
} else {
[super removeReactSubview:(UIView *)subview];
}
}
- (MKAnnotationView *)getAnnotationView
{
if ([self shouldUsePinView]) {
// In this case, we want to render a platform "default" legacy marker.
if (_pinView == nil && _useLegacyPinView) {
_pinView = [[MKPinAnnotationView alloc] initWithAnnotation:self reuseIdentifier: nil];
[self addGestureRecognizerToView:_pinView];
_pinView.annotation = self;
if ([_pinView respondsToSelector:@selector(setPinTintColor:)]) {
_pinView.pinTintColor = self.pinColor;
}
_pinView.draggable = self.draggable;
_pinView.layer.zPosition = self.zIndex;
return _pinView;
}
if (_markerView == nil && !_useLegacyPinView) {
_markerView = [[MKMarkerAnnotationView alloc] initWithAnnotation:self reuseIdentifier: nil];
[self addGestureRecognizerToView:_markerView];
_markerView.annotation = self;
_markerView.draggable = self.draggable;
_markerView.layer.zPosition = self.zIndex;
_markerView.markerTintColor = self.pinColor;
_markerView.titleVisibility = self.titleVisibility ?: MKFeatureVisibilityHidden;
_markerView.subtitleVisibility = self.subtitleVisibility ?: MKFeatureVisibilityHidden;
}
return _markerView ?: _pinView;
} else {
// If it has subviews, it means we are wanting to render a custom marker with arbitrary react views.
// if it has a non-null image, it means we want to render a custom marker with the image.
// In either case, we want to return the AIRMapMarker since it is both an MKAnnotation and an
// MKAnnotationView all at the same time.
self.layer.zPosition = self.zIndex;
return self;
}
}
- (void)fillCalloutView:(SMCalloutView *)calloutView
{
// Set everything necessary on the calloutView before it becomes visible.
// Apply the MKAnnotationView's desired calloutOffset (from the top-middle of the view)
if ([self shouldUsePinView] && !_hasSetCalloutOffset && _useLegacyPinView) {
calloutView.calloutOffset = CGPointMake(-8,0);
} else {
calloutView.calloutOffset = self.calloutOffset;
}
if (self.calloutView) {
calloutView.title = nil;
calloutView.subtitle = nil;
if (self.calloutView.tooltip) {
// if tooltip is true, then the user wants their react view to be the "tooltip" as wwell, so we set
// the background view to something empty/transparent
calloutView.backgroundView = [AIREmptyCalloutBackgroundView new];
} else {
// the default tooltip look is wanted, and the user is just filling the content with their react subviews.
// as a result, we use the default "masked" background view.
calloutView.backgroundView = [SMCalloutMaskedBackgroundView new];
}
// when this is set, the callout's content will be whatever react views the user has put as the callout's
// children.
calloutView.contentView = self.calloutView;
} else {
// if there is no calloutView, it means the user wants to use the default callout behavior with title/subtitle
// pairs.
calloutView.title = self.title;
calloutView.subtitle = self.subtitle;
calloutView.contentView = nil;
calloutView.backgroundView = [SMCalloutMaskedBackgroundView new];
}
}
- (void)showCalloutView
{
_calloutIsOpen = YES;
[self setZIndex:_zIndexBeforeOpen];
MKAnnotationView *annotationView = [self getAnnotationView];
[self setSelected:YES animated:NO];
[self.map selectAnnotation:self animated:NO];
id event = @{
@"action": @"marker-select",
@"id": self.identifier ?: @"unknown",
@"coordinate": @{
@"latitude": @(self.coordinate.latitude),
@"longitude": @(self.coordinate.longitude)
}
};
if (self.map.onMarkerSelect) self.map.onMarkerSelect(event);
if (self.onSelect) self.onSelect(event);
if (![self shouldShowCalloutView]) {
// no callout to show
return;
}
[self fillCalloutView:self.map.calloutView];
// This is where we present our custom callout view... MapKit's built-in callout doesn't have the flexibility
// we need, but a lot of work was done by Nick Farina to make this identical to MapKit's built-in.
[self.map.calloutView presentCalloutFromRect:annotationView.bounds
inView:annotationView
constrainedToView:self.map
animated:YES];
}
#pragma mark - Tap Gesture & Events.
- (void)addTapGestureRecognizer {
[self addGestureRecognizerToView:nil];
}
- (void)addGestureRecognizerToView:(UIView *)view {
if (!view) {
view = self;
}
UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(_handleTap:)];
// setting this to NO allows the parent MapView to continue receiving marker selection events
tapGestureRecognizer.cancelsTouchesInView = NO;
[view addGestureRecognizer:tapGestureRecognizer];
}
- (void)_handleTap:(UITapGestureRecognizer *)recognizer {
AIRMapMarker *marker = self;
if (!marker) return;
if (marker.selected) {
CGPoint touchPoint = [recognizer locationInView:marker.map.calloutView];
CGRect bubbleFrame = [self.calloutView convertRect:marker.map.calloutView.bounds toView:marker.map];
CGPoint touchPointReal = [recognizer locationInView:self.calloutView];
UIView *calloutView = [marker.map.calloutView hitTest:touchPoint withEvent:nil];
if (calloutView) {
// the callout (or its subview) got clicked, not the marker
UIWindow* win = [[[UIApplication sharedApplication] windows] firstObject];
AIRMapCalloutSubview* calloutSubview = nil;
UIView* tmp = calloutView;
while (tmp && tmp != win && tmp != self.calloutView && tmp != self.map) {
if ([tmp respondsToSelector:@selector(onPress)]) {
calloutSubview = (AIRMapCalloutSubview*) tmp;
break;
}
tmp = tmp.superview;
}
id event = @{
@"action": calloutSubview ? @"callout-inside-press" : @"callout-press",
@"id": marker.identifier ?: @"unknown",
@"point": @{
@"x": @(touchPointReal.x),
@"y": @(touchPointReal.y),
},
@"frame": @{
@"x": @(bubbleFrame.origin.x),
@"y": @(bubbleFrame.origin.y),
@"width": @(bubbleFrame.size.width),
@"height": @(bubbleFrame.size.height),
}
};
if (calloutSubview) calloutSubview.onPress(event);
if (marker.onCalloutPress) marker.onCalloutPress(event);
if (marker.calloutView && marker.calloutView.onPress) marker.calloutView.onPress(event);
if (marker.map.onCalloutPress) marker.map.onCalloutPress(event);
return;
}
}
// the actual marker got clicked
CGPoint touchPointReal = [recognizer locationInView:self.calloutView];
id event = @{
@"action": @"marker-press",
@"id": marker.identifier ?: @"unknown",
@"coordinate": @{
@"latitude": @(marker.coordinate.latitude),
@"longitude": @(marker.coordinate.longitude)
},
@"position": @{
@"x": @(touchPointReal.x),
@"y": @(touchPointReal.y),
}
};
if (marker.onPress) marker.onPress(event);
if (marker.map.onMarkerPress) marker.map.onMarkerPress(event);
[marker.map selectAnnotation:marker animated:NO];
}
- (void)hideCalloutView
{
_calloutIsOpen = NO;
[self setZIndex:_zIndexBeforeOpen];
// hide the callout view
[self.map.calloutView dismissCalloutAnimated:YES];
[self setSelected:NO animated:NO];
[self.map deselectAnnotation:self animated:NO];
id event = @{
@"action": @"marker-deselect",
@"id": self.identifier ?: @"unknown",
@"coordinate": @{
@"latitude": @(self.coordinate.latitude),
@"longitude": @(self.coordinate.longitude)
}
};
if (self.map.onMarkerDeselect) self.map.onMarkerDeselect(event);
if (self.onDeselect) self.onDeselect(event);
}
- (void)setCalloutOffset:(CGPoint)calloutOffset
{
_hasSetCalloutOffset = YES;
[super setCalloutOffset:calloutOffset];
}
- (BOOL)shouldShowCalloutView
{
return self.calloutView != nil || self.title != nil || self.subtitle != nil;
}
- (BOOL)shouldUsePinView
{
return self.reactSubviews.count == 0 && !self.imageSrc;
}
- (void)setOpacity:(double)opacity
{
[self setAlpha:opacity];
}
- (void)setImageSrc:(NSString *)imageSrc
{
_imageSrc = imageSrc;
if (_reloadImageCancellationBlock) {
_reloadImageCancellationBlock();
_reloadImageCancellationBlock = nil;
}
_reloadImageCancellationBlock = [[_bridge moduleForName:@"ImageLoader"] loadImageWithURLRequest:[RCTConvert NSURLRequest:_imageSrc]
size:self.bounds.size
scale:RCTScreenScale()
clipped:YES
resizeMode:RCTResizeModeCenter
progressBlock:nil
partialLoadBlock:nil
completionBlock:^(NSError *error, UIImage *image) {
if (error) {
// TODO(lmr): do something with the error?
NSLog(@"%@", error);
}
dispatch_async(dispatch_get_main_queue(), ^{
self.image = image;
});
}];
}
- (void)setPinColor:(UIColor *)pinColor
{
_pinColor = pinColor;
if(_useLegacyPinView && [_pinView respondsToSelector:@selector(setPinTintColor:)]) {
_pinView.pinTintColor = _pinColor;
} else {
_markerView.markerTintColor = _pinColor;
}
}
- (void)setZIndex:(NSInteger)zIndex
{
_zIndexBeforeOpen = zIndex;
_zIndex = _calloutIsOpen ? zIndex + AIR_CALLOUT_OPEN_ZINDEX_BASELINE : zIndex;
self.layer.zPosition = zIndex;
}
- (BOOL)isSelected {
return _isPreselected || [super isSelected];
}
- (void)dealloc {
[self.layer removeObserver:self forKeyPath:@"zPosition"];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
if ([keyPath isEqualToString:@"zPosition"]) {
self.layer.zPosition = _zIndex;
}
}
- (void)setUseLegacyPinView:(BOOL)value {
_useLegacyPinView = value;
}
@end
@@ -0,0 +1,14 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import <React/RCTViewManager.h>
@interface AIRMapMarkerManager : RCTViewManager
@end
@@ -0,0 +1,98 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import "AIRMapMarkerManager.h"
#import <React/RCTConvert+CoreLocation.h>
#import <React/RCTUIManager.h>
#import <React/UIView+React.h>
#import "AIRMapMarker.h"
@interface AIRMapMarkerManager () <MKMapViewDelegate>
@end
@implementation AIRMapMarkerManager
RCT_EXPORT_MODULE()
- (UIView *)view
{
AIRMapMarker *marker = [AIRMapMarker new];
[marker addTapGestureRecognizer];
marker.bridge = self.bridge;
marker.isAccessibilityElement = YES;
marker.accessibilityElementsHidden = NO;
return marker;
}
RCT_EXPORT_VIEW_PROPERTY(identifier, NSString)
RCT_REMAP_VIEW_PROPERTY(testID, accessibilityIdentifier, NSString)
//RCT_EXPORT_VIEW_PROPERTY(reuseIdentifier, NSString)
RCT_EXPORT_VIEW_PROPERTY(title, NSString)
RCT_REMAP_VIEW_PROPERTY(description, subtitle, NSString)
RCT_EXPORT_VIEW_PROPERTY(coordinate, CLLocationCoordinate2D)
RCT_EXPORT_VIEW_PROPERTY(centerOffset, CGPoint)
RCT_EXPORT_VIEW_PROPERTY(calloutOffset, CGPoint)
RCT_REMAP_VIEW_PROPERTY(image, imageSrc, NSString)
RCT_EXPORT_VIEW_PROPERTY(pinColor, UIColor)
RCT_EXPORT_VIEW_PROPERTY(draggable, BOOL)
RCT_EXPORT_VIEW_PROPERTY(zIndex, NSInteger)
RCT_EXPORT_VIEW_PROPERTY(opacity, double)
RCT_EXPORT_VIEW_PROPERTY(isPreselected, BOOL)
RCT_EXPORT_VIEW_PROPERTY(titleVisibility, NSString)
RCT_EXPORT_VIEW_PROPERTY(subtitleVisibility, NSString)
RCT_EXPORT_VIEW_PROPERTY(useLegacyPinView, BOOL)
RCT_EXPORT_VIEW_PROPERTY(onPress, RCTBubblingEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onSelect, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onDeselect, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onCalloutPress, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onDragStart, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onDrag, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onDragEnd, RCTDirectEventBlock)
RCT_EXPORT_METHOD(showCallout:(nonnull NSNumber *)reactTag)
{
[self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
id view = viewRegistry[reactTag];
if (![view isKindOfClass:[AIRMapMarker class]]) {
RCTLogError(@"Invalid view returned from registry, expecting AIRMap, got: %@", view);
} else {
[(AIRMapMarker *) view showCalloutView];
}
}];
}
RCT_EXPORT_METHOD(hideCallout:(nonnull NSNumber *)reactTag)
{
[self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
id view = viewRegistry[reactTag];
if (![view isKindOfClass:[AIRMapMarker class]]) {
RCTLogError(@"Invalid view returned from registry, expecting AIRMap, got: %@", view);
} else {
[(AIRMapMarker *) view hideCalloutView];
}
}];
}
RCT_EXPORT_METHOD(redrawCallout:(nonnull NSNumber *)reactTag)
{
[self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
id view = viewRegistry[reactTag];
if (![view isKindOfClass:[AIRMapMarker class]]) {
RCTLogError(@"Invalid view returned from registry, expecting AIRMap, got: %@", view);
} else {
//no need to do anything here
}
}];
}
@end
@@ -0,0 +1,36 @@
#import "AIRMapCallout.h"
#import <MapKit/MapKit.h>
#import <UIKit/UIKit.h>
#import "RCTConvert+AirMap.h"
#import <React/RCTComponent.h>
#import "AIRMap.h"
#import "AIRMapOverlayRenderer.h"
@class RCTBridge;
@interface AIRMapOverlay : UIView <MKOverlay>
@property (nonatomic, strong) AIRMapOverlayRenderer *renderer;
@property (nonatomic, weak) AIRMap *map;
@property (nonatomic, weak) RCTBridge *bridge;
@property (nonatomic, strong) NSString *name;
@property (nonatomic, copy) NSString *imageSrc;
@property (nonatomic, strong, readonly) UIImage *overlayImage;
@property (nonatomic, copy) NSArray *boundsRect;
@property (nonatomic, assign) NSInteger rotation;
@property (nonatomic, assign) CGFloat transparency;
@property (nonatomic, assign) NSInteger zIndex;
@property (nonatomic, copy) RCTBubblingEventBlock onPress;
#pragma mark MKOverlay protocol
@property(nonatomic, readonly) CLLocationCoordinate2D coordinate;
@property(nonatomic, readonly) MKMapRect boundingMapRect;
- (BOOL)intersectsMapRect:(MKMapRect)mapRect;
- (BOOL)canReplaceMapContent;
@end
@@ -0,0 +1,103 @@
#import "AIRMapOverlay.h"
#import <React/RCTBridge.h>
#import <React/RCTEventDispatcher.h>
#import <React/RCTImageLoaderProtocol.h>
#import <React/RCTUtils.h>
#import <React/UIView+React.h>
@interface AIRMapOverlay()
@property (nonatomic, strong, readwrite) UIImage *overlayImage;
@end
@implementation AIRMapOverlay {
RCTImageLoaderCancellationBlock _reloadImageCancellationBlock;
CLLocationCoordinate2D _southWest;
CLLocationCoordinate2D _northEast;
MKMapRect _mapRect;
}
- (void)setImageSrc:(NSString *)imageSrc
{
NSLog(@">>> SET IMAGESRC: %@", imageSrc);
_imageSrc = imageSrc;
if (_reloadImageCancellationBlock) {
_reloadImageCancellationBlock();
_reloadImageCancellationBlock = nil;
}
__weak typeof(self) weakSelf = self;
_reloadImageCancellationBlock = [[_bridge moduleForName:@"ImageLoader"] loadImageWithURLRequest:[RCTConvert NSURLRequest:_imageSrc]
size:weakSelf.bounds.size
scale:RCTScreenScale()
clipped:YES
resizeMode:RCTResizeModeCenter
progressBlock:nil
partialLoadBlock:nil
completionBlock:^(NSError *error, UIImage *image) {
if (error) {
NSLog(@"%@", error);
}
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@">>> IMAGE: %@", image);
weakSelf.overlayImage = image;
[weakSelf createOverlayRendererIfPossible];
[weakSelf update];
});
}];
}
- (void)setBoundsRect:(NSArray *)boundsRect {
_boundsRect = boundsRect;
_southWest = CLLocationCoordinate2DMake([boundsRect[0][0] doubleValue], [boundsRect[0][1] doubleValue]);
_northEast = CLLocationCoordinate2DMake([boundsRect[1][0] doubleValue], [boundsRect[1][1] doubleValue]);
MKMapPoint southWest = MKMapPointForCoordinate(_southWest);
MKMapPoint northEast = MKMapPointForCoordinate(_northEast);
_mapRect = MKMapRectMake(southWest.x, northEast.y, ABS(northEast.x - southWest.x), ABS(northEast.y - southWest.y));
[self update];
}
- (void)createOverlayRendererIfPossible
{
if (MKMapRectIsEmpty(_mapRect) || !self.overlayImage) return;
__weak typeof(self) weakSelf = self;
self.renderer = [[AIRMapOverlayRenderer alloc] initWithOverlay:weakSelf];
}
- (void)update
{
if (!_renderer) return;
if (_map == nil) return;
[_map removeOverlay:self];
[_map addOverlay:self];
}
#pragma mark MKOverlay implementation
- (CLLocationCoordinate2D)coordinate
{
return MKCoordinateForMapPoint(MKMapPointMake(MKMapRectGetMidX(_mapRect), MKMapRectGetMidY(_mapRect)));
}
- (MKMapRect)boundingMapRect
{
return _mapRect;
}
- (BOOL)intersectsMapRect:(MKMapRect)mapRect
{
return MKMapRectIntersectsRect(_mapRect, mapRect);
}
- (BOOL)canReplaceMapContent
{
return NO;
}
@end
@@ -0,0 +1,5 @@
#import <React/RCTViewManager.h>
@interface AIRMapOverlayManager : RCTViewManager
@end
@@ -0,0 +1,27 @@
#import "AIRMapOverlayManager.h"
#import <React/RCTConvert+CoreLocation.h>
#import <React/RCTUIManager.h>
#import <React/UIView+React.h>
#import "AIRMapOverlay.h"
@interface AIRMapOverlayManager () <MKMapViewDelegate>
@end
@implementation AIRMapOverlayManager
RCT_EXPORT_MODULE()
- (UIView *)view
{
AIRMapOverlay *overlay = [AIRMapOverlay new];
overlay.bridge = self.bridge;
return overlay;
}
RCT_REMAP_VIEW_PROPERTY(bounds, boundsRect, NSArray)
RCT_REMAP_VIEW_PROPERTY(image, imageSrc, NSString)
@end
@@ -0,0 +1,8 @@
#import <MapKit/MapKit.h>
@interface AIRMapOverlayRenderer : MKOverlayRenderer
@property (nonatomic, assign) NSInteger rotation;
@property (nonatomic, assign) CGFloat transparency;
@end
@@ -0,0 +1,30 @@
#import "AIRMapOverlayRenderer.h"
#import "AIRMapOverlay.h"
@implementation AIRMapOverlayRenderer
- (void)drawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale inContext:(CGContextRef)context {
UIImage *image = [(AIRMapOverlay *)self.overlay overlayImage];
CGContextSaveGState(context);
CGImageRef imageReference = image.CGImage;
MKMapRect theMapRect = [self.overlay boundingMapRect];
CGRect theRect = [self rectForMapRect:theMapRect];
CGContextRotateCTM(context, M_PI);
CGContextScaleCTM(context, -1.0, 1.0);
CGContextTranslateCTM(context, 0.0, -theRect.size.height);
CGContextAddRect(context, theRect);
CGContextDrawImage(context, theRect, imageReference);
CGContextRestoreGState(context);
}
- (BOOL)canDrawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale {
return [(AIRMapOverlay *)self.overlay overlayImage] != nil;
}
@end
@@ -0,0 +1,46 @@
//
// Created by Leland Richardson on 12/27/15.
// Copyright (c) 2015 Facebook. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#import <UIKit/UIKit.h>
#import <React/RCTComponent.h>
#import <React/RCTView.h>
#import "AIRMapCoordinate.h"
#import "AIRMap.h"
#import "RCTConvert+AirMap.h"
@interface AIRMapPolygon: MKAnnotationView <MKOverlay>
@property (nonatomic, weak) AIRMap *map;
@property (nonatomic, strong) MKPolygon *polygon;
@property (nonatomic, strong) MKPolygonRenderer *renderer;
@property (nonatomic, strong) NSArray<MKPolygon *> *interiorPolygons;
@property (nonatomic, strong) NSArray<AIRMapCoordinate *> *coordinates;
@property (nonatomic, strong) NSArray<NSArray<AIRMapCoordinate *> *> *holes;
@property (nonatomic, strong) UIColor *fillColor;
@property (nonatomic, strong) UIColor *strokeColor;
@property (nonatomic, assign) CGFloat strokeWidth;
@property (nonatomic, assign) CGFloat miterLimit;
@property (nonatomic, assign) CGLineCap lineCap;
@property (nonatomic, assign) CGLineJoin lineJoin;
@property (nonatomic, assign) CGFloat lineDashPhase;
@property (nonatomic, strong) NSArray <NSNumber *> *lineDashPattern;
@property (nonatomic, copy) RCTBubblingEventBlock onPress;
#pragma mark MKOverlay protocol
@property(nonatomic, readonly) CLLocationCoordinate2D coordinate;
@property(nonatomic, readonly) MKMapRect boundingMapRect;
- (BOOL)intersectsMapRect:(MKMapRect)mapRect;
- (BOOL)canReplaceMapContent;
@end
@@ -0,0 +1,126 @@
//
// Created by Leland Richardson on 12/27/15.
// Copyright (c) 2015 Facebook. All rights reserved.
//
#import "AIRMapPolygon.h"
#import <React/UIView+React.h>
@implementation AIRMapPolygon {
}
- (void)setFillColor:(UIColor *)fillColor {
_fillColor = fillColor;
[self update];
}
- (void)setStrokeColor:(UIColor *)strokeColor {
_strokeColor = strokeColor;
[self update];
}
- (void)setStrokeWidth:(CGFloat)strokeWidth {
_strokeWidth = strokeWidth;
[self update];
}
- (void)setLineJoin:(CGLineJoin)lineJoin {
_lineJoin = lineJoin;
[self update];
}
- (void)setLineCap:(CGLineCap)lineCap {
_lineCap = lineCap;
[self update];
}
- (void)setMiterLimit:(CGFloat)miterLimit {
_miterLimit = miterLimit;
[self update];
}
- (void)setLineDashPhase:(CGFloat)lineDashPhase {
_lineDashPhase = lineDashPhase;
[self update];
}
- (void)setLineDashPattern:(NSArray <NSNumber *> *)lineDashPattern {
_lineDashPattern = lineDashPattern;
[self update];
}
- (void)setCoordinates:(NSArray<AIRMapCoordinate *> *)coordinates {
_coordinates = coordinates;
CLLocationCoordinate2D coords[coordinates.count];
for(int i = 0; i < coordinates.count; i++)
{
coords[i] = coordinates[i].coordinate;
}
self.polygon = [MKPolygon polygonWithCoordinates:coords count:coordinates.count interiorPolygons:_interiorPolygons];
// TODO: we could lazy-initialize the polygon, since we don't need it until the
// polygon is in view.
self.renderer = [[MKPolygonRenderer alloc] initWithPolygon:self.polygon];
[self update];
}
- (void)setHoles:(NSArray<NSArray<AIRMapCoordinate *> *> *)holes {
_holes = holes;
if (holes.count)
{
NSMutableArray<MKPolygon *> *polygons = [NSMutableArray array];
for(int h = 0; h < holes.count; h++)
{
CLLocationCoordinate2D coords[holes[h].count];
for(int i = 0; i < holes[h].count; i++)
{
coords[i] = holes[h][i].coordinate;
}
[polygons addObject:[MKPolygon polygonWithCoordinates:coords count:holes[h].count]];
}
_interiorPolygons = polygons;
}
}
- (void) update
{
if (!_renderer) return;
_renderer.fillColor = _fillColor;
_renderer.strokeColor = _strokeColor;
_renderer.lineWidth = _strokeWidth;
_renderer.lineCap = _lineCap;
_renderer.lineJoin = _lineJoin;
_renderer.miterLimit = _miterLimit;
_renderer.lineDashPhase = _lineDashPhase;
_renderer.lineDashPattern = _lineDashPattern;
if (_map == nil) return;
[_map removeOverlay:self];
[_map addOverlay:self];
}
#pragma mark MKOverlay implementation
- (CLLocationCoordinate2D) coordinate
{
return self.polygon.coordinate;
}
- (MKMapRect) boundingMapRect
{
return self.polygon.boundingMapRect;
}
- (BOOL)intersectsMapRect:(MKMapRect)mapRect
{
BOOL answer = [self.polygon intersectsMapRect:mapRect];
return answer;
}
- (BOOL)canReplaceMapContent
{
return NO;
}
@end
@@ -0,0 +1,10 @@
//
// Created by Leland Richardson on 12/27/15.
// Copyright (c) 2015 Facebook. All rights reserved.
//
#import <React/RCTViewManager.h>
@interface AIRMapPolygonManager : RCTViewManager
@end
@@ -0,0 +1,49 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import "AIRMapPolygonManager.h"
#import <React/RCTBridge.h>
#import <React/RCTConvert.h>
#import <React/RCTConvert+CoreLocation.h>
#import <React/RCTEventDispatcher.h>
#import <React/RCTViewManager.h>
#import <React/UIView+React.h>
#import "RCTConvert+AirMap.h"
#import "AIRMapMarker.h"
#import "AIRMapPolygon.h"
@interface AIRMapPolygonManager()
@end
@implementation AIRMapPolygonManager
RCT_EXPORT_MODULE()
- (UIView *)view
{
AIRMapPolygon *polygon = [AIRMapPolygon new];
return polygon;
}
RCT_EXPORT_VIEW_PROPERTY(coordinates, AIRMapCoordinateArray)
RCT_EXPORT_VIEW_PROPERTY(holes, AIRMapCoordinateArrayArray)
RCT_EXPORT_VIEW_PROPERTY(fillColor, UIColor)
RCT_EXPORT_VIEW_PROPERTY(strokeColor, UIColor)
RCT_EXPORT_VIEW_PROPERTY(strokeWidth, CGFloat)
RCT_EXPORT_VIEW_PROPERTY(lineCap, CGLineCap)
RCT_EXPORT_VIEW_PROPERTY(lineJoin, CGLineJoin)
RCT_EXPORT_VIEW_PROPERTY(miterLimit, CGFloat)
RCT_EXPORT_VIEW_PROPERTY(lineDashPhase, CGFloat)
RCT_EXPORT_VIEW_PROPERTY(lineDashPattern, NSArray)
RCT_EXPORT_VIEW_PROPERTY(onPress, RCTBubblingEventBlock)
@end
@@ -0,0 +1,45 @@
//
// Created by Leland Richardson on 12/27/15.
// Copyright (c) 2015 Facebook. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#import <UIKit/UIKit.h>
#import <React/RCTComponent.h>
#import <React/RCTView.h>
#import "AIRMapCoordinate.h"
#import "AIRMap.h"
#import "RCTConvert+AirMap.h"
@interface AIRMapPolyline: MKAnnotationView <MKOverlay>
@property (nonatomic, weak) AIRMap *map;
@property (nonatomic, strong) MKPolyline *polyline;
@property (nonatomic, strong) MKOverlayPathRenderer *renderer;
@property (nonatomic, strong) NSArray<AIRMapCoordinate *> *coordinates;
@property (nonatomic, strong) UIColor *fillColor;
@property (nonatomic, strong) UIColor *strokeColor;
@property (nonatomic, strong) NSArray<UIColor *> *strokeColors;
@property (nonatomic, assign) CGFloat strokeWidth;
@property (nonatomic, assign) CGFloat miterLimit;
@property (nonatomic, assign) CGLineCap lineCap;
@property (nonatomic, assign) CGLineJoin lineJoin;
@property (nonatomic, assign) CGFloat lineDashPhase;
@property (nonatomic, strong) NSArray <NSNumber *> *lineDashPattern;
@property (nonatomic, assign) BOOL geodesic;
@property (nonatomic, copy) RCTBubblingEventBlock onPress;
#pragma mark MKOverlay protocol
@property(nonatomic, readonly) CLLocationCoordinate2D coordinate;
@property(nonatomic, readonly) MKMapRect boundingMapRect;
- (BOOL)intersectsMapRect:(MKMapRect)mapRect;
- (BOOL)canReplaceMapContent;
@end
@@ -0,0 +1,161 @@
//
// Created by Leland Richardson on 12/27/15.
// Copyright (c) 2015 Facebook. All rights reserved.
//
#import "AIRMapPolyline.h"
#import "AIRMapPolylineRenderer.h"
#import <React/UIView+React.h>
@implementation AIRMapPolyline {
}
- (void)setFillColor:(UIColor *)fillColor {
_fillColor = fillColor;
[self update];
}
- (void)setStrokeColor:(UIColor *)strokeColor {
_strokeColor = strokeColor;
[self update];
}
- (void)setStrokeColors:(NSArray<UIColor *> *)strokeColors {
_strokeColors = strokeColors;
if ((self.renderer != nil) && ![_renderer isKindOfClass:[AIRMapPolylineRenderer class]]) {
self.renderer = [self createRenderer];
}
[self update];
}
- (void)setStrokeWidth:(CGFloat)strokeWidth {
_strokeWidth = strokeWidth;
[self update];
}
- (void)setLineJoin:(CGLineJoin)lineJoin {
_lineJoin = lineJoin;
[self update];
}
- (void)setLineCap:(CGLineCap)lineCap {
_lineCap = lineCap;
[self update];
}
- (void)setMiterLimit:(CGFloat)miterLimit {
_miterLimit = miterLimit;
[self update];
}
- (void)setLineDashPhase:(CGFloat)lineDashPhase {
_lineDashPhase = lineDashPhase;
[self update];
}
- (void)setLineDashPattern:(NSArray <NSNumber *> *)lineDashPattern {
_lineDashPattern = lineDashPattern;
[self update];
}
-(void)setGeodesic:(BOOL)geodesic
{
_geodesic = geodesic;
if(_coordinates){
[self setCoordinates:_coordinates];
}
}
- (void)setCoordinates:(NSArray<AIRMapCoordinate *> *)coordinates {
_coordinates = coordinates;
CLLocationCoordinate2D *coords = calloc(coordinates.count, sizeof(CLLocationCoordinate2D));
for(int i = 0; i < coordinates.count; i++)
{
coords[i] = coordinates[i].coordinate;
}
if(_geodesic){
self.polyline = [MKGeodesicPolyline polylineWithCoordinates:coords count:coordinates.count];
} else {
self.polyline = [MKPolyline polylineWithCoordinates:coords count:coordinates.count];
}
free(coords);
self.renderer = [self createRenderer];
[self update];
}
- (MKOverlayPathRenderer*)createRenderer {
if (self.polyline == nil) return nil;
if (self.strokeColors == nil) {
// Use the default renderer when no array of stroke-colors is defined.
// This behaviour may be changed in the future if we permanently want to
// use the custom renderer, because it can add funtionality that is not
// supported by the default renderer.
return [[MKPolylineRenderer alloc] initWithPolyline:self.polyline];
}
else {
return [[AIRMapPolylineRenderer alloc] initWithOverlay:self polyline:self.polyline];
}
}
- (void) update
{
if (!_renderer) return;
[self updateRenderer:_renderer];
if (_map == nil) return;
[_map removeOverlay:self];
[_map addOverlay:self];
}
- (void) updateRenderer:(MKOverlayPathRenderer*)renderer {
renderer.fillColor = _fillColor;
renderer.strokeColor = _strokeColor;
renderer.lineWidth = _strokeWidth;
renderer.lineCap = _lineCap;
renderer.lineJoin = _lineJoin;
renderer.miterLimit = _miterLimit;
renderer.lineDashPhase = _lineDashPhase;
renderer.lineDashPattern = _lineDashPattern;
if ([renderer isKindOfClass:[AIRMapPolylineRenderer class]]) {
((AIRMapPolylineRenderer*)renderer).strokeColors = _strokeColors;
}
}
#pragma mark MKOverlay implementation
- (CLLocationCoordinate2D) coordinate
{
return self.polyline.coordinate;
}
- (MKMapRect) boundingMapRect
{
return self.polyline.boundingMapRect;
}
- (BOOL)intersectsMapRect:(MKMapRect)mapRect
{
BOOL answer = [self.polyline intersectsMapRect:mapRect];
return answer;
}
- (BOOL)canReplaceMapContent
{
return NO;
}
#pragma mark AIRMapSnapshot implementation
- (void) drawToSnapshot:(MKMapSnapshot *) snapshot context:(CGContextRef) context
{
AIRMapPolylineRenderer* renderer = [[AIRMapPolylineRenderer alloc] initWithSnapshot:snapshot overlay:self polyline:self.polyline];
[self updateRenderer:renderer];
[renderer drawWithZoomScale:2 inContext:context];
}
@end
@@ -0,0 +1,10 @@
//
// Created by Leland Richardson on 12/27/15.
// Copyright (c) 2015 Facebook. All rights reserved.
//
#import <React/RCTViewManager.h>
@interface AIRMapPolylineManager : RCTViewManager
@end
@@ -0,0 +1,48 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import "AIRMapPolylineManager.h"
#import <React/RCTBridge.h>
#import <React/RCTConvert.h>
#import <React/RCTConvert+CoreLocation.h>
#import <React/RCTEventDispatcher.h>
#import <React/RCTViewManager.h>
#import <React/UIView+React.h>
#import "RCTConvert+AirMap.h"
#import "AIRMapMarker.h"
#import "AIRMapPolyline.h"
@interface AIRMapPolylineManager()
@end
@implementation AIRMapPolylineManager
RCT_EXPORT_MODULE()
- (UIView *)view
{
AIRMapPolyline *polyline = [AIRMapPolyline new];
return polyline;
}
RCT_EXPORT_VIEW_PROPERTY(coordinates, AIRMapCoordinateArray)
RCT_EXPORT_VIEW_PROPERTY(strokeColor, UIColor)
RCT_EXPORT_VIEW_PROPERTY(strokeColors, UIColorArray)
RCT_EXPORT_VIEW_PROPERTY(strokeWidth, CGFloat)
RCT_EXPORT_VIEW_PROPERTY(lineCap, CGLineCap)
RCT_EXPORT_VIEW_PROPERTY(lineJoin, CGLineJoin)
RCT_EXPORT_VIEW_PROPERTY(miterLimit, CGFloat)
RCT_EXPORT_VIEW_PROPERTY(lineDashPhase, CGFloat)
RCT_EXPORT_VIEW_PROPERTY(lineDashPattern, NSArray)
RCT_EXPORT_VIEW_PROPERTY(geodesic, BOOL)
RCT_EXPORT_VIEW_PROPERTY(onPress, RCTBubblingEventBlock)
@end
@@ -0,0 +1,19 @@
//
// AIRMapPolylineRenderer.h
// mapDemo
//
// Created by IjzerenHein on 13-11-21.
// Copyright (c) 2017 IjzerenHein. All rights reserved.
//
#import <MapKit/MapKit.h>
@interface AIRMapPolylineRenderer : MKOverlayPathRenderer
-(id)initWithOverlay:(id<MKOverlay>)overlay polyline:(MKPolyline*)polyline;
-(id)initWithSnapshot:(MKMapSnapshot*)snapshot overlay:(id<MKOverlay>)overlay polyline:(MKPolyline*)polyline;
-(void)drawWithZoomScale:(MKZoomScale)zoomScale inContext:(CGContextRef)context;
@property (nonatomic, strong) NSArray<UIColor *> *strokeColors;
@end
@@ -0,0 +1,240 @@
//
// AIRMapPolylineRenderer.h
// mapDemo
//
// Created by IjzerenHein on 13-11-21.
// Copyright (c) 2017 IjzerenHein. All rights reserved.
//
#import "AIRMapPolylineRenderer.h"
@interface AIRMapPolylineRendererSegment : NSObject
- (id)initWithPoint:(CGPoint)point color:(UIColor*)color;
- (void) addPoint:(CGPoint)point color:(UIColor*)color;
@property CGMutablePathRef path;
@property UIColor *startColor;
@property UIColor *endColor;
@property CGPoint startPoint;
@property CGPoint endPoint;
@end
@implementation AIRMapPolylineRendererSegment
- (id)initWithPoint:(CGPoint)point color:(UIColor*)color
{
self = [super init];
if (self){
self.path = CGPathCreateMutable();
self.startColor = color;
self.startPoint = point;
self.endPoint = point;
CGPathMoveToPoint(self.path, nil, point.x, point.y);
}
return self;
}
- (void) addPoint:(CGPoint)point color:(UIColor*)color
{
self.endPoint = point;
self.endColor = color;
CGPathAddLineToPoint(self.path, nil, point.x, point.y);
}
@end
@implementation AIRMapPolylineRenderer {
MKPolyline* _polyline;
NSArray<UIColor *> *_strokeColors;
MKMapSnapshot* _snapshot;
CLLocationCoordinate2D* _coordinates;
}
@synthesize strokeColors;
- (id)initWithOverlay:(id<MKOverlay>)overlay polyline:(MKPolyline*)polyline
{
self = [super initWithOverlay:overlay];
if (self){
_polyline = polyline;
[self createPath];
}
return self;
}
- (id)initWithSnapshot:(MKMapSnapshot*)snapshot overlay:(id<MKOverlay>)overlay polyline:(MKPolyline*)polyline
{
self = [super initWithOverlay:overlay];
if (self){
_snapshot = snapshot;
_polyline = polyline;
_coordinates = malloc(sizeof(CLLocationCoordinate2D) * [_polyline pointCount]);
[_polyline getCoordinates:_coordinates range:NSMakeRange(0, [_polyline pointCount])];
}
return self;
}
- (void) dealloc
{
if (_coordinates) free(_coordinates);
}
- (CGPoint) pointForIndex:(NSUInteger)index
{
if (_snapshot != nil) {
return [_snapshot pointForCoordinate:_coordinates[index]];
}
else {
return [self pointForMapPoint:_polyline.points[index]];
}
}
- (UIColor*) colorForIndex:(NSUInteger)index
{
if ((_strokeColors == nil) || !_strokeColors.count) return self.strokeColor;
index = MIN(index, _strokeColors.count - 1);
UIColor* color = _strokeColors[index];
CGFloat pc_r,pc_g,pc_b,pc_a;
[color getRed:&pc_r green:&pc_g blue:&pc_b alpha:&pc_a];
return (pc_a == 0) ? nil : color;
}
- (void) createPath
{
CGMutablePathRef path = CGPathCreateMutable();
BOOL first = YES;
for (NSUInteger i = 0, n = _polyline.pointCount; i < n; i++){
CGPoint point = [self pointForIndex:i];
if (first) {
CGPathMoveToPoint(path, nil, point.x, point.y);
first = NO;
} else {
CGPathAddLineToPoint(path, nil, point.x, point.y);
}
}
self.path = path;
}
- (NSArray*) createSegments
{
NSMutableArray* segments = [NSMutableArray new];
if (_polyline.pointCount <= 1) return segments;
AIRMapPolylineRendererSegment* segment = nil;
for (NSUInteger i = 0, n = _polyline.pointCount; i < n; i++){
CGPoint point = [self pointForIndex:i];
UIColor* color = [self colorForIndex:i];
if (segment == nil) {
// Start new segment
segment = [[AIRMapPolylineRendererSegment alloc] initWithPoint:point color:color];
[segments addObject:segment];
}
else if (((color == nil) && (segment.endColor == nil)) ||
((color != nil) && [segment.startColor isEqual:color])) {
// Append point to segment
[segment addPoint:point color: color];
}
else {
// Close the last segment if needed
if (segment.endColor == nil) {
[segment addPoint:point color:color];
}
else {
// Add transition gradient
segment = [[AIRMapPolylineRendererSegment alloc] initWithPoint:segment.endPoint color:segment.endColor];
[segment addPoint:point color:color];
[segments addObject:segment];
}
// Start new segment
if (i < (n - 1)) {
segment = [[AIRMapPolylineRendererSegment alloc] initWithPoint:point color:color];
[segments addObject:segment];
}
}
}
// Remove last segment in case it only contains a single path point
if ((segment != nil) && (segment.endColor == nil)) {
[segments removeLastObject];
}
return segments;
}
- (void) setStrokeColors:(NSArray<UIColor *> *)strokeColors
{
if (_strokeColors != strokeColors) {
_strokeColors = strokeColors;
}
}
- (void) setStrokeColor:(UIColor *)strokeColor
{
if (super.strokeColor != strokeColor) {
super.strokeColor = strokeColor;
}
}
- (void) drawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale inContext:(CGContextRef)context
{
CGRect pointsRect = CGPathGetBoundingBox(self.path);
CGRect mapRectCG = [self rectForMapRect:mapRect];
if (!CGRectIntersectsRect(pointsRect, mapRectCG)) return;
[self drawWithZoomScale:zoomScale inContext:context];
}
- (void) drawWithZoomScale:(MKZoomScale)zoomScale inContext:(CGContextRef)context
{
CGFloat lineWidth = (self.lineWidth / zoomScale) * 2.0;
CGContextSetLineWidth(context, lineWidth);
CGContextSetLineCap(context, self.lineCap);
CGContextSetLineJoin(context, self.lineJoin);
CGContextSetFillColorWithColor(context, self.fillColor.CGColor);
CGContextSetMiterLimit(context, self.miterLimit);
CGFloat dashes[self.lineDashPattern.count];
for (NSUInteger i = 0; i < self.lineDashPattern.count; i++) {
dashes[i] = self.lineDashPattern[i].floatValue;
}
CGContextSetLineDash(context, self.lineDashPhase, dashes, self.lineDashPattern.count);
NSArray* segments = [self createSegments];
for (NSUInteger i = 0, n = segments.count; i < n; i++) {
AIRMapPolylineRendererSegment* segment = segments[i];
CGContextBeginPath(context);
CGContextAddPath(context, segment.path);
// When segment has two colors, draw it as a gradient
if (![segment.startColor isEqual:segment.endColor]) {
CGFloat pc_r,pc_g,pc_b,pc_a,
cc_r,cc_g,cc_b,cc_a;
[segment.startColor getRed:&pc_r green:&pc_g blue:&pc_b alpha:&pc_a];
[segment.endColor getRed:&cc_r green:&cc_g blue:&cc_b alpha:&cc_a];
CGFloat gradientColors[8] = {pc_r,pc_g,pc_b,pc_a,
cc_r,cc_g,cc_b,cc_a};
CGFloat gradientLocation[2] = {0,1};
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, gradientColors, gradientLocation, 2);
CGColorSpaceRelease(colorSpace);
CGContextReplacePathWithStrokedPath(context);
CGContextClip(context);
CGContextDrawLinearGradient(
context,
gradient,
segment.startPoint,
segment.endPoint,
kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation
);
CGGradientRelease(gradient);
CGContextResetClip(context);
}
else {
CGContextSetStrokeColorWithColor(context, segment.startColor.CGColor);
CGContextStrokePath(context);
}
}
}
@end

Some files were not shown because too many files have changed in this diff Show More