react-native-maps 2.0.0-beta.1 → 2.0.0-beta.11

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 +9 -83
  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 +66 -157
  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} +90 -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 +223 -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 +385 -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 +4 -4
  82. package/ios/{AirMaps/RCTConvert+AirMap.h → Maps/RCTConvert+RNMMap.h} +1 -1
  83. package/ios/{AirMaps/RCTConvert+AirMap.m → Maps/RCTConvert+RNMMap.m} +25 -8
  84. package/ios/{AirMaps/AIRMap.h → Maps/RNMMap.h} +8 -8
  85. package/ios/{AirMaps/AIRMap.m → Maps/RNMMap.m} +60 -56
  86. package/ios/{AirMaps/AIRMapCallout.h → Maps/RNMMapCallout.h} +1 -1
  87. package/ios/{AirMaps/AIRMapCallout.m → Maps/RNMMapCallout.m} +2 -2
  88. package/ios/{AirMaps/AIRMapCircleManager.h → Maps/RNMMapCalloutManager.h} +2 -2
  89. package/ios/{AirMaps/AIRMapCalloutManager.m → Maps/RNMMapCalloutManager.m} +7 -7
  90. package/ios/{AirMaps/AIRMapCalloutSubview.h → Maps/RNMMapCalloutSubview.h} +3 -3
  91. package/ios/{AirMaps/AIRMapCalloutSubview.m → Maps/RNMMapCalloutSubview.m} +4 -4
  92. package/ios/Maps/RNMMapCalloutSubviewManager.h +14 -0
  93. package/ios/Maps/RNMMapCalloutSubviewManager.m +24 -0
  94. package/ios/{AirMaps/AIRMapCircle.h → Maps/RNMMapCircle.h} +5 -5
  95. package/ios/{AirMaps/AIRMapCircle.m → Maps/RNMMapCircle.m} +3 -3
  96. package/ios/{AirMaps/AIRMapCalloutManager.h → Maps/RNMMapCircleManager.h} +2 -2
  97. package/ios/{AirMaps/AIRMapCircleManager.m → Maps/RNMMapCircleManager.m} +7 -7
  98. package/ios/{AirMaps/AIRMapCoordinate.h → Maps/RNMMapCoordinate.h} +2 -2
  99. package/ios/{AirMaps/AIRMapCoordinate.m → Maps/RNMMapCoordinate.m} +3 -3
  100. package/ios/{AirMaps/AIRMapLocalTile.h → Maps/RNMMapLocalTile.h} +7 -7
  101. package/ios/{AirMaps/AIRMapLocalTile.m → Maps/RNMMapLocalTile.m} +6 -6
  102. package/ios/{AirMaps/AIRMapLocalTileManager.h → Maps/RNMMapLocalTileManager.h} +3 -3
  103. package/ios/{AirMaps/AIRMapLocalTileManager.m → Maps/RNMMapLocalTileManager.m} +9 -9
  104. package/ios/{AirMaps/AIRMapLocalTileOverlay.h → Maps/RNMMapLocalTileOverlay.h} +2 -2
  105. package/ios/{AirMaps/AIRMapLocalTileOverlay.m → Maps/RNMMapLocalTileOverlay.m} +5 -5
  106. package/ios/{AirMaps/AIRMapManager.h → Maps/RNMMapManager.h} +6 -6
  107. package/ios/Maps/RNMMapManager.m +830 -0
  108. package/ios/{AirMaps/AIRMapMarker.h → Maps/RNMMapMarker.h} +8 -8
  109. package/ios/{AirMaps/AIRMapMarker.m → Maps/RNMMapMarker.m} +13 -13
  110. package/ios/{AirMaps/AIRMapMarkerManager.h → Maps/RNMMapMarkerManager.h} +1 -1
  111. package/ios/{AirMaps/AIRMapMarkerManager.m → Maps/RNMMapMarkerManager.m} +14 -14
  112. package/ios/{AirMaps/AIRMapOverlay.h → Maps/RNMMapOverlay.h} +7 -7
  113. package/ios/{AirMaps/AIRMapOverlay.m → Maps/RNMMapOverlay.m} +4 -4
  114. package/ios/Maps/RNMMapOverlayManager.h +5 -0
  115. package/ios/{AirMaps/AIRMapOverlayManager.m → Maps/RNMMapOverlayManager.m} +6 -6
  116. package/ios/{AirMaps/AIRMapOverlayRenderer.h → Maps/RNMMapOverlayRenderer.h} +1 -1
  117. package/ios/{AirMaps/AIRMapOverlayRenderer.m → Maps/RNMMapOverlayRenderer.m} +5 -5
  118. package/ios/{AirMaps/AIRMapPolygon.h → Maps/RNMMapPolygon.h} +7 -7
  119. package/ios/{AirMaps/AIRMapPolygon.m → Maps/RNMMapPolygon.m} +4 -4
  120. package/ios/{AirMaps/AIRMapPolygonManager.h → Maps/RNMMapPolygonManager.h} +2 -2
  121. package/ios/{AirMaps/AIRMapPolygonManager.m → Maps/RNMMapPolygonManager.m} +10 -10
  122. package/ios/{AirMaps/AIRMapPolyline.h → Maps/RNMMapPolyline.h} +6 -6
  123. package/ios/{AirMaps/AIRMapPolyline.m → Maps/RNMMapPolyline.m} +11 -11
  124. package/ios/{AirMaps/AIRMapPolylineManager.h → Maps/RNMMapPolylineManager.h} +2 -2
  125. package/ios/{AirMaps/AIRMapPolylineManager.m → Maps/RNMMapPolylineManager.m} +9 -9
  126. package/ios/{AirMaps/AIRMapPolylineRenderer.h → Maps/RNMMapPolylineRenderer.h} +2 -2
  127. package/ios/{AirMaps/AIRMapPolylineRenderer.m → Maps/RNMMapPolylineRenderer.m} +10 -10
  128. package/ios/{AirMaps/AIRMapSnapshot.h → Maps/RNMMapSnapshot.h} +6 -6
  129. package/ios/{AirMaps/AIRMapUrlTile.h → Maps/RNMMapUrlTile.h} +18 -18
  130. package/ios/{AirMaps/AIRMapUrlTile.m → Maps/RNMMapUrlTile.m} +7 -7
  131. package/ios/{AirMaps/AIRMapUrlTileCachedOverlay.h → Maps/RNMMapUrlTileCachedOverlay.h} +3 -3
  132. package/ios/{AirMaps/AIRMapUrlTileCachedOverlay.m → Maps/RNMMapUrlTileCachedOverlay.m} +10 -10
  133. package/ios/{AirMaps/AIRMapUrlTileManager.h → Maps/RNMMapUrlTileManager.h} +3 -3
  134. package/ios/{AirMaps/AIRMapUrlTileManager.m → Maps/RNMMapUrlTileManager.m} +9 -9
  135. package/ios/Maps/RNMMapViewModule.h +5 -0
  136. package/ios/Maps/RNMMapViewModule.m +465 -0
  137. package/ios/{AirMaps/AIRMapWMSTile.h → Maps/RNMMapWMSTile.h} +11 -11
  138. package/ios/{AirMaps/AIRMapWMSTile.m → Maps/RNMMapWMSTile.m} +15 -15
  139. package/ios/{AirMaps/AIRMapWMSTileManager.h → Maps/RNMMapWMSTileManager.h} +3 -3
  140. package/ios/{AirMaps/AIRMapWMSTileManager.m → Maps/RNMMapWMSTileManager.m} +9 -9
  141. package/ios/RNMaps.xcodeproj/project.pbxproj +647 -0
  142. package/lib/Geojson.d.ts +1 -1
  143. package/lib/MapCallout.js +2 -2
  144. package/lib/MapCalloutSubview.js +2 -2
  145. package/lib/MapCircle.js +2 -2
  146. package/lib/MapHeatmap.js +2 -2
  147. package/lib/MapLocalTile.js +2 -2
  148. package/lib/MapMarker.d.ts +2 -3
  149. package/lib/MapMarker.js +2 -4
  150. package/lib/MapOverlay.d.ts +1 -2
  151. package/lib/MapOverlay.js +2 -4
  152. package/lib/MapPolygon.js +2 -2
  153. package/lib/MapPolyline.js +2 -2
  154. package/lib/MapUrlTile.js +2 -2
  155. package/lib/MapView.d.ts +21 -16
  156. package/lib/MapView.js +92 -118
  157. package/lib/MapView.types.d.ts +8 -3
  158. package/lib/MapViewNativeComponent.d.ts +0 -15
  159. package/lib/MapViewNativeComponent.js +0 -17
  160. package/lib/MapWMSTile.js +2 -2
  161. package/lib/NativeGoogleMapViewModule.d.ts +25 -0
  162. package/lib/NativeGoogleMapViewModule.js +4 -0
  163. package/lib/NativeMapViewModule.d.ts +29 -0
  164. package/lib/NativeMapViewModule.js +4 -0
  165. package/lib/decorateMapComponent.d.ts +1 -1
  166. package/lib/decorateMapComponent.js +3 -3
  167. package/lib/index.d.ts +14 -21
  168. package/lib/index.js +10 -38
  169. package/package.json +6 -6
  170. package/react-native-google-maps.podspec +1 -1
  171. package/react-native-maps.podspec +2 -2
  172. package/android/src/main/java/com/rnmaps/maps/MapModule.java +0 -380
  173. package/ios/AirGoogleMaps/AIRGoogleMapCalloutSubviewManager.m +0 -28
  174. package/ios/AirGoogleMaps/AIRGoogleMapHeatmapManager.h +0 -11
  175. package/ios/AirGoogleMaps/AIRGoogleMapManager.m +0 -597
  176. package/ios/AirMaps/AIRMapCalloutSubviewManager.h +0 -14
  177. package/ios/AirMaps/AIRMapCalloutSubviewManager.m +0 -24
  178. package/ios/AirMaps/AIRMapManager.m +0 -1253
  179. package/ios/AirMaps/AIRMapOverlayManager.h +0 -5
  180. package/ios/AirMaps/AIRWeakMapReference.h +0 -24
  181. package/ios/AirMaps/AIRWeakMapReference.m +0 -23
  182. package/ios/AirMaps/AIRWeakTimerReference.h +0 -21
  183. package/ios/AirMaps/AIRWeakTimerReference.m +0 -42
  184. package/ios/AirMaps.xcodeproj/project.pbxproj +0 -587
  185. /package/ios/{AirGoogleMaps → GoogleMaps}/RCTConvert+GMSMapViewType.h +0 -0
  186. /package/ios/{AirMaps → Maps}/Callout/SMCalloutView.m +0 -0
