react-native-maps 1.7.1 → 2.0.0-beta.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (186) hide show
  1. package/README.md +34 -11
  2. package/android/build.gradle +41 -10
  3. package/android/gradle/wrapper/gradle-wrapper.properties +1 -1
  4. package/android/src/main/java/com/rnmaps/maps/MapCalloutManager.java +1 -1
  5. package/android/src/main/java/com/rnmaps/maps/MapCircleManager.java +1 -1
  6. package/android/src/main/java/com/rnmaps/maps/MapGradientPolyline.java +4 -4
  7. package/android/src/main/java/com/rnmaps/maps/MapGradientPolylineManager.java +1 -1
  8. package/android/src/main/java/com/rnmaps/maps/MapHeatmapManager.java +1 -1
  9. package/android/src/main/java/com/rnmaps/maps/MapLiteManager.java +1 -1
  10. package/android/src/main/java/com/rnmaps/maps/MapLocalTile.java +4 -4
  11. package/android/src/main/java/com/rnmaps/maps/MapLocalTileManager.java +1 -1
  12. package/android/src/main/java/com/rnmaps/maps/MapManager.java +6 -63
  13. package/android/src/main/java/com/rnmaps/maps/MapMarker.java +2 -2
  14. package/android/src/main/java/com/rnmaps/maps/MapMarkerManager.java +10 -27
  15. package/android/src/main/java/com/rnmaps/maps/MapOverlayManager.java +1 -1
  16. package/android/src/main/java/com/rnmaps/maps/MapPolygonManager.java +1 -1
  17. package/android/src/main/java/com/rnmaps/maps/MapPolylineManager.java +1 -1
  18. package/android/src/main/java/com/rnmaps/maps/MapTileProvider.java +7 -5
  19. package/android/src/main/java/com/rnmaps/maps/MapUrlTileManager.java +1 -1
  20. package/android/src/main/java/com/rnmaps/maps/MapView.java +60 -149
  21. package/android/src/main/java/com/rnmaps/maps/MapViewModule.java +598 -0
  22. package/android/src/main/java/com/rnmaps/maps/MapWMSTile.java +6 -6
  23. package/android/src/main/java/com/rnmaps/maps/MapWMSTileManager.java +1 -1
  24. package/android/src/main/java/com/rnmaps/maps/MapsPackage.java +1 -1
  25. package/android/src/main/java/com/rnmaps/maps/SizeReportingShadowNode.java +1 -1
  26. package/ios/{AirGoogleMaps → GoogleMaps}/RCTConvert+GMSMapViewType.m +8 -0
  27. package/ios/{AirGoogleMaps/AIRDummyView.h → GoogleMaps/RNMDummyView.h} +3 -3
  28. package/ios/{AirGoogleMaps/AIRDummyView.m → GoogleMaps/RNMDummyView.m} +4 -4
  29. package/ios/{AirGoogleMaps/AIRGMSMarker.h → GoogleMaps/RNMGMSMarker.h} +6 -6
  30. package/ios/{AirGoogleMaps/AIRGMSMarker.m → GoogleMaps/RNMGMSMarker.m} +4 -4
  31. package/ios/{AirGoogleMaps/AIRGMSPolygon.h → GoogleMaps/RNMGMSPolygon.h} +4 -4
  32. package/ios/{AirGoogleMaps/AIRGMSPolygon.m → GoogleMaps/RNMGMSPolygon.m} +4 -4
  33. package/ios/{AirGoogleMaps/AIRGMSPolyline.h → GoogleMaps/RNMGMSPolyline.h} +4 -4
  34. package/ios/{AirGoogleMaps/AIRGMSPolyline.m → GoogleMaps/RNMGMSPolyline.m} +4 -4
  35. package/ios/{AirGoogleMaps/AIRGoogleMap.h → GoogleMaps/RNMGoogleMap.h} +5 -5
  36. package/ios/{AirGoogleMaps/AIRGoogleMap.m → GoogleMaps/RNMGoogleMap.m} +81 -77
  37. package/ios/{AirGoogleMaps/AIRGoogleMapCallout.h → GoogleMaps/RNMGoogleMapCallout.h} +3 -3
  38. package/ios/{AirGoogleMaps/AIRGoogleMapCallout.m → GoogleMaps/RNMGoogleMapCallout.m} +4 -4
  39. package/ios/{AirGoogleMaps/AIRGoogleMapCalloutManager.h → GoogleMaps/RNMGoogleMapCalloutManager.h} +3 -3
  40. package/ios/{AirGoogleMaps/AIRGoogleMapCalloutManager.m → GoogleMaps/RNMGoogleMapCalloutManager.m} +7 -7
  41. package/ios/{AirGoogleMaps/AIRGoogleMapCalloutSubview.h → GoogleMaps/RNMGoogleMapCalloutSubview.h} +3 -3
  42. package/ios/{AirGoogleMaps/AIRGoogleMapCalloutSubview.m → GoogleMaps/RNMGoogleMapCalloutSubview.m} +4 -4
  43. package/ios/{AirGoogleMaps/AIRGoogleMapCalloutSubviewManager.h → GoogleMaps/RNMGoogleMapCalloutSubviewManager.h} +3 -3
  44. package/ios/GoogleMaps/RNMGoogleMapCalloutSubviewManager.m +28 -0
  45. package/ios/{AirGoogleMaps/AIRGoogleMapCircle.h → GoogleMaps/RNMGoogleMapCircle.h} +3 -3
  46. package/ios/{AirGoogleMaps/AIRGoogleMapCircle.m → GoogleMaps/RNMGoogleMapCircle.m} +3 -3
  47. package/ios/{AirGoogleMaps/AIRGoogleMapCircleManager.h → GoogleMaps/RNMGoogleMapCircleManager.h} +2 -2
  48. package/ios/{AirGoogleMaps/AIRGoogleMapCircleManager.m → GoogleMaps/RNMGoogleMapCircleManager.m} +7 -7
  49. package/ios/{AirGoogleMaps/AIRGoogleMapHeatmap.h → GoogleMaps/RNMGoogleMapHeatmap.h} +3 -3
  50. package/ios/{AirGoogleMaps/AIRGoogleMapHeatmap.m → GoogleMaps/RNMGoogleMapHeatmap.m} +4 -4
  51. package/ios/GoogleMaps/RNMGoogleMapHeatmapManager.h +11 -0
  52. package/ios/{AirGoogleMaps/AIRGoogleMapHeatmapManager.m → GoogleMaps/RNMGoogleMapHeatmapManager.m} +9 -9
  53. package/ios/{AirGoogleMaps/AIRGoogleMapManager.h → GoogleMaps/RNMGoogleMapManager.h} +3 -3
  54. package/ios/GoogleMaps/RNMGoogleMapManager.m +256 -0
  55. package/ios/{AirGoogleMaps/AIRGoogleMapMarker.h → GoogleMaps/RNMGoogleMapMarker.h} +15 -15
  56. package/ios/{AirGoogleMaps/AIRGoogleMapMarker.m → GoogleMaps/RNMGoogleMapMarker.m} +23 -23
  57. package/ios/{AirGoogleMaps/AIRGoogleMapMarkerManager.h → GoogleMaps/RNMGoogleMapMarkerManager.h} +3 -3
  58. package/ios/{AirGoogleMaps/AIRGoogleMapMarkerManager.m → GoogleMaps/RNMGoogleMapMarkerManager.m} +20 -20
  59. package/ios/{AirGoogleMaps/AIRGoogleMapOverlay.h → GoogleMaps/RNMGoogleMapOverlay.h} +4 -4
  60. package/ios/{AirGoogleMaps/AIRGoogleMapOverlay.m → GoogleMaps/RNMGoogleMapOverlay.m} +4 -4
  61. package/ios/{AirGoogleMaps/AIRGoogleMapOverlayManager.h → GoogleMaps/RNMGoogleMapOverlayManager.h} +2 -2
  62. package/ios/{AirGoogleMaps/AIRGoogleMapOverlayManager.m → GoogleMaps/RNMGoogleMapOverlayManager.m} +6 -6
  63. package/ios/{AirGoogleMaps/AIRGoogleMapPolygon.h → GoogleMaps/RNMGoogleMapPolygon.h} +7 -7
  64. package/ios/{AirGoogleMaps/AIRGoogleMapPolygon.m → GoogleMaps/RNMGoogleMapPolygon.m} +7 -7
  65. package/ios/{AirGoogleMaps/AIRGoogleMapPolylineManager.h → GoogleMaps/RNMGoogleMapPolygonManager.h} +2 -2
  66. package/ios/{AirGoogleMaps/AIRGoogleMapPolygonManager.m → GoogleMaps/RNMGoogleMapPolygonManager.m} +10 -10
  67. package/ios/{AirGoogleMaps/AIRGoogleMapPolyline.h → GoogleMaps/RNMGoogleMapPolyline.h} +7 -7
  68. package/ios/{AirGoogleMaps/AIRGoogleMapPolyline.m → GoogleMaps/RNMGoogleMapPolyline.m} +9 -9
  69. package/ios/{AirGoogleMaps/AIRGoogleMapPolygonManager.h → GoogleMaps/RNMGoogleMapPolylineManager.h} +2 -2
  70. package/ios/{AirGoogleMaps/AIRGoogleMapPolylineManager.m → GoogleMaps/RNMGoogleMapPolylineManager.m} +9 -9
  71. package/ios/{AirGoogleMaps/AIRGoogleMapUrlTile.h → GoogleMaps/RNMGoogleMapUrlTile.h} +2 -2
  72. package/ios/{AirGoogleMaps/AIRGoogleMapUrlTile.m → GoogleMaps/RNMGoogleMapUrlTile.m} +3 -3
  73. package/ios/{AirGoogleMaps/AIRGoogleMapUrlTileManager.h → GoogleMaps/RNMGoogleMapUrlTileManager.h} +2 -2
  74. package/ios/{AirGoogleMaps/AIRGoogleMapURLTileManager.m → GoogleMaps/RNMGoogleMapUrlTileManager.m} +7 -7
  75. package/ios/GoogleMaps/RNMGoogleMapViewModule.h +5 -0
  76. package/ios/GoogleMaps/RNMGoogleMapViewModule.m +380 -0
  77. package/ios/{AirGoogleMaps/AIRGoogleMapWMSTile.h → GoogleMaps/RNMGoogleMapWMSTile.h} +3 -3
  78. package/ios/{AirGoogleMaps/AIRGoogleMapWMSTile.m → GoogleMaps/RNMGoogleMapWMSTile.m} +4 -4
  79. package/ios/{AirGoogleMaps/AIRGoogleMapWMSTileManager.h → GoogleMaps/RNMGoogleMapWMSTileManager.h} +3 -3
  80. package/ios/{AirGoogleMaps/AIRGoogleMapWMSTileManager.m → GoogleMaps/RNMGoogleMapWMSTileManager.m} +8 -8
  81. package/ios/{AirMaps → Maps}/Callout/SMCalloutView.h +9 -8
  82. package/ios/{AirMaps → Maps}/Callout/SMCalloutView.m +118 -118
  83. package/ios/{AirMaps/RCTConvert+AirMap.h → Maps/RCTConvert+RNMMap.h} +1 -1
  84. package/ios/{AirMaps/RCTConvert+AirMap.m → Maps/RCTConvert+RNMMap.m} +25 -8
  85. package/ios/{AirMaps/AIRMap.h → Maps/RNMMap.h} +8 -8
  86. package/ios/{AirMaps/AIRMap.m → Maps/RNMMap.m} +60 -56
  87. package/ios/{AirMaps/AIRMapCallout.h → Maps/RNMMapCallout.h} +1 -1
  88. package/ios/{AirMaps/AIRMapCallout.m → Maps/RNMMapCallout.m} +2 -2
  89. package/ios/{AirMaps/AIRMapCircleManager.h → Maps/RNMMapCalloutManager.h} +2 -2
  90. package/ios/{AirMaps/AIRMapCalloutManager.m → Maps/RNMMapCalloutManager.m} +7 -7
  91. package/ios/{AirMaps/AIRMapCalloutSubview.h → Maps/RNMMapCalloutSubview.h} +3 -3
  92. package/ios/{AirMaps/AIRMapCalloutSubview.m → Maps/RNMMapCalloutSubview.m} +4 -4
  93. package/ios/Maps/RNMMapCalloutSubviewManager.h +14 -0
  94. package/ios/Maps/RNMMapCalloutSubviewManager.m +24 -0
  95. package/ios/{AirMaps/AIRMapCircle.h → Maps/RNMMapCircle.h} +5 -5
  96. package/ios/{AirMaps/AIRMapCircle.m → Maps/RNMMapCircle.m} +3 -3
  97. package/ios/{AirMaps/AIRMapCalloutManager.h → Maps/RNMMapCircleManager.h} +2 -2
  98. package/ios/{AirMaps/AIRMapCircleManager.m → Maps/RNMMapCircleManager.m} +7 -7
  99. package/ios/{AirMaps/AIRMapCoordinate.h → Maps/RNMMapCoordinate.h} +2 -2
  100. package/ios/{AirMaps/AIRMapCoordinate.m → Maps/RNMMapCoordinate.m} +3 -3
  101. package/ios/{AirMaps/AIRMapLocalTile.h → Maps/RNMMapLocalTile.h} +7 -7
  102. package/ios/{AirMaps/AIRMapLocalTile.m → Maps/RNMMapLocalTile.m} +6 -6
  103. package/ios/{AirMaps/AIRMapLocalTileManager.h → Maps/RNMMapLocalTileManager.h} +3 -3
  104. package/ios/{AirMaps/AIRMapLocalTileManager.m → Maps/RNMMapLocalTileManager.m} +9 -9
  105. package/ios/{AirMaps/AIRMapLocalTileOverlay.h → Maps/RNMMapLocalTileOverlay.h} +2 -2
  106. package/ios/{AirMaps/AIRMapLocalTileOverlay.m → Maps/RNMMapLocalTileOverlay.m} +5 -5
  107. package/ios/{AirMaps/AIRMapManager.h → Maps/RNMMapManager.h} +6 -6
  108. package/ios/Maps/RNMMapManager.m +854 -0
  109. package/ios/{AirMaps/AIRMapMarker.h → Maps/RNMMapMarker.h} +8 -8
  110. package/ios/{AirMaps/AIRMapMarker.m → Maps/RNMMapMarker.m} +22 -25
  111. package/ios/{AirMaps/AIRMapMarkerManager.h → Maps/RNMMapMarkerManager.h} +1 -1
  112. package/ios/{AirMaps/AIRMapMarkerManager.m → Maps/RNMMapMarkerManager.m} +14 -14
  113. package/ios/{AirMaps/AIRMapOverlay.h → Maps/RNMMapOverlay.h} +7 -7
  114. package/ios/{AirMaps/AIRMapOverlay.m → Maps/RNMMapOverlay.m} +4 -4
  115. package/ios/Maps/RNMMapOverlayManager.h +5 -0
  116. package/ios/{AirMaps/AIRMapOverlayManager.m → Maps/RNMMapOverlayManager.m} +6 -6
  117. package/ios/{AirMaps/AIRMapOverlayRenderer.h → Maps/RNMMapOverlayRenderer.h} +1 -1
  118. package/ios/{AirMaps/AIRMapOverlayRenderer.m → Maps/RNMMapOverlayRenderer.m} +5 -5
  119. package/ios/{AirMaps/AIRMapPolygon.h → Maps/RNMMapPolygon.h} +7 -7
  120. package/ios/{AirMaps/AIRMapPolygon.m → Maps/RNMMapPolygon.m} +4 -4
  121. package/ios/{AirMaps/AIRMapPolygonManager.h → Maps/RNMMapPolygonManager.h} +2 -2
  122. package/ios/{AirMaps/AIRMapPolygonManager.m → Maps/RNMMapPolygonManager.m} +10 -10
  123. package/ios/{AirMaps/AIRMapPolyline.h → Maps/RNMMapPolyline.h} +6 -6
  124. package/ios/{AirMaps/AIRMapPolyline.m → Maps/RNMMapPolyline.m} +11 -11
  125. package/ios/{AirMaps/AIRMapPolylineManager.h → Maps/RNMMapPolylineManager.h} +2 -2
  126. package/ios/{AirMaps/AIRMapPolylineManager.m → Maps/RNMMapPolylineManager.m} +9 -9
  127. package/ios/{AirMaps/AIRMapPolylineRenderer.h → Maps/RNMMapPolylineRenderer.h} +2 -2
  128. package/ios/{AirMaps/AIRMapPolylineRenderer.m → Maps/RNMMapPolylineRenderer.m} +10 -10
  129. package/ios/{AirMaps/AIRMapSnapshot.h → Maps/RNMMapSnapshot.h} +6 -6
  130. package/ios/{AirMaps/AIRMapUrlTile.h → Maps/RNMMapUrlTile.h} +18 -18
  131. package/ios/{AirMaps/AIRMapUrlTile.m → Maps/RNMMapUrlTile.m} +7 -7
  132. package/ios/{AirMaps/AIRMapUrlTileCachedOverlay.h → Maps/RNMMapUrlTileCachedOverlay.h} +3 -3
  133. package/ios/{AirMaps/AIRMapUrlTileCachedOverlay.m → Maps/RNMMapUrlTileCachedOverlay.m} +10 -10
  134. package/ios/{AirMaps/AIRMapUrlTileManager.h → Maps/RNMMapUrlTileManager.h} +3 -3
  135. package/ios/{AirMaps/AIRMapUrlTileManager.m → Maps/RNMMapUrlTileManager.m} +9 -9
  136. package/ios/Maps/RNMMapViewModule.h +5 -0
  137. package/ios/Maps/RNMMapViewModule.m +459 -0
  138. package/ios/{AirMaps/AIRMapWMSTile.h → Maps/RNMMapWMSTile.h} +11 -11
  139. package/ios/{AirMaps/AIRMapWMSTile.m → Maps/RNMMapWMSTile.m} +15 -15
  140. package/ios/{AirMaps/AIRMapWMSTileManager.h → Maps/RNMMapWMSTileManager.h} +3 -3
  141. package/ios/{AirMaps/AIRMapWMSTileManager.m → Maps/RNMMapWMSTileManager.m} +9 -9
  142. package/ios/RNMaps.xcodeproj/project.pbxproj +647 -0
  143. package/lib/Geojson.d.ts +1 -1
  144. package/lib/MapCallout.js +2 -2
  145. package/lib/MapCalloutSubview.js +2 -2
  146. package/lib/MapCircle.js +2 -2
  147. package/lib/MapHeatmap.js +2 -2
  148. package/lib/MapLocalTile.js +2 -2
  149. package/lib/MapMarker.d.ts +2 -3
  150. package/lib/MapMarker.js +2 -4
  151. package/lib/MapOverlay.d.ts +1 -2
  152. package/lib/MapOverlay.js +2 -4
  153. package/lib/MapPolygon.js +2 -2
  154. package/lib/MapPolyline.js +2 -2
  155. package/lib/MapUrlTile.js +2 -2
  156. package/lib/MapView.d.ts +14 -14
  157. package/lib/MapView.js +92 -107
  158. package/lib/MapView.types.d.ts +8 -3
  159. package/lib/MapViewNativeComponent.d.ts +1 -8
  160. package/lib/MapViewNativeComponent.js +1 -10
  161. package/lib/MapWMSTile.js +2 -2
  162. package/lib/NativeGoogleMapViewModule.d.ts +25 -0
  163. package/lib/NativeGoogleMapViewModule.js +4 -0
  164. package/lib/NativeMapViewModule.d.ts +29 -0
  165. package/lib/NativeMapViewModule.js +4 -0
  166. package/lib/decorateMapComponent.d.ts +1 -1
  167. package/lib/decorateMapComponent.js +3 -3
  168. package/lib/index.d.ts +14 -21
  169. package/lib/index.js +10 -38
  170. package/package.json +6 -6
  171. package/react-native-google-maps.podspec +1 -1
  172. package/react-native-maps.podspec +2 -2
  173. package/android/src/main/java/com/rnmaps/maps/MapModule.java +0 -380
  174. package/ios/AirGoogleMaps/AIRGoogleMapCalloutSubviewManager.m +0 -28
  175. package/ios/AirGoogleMaps/AIRGoogleMapHeatmapManager.h +0 -11
  176. package/ios/AirGoogleMaps/AIRGoogleMapManager.m +0 -597
  177. package/ios/AirMaps/AIRMapCalloutSubviewManager.h +0 -14
  178. package/ios/AirMaps/AIRMapCalloutSubviewManager.m +0 -24
  179. package/ios/AirMaps/AIRMapManager.m +0 -1253
  180. package/ios/AirMaps/AIRMapOverlayManager.h +0 -5
  181. package/ios/AirMaps/AIRWeakMapReference.h +0 -24
  182. package/ios/AirMaps/AIRWeakMapReference.m +0 -23
  183. package/ios/AirMaps/AIRWeakTimerReference.h +0 -21
  184. package/ios/AirMaps/AIRWeakTimerReference.m +0 -42
  185. package/ios/AirMaps.xcodeproj/project.pbxproj +0 -587
  186. /package/ios/{AirGoogleMaps → GoogleMaps}/RCTConvert+GMSMapViewType.h +0 -0
