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>