@@ -0,0 +1,830 @@
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 Gesture Recognizer Handlers
174
+
175
+ #define MAX_DISTANCE_PX 10.0f
176
+ - (void)handleMapTap:(UITapGestureRecognizer *)recognizer {
177
+ RNMMap *map = (RNMMap *)recognizer.view;
178
+
179
+ CGPoint tapPoint = [recognizer locationInView:map];
180
+ CLLocationCoordinate2D tapCoordinate = [map convertPoint:tapPoint toCoordinateFromView:map];
181
+ MKMapPoint mapPoint = MKMapPointForCoordinate(tapCoordinate);
182
+ CGPoint mapPointAsCGP = CGPointMake(mapPoint.x, mapPoint.y);
183
+
184
+ double maxMeters = [self metersFromPixel:MAX_DISTANCE_PX atPoint:tapPoint forMap:map];
185
+ float nearestDistance = MAXFLOAT;
186
+ RNMMapPolyline *nearestPolyline = nil;
187
+
188
+ for (id<MKOverlay> overlay in map.overlays) {
189
+ if([overlay isKindOfClass:[RNMMapPolygon class]]){
190
+ RNMMapPolygon *polygon = (RNMMapPolygon*) overlay;
191
+ if (polygon.onPress) {
192
+ CGMutablePathRef mpr = CGPathCreateMutable();
193
+
194
+ for(int i = 0; i < polygon.coordinates.count; i++) {
195
+ RNMMapCoordinate *c = polygon.coordinates[i];
196
+ MKMapPoint mp = MKMapPointForCoordinate(c.coordinate);
197
+ if (i == 0) {
198
+ CGPathMoveToPoint(mpr, NULL, mp.x, mp.y);
199
+ } else {
200
+ CGPathAddLineToPoint(mpr, NULL, mp.x, mp.y);
201
+ }
202
+ }
203
+
204
+ if (CGPathContainsPoint(mpr, NULL, mapPointAsCGP, FALSE)) {
205
+ id event = @{
206
+ @"action": @"polygon-press",
207
+ @"coordinate": @{
208
+ @"latitude": @(tapCoordinate.latitude),
209
+ @"longitude": @(tapCoordinate.longitude),
210
+ },
211
+ };
212
+ polygon.onPress(event);
213
+ }
214
+
215
+ CGPathRelease(mpr);
216
+ }
217
+ }
218
+
219
+ if([overlay isKindOfClass:[RNMMapPolyline class]]){
220
+ RNMMapPolyline *polyline = (RNMMapPolyline*) overlay;
221
+ if (polyline.onPress) {
222
+ float distance = [self distanceOfPoint:MKMapPointForCoordinate(tapCoordinate)
223
+ toPoly:polyline];
224
+ if (distance < nearestDistance) {
225
+ nearestDistance = distance;
226
+ nearestPolyline = polyline;
227
+ }
228
+ }
229
+ }
230
+
231
+ if ([overlay isKindOfClass:[RNMMapOverlay class]]) {
232
+ RNMMapOverlay *imageOverlay = (RNMMapOverlay*) overlay;
233
+ if (MKMapRectContainsPoint(imageOverlay.boundingMapRect, mapPoint)) {
234
+ if (imageOverlay.onPress) {
235
+ id event = @{
236
+ @"action": @"image-overlay-press",
237
+ @"name": imageOverlay.name ?: @"unknown",
238
+ @"coordinate": @{
239
+ @"latitude": @(imageOverlay.coordinate.latitude),
240
+ @"longitude": @(imageOverlay.coordinate.longitude)
241
+ }
242
+ };
243
+ imageOverlay.onPress(event);
244
+ }
245
+ }
246
+ }
247
+
248
+ }
249
+
250
+ if (nearestDistance <= maxMeters) {
251
+ id event = @{
252
+ @"action": @"polyline-press",
253
+ @"coordinate": @{
254
+ @"latitude": @(tapCoordinate.latitude),
255
+ @"longitude": @(tapCoordinate.longitude)
256
+ }
257
+ };
258
+ nearestPolyline.onPress(event);
259
+ }
260
+
261
+ if (!map.onPress) return;
262
+ map.onPress(@{
263
+ @"coordinate": @{
264
+ @"latitude": @(tapCoordinate.latitude),
265
+ @"longitude": @(tapCoordinate.longitude),
266
+ },
267
+ @"position": @{
268
+ @"x": @(tapPoint.x),
269
+ @"y": @(tapPoint.y),
270
+ },
271
+ });
272
+
273
+ }
274
+
275
+ - (void)handleMapDrag:(UIPanGestureRecognizer*)recognizer {
276
+ RNMMap *map = (RNMMap *)recognizer.view;
277
+ if (!map.onPanDrag) return;
278
+
279
+ CGPoint touchPoint = [recognizer locationInView:map];
280
+ CLLocationCoordinate2D coord = [map convertPoint:touchPoint toCoordinateFromView:map];
281
+ map.onPanDrag(@{
282
+ @"coordinate": @{
283
+ @"latitude": @(coord.latitude),
284
+ @"longitude": @(coord.longitude),
285
+ },
286
+ @"position": @{
287
+ @"x": @(touchPoint.x),
288
+ @"y": @(touchPoint.y),
289
+ },
290
+ });
291
+
292
+ }
293
+
294
+ - (void)handleMapDoubleTap:(UIPanGestureRecognizer*)recognizer {
295
+ RNMMap *map = (RNMMap *)recognizer.view;
296
+ if (!map.onDoublePress) return;
297
+
298
+ CGPoint touchPoint = [recognizer locationInView:map];
299
+ CLLocationCoordinate2D coord = [map convertPoint:touchPoint toCoordinateFromView:map];
300
+ map.onDoublePress(@{
301
+ @"coordinate": @{
302
+ @"latitude": @(coord.latitude),
303
+ @"longitude": @(coord.longitude),
304
+ },
305
+ @"position": @{
306
+ @"x": @(touchPoint.x),
307
+ @"y": @(touchPoint.y),
308
+ },
309
+ });
310
+
311
+ }
312
+
313
+
314
+ - (void)handleMapLongPress:(UITapGestureRecognizer *)recognizer {
315
+
316
+ // NOTE: android only does the equivalent of "began", so we only send in this case
317
+ if (recognizer.state != UIGestureRecognizerStateBegan) return;
318
+
319
+ RNMMap *map = (RNMMap *)recognizer.view;
320
+ if (!map.onLongPress) return;
321
+
322
+ CGPoint touchPoint = [recognizer locationInView:map];
323
+ CLLocationCoordinate2D coord = [map convertPoint:touchPoint toCoordinateFromView:map];
324
+
325
+ map.onLongPress(@{
326
+ @"coordinate": @{
327
+ @"latitude": @(coord.latitude),
328
+ @"longitude": @(coord.longitude),
329
+ },
330
+ @"position": @{
331
+ @"x": @(touchPoint.x),
332
+ @"y": @(touchPoint.y),
333
+ },
334
+ });
335
+ }
336
+
337
+ #pragma mark MKMapViewDelegate
338
+
339
+ #pragma mark Polyline stuff
340
+
341
+ - (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id <MKOverlay>)overlay{
342
+ if ([overlay isKindOfClass:[RNMMapPolyline class]]) {
343
+ return ((RNMMapPolyline *)overlay).renderer;
344
+ } else if ([overlay isKindOfClass:[RNMMapPolygon class]]) {
345
+ return ((RNMMapPolygon *)overlay).renderer;
346
+ } else if ([overlay isKindOfClass:[RNMMapCircle class]]) {
347
+ return ((RNMMapCircle *)overlay).renderer;
348
+ } else if ([overlay isKindOfClass:[RNMMapUrlTile class]]) {
349
+ return ((RNMMapUrlTile *)overlay).renderer;
350
+ } else if ([overlay isKindOfClass:[RNMMapWMSTile class]]) {
351
+ return ((RNMMapWMSTile *)overlay).renderer;
352
+ } else if ([overlay isKindOfClass:[RNMMapLocalTile class]]) {
353
+ return ((RNMMapLocalTile *)overlay).renderer;
354
+ } else if ([overlay isKindOfClass:[RNMMapOverlay class]]) {
355
+ return ((RNMMapOverlay *)overlay).renderer;
356
+ } else if([overlay isKindOfClass:[MKTileOverlay class]]) {
357
+ return [[MKTileOverlayRenderer alloc] initWithTileOverlay:overlay];
358
+ } else {
359
+ return nil;
360
+ }
361
+ }
362
+
363
+
364
+ #pragma mark Annotation Stuff
365
+
366
+ - (void)mapView:(RNMMap *)mapView didAddAnnotationViews:(NSArray<MKAnnotationView *> *)views
367
+ {
368
+ if(!mapView.userLocationCalloutEnabled){
369
+ for(MKAnnotationView* view in views){
370
+ if ([view.annotation isKindOfClass:[MKUserLocation class]]){
371
+ [view setEnabled:NO];
372
+ [view setCanShowCallout:NO];
373
+ break;
374
+ }
375
+ }
376
+ }
377
+ }
378
+
379
+
380
+ - (void)mapView:(RNMMap *)mapView didSelectAnnotationView:(MKAnnotationView *)view
381
+ {
382
+ if ([view.annotation isKindOfClass:[RNMMapMarker class]]) {
383
+ [(RNMMapMarker *)view.annotation showCalloutView];
384
+ } else if ([view.annotation isKindOfClass:[MKUserLocation class]] && mapView.userLocationAnnotationTitle != nil && view.annotation.title != mapView.userLocationAnnotationTitle) {
385
+ [(MKUserLocation*)view.annotation setTitle: mapView.userLocationAnnotationTitle];
386
+ }
387
+
388
+ }
389
+
390
+ - (void)mapView:(RNMMap *)mapView didDeselectAnnotationView:(MKAnnotationView *)view {
391
+ if ([view.annotation isKindOfClass:[RNMMapMarker class]]) {
392
+ [(RNMMapMarker *)view.annotation hideCalloutView];
393
+ }
394
+ }
395
+
396
+ - (MKAnnotationView *)mapView:(__unused RNMMap *)mapView viewForAnnotation:(RNMMapMarker *)marker
397
+ {
398
+ if (![marker isKindOfClass:[RNMMapMarker class]]) {
399
+ if ([marker isKindOfClass:[MKUserLocation class]] && mapView.userLocationAnnotationTitle != nil) {
400
+ [(MKUserLocation*)marker setTitle: mapView.userLocationAnnotationTitle];
401
+ return nil;
402
+ }
403
+ return nil;
404
+ }
405
+
406
+ marker.map = mapView;
407
+ return [marker getAnnotationView];
408
+ }
409
+
410
+ static int kDragCenterContext;
411
+
412
+ - (void)mapView:(RNMMap *)mapView
413
+ annotationView:(MKAnnotationView *)view
414
+ didChangeDragState:(MKAnnotationViewDragState)newState
415
+ fromOldState:(MKAnnotationViewDragState)oldState
416
+ {
417
+ if (![view.annotation isKindOfClass:[RNMMapMarker class]]) return;
418
+ RNMMapMarker *marker = (RNMMapMarker *)view.annotation;
419
+
420
+ BOOL isPinView = [view isKindOfClass:[MKMarkerAnnotationView class]];
421
+
422
+ id event = @{
423
+ @"id": marker.identifier ?: @"unknown",
424
+ @"coordinate": @{
425
+ @"latitude": @(marker.coordinate.latitude),
426
+ @"longitude": @(marker.coordinate.longitude)
427
+ }
428
+ };
429
+
430
+ if (newState == MKAnnotationViewDragStateEnding || newState == MKAnnotationViewDragStateCanceling) {
431
+ if (!isPinView) {
432
+ [view setDragState:MKAnnotationViewDragStateNone animated:NO];
433
+ }
434
+ if (mapView.onMarkerDragEnd) mapView.onMarkerDragEnd(event);
435
+ if (marker.onDragEnd) marker.onDragEnd(event);
436
+
437
+ if(_hasObserver) [view removeObserver:self forKeyPath:@"center"];
438
+ _hasObserver = NO;
439
+ } else if (newState == MKAnnotationViewDragStateStarting) {
440
+ // MapKit doesn't emit continuous drag events. To get around this, we are going to use KVO.
441
+ [view addObserver:self forKeyPath:@"center" options:NSKeyValueObservingOptionNew context:&kDragCenterContext];
442
+ _hasObserver = YES;
443
+ if (mapView.onMarkerDragStart) mapView.onMarkerDragStart(event);
444
+ if (marker.onDragStart) marker.onDragStart(event);
445
+ }
446
+ }
447
+
448
+ - (void)observeValueForKeyPath:(NSString *)keyPath
449
+ ofObject:(id)object
450
+ change:(NSDictionary *)change
451
+ context:(void *)context
452
+ {
453
+ if ([keyPath isEqualToString:@"center"] && [object isKindOfClass:[MKAnnotationView class]]) {
454
+ MKAnnotationView *view = (MKAnnotationView *)object;
455
+ RNMMapMarker *marker = (RNMMapMarker *)view.annotation;
456
+
457
+ // a marker we don't control might be getting dragged. Check just in case.
458
+ if (!marker) return;
459
+
460
+ RNMMap *map = marker.map;
461
+
462
+ // don't waste time calculating if there are no events to listen to it
463
+ if (!map.onMarkerDrag && !marker.onDrag) return;
464
+
465
+ CGPoint position = CGPointMake(view.center.x - view.centerOffset.x, view.center.y - view.centerOffset.y);
466
+ CLLocationCoordinate2D coordinate = [map convertPoint:position toCoordinateFromView:map];
467
+
468
+ id event = @{
469
+ @"id": marker.identifier ?: @"unknown",
470
+ @"position": @{
471
+ @"x": @(position.x),
472
+ @"y": @(position.y),
473
+ },
474
+ @"coordinate": @{
475
+ @"latitude": @(coordinate.latitude),
476
+ @"longitude": @(coordinate.longitude),
477
+ }
478
+ };
479
+
480
+ if (map.onMarkerDrag) map.onMarkerDrag(event);
481
+ if (marker.onDrag) marker.onDrag(event);
482
+
483
+ } else {
484
+ // This message is not for me; pass it on to super.
485
+ [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
486
+ }
487
+ }
488
+
489
+ - (void)mapView:(RNMMap *)mapView didUpdateUserLocation:(MKUserLocation *)location
490
+ {
491
+ id event = @{@"coordinate": @{
492
+ @"latitude": @(location.coordinate.latitude),
493
+ @"longitude": @(location.coordinate.longitude),
494
+ @"altitude": @(location.location.altitude),
495
+ @"timestamp": @(location.location.timestamp.timeIntervalSinceReferenceDate * 1000),
496
+ @"accuracy": @(location.location.horizontalAccuracy),
497
+ @"altitudeAccuracy": @(location.location.verticalAccuracy),
498
+ @"speed": @(location.location.speed),
499
+ @"heading": @(location.location.course),
500
+ }
501
+ };
502
+
503
+ if (mapView.onUserLocationChange) {
504
+ mapView.onUserLocationChange(event);
505
+ }
506
+
507
+ if (mapView.followUserLocation) {
508
+ [mapView setCenterCoordinate:location.coordinate animated:YES];
509
+ }
510
+
511
+ }
512
+
513
+ - (void)mapViewDidChangeVisibleRegion:(RNMMap *)mapView
514
+ {
515
+ [self _regionChanged:mapView];
516
+ }
517
+
518
+ - (void)mapView:(RNMMap *)mapView regionDidChangeAnimated:(__unused BOOL)animated
519
+ {
520
+ CGFloat zoomLevel = [self zoomLevel:mapView];
521
+
522
+ // Don't send region did change events until map has
523
+ // started rendering, as these won't represent the final location
524
+ if(mapView.hasStartedRendering){
525
+ [self _regionChanged:mapView];
526
+ }
527
+
528
+ if (zoomLevel < mapView.minZoomLevel) {
529
+ [self setCenterCoordinate:[mapView centerCoordinate] zoomLevel:mapView.minZoomLevel animated:TRUE mapView:mapView];
530
+ }
531
+ else if (zoomLevel > mapView.maxZoomLevel) {
532
+ [self setCenterCoordinate:[mapView centerCoordinate] zoomLevel:mapView.maxZoomLevel animated:TRUE mapView:mapView];
533
+ }
534
+
535
+ // Don't send region did change events until map has
536
+ // started rendering, as these won't represent the final location
537
+ if (mapView.hasStartedRendering) {
538
+ [self _emitRegionChangeEvent:mapView continuous:NO];
539
+ };
540
+
541
+ mapView.pendingCenter = mapView.region.center;
542
+ mapView.pendingSpan = mapView.region.span;
543
+ }
544
+
545
+ - (void)mapViewWillStartRenderingMap:(RNMMap *)mapView
546
+ {
547
+ if (!mapView.hasStartedRendering) {
548
+ mapView.onMapReady(@{});
549
+ mapView.hasStartedRendering = YES;
550
+ }
551
+ [mapView beginLoading];
552
+ }
553
+
554
+ - (void)mapViewDidFinishRenderingMap:(RNMMap *)mapView fullyRendered:(BOOL)fullyRendered
555
+ {
556
+ [mapView finishLoading];
557
+ }
558
+
559
+ #pragma mark Private
560
+
561
+ - (void)_regionChanged:(RNMMap *)mapView
562
+ {
563
+ BOOL needZoom = NO;
564
+ CGFloat newLongitudeDelta = 0.0f;
565
+ MKCoordinateRegion region = mapView.region;
566
+ // On iOS 7, it's possible that we observe invalid locations during initialization of the map.
567
+ // Filter those out.
568
+ if (!CLLocationCoordinate2DIsValid(region.center)) {
569
+ return;
570
+ }
571
+ // 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.
572
+ // 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.
573
+ if (mapView.maxDelta > FLT_EPSILON && region.span.longitudeDelta > mapView.maxDelta) {
574
+ needZoom = YES;
575
+ newLongitudeDelta = mapView.maxDelta * (1 - RNMMapZoomBoundBuffer);
576
+ } else if (mapView.minDelta > FLT_EPSILON && region.span.longitudeDelta < mapView.minDelta) {
577
+ needZoom = YES;
578
+ newLongitudeDelta = mapView.minDelta * (1 + RNMMapZoomBoundBuffer);
579
+ }
580
+ if (needZoom) {
581
+ region.span.latitudeDelta = region.span.latitudeDelta / region.span.longitudeDelta * newLongitudeDelta;
582
+ region.span.longitudeDelta = newLongitudeDelta;
583
+ mapView.region = region;
584
+ }
585
+
586
+ // Continuously observe region changes
587
+ [self _emitRegionChangeEvent:mapView continuous:YES];
588
+ }
589
+
590
+ - (void)_emitRegionChangeEvent:(RNMMap *)mapView continuous:(BOOL)continuous
591
+ {
592
+ if (!mapView.ignoreRegionChanges && mapView.onChange) {
593
+ MKCoordinateRegion region = mapView.region;
594
+ if (!CLLocationCoordinate2DIsValid(region.center)) {
595
+ return;
596
+ }
597
+
598
+ #define FLUSH_NAN(value) (isnan(value) ? 0 : value)
599
+ mapView.onChange(@{
600
+ @"continuous": @(continuous),
601
+ @"region": @{
602
+ @"latitude": @(FLUSH_NAN(region.center.latitude)),
603
+ @"longitude": @(FLUSH_NAN(region.center.longitude)),
604
+ @"latitudeDelta": @(FLUSH_NAN(region.span.latitudeDelta)),
605
+ @"longitudeDelta": @(FLUSH_NAN(region.span.longitudeDelta)),
606
+ }
607
+ });
608
+ }
609
+ }
610
+
611
+ /** Returns the distance of |pt| to |poly| in meters
612
+ *
613
+ *
614
+ */
615
+ - (double)distanceOfPoint:(MKMapPoint)pt toPoly:(RNMMapPolyline *)poly
616
+ {
617
+ double distance = MAXFLOAT;
618
+ for (int n = 0; n < poly.coordinates.count - 1; n++) {
619
+
620
+ MKMapPoint ptA = MKMapPointForCoordinate(poly.coordinates[n].coordinate);
621
+ MKMapPoint ptB = MKMapPointForCoordinate(poly.coordinates[n + 1].coordinate);
622
+
623
+ double xDelta = ptB.x - ptA.x;
624
+ double yDelta = ptB.y - ptA.y;
625
+
626
+ if (xDelta == 0.0 && yDelta == 0.0) {
627
+ continue;
628
+ }
629
+
630
+ double u = ((pt.x - ptA.x) * xDelta + (pt.y - ptA.y) * yDelta) / (xDelta * xDelta + yDelta * yDelta);
631
+ MKMapPoint ptClosest;
632
+ if (u < 0.0) {
633
+ ptClosest = ptA;
634
+ }
635
+ else if (u > 1.0) {
636
+ ptClosest = ptB;
637
+ }
638
+ else {
639
+ ptClosest = MKMapPointMake(ptA.x + u * xDelta, ptA.y + u * yDelta);
640
+ }
641
+
642
+ distance = MIN(distance, MKMetersBetweenMapPoints(ptClosest, pt));
643
+ }
644
+
645
+ return distance;
646
+ }
647
+
648
+
649
+ /** Converts |px| to meters at location |pt| */
650
+ - (double)metersFromPixel:(NSUInteger)px atPoint:(CGPoint)pt forMap:(RNMMap *)mapView
651
+ {
652
+ CGPoint ptB = CGPointMake(pt.x + px, pt.y);
653
+
654
+ CLLocationCoordinate2D coordA = [mapView convertPoint:pt toCoordinateFromView:mapView];
655
+ CLLocationCoordinate2D coordB = [mapView convertPoint:ptB toCoordinateFromView:mapView];
656
+
657
+ return MKMetersBetweenMapPoints(MKMapPointForCoordinate(coordA), MKMapPointForCoordinate(coordB));
658
+ }
659
+
660
+ + (double)longitudeToPixelSpaceX:(double)longitude
661
+ {
662
+ return round(MERCATOR_OFFSET + MERCATOR_RADIUS * longitude * M_PI / 180.0);
663
+ }
664
+
665
+ + (double)latitudeToPixelSpaceY:(double)latitude
666
+ {
667
+ if (latitude == 90.0) {
668
+ return 0;
669
+ } else if (latitude == -90.0) {
670
+ return MERCATOR_OFFSET * 2;
671
+ } else {
672
+ return round(MERCATOR_OFFSET - MERCATOR_RADIUS * logf((1 + sinf(latitude * M_PI / 180.0)) / (1 - sinf(latitude * M_PI / 180.0))) / 2.0);
673
+ }
674
+ }
675
+
676
+ + (double)pixelSpaceXToLongitude:(double)pixelX
677
+ {
678
+ return ((round(pixelX) - MERCATOR_OFFSET) / MERCATOR_RADIUS) * 180.0 / M_PI;
679
+ }
680
+
681
+ + (double)pixelSpaceYToLatitude:(double)pixelY
682
+ {
683
+ return (M_PI / 2.0 - 2.0 * atan(exp((round(pixelY) - MERCATOR_OFFSET) / MERCATOR_RADIUS))) * 180.0 / M_PI;
684
+ }
685
+
686
+ #pragma mark -
687
+ #pragma mark Helper methods
688
+
689
+ - (MKCoordinateSpan)coordinateSpanWithMapView:(RNMMap *)mapView
690
+ centerCoordinate:(CLLocationCoordinate2D)centerCoordinate
691
+ andZoomLevel:(double)zoomLevel
692
+ {
693
+ // convert center coordiate to pixel space
694
+ double centerPixelX = [RNMMapManager longitudeToPixelSpaceX:centerCoordinate.longitude];
695
+ double centerPixelY = [RNMMapManager latitudeToPixelSpaceY:centerCoordinate.latitude];
696
+
697
+ // determine the scale value from the zoom level
698
+ double zoomExponent = RNMMapMaxZoomLevel - zoomLevel;
699
+ double zoomScale = pow(2, zoomExponent);
700
+
701
+ // scale the map’s size in pixel space
702
+ CGSize mapSizeInPixels = mapView.bounds.size;
703
+ double scaledMapWidth = mapSizeInPixels.width * zoomScale;
704
+ double scaledMapHeight = mapSizeInPixels.height * zoomScale;
705
+
706
+ // figure out the position of the top-left pixel
707
+ double topLeftPixelX = centerPixelX - (scaledMapWidth / 2);
708
+ double topLeftPixelY = centerPixelY - (scaledMapHeight / 2);
709
+
710
+ // find delta between left and right longitudes
711
+ CLLocationDegrees minLng = [RNMMapManager pixelSpaceXToLongitude:topLeftPixelX];
712
+ CLLocationDegrees maxLng = [RNMMapManager pixelSpaceXToLongitude:topLeftPixelX + scaledMapWidth];
713
+ CLLocationDegrees longitudeDelta = maxLng - minLng;
714
+
715
+ // find delta between top and bottom latitudes
716
+ CLLocationDegrees minLat = [RNMMapManager pixelSpaceYToLatitude:topLeftPixelY];
717
+ CLLocationDegrees maxLat = [RNMMapManager pixelSpaceYToLatitude:topLeftPixelY + scaledMapHeight];
718
+ CLLocationDegrees latitudeDelta = -1 * (maxLat - minLat);
719
+
720
+ // create and return the lat/lng span
721
+ MKCoordinateSpan span = MKCoordinateSpanMake(latitudeDelta, longitudeDelta);
722
+ return span;
723
+ }
724
+
725
+ #pragma mark -
726
+ #pragma mark Public methods
727
+
728
+ - (void)setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate
729
+ zoomLevel:(double)zoomLevel
730
+ animated:(BOOL)animated
731
+ mapView:(RNMMap *)mapView
732
+ {
733
+ // clamp large numbers to 28
734
+ zoomLevel = MIN(zoomLevel, RNMMapMaxZoomLevel);
735
+
736
+ // use the zoom level to compute the region
737
+ MKCoordinateSpan span = [self coordinateSpanWithMapView:mapView centerCoordinate:centerCoordinate andZoomLevel:zoomLevel];
738
+ MKCoordinateRegion region = MKCoordinateRegionMake(centerCoordinate, span);
739
+
740
+ // set the region like normal
741
+ [mapView setRegion:region animated:animated];
742
+ }
743
+
744
+ //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).
745
+ -(MKCoordinateRegion)coordinateRegionWithMapView:(RNMMap *)mapView
746
+ centerCoordinate:(CLLocationCoordinate2D)centerCoordinate
747
+ andZoomLevel:(double)zoomLevel
748
+ {
749
+ // clamp lat/long values to appropriate ranges
750
+ centerCoordinate.latitude = MIN(MAX(-90.0, centerCoordinate.latitude), 90.0);
751
+ centerCoordinate.longitude = fmod(centerCoordinate.longitude, 180.0);
752
+
753
+ // convert center coordiate to pixel space
754
+ double centerPixelX = [RNMMapManager longitudeToPixelSpaceX:centerCoordinate.longitude];
755
+ double centerPixelY = [RNMMapManager latitudeToPixelSpaceY:centerCoordinate.latitude];
756
+
757
+ // determine the scale value from the zoom level
758
+ double zoomExponent = RNMMapMaxZoomLevel - zoomLevel;
759
+ double zoomScale = pow(2, zoomExponent);
760
+
761
+ // scale the map’s size in pixel space
762
+ CGSize mapSizeInPixels = mapView.bounds.size;
763
+ double scaledMapWidth = mapSizeInPixels.width * zoomScale;
764
+ double scaledMapHeight = mapSizeInPixels.height * zoomScale;
765
+
766
+ // figure out the position of the left pixel
767
+ double topLeftPixelX = centerPixelX - (scaledMapWidth / 2);
768
+
769
+ // find delta between left and right longitudes
770
+ CLLocationDegrees minLng = [RNMMapManager pixelSpaceXToLongitude:topLeftPixelX];
771
+ CLLocationDegrees maxLng = [RNMMapManager pixelSpaceXToLongitude:topLeftPixelX + scaledMapWidth];
772
+ CLLocationDegrees longitudeDelta = maxLng - minLng;
773
+
774
+ // if we’re at a pole then calculate the distance from the pole towards the equator
775
+ // as MKMapView doesn’t like drawing boxes over the poles
776
+ double topPixelY = centerPixelY - (scaledMapHeight / 2);
777
+ double bottomPixelY = centerPixelY + (scaledMapHeight / 2);
778
+ BOOL adjustedCenterPoint = NO;
779
+ if (topPixelY > MERCATOR_OFFSET * 2) {
780
+ topPixelY = centerPixelY - scaledMapHeight;
781
+ bottomPixelY = MERCATOR_OFFSET * 2;
782
+ adjustedCenterPoint = YES;
783
+ }
784
+
785
+ // find delta between top and bottom latitudes
786
+ CLLocationDegrees minLat = [RNMMapManager pixelSpaceYToLatitude:topPixelY];
787
+ CLLocationDegrees maxLat = [RNMMapManager pixelSpaceYToLatitude:bottomPixelY];
788
+ CLLocationDegrees latitudeDelta = -1 * (maxLat - minLat);
789
+
790
+ // create and return the lat/lng span
791
+ MKCoordinateSpan span = MKCoordinateSpanMake(latitudeDelta, longitudeDelta);
792
+ MKCoordinateRegion region = MKCoordinateRegionMake(centerCoordinate, span);
793
+ // once again, MKMapView doesn’t like drawing boxes over the poles
794
+ // so adjust the center coordinate to the center of the resulting region
795
+ if (adjustedCenterPoint) {
796
+ region.center.latitude = [RNMMapManager pixelSpaceYToLatitude:((bottomPixelY + topPixelY) / 2.0)];
797
+ }
798
+
799
+ return region;
800
+ }
801
+
802
+ - (double) zoomLevel:(RNMMap *)mapView {
803
+ MKCoordinateRegion region = mapView.region;
804
+
805
+ double centerPixelX = [RNMMapManager longitudeToPixelSpaceX: region.center.longitude];
806
+ double topLeftPixelX = [RNMMapManager longitudeToPixelSpaceX: region.center.longitude - region.span.longitudeDelta / 2];
807
+
808
+ double scaledMapWidth = (centerPixelX - topLeftPixelX) * 2;
809
+ CGSize mapSizeInPixels = mapView.bounds.size;
810
+ double zoomScale = scaledMapWidth / mapSizeInPixels.width;
811
+ double zoomExponent = log(zoomScale) / log(2);
812
+ double zoomLevel = RNMMapMaxZoomLevel - zoomExponent;
813
+
814
+ return zoomLevel;
815
+ }
816
+
817
+ #pragma mark MKMapViewDelegate - Tracking the User Location
818
+
819
+ - (void)mapView:(RNMMap *)mapView didFailToLocateUserWithError:(NSError *)error {
820
+ id event = @{@"error": @{ @"message": error.localizedDescription }};
821
+ if (mapView.onUserLocationChange) {
822
+ mapView.onUserLocationChange(event);
823
+ }
824
+ }
825
+
826
+ - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
827
+ return YES;
828
+ }
829
+
830
+ @end