@@ -0,0 +1,854 @@
1
+ /**
2
+ * Copyright (c) 2015-present, Facebook, Inc.
3
+ * All rights reserved.
4
+ *
5
+ * This source code is licensed under the BSD-style license found in the
6
+ * LICENSE file in the root directory of this source tree. An additional grant
7
+ * of patent rights can be found in the PATENTS file in the same directory.
8
+ */
9
+
10
+ #import "RNMMapManager.h"
11
+
12
+ #import <React/RCTBridge.h>
13
+ #import <React/RCTUIManager.h>
14
+ #import <React/RCTConvert.h>
15
+ #import <React/RCTConvert+CoreLocation.h>
16
+ #import <React/RCTEventDispatcher.h>
17
+ #import <React/RCTViewManager.h>
18
+ #import <React/UIView+React.h>
19
+ #import "RNMMap.h"
20
+ #import "RNMMapMarker.h"
21
+ #import "RNMMapPolyline.h"
22
+ #import "RNMMapPolygon.h"
23
+ #import "RNMMapCircle.h"
24
+ #import "SMCalloutView.h"
25
+ #import "RNMMapUrlTile.h"
26
+ #import "RNMMapWMSTile.h"
27
+ #import "RNMMapLocalTile.h"
28
+ #import "RNMMapSnapshot.h"
29
+ #import "RCTConvert+RNMMap.h"
30
+ #import "RNMMapOverlay.h"
31
+ #import <MapKit/MapKit.h>
32
+
33
+ static NSString *const RCTMapViewKey = @"MapView";
34
+
35
+
36
+ @interface RNMMapManager() <MKMapViewDelegate, UIGestureRecognizerDelegate>
37
+
38
+ - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer;
39
+
40
+ @end
41
+
42
+ @implementation RNMMapManager{
43
+ BOOL _hasObserver;
44
+ }
45
+
46
+ RCT_EXPORT_MODULE(RNMMap)
47
+
48
+ - (UIView *)view
49
+ {
50
+ RNMMap *map = [RNMMap new];
51
+ map.delegate = self;
52
+
53
+ map.isAccessibilityElement = NO;
54
+ map.accessibilityElementsHidden = NO;
55
+
56
+ // MKMapView doesn't report tap events, so we attach gesture recognizers to it
57
+ UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleMapTap:)];
58
+ UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleMapDoubleTap:)];
59
+ [doubleTap setNumberOfTapsRequired:2];
60
+ [tap requireGestureRecognizerToFail:doubleTap];
61
+
62
+ UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleMapLongPress:)];
63
+ UIPanGestureRecognizer *drag = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleMapDrag:)];
64
+ [drag setMinimumNumberOfTouches:1];
65
+ // setting this to NO allows the parent MapView to continue receiving marker selection events
66
+ tap.cancelsTouchesInView = NO;
67
+ doubleTap.cancelsTouchesInView = NO;
68
+ longPress.cancelsTouchesInView = NO;
69
+
70
+ doubleTap.delegate = self;
71
+
72
+ // disable drag by default
73
+ drag.enabled = NO;
74
+ drag.delegate = self;
75
+
76
+ [map addGestureRecognizer:tap];
77
+ [map addGestureRecognizer:doubleTap];
78
+ [map addGestureRecognizer:longPress];
79
+ [map addGestureRecognizer:drag];
80
+
81
+ return map;
82
+ }
83
+
84
+ RCT_EXPORT_VIEW_PROPERTY(boundary, MKMapCameraBoundary*)
85
+ RCT_EXPORT_VIEW_PROPERTY(cacheEnabled, BOOL)
86
+ RCT_EXPORT_VIEW_PROPERTY(compassOffset, CGPoint)
87
+ RCT_EXPORT_VIEW_PROPERTY(followsUserLocation, BOOL)
88
+ RCT_EXPORT_VIEW_PROPERTY(handlePanDrag, BOOL)
89
+ RCT_EXPORT_VIEW_PROPERTY(isAccessibilityElement, BOOL)
90
+ RCT_EXPORT_VIEW_PROPERTY(kmlSrc, NSString)
91
+ RCT_EXPORT_VIEW_PROPERTY(legalLabelInsets, UIEdgeInsets)
92
+ RCT_EXPORT_VIEW_PROPERTY(loadingBackgroundColor, UIColor)
93
+ RCT_EXPORT_VIEW_PROPERTY(loadingEnabled, BOOL)
94
+ RCT_EXPORT_VIEW_PROPERTY(loadingIndicatorColor, UIColor)
95
+ RCT_EXPORT_VIEW_PROPERTY(mapPadding, UIEdgeInsets)
96
+ RCT_EXPORT_VIEW_PROPERTY(mapType, MKMapType)
97
+ RCT_EXPORT_VIEW_PROPERTY(maxDelta, CGFloat)
98
+ RCT_EXPORT_VIEW_PROPERTY(maxZoomLevel, CGFloat)
99
+ RCT_EXPORT_VIEW_PROPERTY(minDelta, CGFloat)
100
+ RCT_EXPORT_VIEW_PROPERTY(minZoomLevel, CGFloat)
101
+ RCT_EXPORT_VIEW_PROPERTY(onCalloutPress, RCTDirectEventBlock)
102
+ RCT_EXPORT_VIEW_PROPERTY(onChange, RCTBubblingEventBlock)
103
+ RCT_EXPORT_VIEW_PROPERTY(onDoublePress, RCTBubblingEventBlock)
104
+ RCT_EXPORT_VIEW_PROPERTY(onLongPress, RCTBubblingEventBlock)
105
+ RCT_EXPORT_VIEW_PROPERTY(onMapReady, RCTBubblingEventBlock)
106
+ RCT_EXPORT_VIEW_PROPERTY(onMarkerDeselect, RCTDirectEventBlock)
107
+ RCT_EXPORT_VIEW_PROPERTY(onMarkerDrag, RCTDirectEventBlock)
108
+ RCT_EXPORT_VIEW_PROPERTY(onMarkerDragEnd, RCTDirectEventBlock)
109
+ RCT_EXPORT_VIEW_PROPERTY(onMarkerDragStart, RCTDirectEventBlock)
110
+ RCT_EXPORT_VIEW_PROPERTY(onMarkerPress, RCTDirectEventBlock)
111
+ RCT_EXPORT_VIEW_PROPERTY(onMarkerSelect, RCTDirectEventBlock)
112
+ RCT_EXPORT_VIEW_PROPERTY(onPanDrag, RCTBubblingEventBlock)
113
+ RCT_EXPORT_VIEW_PROPERTY(onPress, RCTBubblingEventBlock)
114
+ RCT_EXPORT_VIEW_PROPERTY(onUserLocationChange, RCTBubblingEventBlock)
115
+ RCT_EXPORT_VIEW_PROPERTY(pitchEnabled, BOOL)
116
+ RCT_EXPORT_VIEW_PROPERTY(rotateEnabled, BOOL)
117
+ RCT_EXPORT_VIEW_PROPERTY(scrollEnabled, BOOL)
118
+ RCT_EXPORT_VIEW_PROPERTY(showsBuildings, BOOL)
119
+ RCT_EXPORT_VIEW_PROPERTY(showsCompass, BOOL)
120
+ RCT_EXPORT_VIEW_PROPERTY(showsPointsOfInterest, BOOL)
121
+ RCT_EXPORT_VIEW_PROPERTY(showsScale, BOOL)
122
+ RCT_EXPORT_VIEW_PROPERTY(showsTraffic, BOOL)
123
+ RCT_EXPORT_VIEW_PROPERTY(showsUserLocation, BOOL)
124
+ RCT_EXPORT_VIEW_PROPERTY(tintColor, UIColor)
125
+ RCT_EXPORT_VIEW_PROPERTY(userInterfaceStyle, NSString)
126
+ RCT_EXPORT_VIEW_PROPERTY(userLocationAnnotationTitle, NSString)
127
+ RCT_EXPORT_VIEW_PROPERTY(userLocationCalloutEnabled, BOOL)
128
+ RCT_EXPORT_VIEW_PROPERTY(zoomEnabled, BOOL)
129
+ RCT_REMAP_VIEW_PROPERTY(testID, accessibilityIdentifier, NSString)
130
+ RCT_CUSTOM_VIEW_PROPERTY(camera, MKMapCamera*, RNMMap)
131
+ {
132
+ if (json == nil) return;
133
+
134
+ // don't emit region change events when we are setting the camera
135
+ BOOL originalIgnore = view.ignoreRegionChanges;
136
+ view.ignoreRegionChanges = YES;
137
+ [view setCamera:[RCTConvert MKMapCamera:json] animated:NO];
138
+ view.ignoreRegionChanges = originalIgnore;
139
+ }
140
+ RCT_CUSTOM_VIEW_PROPERTY(initialCamera, MKMapCamera, RNMMap)
141
+ {
142
+ if (json == nil) return;
143
+
144
+ // don't emit region change events when we are setting the initialCamera
145
+ BOOL originalIgnore = view.ignoreRegionChanges;
146
+ view.ignoreRegionChanges = YES;
147
+ [view setInitialCamera:[RCTConvert MKMapCamera:json]];
148
+ view.ignoreRegionChanges = originalIgnore;
149
+ }
150
+
151
+ RCT_CUSTOM_VIEW_PROPERTY(initialRegion, MKCoordinateRegion, RNMMap)
152
+ {
153
+ if (json == nil) return;
154
+
155
+ // don't emit region change events when we are setting the initialRegion
156
+ BOOL originalIgnore = view.ignoreRegionChanges;
157
+ view.ignoreRegionChanges = YES;
158
+ [view setInitialRegion:[RCTConvert MKCoordinateRegion:json]];
159
+ view.ignoreRegionChanges = originalIgnore;
160
+ }
161
+
162
+ RCT_CUSTOM_VIEW_PROPERTY(region, MKCoordinateRegion, RNMMap)
163
+ {
164
+ if (json == nil) return;
165
+
166
+ // don't emit region change events when we are setting the region
167
+ BOOL originalIgnore = view.ignoreRegionChanges;
168
+ view.ignoreRegionChanges = YES;
169
+ [view setRegion:[RCTConvert MKCoordinateRegion:json] animated:NO];
170
+ view.ignoreRegionChanges = originalIgnore;
171
+ }
172
+
173
+ #pragma mark exported MapView methods
174
+
175
+ RCT_EXPORT_METHOD(setCamera:(nonnull NSNumber *)reactTag
176
+ camera:(id)json)
177
+ {
178
+ [self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
179
+ id view = viewRegistry[reactTag];
180
+ if (![view isKindOfClass:[RNMMap class]]) {
181
+ RCTLogError(@"Invalid view returned from registry, expecting RNMMap, got: %@", view);
182
+ } else {
183
+ RNMMap *mapView = (RNMMap *)view;
184
+
185
+ // Merge the changes given with the current camera
186
+ MKMapCamera *camera = [RCTConvert MKMapCameraWithDefaults:json existingCamera:[mapView camera]];
187
+
188
+ // don't emit region change events when we are setting the camera
189
+ BOOL originalIgnore = mapView.ignoreRegionChanges;
190
+ mapView.ignoreRegionChanges = YES;
191
+ [mapView setCamera:camera animated:NO];
192
+ mapView.ignoreRegionChanges = originalIgnore;
193
+ }
194
+ }];
195
+ }
196
+
197
+ #pragma mark Gesture Recognizer Handlers
198
+
199
+ #define MAX_DISTANCE_PX 10.0f
200
+ - (void)handleMapTap:(UITapGestureRecognizer *)recognizer {
201
+ RNMMap *map = (RNMMap *)recognizer.view;
202
+
203
+ CGPoint tapPoint = [recognizer locationInView:map];
204
+ CLLocationCoordinate2D tapCoordinate = [map convertPoint:tapPoint toCoordinateFromView:map];
205
+ MKMapPoint mapPoint = MKMapPointForCoordinate(tapCoordinate);
206
+ CGPoint mapPointAsCGP = CGPointMake(mapPoint.x, mapPoint.y);
207
+
208
+ double maxMeters = [self metersFromPixel:MAX_DISTANCE_PX atPoint:tapPoint forMap:map];
209
+ float nearestDistance = MAXFLOAT;
210
+ RNMMapPolyline *nearestPolyline = nil;
211
+
212
+ for (id<MKOverlay> overlay in map.overlays) {
213
+ if([overlay isKindOfClass:[RNMMapPolygon class]]){
214
+ RNMMapPolygon *polygon = (RNMMapPolygon*) overlay;
215
+ if (polygon.onPress) {
216
+ CGMutablePathRef mpr = CGPathCreateMutable();
217
+
218
+ for(int i = 0; i < polygon.coordinates.count; i++) {
219
+ RNMMapCoordinate *c = polygon.coordinates[i];
220
+ MKMapPoint mp = MKMapPointForCoordinate(c.coordinate);
221
+ if (i == 0) {
222
+ CGPathMoveToPoint(mpr, NULL, mp.x, mp.y);
223
+ } else {
224
+ CGPathAddLineToPoint(mpr, NULL, mp.x, mp.y);
225
+ }
226
+ }
227
+
228
+ if (CGPathContainsPoint(mpr, NULL, mapPointAsCGP, FALSE)) {
229
+ id event = @{
230
+ @"action": @"polygon-press",
231
+ @"coordinate": @{
232
+ @"latitude": @(tapCoordinate.latitude),
233
+ @"longitude": @(tapCoordinate.longitude),
234
+ },
235
+ };
236
+ polygon.onPress(event);
237
+ }
238
+
239
+ CGPathRelease(mpr);
240
+ }
241
+ }
242
+
243
+ if([overlay isKindOfClass:[RNMMapPolyline class]]){
244
+ RNMMapPolyline *polyline = (RNMMapPolyline*) overlay;
245
+ if (polyline.onPress) {
246
+ float distance = [self distanceOfPoint:MKMapPointForCoordinate(tapCoordinate)
247
+ toPoly:polyline];
248
+ if (distance < nearestDistance) {
249
+ nearestDistance = distance;
250
+ nearestPolyline = polyline;
251
+ }
252
+ }
253
+ }
254
+
255
+ if ([overlay isKindOfClass:[RNMMapOverlay class]]) {
256
+ RNMMapOverlay *imageOverlay = (RNMMapOverlay*) overlay;
257
+ if (MKMapRectContainsPoint(imageOverlay.boundingMapRect, mapPoint)) {
258
+ if (imageOverlay.onPress) {
259
+ id event = @{
260
+ @"action": @"image-overlay-press",
261
+ @"name": imageOverlay.name ?: @"unknown",
262
+ @"coordinate": @{
263
+ @"latitude": @(imageOverlay.coordinate.latitude),
264
+ @"longitude": @(imageOverlay.coordinate.longitude)
265
+ }
266
+ };
267
+ imageOverlay.onPress(event);
268
+ }
269
+ }
270
+ }
271
+
272
+ }
273
+
274
+ if (nearestDistance <= maxMeters) {
275
+ id event = @{
276
+ @"action": @"polyline-press",
277
+ @"coordinate": @{
278
+ @"latitude": @(tapCoordinate.latitude),
279
+ @"longitude": @(tapCoordinate.longitude)
280
+ }
281
+ };
282
+ nearestPolyline.onPress(event);
283
+ }
284
+
285
+ if (!map.onPress) return;
286
+ map.onPress(@{
287
+ @"coordinate": @{
288
+ @"latitude": @(tapCoordinate.latitude),
289
+ @"longitude": @(tapCoordinate.longitude),
290
+ },
291
+ @"position": @{
292
+ @"x": @(tapPoint.x),
293
+ @"y": @(tapPoint.y),
294
+ },
295
+ });
296
+
297
+ }
298
+
299
+ - (void)handleMapDrag:(UIPanGestureRecognizer*)recognizer {
300
+ RNMMap *map = (RNMMap *)recognizer.view;
301
+ if (!map.onPanDrag) return;
302
+
303
+ CGPoint touchPoint = [recognizer locationInView:map];
304
+ CLLocationCoordinate2D coord = [map convertPoint:touchPoint toCoordinateFromView:map];
305
+ map.onPanDrag(@{
306
+ @"coordinate": @{
307
+ @"latitude": @(coord.latitude),
308
+ @"longitude": @(coord.longitude),
309
+ },
310
+ @"position": @{
311
+ @"x": @(touchPoint.x),
312
+ @"y": @(touchPoint.y),
313
+ },
314
+ });
315
+
316
+ }
317
+
318
+ - (void)handleMapDoubleTap:(UIPanGestureRecognizer*)recognizer {
319
+ RNMMap *map = (RNMMap *)recognizer.view;
320
+ if (!map.onDoublePress) return;
321
+
322
+ CGPoint touchPoint = [recognizer locationInView:map];
323
+ CLLocationCoordinate2D coord = [map convertPoint:touchPoint toCoordinateFromView:map];
324
+ map.onDoublePress(@{
325
+ @"coordinate": @{
326
+ @"latitude": @(coord.latitude),
327
+ @"longitude": @(coord.longitude),
328
+ },
329
+ @"position": @{
330
+ @"x": @(touchPoint.x),
331
+ @"y": @(touchPoint.y),
332
+ },
333
+ });
334
+
335
+ }
336
+
337
+
338
+ - (void)handleMapLongPress:(UITapGestureRecognizer *)recognizer {
339
+
340
+ // NOTE: android only does the equivalent of "began", so we only send in this case
341
+ if (recognizer.state != UIGestureRecognizerStateBegan) return;
342
+
343
+ RNMMap *map = (RNMMap *)recognizer.view;
344
+ if (!map.onLongPress) return;
345
+
346
+ CGPoint touchPoint = [recognizer locationInView:map];
347
+ CLLocationCoordinate2D coord = [map convertPoint:touchPoint toCoordinateFromView:map];
348
+
349
+ map.onLongPress(@{
350
+ @"coordinate": @{
351
+ @"latitude": @(coord.latitude),
352
+ @"longitude": @(coord.longitude),
353
+ },
354
+ @"position": @{
355
+ @"x": @(touchPoint.x),
356
+ @"y": @(touchPoint.y),
357
+ },
358
+ });
359
+ }
360
+
361
+ #pragma mark MKMapViewDelegate
362
+
363
+ #pragma mark Polyline stuff
364
+
365
+ - (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id <MKOverlay>)overlay{
366
+ if ([overlay isKindOfClass:[RNMMapPolyline class]]) {
367
+ return ((RNMMapPolyline *)overlay).renderer;
368
+ } else if ([overlay isKindOfClass:[RNMMapPolygon class]]) {
369
+ return ((RNMMapPolygon *)overlay).renderer;
370
+ } else if ([overlay isKindOfClass:[RNMMapCircle class]]) {
371
+ return ((RNMMapCircle *)overlay).renderer;
372
+ } else if ([overlay isKindOfClass:[RNMMapUrlTile class]]) {
373
+ return ((RNMMapUrlTile *)overlay).renderer;
374
+ } else if ([overlay isKindOfClass:[RNMMapWMSTile class]]) {
375
+ return ((RNMMapWMSTile *)overlay).renderer;
376
+ } else if ([overlay isKindOfClass:[RNMMapLocalTile class]]) {
377
+ return ((RNMMapLocalTile *)overlay).renderer;
378
+ } else if ([overlay isKindOfClass:[RNMMapOverlay class]]) {
379
+ return ((RNMMapOverlay *)overlay).renderer;
380
+ } else if([overlay isKindOfClass:[MKTileOverlay class]]) {
381
+ return [[MKTileOverlayRenderer alloc] initWithTileOverlay:overlay];
382
+ } else {
383
+ return nil;
384
+ }
385
+ }
386
+
387
+
388
+ #pragma mark Annotation Stuff
389
+
390
+ - (void)mapView:(RNMMap *)mapView didAddAnnotationViews:(NSArray<MKAnnotationView *> *)views
391
+ {
392
+ if(!mapView.userLocationCalloutEnabled){
393
+ for(MKAnnotationView* view in views){
394
+ if ([view.annotation isKindOfClass:[MKUserLocation class]]){
395
+ [view setEnabled:NO];
396
+ [view setCanShowCallout:NO];
397
+ break;
398
+ }
399
+ }
400
+ }
401
+ }
402
+
403
+
404
+ - (void)mapView:(RNMMap *)mapView didSelectAnnotationView:(MKAnnotationView *)view
405
+ {
406
+ if ([view.annotation isKindOfClass:[RNMMapMarker class]]) {
407
+ [(RNMMapMarker *)view.annotation showCalloutView];
408
+ } else if ([view.annotation isKindOfClass:[MKUserLocation class]] && mapView.userLocationAnnotationTitle != nil && view.annotation.title != mapView.userLocationAnnotationTitle) {
409
+ [(MKUserLocation*)view.annotation setTitle: mapView.userLocationAnnotationTitle];
410
+ }
411
+
412
+ }
413
+
414
+ - (void)mapView:(RNMMap *)mapView didDeselectAnnotationView:(MKAnnotationView *)view {
415
+ if ([view.annotation isKindOfClass:[RNMMapMarker class]]) {
416
+ [(RNMMapMarker *)view.annotation hideCalloutView];
417
+ }
418
+ }
419
+
420
+ - (MKAnnotationView *)mapView:(__unused RNMMap *)mapView viewForAnnotation:(RNMMapMarker *)marker
421
+ {
422
+ if (![marker isKindOfClass:[RNMMapMarker class]]) {
423
+ if ([marker isKindOfClass:[MKUserLocation class]] && mapView.userLocationAnnotationTitle != nil) {
424
+ [(MKUserLocation*)marker setTitle: mapView.userLocationAnnotationTitle];
425
+ return nil;
426
+ }
427
+ return nil;
428
+ }
429
+
430
+ marker.map = mapView;
431
+ return [marker getAnnotationView];
432
+ }
433
+
434
+ static int kDragCenterContext;
435
+
436
+ - (void)mapView:(RNMMap *)mapView
437
+ annotationView:(MKAnnotationView *)view
438
+ didChangeDragState:(MKAnnotationViewDragState)newState
439
+ fromOldState:(MKAnnotationViewDragState)oldState
440
+ {
441
+ if (![view.annotation isKindOfClass:[RNMMapMarker class]]) return;
442
+ RNMMapMarker *marker = (RNMMapMarker *)view.annotation;
443
+
444
+ BOOL isPinView = [view isKindOfClass:[MKMarkerAnnotationView class]];
445
+
446
+ id event = @{
447
+ @"id": marker.identifier ?: @"unknown",
448
+ @"coordinate": @{
449
+ @"latitude": @(marker.coordinate.latitude),
450
+ @"longitude": @(marker.coordinate.longitude)
451
+ }
452
+ };
453
+
454
+ if (newState == MKAnnotationViewDragStateEnding || newState == MKAnnotationViewDragStateCanceling) {
455
+ if (!isPinView) {
456
+ [view setDragState:MKAnnotationViewDragStateNone animated:NO];
457
+ }
458
+ if (mapView.onMarkerDragEnd) mapView.onMarkerDragEnd(event);
459
+ if (marker.onDragEnd) marker.onDragEnd(event);
460
+
461
+ if(_hasObserver) [view removeObserver:self forKeyPath:@"center"];
462
+ _hasObserver = NO;
463
+ } else if (newState == MKAnnotationViewDragStateStarting) {
464
+ // MapKit doesn't emit continuous drag events. To get around this, we are going to use KVO.
465
+ [view addObserver:self forKeyPath:@"center" options:NSKeyValueObservingOptionNew context:&kDragCenterContext];
466
+ _hasObserver = YES;
467
+ if (mapView.onMarkerDragStart) mapView.onMarkerDragStart(event);
468
+ if (marker.onDragStart) marker.onDragStart(event);
469
+ }
470
+ }
471
+
472
+ - (void)observeValueForKeyPath:(NSString *)keyPath
473
+ ofObject:(id)object
474
+ change:(NSDictionary *)change
475
+ context:(void *)context
476
+ {
477
+ if ([keyPath isEqualToString:@"center"] && [object isKindOfClass:[MKAnnotationView class]]) {
478
+ MKAnnotationView *view = (MKAnnotationView *)object;
479
+ RNMMapMarker *marker = (RNMMapMarker *)view.annotation;
480
+
481
+ // a marker we don't control might be getting dragged. Check just in case.
482
+ if (!marker) return;
483
+
484
+ RNMMap *map = marker.map;
485
+
486
+ // don't waste time calculating if there are no events to listen to it
487
+ if (!map.onMarkerDrag && !marker.onDrag) return;
488
+
489
+ CGPoint position = CGPointMake(view.center.x - view.centerOffset.x, view.center.y - view.centerOffset.y);
490
+ CLLocationCoordinate2D coordinate = [map convertPoint:position toCoordinateFromView:map];
491
+
492
+ id event = @{
493
+ @"id": marker.identifier ?: @"unknown",
494
+ @"position": @{
495
+ @"x": @(position.x),
496
+ @"y": @(position.y),
497
+ },
498
+ @"coordinate": @{
499
+ @"latitude": @(coordinate.latitude),
500
+ @"longitude": @(coordinate.longitude),
501
+ }
502
+ };
503
+
504
+ if (map.onMarkerDrag) map.onMarkerDrag(event);
505
+ if (marker.onDrag) marker.onDrag(event);
506
+
507
+ } else {
508
+ // This message is not for me; pass it on to super.
509
+ [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
510
+ }
511
+ }
512
+
513
+ - (void)mapView:(RNMMap *)mapView didUpdateUserLocation:(MKUserLocation *)location
514
+ {
515
+ id event = @{@"coordinate": @{
516
+ @"latitude": @(location.coordinate.latitude),
517
+ @"longitude": @(location.coordinate.longitude),
518
+ @"altitude": @(location.location.altitude),
519
+ @"timestamp": @(location.location.timestamp.timeIntervalSinceReferenceDate * 1000),
520
+ @"accuracy": @(location.location.horizontalAccuracy),
521
+ @"altitudeAccuracy": @(location.location.verticalAccuracy),
522
+ @"speed": @(location.location.speed),
523
+ @"heading": @(location.location.course),
524
+ }
525
+ };
526
+
527
+ if (mapView.onUserLocationChange) {
528
+ mapView.onUserLocationChange(event);
529
+ }
530
+
531
+ if (mapView.followUserLocation) {
532
+ [mapView setCenterCoordinate:location.coordinate animated:YES];
533
+ }
534
+
535
+ }
536
+
537
+ - (void)mapViewDidChangeVisibleRegion:(RNMMap *)mapView
538
+ {
539
+ [self _regionChanged:mapView];
540
+ }
541
+
542
+ - (void)mapView:(RNMMap *)mapView regionDidChangeAnimated:(__unused BOOL)animated
543
+ {
544
+ CGFloat zoomLevel = [self zoomLevel:mapView];
545
+
546
+ // Don't send region did change events until map has
547
+ // started rendering, as these won't represent the final location
548
+ if(mapView.hasStartedRendering){
549
+ [self _regionChanged:mapView];
550
+ }
551
+
552
+ if (zoomLevel < mapView.minZoomLevel) {
553
+ [self setCenterCoordinate:[mapView centerCoordinate] zoomLevel:mapView.minZoomLevel animated:TRUE mapView:mapView];
554
+ }
555
+ else if (zoomLevel > mapView.maxZoomLevel) {
556
+ [self setCenterCoordinate:[mapView centerCoordinate] zoomLevel:mapView.maxZoomLevel animated:TRUE mapView:mapView];
557
+ }
558
+
559
+ // Don't send region did change events until map has
560
+ // started rendering, as these won't represent the final location
561
+ if (mapView.hasStartedRendering) {
562
+ [self _emitRegionChangeEvent:mapView continuous:NO];
563
+ };
564
+
565
+ mapView.pendingCenter = mapView.region.center;
566
+ mapView.pendingSpan = mapView.region.span;
567
+ }
568
+
569
+ - (void)mapViewWillStartRenderingMap:(RNMMap *)mapView
570
+ {
571
+ if (!mapView.hasStartedRendering) {
572
+ mapView.onMapReady(@{});
573
+ mapView.hasStartedRendering = YES;
574
+ }
575
+ [mapView beginLoading];
576
+ }
577
+
578
+ - (void)mapViewDidFinishRenderingMap:(RNMMap *)mapView fullyRendered:(BOOL)fullyRendered
579
+ {
580
+ [mapView finishLoading];
581
+ }
582
+
583
+ #pragma mark Private
584
+
585
+ - (void)_regionChanged:(RNMMap *)mapView
586
+ {
587
+ BOOL needZoom = NO;
588
+ CGFloat newLongitudeDelta = 0.0f;
589
+ MKCoordinateRegion region = mapView.region;
590
+ // On iOS 7, it's possible that we observe invalid locations during initialization of the map.
591
+ // Filter those out.
592
+ if (!CLLocationCoordinate2DIsValid(region.center)) {
593
+ return;
594
+ }
595
+ // Calculation on float is not 100% accurate. If user zoom to max/min and then move, it's likely the map will auto zoom to max/min from time to time.
596
+ // So let's try to make map zoom back to 99% max or 101% min so that there are some buffer that moving the map won't constantly hitting the max/min bound.
597
+ if (mapView.maxDelta > FLT_EPSILON && region.span.longitudeDelta > mapView.maxDelta) {
598
+ needZoom = YES;
599
+ newLongitudeDelta = mapView.maxDelta * (1 - RNMMapZoomBoundBuffer);
600
+ } else if (mapView.minDelta > FLT_EPSILON && region.span.longitudeDelta < mapView.minDelta) {
601
+ needZoom = YES;
602
+ newLongitudeDelta = mapView.minDelta * (1 + RNMMapZoomBoundBuffer);
603
+ }
604
+ if (needZoom) {
605
+ region.span.latitudeDelta = region.span.latitudeDelta / region.span.longitudeDelta * newLongitudeDelta;
606
+ region.span.longitudeDelta = newLongitudeDelta;
607
+ mapView.region = region;
608
+ }
609
+
610
+ // Continuously observe region changes
611
+ [self _emitRegionChangeEvent:mapView continuous:YES];
612
+ }
613
+
614
+ - (void)_emitRegionChangeEvent:(RNMMap *)mapView continuous:(BOOL)continuous
615
+ {
616
+ if (!mapView.ignoreRegionChanges && mapView.onChange) {
617
+ MKCoordinateRegion region = mapView.region;
618
+ if (!CLLocationCoordinate2DIsValid(region.center)) {
619
+ return;
620
+ }
621
+
622
+ #define FLUSH_NAN(value) (isnan(value) ? 0 : value)
623
+ mapView.onChange(@{
624
+ @"continuous": @(continuous),
625
+ @"region": @{
626
+ @"latitude": @(FLUSH_NAN(region.center.latitude)),
627
+ @"longitude": @(FLUSH_NAN(region.center.longitude)),
628
+ @"latitudeDelta": @(FLUSH_NAN(region.span.latitudeDelta)),
629
+ @"longitudeDelta": @(FLUSH_NAN(region.span.longitudeDelta)),
630
+ }
631
+ });
632
+ }
633
+ }
634
+
635
+ /** Returns the distance of |pt| to |poly| in meters
636
+ *
637
+ *
638
+ */
639
+ - (double)distanceOfPoint:(MKMapPoint)pt toPoly:(RNMMapPolyline *)poly
640
+ {
641
+ double distance = MAXFLOAT;
642
+ for (int n = 0; n < poly.coordinates.count - 1; n++) {
643
+
644
+ MKMapPoint ptA = MKMapPointForCoordinate(poly.coordinates[n].coordinate);
645
+ MKMapPoint ptB = MKMapPointForCoordinate(poly.coordinates[n + 1].coordinate);
646
+
647
+ double xDelta = ptB.x - ptA.x;
648
+ double yDelta = ptB.y - ptA.y;
649
+
650
+ if (xDelta == 0.0 && yDelta == 0.0) {
651
+ continue;
652
+ }
653
+
654
+ double u = ((pt.x - ptA.x) * xDelta + (pt.y - ptA.y) * yDelta) / (xDelta * xDelta + yDelta * yDelta);
655
+ MKMapPoint ptClosest;
656
+ if (u < 0.0) {
657
+ ptClosest = ptA;
658
+ }
659
+ else if (u > 1.0) {
660
+ ptClosest = ptB;
661
+ }
662
+ else {
663
+ ptClosest = MKMapPointMake(ptA.x + u * xDelta, ptA.y + u * yDelta);
664
+ }
665
+
666
+ distance = MIN(distance, MKMetersBetweenMapPoints(ptClosest, pt));
667
+ }
668
+
669
+ return distance;
670
+ }
671
+
672
+
673
+ /** Converts |px| to meters at location |pt| */
674
+ - (double)metersFromPixel:(NSUInteger)px atPoint:(CGPoint)pt forMap:(RNMMap *)mapView
675
+ {
676
+ CGPoint ptB = CGPointMake(pt.x + px, pt.y);
677
+
678
+ CLLocationCoordinate2D coordA = [mapView convertPoint:pt toCoordinateFromView:mapView];
679
+ CLLocationCoordinate2D coordB = [mapView convertPoint:ptB toCoordinateFromView:mapView];
680
+
681
+ return MKMetersBetweenMapPoints(MKMapPointForCoordinate(coordA), MKMapPointForCoordinate(coordB));
682
+ }
683
+
684
+ + (double)longitudeToPixelSpaceX:(double)longitude
685
+ {
686
+ return round(MERCATOR_OFFSET + MERCATOR_RADIUS * longitude * M_PI / 180.0);
687
+ }
688
+
689
+ + (double)latitudeToPixelSpaceY:(double)latitude
690
+ {
691
+ if (latitude == 90.0) {
692
+ return 0;
693
+ } else if (latitude == -90.0) {
694
+ return MERCATOR_OFFSET * 2;
695
+ } else {
696
+ return round(MERCATOR_OFFSET - MERCATOR_RADIUS * logf((1 + sinf(latitude * M_PI / 180.0)) / (1 - sinf(latitude * M_PI / 180.0))) / 2.0);
697
+ }
698
+ }
699
+
700
+ + (double)pixelSpaceXToLongitude:(double)pixelX
701
+ {
702
+ return ((round(pixelX) - MERCATOR_OFFSET) / MERCATOR_RADIUS) * 180.0 / M_PI;
703
+ }
704
+
705
+ + (double)pixelSpaceYToLatitude:(double)pixelY
706
+ {
707
+ return (M_PI / 2.0 - 2.0 * atan(exp((round(pixelY) - MERCATOR_OFFSET) / MERCATOR_RADIUS))) * 180.0 / M_PI;
708
+ }
709
+
710
+ #pragma mark -
711
+ #pragma mark Helper methods
712
+
713
+ - (MKCoordinateSpan)coordinateSpanWithMapView:(RNMMap *)mapView
714
+ centerCoordinate:(CLLocationCoordinate2D)centerCoordinate
715
+ andZoomLevel:(double)zoomLevel
716
+ {
717
+ // convert center coordiate to pixel space
718
+ double centerPixelX = [RNMMapManager longitudeToPixelSpaceX:centerCoordinate.longitude];
719
+ double centerPixelY = [RNMMapManager latitudeToPixelSpaceY:centerCoordinate.latitude];
720
+
721
+ // determine the scale value from the zoom level
722
+ double zoomExponent = RNMMapMaxZoomLevel - zoomLevel;
723
+ double zoomScale = pow(2, zoomExponent);
724
+
725
+ // scale the map’s size in pixel space
726
+ CGSize mapSizeInPixels = mapView.bounds.size;
727
+ double scaledMapWidth = mapSizeInPixels.width * zoomScale;
728
+ double scaledMapHeight = mapSizeInPixels.height * zoomScale;
729
+
730
+ // figure out the position of the top-left pixel
731
+ double topLeftPixelX = centerPixelX - (scaledMapWidth / 2);
732
+ double topLeftPixelY = centerPixelY - (scaledMapHeight / 2);
733
+
734
+ // find delta between left and right longitudes
735
+ CLLocationDegrees minLng = [RNMMapManager pixelSpaceXToLongitude:topLeftPixelX];
736
+ CLLocationDegrees maxLng = [RNMMapManager pixelSpaceXToLongitude:topLeftPixelX + scaledMapWidth];
737
+ CLLocationDegrees longitudeDelta = maxLng - minLng;
738
+
739
+ // find delta between top and bottom latitudes
740
+ CLLocationDegrees minLat = [RNMMapManager pixelSpaceYToLatitude:topLeftPixelY];
741
+ CLLocationDegrees maxLat = [RNMMapManager pixelSpaceYToLatitude:topLeftPixelY + scaledMapHeight];
742
+ CLLocationDegrees latitudeDelta = -1 * (maxLat - minLat);
743
+
744
+ // create and return the lat/lng span
745
+ MKCoordinateSpan span = MKCoordinateSpanMake(latitudeDelta, longitudeDelta);
746
+ return span;
747
+ }
748
+
749
+ #pragma mark -
750
+ #pragma mark Public methods
751
+
752
+ - (void)setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate
753
+ zoomLevel:(double)zoomLevel
754
+ animated:(BOOL)animated
755
+ mapView:(RNMMap *)mapView
756
+ {
757
+ // clamp large numbers to 28
758
+ zoomLevel = MIN(zoomLevel, RNMMapMaxZoomLevel);
759
+
760
+ // use the zoom level to compute the region
761
+ MKCoordinateSpan span = [self coordinateSpanWithMapView:mapView centerCoordinate:centerCoordinate andZoomLevel:zoomLevel];
762
+ MKCoordinateRegion region = MKCoordinateRegionMake(centerCoordinate, span);
763
+
764
+ // set the region like normal
765
+ [mapView setRegion:region animated:animated];
766
+ }
767
+
768
+ //KMapView cannot display tiles that cross the pole (as these would involve wrapping the map from top to bottom, something that a Mercator projection just cannot do).
769
+ -(MKCoordinateRegion)coordinateRegionWithMapView:(RNMMap *)mapView
770
+ centerCoordinate:(CLLocationCoordinate2D)centerCoordinate
771
+ andZoomLevel:(double)zoomLevel
772
+ {
773
+ // clamp lat/long values to appropriate ranges
774
+ centerCoordinate.latitude = MIN(MAX(-90.0, centerCoordinate.latitude), 90.0);
775
+ centerCoordinate.longitude = fmod(centerCoordinate.longitude, 180.0);
776
+
777
+ // convert center coordiate to pixel space
778
+ double centerPixelX = [RNMMapManager longitudeToPixelSpaceX:centerCoordinate.longitude];
779
+ double centerPixelY = [RNMMapManager latitudeToPixelSpaceY:centerCoordinate.latitude];
780
+
781
+ // determine the scale value from the zoom level
782
+ double zoomExponent = RNMMapMaxZoomLevel - zoomLevel;
783
+ double zoomScale = pow(2, zoomExponent);
784
+
785
+ // scale the map’s size in pixel space
786
+ CGSize mapSizeInPixels = mapView.bounds.size;
787
+ double scaledMapWidth = mapSizeInPixels.width * zoomScale;
788
+ double scaledMapHeight = mapSizeInPixels.height * zoomScale;
789
+
790
+ // figure out the position of the left pixel
791
+ double topLeftPixelX = centerPixelX - (scaledMapWidth / 2);
792
+
793
+ // find delta between left and right longitudes
794
+ CLLocationDegrees minLng = [RNMMapManager pixelSpaceXToLongitude:topLeftPixelX];
795
+ CLLocationDegrees maxLng = [RNMMapManager pixelSpaceXToLongitude:topLeftPixelX + scaledMapWidth];
796
+ CLLocationDegrees longitudeDelta = maxLng - minLng;
797
+
798
+ // if we’re at a pole then calculate the distance from the pole towards the equator
799
+ // as MKMapView doesn’t like drawing boxes over the poles
800
+ double topPixelY = centerPixelY - (scaledMapHeight / 2);
801
+ double bottomPixelY = centerPixelY + (scaledMapHeight / 2);
802
+ BOOL adjustedCenterPoint = NO;
803
+ if (topPixelY > MERCATOR_OFFSET * 2) {
804
+ topPixelY = centerPixelY - scaledMapHeight;
805
+ bottomPixelY = MERCATOR_OFFSET * 2;
806
+ adjustedCenterPoint = YES;
807
+ }
808
+
809
+ // find delta between top and bottom latitudes
810
+ CLLocationDegrees minLat = [RNMMapManager pixelSpaceYToLatitude:topPixelY];
811
+ CLLocationDegrees maxLat = [RNMMapManager pixelSpaceYToLatitude:bottomPixelY];
812
+ CLLocationDegrees latitudeDelta = -1 * (maxLat - minLat);
813
+
814
+ // create and return the lat/lng span
815
+ MKCoordinateSpan span = MKCoordinateSpanMake(latitudeDelta, longitudeDelta);
816
+ MKCoordinateRegion region = MKCoordinateRegionMake(centerCoordinate, span);
817
+ // once again, MKMapView doesn’t like drawing boxes over the poles
818
+ // so adjust the center coordinate to the center of the resulting region
819
+ if (adjustedCenterPoint) {
820
+ region.center.latitude = [RNMMapManager pixelSpaceYToLatitude:((bottomPixelY + topPixelY) / 2.0)];
821
+ }
822
+
823
+ return region;
824
+ }
825
+
826
+ - (double) zoomLevel:(RNMMap *)mapView {
827
+ MKCoordinateRegion region = mapView.region;
828
+
829
+ double centerPixelX = [RNMMapManager longitudeToPixelSpaceX: region.center.longitude];
830
+ double topLeftPixelX = [RNMMapManager longitudeToPixelSpaceX: region.center.longitude - region.span.longitudeDelta / 2];
831
+
832
+ double scaledMapWidth = (centerPixelX - topLeftPixelX) * 2;
833
+ CGSize mapSizeInPixels = mapView.bounds.size;
834
+ double zoomScale = scaledMapWidth / mapSizeInPixels.width;
835
+ double zoomExponent = log(zoomScale) / log(2);
836
+ double zoomLevel = RNMMapMaxZoomLevel - zoomExponent;
837
+
838
+ return zoomLevel;
839
+ }
840
+
841
+ #pragma mark MKMapViewDelegate - Tracking the User Location
842
+
843
+ - (void)mapView:(RNMMap *)mapView didFailToLocateUserWithError:(NSError *)error {
844
+ id event = @{@"error": @{ @"message": error.localizedDescription }};
845
+ if (mapView.onUserLocationChange) {
846
+ mapView.onUserLocationChange(event);
847
+ }
848
+ }
849
+
850
+ - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
851
+ return YES;
852
+ }
853
+
854
+ @end