@lugg/maps 0.2.0-alpha.9 → 1.0.0-beta.1

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 (184) hide show
  1. package/README.md +21 -20
  2. package/android/build.gradle +1 -1
  3. package/android/src/main/java/com/luggmaps/LuggCalloutView.kt +74 -0
  4. package/android/src/main/java/com/luggmaps/LuggCalloutViewManager.kt +38 -0
  5. package/android/src/main/java/com/luggmaps/LuggMapView.kt +290 -0
  6. package/android/src/main/java/com/luggmaps/{LuggGoogleMapViewManager.kt → LuggMapViewManager.kt} +99 -36
  7. package/android/src/main/java/com/luggmaps/LuggMapWrapperView.kt +11 -14
  8. package/android/src/main/java/com/luggmaps/LuggMarkerView.kt +187 -21
  9. package/android/src/main/java/com/luggmaps/LuggMarkerViewManager.kt +28 -0
  10. package/android/src/main/java/com/luggmaps/LuggPackage.kt +8 -4
  11. package/android/src/main/java/com/luggmaps/LuggPolygonView.kt +85 -0
  12. package/android/src/main/java/com/luggmaps/LuggPolygonViewManager.kt +100 -0
  13. package/android/src/main/java/com/luggmaps/LuggPolylineView.kt +16 -0
  14. package/android/src/main/java/com/luggmaps/LuggPolylineViewManager.kt +22 -0
  15. package/android/src/main/java/com/luggmaps/core/GoogleMapProvider.kt +874 -0
  16. package/android/src/main/java/com/luggmaps/core/MapProviderDelegate.kt +60 -0
  17. package/android/src/main/java/com/luggmaps/core/PolylineAnimator.kt +89 -24
  18. package/android/src/main/java/com/luggmaps/events/LongPressEvent.kt +29 -0
  19. package/android/src/main/java/com/luggmaps/events/MarkerDragEvent.kt +41 -0
  20. package/android/src/main/java/com/luggmaps/events/MarkerPressEvent.kt +34 -0
  21. package/android/src/main/java/com/luggmaps/events/PolygonPressEvent.kt +12 -0
  22. package/android/src/main/java/com/luggmaps/events/PressEvent.kt +29 -0
  23. package/ios/LuggCalloutView.h +23 -0
  24. package/ios/LuggCalloutView.mm +145 -0
  25. package/ios/LuggMapView.h +9 -0
  26. package/ios/LuggMapView.mm +343 -0
  27. package/ios/LuggMarkerView.h +15 -0
  28. package/ios/LuggMarkerView.mm +136 -2
  29. package/ios/LuggPolygonView.h +31 -0
  30. package/ios/LuggPolygonView.mm +151 -0
  31. package/ios/LuggPolylineView.h +4 -0
  32. package/ios/LuggPolylineView.mm +23 -0
  33. package/ios/core/AppleMapProvider.h +15 -0
  34. package/ios/core/AppleMapProvider.mm +1173 -0
  35. package/ios/core/GMSPolylineAnimator.h +3 -0
  36. package/ios/core/GMSPolylineAnimator.m +101 -15
  37. package/ios/core/GoogleMapProvider.h +13 -0
  38. package/ios/core/GoogleMapProvider.mm +798 -0
  39. package/ios/core/LuggAnnotationView.h +12 -0
  40. package/ios/core/LuggAnnotationView.mm +55 -0
  41. package/ios/core/MKPolylineAnimator.h +4 -0
  42. package/ios/core/MKPolylineAnimator.m +167 -42
  43. package/ios/core/MapProviderDelegate.h +84 -0
  44. package/ios/core/PolylineAnimatorBase.h +24 -1
  45. package/ios/core/PolylineAnimatorBase.m +82 -19
  46. package/ios/events/LongPressEvent.h +29 -0
  47. package/ios/events/MarkerDragEvent.h +69 -0
  48. package/ios/events/MarkerPressEvent.h +29 -0
  49. package/ios/events/PolygonPressEvent.h +20 -0
  50. package/ios/events/PressEvent.h +29 -0
  51. package/ios/extensions/MKMapView+Zoom.h +2 -0
  52. package/ios/extensions/MKMapView+Zoom.m +14 -4
  53. package/lib/module/MapProvider.js +2 -4
  54. package/lib/module/MapProvider.js.map +1 -1
  55. package/lib/module/MapProvider.web.js +14 -7
  56. package/lib/module/MapProvider.web.js.map +1 -1
  57. package/lib/module/MapView.js +33 -16
  58. package/lib/module/MapView.js.map +1 -1
  59. package/lib/module/MapView.web.js +296 -181
  60. package/lib/module/MapView.web.js.map +1 -1
  61. package/lib/module/components/GeoJson.js +159 -0
  62. package/lib/module/components/GeoJson.js.map +1 -0
  63. package/lib/module/components/GeoJson.types.js +4 -0
  64. package/lib/module/components/GeoJson.types.js.map +1 -0
  65. package/lib/module/components/Marker.js +49 -8
  66. package/lib/module/components/Marker.js.map +1 -1
  67. package/lib/module/components/Marker.types.js +4 -0
  68. package/lib/module/components/Marker.types.js.map +1 -0
  69. package/lib/module/components/Marker.web.js +159 -24
  70. package/lib/module/components/Marker.web.js.map +1 -1
  71. package/lib/module/components/Polygon.js +46 -0
  72. package/lib/module/components/Polygon.js.map +1 -0
  73. package/lib/module/components/Polygon.types.js +4 -0
  74. package/lib/module/components/Polygon.types.js.map +1 -0
  75. package/lib/module/components/Polygon.web.js +87 -0
  76. package/lib/module/components/Polygon.web.js.map +1 -0
  77. package/lib/module/components/Polyline.js +17 -4
  78. package/lib/module/components/Polyline.js.map +1 -1
  79. package/lib/module/components/Polyline.types.js +4 -0
  80. package/lib/module/components/Polyline.types.js.map +1 -0
  81. package/lib/module/components/Polyline.web.js +108 -31
  82. package/lib/module/components/Polyline.web.js.map +1 -1
  83. package/lib/module/components/index.js +4 -2
  84. package/lib/module/components/index.js.map +1 -1
  85. package/lib/module/components/index.web.js +2 -0
  86. package/lib/module/components/index.web.js.map +1 -1
  87. package/lib/module/fabric/LuggCalloutViewNativeComponent.ts +20 -0
  88. package/lib/module/fabric/{LuggGoogleMapViewNativeComponent.ts → LuggMapViewNativeComponent.ts} +43 -7
  89. package/lib/module/fabric/LuggMarkerViewNativeComponent.ts +49 -1
  90. package/lib/module/fabric/LuggPolygonViewNativeComponent.ts +25 -0
  91. package/lib/module/fabric/LuggPolylineViewNativeComponent.ts +8 -0
  92. package/lib/module/index.js +4 -1
  93. package/lib/module/index.js.map +1 -1
  94. package/lib/module/index.web.js +4 -1
  95. package/lib/module/index.web.js.map +1 -1
  96. package/lib/typescript/src/MapProvider.d.ts +1 -1
  97. package/lib/typescript/src/MapProvider.d.ts.map +1 -1
  98. package/lib/typescript/src/MapProvider.web.d.ts +23 -1
  99. package/lib/typescript/src/MapProvider.web.d.ts.map +1 -1
  100. package/lib/typescript/src/MapView.d.ts +4 -4
  101. package/lib/typescript/src/MapView.d.ts.map +1 -1
  102. package/lib/typescript/src/MapView.types.d.ts +35 -9
  103. package/lib/typescript/src/MapView.types.d.ts.map +1 -1
  104. package/lib/typescript/src/MapView.web.d.ts +2 -11
  105. package/lib/typescript/src/MapView.web.d.ts.map +1 -1
  106. package/lib/typescript/src/components/GeoJson.d.ts +4 -0
  107. package/lib/typescript/src/components/GeoJson.d.ts.map +1 -0
  108. package/lib/typescript/src/components/GeoJson.types.d.ts +89 -0
  109. package/lib/typescript/src/components/GeoJson.types.d.ts.map +1 -0
  110. package/lib/typescript/src/components/Marker.d.ts +6 -33
  111. package/lib/typescript/src/components/Marker.d.ts.map +1 -1
  112. package/lib/typescript/src/components/Marker.types.d.ts +100 -0
  113. package/lib/typescript/src/components/Marker.types.d.ts.map +1 -0
  114. package/lib/typescript/src/components/Marker.web.d.ts +2 -5
  115. package/lib/typescript/src/components/Marker.web.d.ts.map +1 -1
  116. package/lib/typescript/src/components/Polygon.d.ts +10 -0
  117. package/lib/typescript/src/components/Polygon.d.ts.map +1 -0
  118. package/lib/typescript/src/components/Polygon.types.d.ts +33 -0
  119. package/lib/typescript/src/components/Polygon.types.d.ts.map +1 -0
  120. package/lib/typescript/src/components/Polygon.web.d.ts +3 -0
  121. package/lib/typescript/src/components/Polygon.web.d.ts.map +1 -0
  122. package/lib/typescript/src/components/Polyline.d.ts +6 -21
  123. package/lib/typescript/src/components/Polyline.d.ts.map +1 -1
  124. package/lib/typescript/src/components/Polyline.types.d.ts +53 -0
  125. package/lib/typescript/src/components/Polyline.types.d.ts.map +1 -0
  126. package/lib/typescript/src/components/Polyline.web.d.ts +2 -5
  127. package/lib/typescript/src/components/Polyline.web.d.ts.map +1 -1
  128. package/lib/typescript/src/components/index.d.ts +8 -2
  129. package/lib/typescript/src/components/index.d.ts.map +1 -1
  130. package/lib/typescript/src/components/index.web.d.ts +6 -2
  131. package/lib/typescript/src/components/index.web.d.ts.map +1 -1
  132. package/lib/typescript/src/fabric/LuggCalloutViewNativeComponent.d.ts +13 -0
  133. package/lib/typescript/src/fabric/LuggCalloutViewNativeComponent.d.ts.map +1 -0
  134. package/lib/typescript/src/fabric/{LuggGoogleMapViewNativeComponent.d.ts → LuggMapViewNativeComponent.d.ts} +30 -4
  135. package/lib/typescript/src/fabric/LuggMapViewNativeComponent.d.ts.map +1 -0
  136. package/lib/typescript/src/fabric/LuggMarkerViewNativeComponent.d.ts +45 -1
  137. package/lib/typescript/src/fabric/LuggMarkerViewNativeComponent.d.ts.map +1 -1
  138. package/lib/typescript/src/fabric/LuggPolygonViewNativeComponent.d.ts +18 -0
  139. package/lib/typescript/src/fabric/LuggPolygonViewNativeComponent.d.ts.map +1 -0
  140. package/lib/typescript/src/fabric/LuggPolylineViewNativeComponent.d.ts +7 -0
  141. package/lib/typescript/src/fabric/LuggPolylineViewNativeComponent.d.ts.map +1 -1
  142. package/lib/typescript/src/index.d.ts +11 -3
  143. package/lib/typescript/src/index.d.ts.map +1 -1
  144. package/lib/typescript/src/index.web.d.ts +9 -1
  145. package/lib/typescript/src/index.web.d.ts.map +1 -1
  146. package/lib/typescript/src/types.d.ts +11 -0
  147. package/lib/typescript/src/types.d.ts.map +1 -1
  148. package/package.json +11 -9
  149. package/src/MapProvider.tsx +1 -3
  150. package/src/MapProvider.web.tsx +22 -3
  151. package/src/MapView.tsx +32 -26
  152. package/src/MapView.types.ts +43 -9
  153. package/src/MapView.web.tsx +368 -210
  154. package/src/components/GeoJson.tsx +221 -0
  155. package/src/components/GeoJson.types.ts +118 -0
  156. package/src/components/Marker.tsx +75 -38
  157. package/src/components/Marker.types.ts +102 -0
  158. package/src/components/Marker.web.tsx +197 -19
  159. package/src/components/Polygon.tsx +52 -0
  160. package/src/components/Polygon.types.ts +33 -0
  161. package/src/components/Polygon.web.tsx +104 -0
  162. package/src/components/Polyline.tsx +23 -22
  163. package/src/components/Polyline.types.ts +55 -0
  164. package/src/components/Polyline.web.tsx +151 -37
  165. package/src/components/index.ts +17 -2
  166. package/src/components/index.web.ts +6 -2
  167. package/src/fabric/LuggCalloutViewNativeComponent.ts +20 -0
  168. package/src/fabric/{LuggGoogleMapViewNativeComponent.ts → LuggMapViewNativeComponent.ts} +43 -7
  169. package/src/fabric/LuggMarkerViewNativeComponent.ts +49 -1
  170. package/src/fabric/LuggPolygonViewNativeComponent.ts +25 -0
  171. package/src/fabric/LuggPolylineViewNativeComponent.ts +8 -0
  172. package/src/index.ts +30 -1
  173. package/src/index.web.ts +16 -1
  174. package/src/types.ts +13 -0
  175. package/android/src/main/java/com/luggmaps/LuggGoogleMapView.kt +0 -511
  176. package/ios/LuggAppleMapView.h +0 -16
  177. package/ios/LuggAppleMapView.mm +0 -592
  178. package/ios/LuggGoogleMapView.h +0 -13
  179. package/ios/LuggGoogleMapView.mm +0 -455
  180. package/lib/module/fabric/LuggAppleMapViewNativeComponent.ts +0 -83
  181. package/lib/typescript/src/fabric/LuggAppleMapViewNativeComponent.d.ts +0 -54
  182. package/lib/typescript/src/fabric/LuggAppleMapViewNativeComponent.d.ts.map +0 -1
  183. package/lib/typescript/src/fabric/LuggGoogleMapViewNativeComponent.d.ts.map +0 -1
  184. package/src/fabric/LuggAppleMapViewNativeComponent.ts +0 -83
@@ -0,0 +1,1173 @@
1
+ #import "AppleMapProvider.h"
2
+ #import "../LuggCalloutView.h"
3
+ #import "../LuggMarkerView.h"
4
+ #import "../LuggPolygonView.h"
5
+ #import "../LuggPolylineView.h"
6
+ #import "../extensions/MKMapView+Zoom.h"
7
+ #import "LuggAnnotationView.h"
8
+ #import "MKPolylineAnimator.h"
9
+
10
+ @interface AppleMarkerAnnotation : NSObject <MKAnnotation>
11
+ @property(nonatomic, assign) CLLocationCoordinate2D coordinate;
12
+ @property(nonatomic, copy, nullable) NSString *title;
13
+ @property(nonatomic, copy, nullable) NSString *subtitle;
14
+ @property(nonatomic, strong) LuggMarkerView *markerView;
15
+ @property(nonatomic, weak) MKAnnotationView *annotationView;
16
+ @end
17
+
18
+ @implementation AppleMarkerAnnotation
19
+ @end
20
+
21
+ @implementation LuggAppleMapViewContent
22
+ @end
23
+
24
+ @interface AppleMapProvider () <
25
+ LuggMarkerViewDelegate, LuggCalloutViewDelegate, LuggPolylineViewDelegate,
26
+ LuggPolygonViewDelegate, UIGestureRecognizerDelegate>
27
+ @end
28
+
29
+ @implementation AppleMapProvider {
30
+ UIView *_wrapperView;
31
+ LuggAppleMapViewContent *_mapView;
32
+ BOOL _isMapReady;
33
+ BOOL _isDragging;
34
+ double _minZoom;
35
+ double _maxZoom;
36
+ NSMapTable<id<MKOverlay>, LuggPolylineView *> *_overlayToPolylineMap;
37
+ NSMapTable<id<MKOverlay>, LuggPolygonView *> *_overlayToPolygonMap;
38
+ UITapGestureRecognizer *_tapGesture;
39
+ UILongPressGestureRecognizer *_longPressGesture;
40
+ LuggMarkerView *_activeNonBubbledMarker;
41
+ BOOL _isReselectingAnnotation;
42
+ // Edge insets animation
43
+ CADisplayLink *_edgeInsetsDisplayLink;
44
+ UIEdgeInsets _edgeInsetsFrom;
45
+ UIEdgeInsets _edgeInsetsTo;
46
+ CFTimeInterval _edgeInsetsAnimationStart;
47
+ CFTimeInterval _edgeInsetsAnimationDuration;
48
+ }
49
+
50
+ @synthesize delegate = _delegate;
51
+
52
+ - (instancetype)init {
53
+ if (self = [super init]) {
54
+ _overlayToPolylineMap = [NSMapTable strongToWeakObjectsMapTable];
55
+ _overlayToPolygonMap = [NSMapTable strongToWeakObjectsMapTable];
56
+ }
57
+ return self;
58
+ }
59
+
60
+ - (BOOL)isMapReady {
61
+ return _isMapReady;
62
+ }
63
+
64
+ - (MKMapView *)mapView {
65
+ return _mapView;
66
+ }
67
+
68
+ #pragma mark - MapProvider
69
+
70
+ - (void)initializeMapInView:(UIView *)wrapperView
71
+ initialCoordinate:(CLLocationCoordinate2D)coordinate
72
+ initialZoom:(double)zoom {
73
+ if (_mapView)
74
+ return;
75
+
76
+ _mapView = [[LuggAppleMapViewContent alloc] initWithFrame:wrapperView.bounds];
77
+ _mapView.autoresizingMask =
78
+ UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
79
+ _mapView.delegate = self;
80
+ _mapView.insetsLayoutMarginsFromSafeArea = NO;
81
+
82
+ [self applyZoomRange];
83
+
84
+ _tapGesture =
85
+ [[UITapGestureRecognizer alloc] initWithTarget:self
86
+ action:@selector(handleTap:)];
87
+ _tapGesture.cancelsTouchesInView = NO;
88
+ _tapGesture.delegate = self;
89
+ [_mapView addGestureRecognizer:_tapGesture];
90
+
91
+ _longPressGesture = [[UILongPressGestureRecognizer alloc]
92
+ initWithTarget:self
93
+ action:@selector(handleLongPress:)];
94
+ _longPressGesture.delegate = self;
95
+ [_mapView addGestureRecognizer:_longPressGesture];
96
+
97
+ [_tapGesture requireGestureRecognizerToFail:_longPressGesture];
98
+
99
+ _wrapperView = wrapperView;
100
+ [wrapperView addSubview:_mapView];
101
+
102
+ MKCoordinateRegion region = [_mapView regionForCenterCoordinate:coordinate
103
+ zoomLevel:zoom];
104
+ [_mapView setRegion:region animated:NO];
105
+
106
+ _isMapReady = YES;
107
+
108
+ [_delegate mapProviderDidReady];
109
+ }
110
+
111
+ - (void)destroy {
112
+ [self dismissNonBubbledCallout];
113
+ [self stopEdgeInsetsAnimation];
114
+ if (_tapGesture) {
115
+ [_mapView removeGestureRecognizer:_tapGesture];
116
+ _tapGesture = nil;
117
+ }
118
+ if (_longPressGesture) {
119
+ [_mapView removeGestureRecognizer:_longPressGesture];
120
+ _longPressGesture = nil;
121
+ }
122
+ [_mapView removeFromSuperview];
123
+ _mapView = nil;
124
+ _isMapReady = NO;
125
+ }
126
+
127
+ #pragma mark - Props
128
+
129
+ - (void)setZoomEnabled:(BOOL)enabled {
130
+ _mapView.zoomEnabled = enabled;
131
+ }
132
+
133
+ - (void)setScrollEnabled:(BOOL)enabled {
134
+ _mapView.scrollEnabled = enabled;
135
+ }
136
+
137
+ - (void)setRotateEnabled:(BOOL)enabled {
138
+ _mapView.rotateEnabled = enabled;
139
+ }
140
+
141
+ - (void)setPitchEnabled:(BOOL)enabled {
142
+ _mapView.pitchEnabled = enabled;
143
+ }
144
+
145
+ - (void)setUserLocationEnabled:(BOOL)enabled {
146
+ _mapView.showsUserLocation = enabled;
147
+ }
148
+
149
+ - (void)setTheme:(NSInteger)theme {
150
+ switch (theme) {
151
+ case 1: // Dark
152
+ _mapView.overrideUserInterfaceStyle = UIUserInterfaceStyleDark;
153
+ break;
154
+ case 0: // Light
155
+ _mapView.overrideUserInterfaceStyle = UIUserInterfaceStyleLight;
156
+ break;
157
+ default: // System
158
+ _mapView.overrideUserInterfaceStyle = UIUserInterfaceStyleUnspecified;
159
+ break;
160
+ }
161
+ }
162
+
163
+ - (void)setMinZoom:(double)minZoom {
164
+ _minZoom = minZoom;
165
+ [self applyZoomRange];
166
+ }
167
+
168
+ - (void)setMaxZoom:(double)maxZoom {
169
+ _maxZoom = maxZoom;
170
+ [self applyZoomRange];
171
+ }
172
+
173
+ - (void)setEdgeInsets:(UIEdgeInsets)edgeInsets
174
+ oldEdgeInsets:(UIEdgeInsets)oldEdgeInsets {
175
+ CGFloat oldOffsetX = (oldEdgeInsets.left - oldEdgeInsets.right) / 2.0;
176
+ CGFloat oldOffsetY = (oldEdgeInsets.top - oldEdgeInsets.bottom) / 2.0;
177
+ CGFloat newOffsetX = (edgeInsets.left - edgeInsets.right) / 2.0;
178
+ CGFloat newOffsetY = (edgeInsets.top - edgeInsets.bottom) / 2.0;
179
+
180
+ CGFloat deltaX = newOffsetX - oldOffsetX;
181
+ CGFloat deltaY = newOffsetY - oldOffsetY;
182
+
183
+ _mapView.layoutMargins = edgeInsets;
184
+
185
+ if (deltaX != 0 || deltaY != 0) {
186
+ CLLocationCoordinate2D currentCenter = _mapView.centerCoordinate;
187
+ CGPoint centerPoint = [_mapView convertCoordinate:currentCenter
188
+ toPointToView:_mapView];
189
+ CGPoint newPoint =
190
+ CGPointMake(centerPoint.x - deltaX, centerPoint.y - deltaY);
191
+ CLLocationCoordinate2D newCenter = [_mapView convertPoint:newPoint
192
+ toCoordinateFromView:_mapView];
193
+ [_mapView setCenterCoordinate:newCenter animated:NO];
194
+ }
195
+ }
196
+
197
+ - (void)setEdgeInsets:(UIEdgeInsets)edgeInsets
198
+ oldEdgeInsets:(UIEdgeInsets)oldEdgeInsets
199
+ duration:(double)duration {
200
+ [self stopEdgeInsetsAnimation];
201
+
202
+ if (duration != 0 && _mapView) {
203
+ double actualDuration = duration < 0 ? 0.3 : duration / 1000.0;
204
+ _edgeInsetsFrom = oldEdgeInsets;
205
+ _edgeInsetsTo = edgeInsets;
206
+ _edgeInsetsAnimationDuration = actualDuration;
207
+ _edgeInsetsAnimationStart = CACurrentMediaTime();
208
+
209
+ _edgeInsetsDisplayLink = [CADisplayLink
210
+ displayLinkWithTarget:self
211
+ selector:@selector(edgeInsetsAnimationTick:)];
212
+ [_edgeInsetsDisplayLink addToRunLoop:[NSRunLoop mainRunLoop]
213
+ forMode:NSRunLoopCommonModes];
214
+ } else {
215
+ [self setEdgeInsets:edgeInsets oldEdgeInsets:oldEdgeInsets];
216
+ }
217
+ }
218
+
219
+ - (void)edgeInsetsAnimationTick:(CADisplayLink *)displayLink {
220
+ CFTimeInterval elapsed = CACurrentMediaTime() - _edgeInsetsAnimationStart;
221
+ CGFloat progress = MIN(elapsed / _edgeInsetsAnimationDuration, 1.0);
222
+
223
+ // Ease out cubic
224
+ CGFloat t = 1.0 - (1.0 - progress) * (1.0 - progress) * (1.0 - progress);
225
+
226
+ UIEdgeInsets current = UIEdgeInsetsMake(
227
+ _edgeInsetsFrom.top + (_edgeInsetsTo.top - _edgeInsetsFrom.top) * t,
228
+ _edgeInsetsFrom.left + (_edgeInsetsTo.left - _edgeInsetsFrom.left) * t,
229
+ _edgeInsetsFrom.bottom +
230
+ (_edgeInsetsTo.bottom - _edgeInsetsFrom.bottom) * t,
231
+ _edgeInsetsFrom.right +
232
+ (_edgeInsetsTo.right - _edgeInsetsFrom.right) * t);
233
+
234
+ [self setEdgeInsets:current oldEdgeInsets:_mapView.layoutMargins];
235
+
236
+ if (progress >= 1.0) {
237
+ [self stopEdgeInsetsAnimation];
238
+ }
239
+ }
240
+
241
+ - (void)stopEdgeInsetsAnimation {
242
+ [_edgeInsetsDisplayLink invalidate];
243
+ _edgeInsetsDisplayLink = nil;
244
+ }
245
+
246
+ - (CLLocationDistance)cameraDistanceForZoomLevel:(double)zoomLevel {
247
+ return 128000000.0 / pow(2, zoomLevel);
248
+ }
249
+
250
+ - (void)applyZoomRange {
251
+ if (!_mapView)
252
+ return;
253
+
254
+ CLLocationDistance minDistance =
255
+ _maxZoom > 0 ? [self cameraDistanceForZoomLevel:_maxZoom] : 0;
256
+ CLLocationDistance maxDistance =
257
+ _minZoom > 0 ? [self cameraDistanceForZoomLevel:_minZoom] : -1;
258
+
259
+ MKMapCameraZoomRange *zoomRange = [[MKMapCameraZoomRange alloc]
260
+ initWithMinCenterCoordinateDistance:minDistance
261
+ maxCenterCoordinateDistance:maxDistance];
262
+ _mapView.cameraZoomRange = zoomRange;
263
+ }
264
+
265
+ - (LuggPolygonView *)hitTestPolygonAtPoint:(CGPoint)point {
266
+ CLLocationCoordinate2D tapCoordinate = [_mapView convertPoint:point
267
+ toCoordinateFromView:_mapView];
268
+ MKMapPoint mapPoint = MKMapPointForCoordinate(tapCoordinate);
269
+ CGPoint mapPointAsCGP = CGPointMake(mapPoint.x, mapPoint.y);
270
+
271
+ NSArray<id<MKOverlay>> *overlays = _mapView.overlays;
272
+ for (NSInteger i = overlays.count - 1; i >= 0; i--) {
273
+ id<MKOverlay> overlay = overlays[i];
274
+ if (![overlay isKindOfClass:[MKPolygon class]])
275
+ continue;
276
+
277
+ LuggPolygonView *polygonView = [_overlayToPolygonMap objectForKey:overlay];
278
+ if (!polygonView || !polygonView.tappable)
279
+ continue;
280
+
281
+ NSArray<CLLocation *> *coordinates = polygonView.coordinates;
282
+ if (coordinates.count == 0)
283
+ continue;
284
+
285
+ CGMutablePathRef path = CGPathCreateMutable();
286
+ for (NSUInteger j = 0; j < coordinates.count; j++) {
287
+ MKMapPoint mp = MKMapPointForCoordinate(coordinates[j].coordinate);
288
+ if (j == 0) {
289
+ CGPathMoveToPoint(path, NULL, mp.x, mp.y);
290
+ } else {
291
+ CGPathAddLineToPoint(path, NULL, mp.x, mp.y);
292
+ }
293
+ }
294
+ CGPathCloseSubpath(path);
295
+
296
+ for (NSArray<CLLocation *> *hole in polygonView.holes) {
297
+ for (NSUInteger j = 0; j < hole.count; j++) {
298
+ MKMapPoint mp = MKMapPointForCoordinate(hole[j].coordinate);
299
+ if (j == 0) {
300
+ CGPathMoveToPoint(path, NULL, mp.x, mp.y);
301
+ } else {
302
+ CGPathAddLineToPoint(path, NULL, mp.x, mp.y);
303
+ }
304
+ }
305
+ CGPathCloseSubpath(path);
306
+ }
307
+
308
+ BOOL contains = CGPathContainsPoint(path, NULL, mapPointAsCGP, YES);
309
+ CGPathRelease(path);
310
+
311
+ if (contains)
312
+ return polygonView;
313
+ }
314
+ return nil;
315
+ }
316
+
317
+ - (BOOL)hitTestAnnotationAtPoint:(CGPoint)point {
318
+ for (id<MKAnnotation> annotation in _mapView.annotations) {
319
+ MKAnnotationView *view = [_mapView viewForAnnotation:annotation];
320
+ if (!view)
321
+ continue;
322
+ CGPoint local = [view convertPoint:point fromView:_mapView];
323
+ if ([view pointInside:local withEvent:nil])
324
+ return YES;
325
+ }
326
+ return NO;
327
+ }
328
+
329
+ - (BOOL)hitTestCalloutAtPoint:(CGPoint)point {
330
+ if (!_activeNonBubbledMarker)
331
+ return NO;
332
+
333
+ UIView *contentView = _activeNonBubbledMarker.calloutView.contentView;
334
+ CGPoint local = [contentView convertPoint:point fromView:_mapView];
335
+ return [contentView pointInside:local withEvent:nil];
336
+ }
337
+
338
+ - (void)handleTap:(UITapGestureRecognizer *)gesture {
339
+ if (gesture.state != UIGestureRecognizerStateEnded)
340
+ return;
341
+
342
+ CGPoint point = [gesture locationInView:_mapView];
343
+ if ([self hitTestCalloutAtPoint:point])
344
+ return;
345
+
346
+ [self dismissNonBubbledCallout];
347
+
348
+ if ([self hitTestAnnotationAtPoint:point])
349
+ return;
350
+
351
+ LuggPolygonView *polygonView = [self hitTestPolygonAtPoint:point];
352
+ if (polygonView) {
353
+ [polygonView emitPressEvent];
354
+ } else {
355
+ CLLocationCoordinate2D coordinate = [_mapView convertPoint:point
356
+ toCoordinateFromView:_mapView];
357
+ [_delegate mapProviderDidPress:coordinate.latitude
358
+ longitude:coordinate.longitude
359
+ x:point.x
360
+ y:point.y];
361
+ }
362
+ }
363
+
364
+ - (void)handleLongPress:(UILongPressGestureRecognizer *)gesture {
365
+ if (gesture.state != UIGestureRecognizerStateBegan)
366
+ return;
367
+
368
+ CGPoint point = [gesture locationInView:_mapView];
369
+ CLLocationCoordinate2D coordinate = [_mapView convertPoint:point
370
+ toCoordinateFromView:_mapView];
371
+ [_delegate mapProviderDidLongPress:coordinate.latitude
372
+ longitude:coordinate.longitude
373
+ x:point.x
374
+ y:point.y];
375
+ }
376
+
377
+ - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
378
+ shouldRecognizeSimultaneouslyWithGestureRecognizer:
379
+ (UIGestureRecognizer *)otherGestureRecognizer {
380
+ return YES;
381
+ }
382
+
383
+ #pragma mark - MKMapViewDelegate
384
+
385
+ - (BOOL)isUserInteracting {
386
+ UIView *mapContainerView = _mapView.subviews.firstObject;
387
+ for (UIGestureRecognizer *gesture in mapContainerView.gestureRecognizers) {
388
+ if (gesture.state == UIGestureRecognizerStateBegan ||
389
+ gesture.state == UIGestureRecognizerStateChanged) {
390
+ return YES;
391
+ }
392
+ }
393
+ return NO;
394
+ }
395
+
396
+ - (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated {
397
+ _isDragging = [self isUserInteracting];
398
+ if (_isDragging) {
399
+ for (LuggPolylineView *polylineView in _overlayToPolylineMap
400
+ .objectEnumerator) {
401
+ MKPolylineAnimator *renderer =
402
+ (MKPolylineAnimator *)polylineView.renderer;
403
+ [renderer pause];
404
+ }
405
+ }
406
+ }
407
+
408
+ - (void)mapViewDidChangeVisibleRegion:(MKMapView *)mapView {
409
+ [_delegate mapProviderDidMoveCamera:mapView.centerCoordinate.latitude
410
+ longitude:mapView.centerCoordinate.longitude
411
+ zoom:mapView.zoomLevel
412
+ gesture:_isDragging];
413
+ [self positionNonBubbledCallout];
414
+ }
415
+
416
+ - (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
417
+ BOOL wasDragging = _isDragging;
418
+ _isDragging = NO;
419
+ if (wasDragging) {
420
+ for (LuggPolylineView *polylineView in _overlayToPolylineMap
421
+ .objectEnumerator) {
422
+ MKPolylineAnimator *renderer =
423
+ (MKPolylineAnimator *)polylineView.renderer;
424
+ [renderer resume];
425
+ }
426
+ }
427
+ [_delegate mapProviderDidIdleCamera:mapView.centerCoordinate.latitude
428
+ longitude:mapView.centerCoordinate.longitude
429
+ zoom:mapView.zoomLevel
430
+ gesture:wasDragging];
431
+ }
432
+
433
+ - (MKAnnotationView *)mapView:(MKMapView *)mapView
434
+ viewForAnnotation:(id<MKAnnotation>)annotation {
435
+ if (![annotation isKindOfClass:[AppleMarkerAnnotation class]]) {
436
+ return nil;
437
+ }
438
+
439
+ AppleMarkerAnnotation *markerAnnotation = (AppleMarkerAnnotation *)annotation;
440
+ LuggMarkerView *markerView = markerAnnotation.markerView;
441
+
442
+ if (!markerView) {
443
+ return nil;
444
+ }
445
+
446
+ if (!markerView.hasCustomView) {
447
+ LuggMarkerAnnotationView *markerAnnotationView =
448
+ [[LuggMarkerAnnotationView alloc] initWithAnnotation:annotation
449
+ reuseIdentifier:nil];
450
+ markerAnnotationView.canShowCallout = YES;
451
+ markerAnnotationView.displayPriority = MKFeatureDisplayPriorityRequired;
452
+ markerAnnotationView.layer.zPosition = markerView.zIndex;
453
+ markerAnnotationView.zPriority = markerView.zIndex;
454
+ markerAnnotationView.draggable = markerView.draggable;
455
+ [self applyCalloutView:markerView annotationView:markerAnnotationView];
456
+ [self addCenterTapGesture:markerAnnotationView];
457
+ markerAnnotation.annotationView = markerAnnotationView;
458
+ return markerAnnotationView;
459
+ }
460
+
461
+ LuggAnnotationView *annotationView =
462
+ [[LuggAnnotationView alloc] initWithAnnotation:annotation
463
+ reuseIdentifier:nil];
464
+ annotationView.canShowCallout = YES;
465
+ annotationView.displayPriority = MKFeatureDisplayPriorityRequired;
466
+ annotationView.layer.zPosition = markerView.zIndex;
467
+ annotationView.zPriority = markerView.zIndex;
468
+ annotationView.draggable = markerView.draggable;
469
+ [self addCenterTapGesture:annotationView];
470
+
471
+ [self applyCalloutView:markerView annotationView:annotationView];
472
+
473
+ if (!markerView.rasterize) {
474
+ UIView *iconView = markerView.iconView;
475
+ [iconView removeFromSuperview];
476
+ [annotationView addSubview:iconView];
477
+ }
478
+
479
+ [self applyMarkerStyle:markerView annotationView:annotationView];
480
+ markerAnnotation.annotationView = annotationView;
481
+
482
+ return annotationView;
483
+ }
484
+
485
+ - (MKOverlayRenderer *)mapView:(MKMapView *)mapView
486
+ rendererForOverlay:(id<MKOverlay>)overlay {
487
+ if ([overlay isKindOfClass:[MKPolyline class]]) {
488
+ LuggPolylineView *polylineView =
489
+ [_overlayToPolylineMap objectForKey:overlay];
490
+ MKPolyline *polyline = (MKPolyline *)overlay;
491
+
492
+ if (polylineView) {
493
+ NSArray<UIColor *> *colors = polylineView.strokeColors;
494
+
495
+ MKPolylineAnimator *renderer =
496
+ [[MKPolylineAnimator alloc] initWithPolyline:polyline];
497
+ renderer.lineWidth = polylineView.strokeWidth;
498
+ renderer.strokeColor = colors.firstObject;
499
+ if (colors.count > 1) {
500
+ renderer.strokeColors = colors;
501
+ }
502
+ renderer.animatedOptions = polylineView.animatedOptions;
503
+ renderer.animated = polylineView.animated;
504
+ polylineView.renderer = renderer;
505
+ return renderer;
506
+ }
507
+
508
+ MKPolylineRenderer *renderer =
509
+ [[MKPolylineRenderer alloc] initWithPolyline:polyline];
510
+ return renderer;
511
+ }
512
+
513
+ if ([overlay isKindOfClass:[MKPolygon class]]) {
514
+ LuggPolygonView *polygonView = [_overlayToPolygonMap objectForKey:overlay];
515
+ MKPolygon *polygon = (MKPolygon *)overlay;
516
+
517
+ MKPolygonRenderer *renderer =
518
+ [[MKPolygonRenderer alloc] initWithPolygon:polygon];
519
+ if (polygonView) {
520
+ renderer.fillColor = polygonView.fillColor;
521
+ renderer.strokeColor = polygonView.strokeColor;
522
+ renderer.lineWidth = polygonView.strokeWidth;
523
+ polygonView.renderer = renderer;
524
+ }
525
+ return renderer;
526
+ }
527
+
528
+ return nil;
529
+ }
530
+
531
+ - (void)mapView:(MKMapView *)mapView
532
+ didSelectAnnotationView:(MKAnnotationView *)view {
533
+ if (![view.annotation isKindOfClass:[AppleMarkerAnnotation class]])
534
+ return;
535
+
536
+ AppleMarkerAnnotation *annotation = (AppleMarkerAnnotation *)view.annotation;
537
+ LuggMarkerView *markerView = annotation.markerView;
538
+
539
+ if (markerView) {
540
+ CGPoint point = [_mapView convertCoordinate:markerView.coordinate
541
+ toPointToView:_mapView];
542
+ [markerView emitPressEventWithPoint:point];
543
+
544
+ LuggCalloutView *calloutView = markerView.calloutView;
545
+ if (calloutView && !calloutView.bubbled && calloutView.hasCustomContent) {
546
+ [self showNonBubbledCallout:markerView];
547
+ }
548
+ }
549
+ }
550
+
551
+ - (void)mapView:(MKMapView *)mapView
552
+ didDeselectAnnotationView:(MKAnnotationView *)view {
553
+ if (![view.annotation isKindOfClass:[AppleMarkerAnnotation class]])
554
+ return;
555
+
556
+ AppleMarkerAnnotation *annotation = (AppleMarkerAnnotation *)view.annotation;
557
+ LuggMarkerView *markerView = annotation.markerView;
558
+
559
+ if (markerView && _activeNonBubbledMarker == markerView &&
560
+ !_isReselectingAnnotation) {
561
+ _isReselectingAnnotation = YES;
562
+ [_mapView selectAnnotation:annotation animated:NO];
563
+ _isReselectingAnnotation = NO;
564
+ }
565
+ }
566
+
567
+ - (void)showNonBubbledCallout:(LuggMarkerView *)markerView {
568
+ [self dismissNonBubbledCallout];
569
+
570
+ LuggCalloutView *calloutView = markerView.calloutView;
571
+ UIView *contentView = calloutView.contentView;
572
+ [contentView removeFromSuperview];
573
+
574
+ contentView.userInteractionEnabled = YES;
575
+ calloutView.delegate = self;
576
+
577
+ AppleMarkerAnnotation *annotation =
578
+ (AppleMarkerAnnotation *)markerView.marker;
579
+ MKAnnotationView *annotationView = annotation.annotationView;
580
+ if (annotationView) {
581
+ annotationView.clipsToBounds = NO;
582
+ [annotationView addSubview:contentView];
583
+ } else {
584
+ [_wrapperView addSubview:contentView];
585
+ }
586
+
587
+ _activeNonBubbledMarker = markerView;
588
+ [self positionNonBubbledCallout];
589
+ }
590
+
591
+ - (void)calloutViewDidUpdate:(LuggCalloutView *)calloutView {
592
+ [self positionNonBubbledCallout];
593
+ }
594
+
595
+ - (void)positionNonBubbledCallout {
596
+ if (!_activeNonBubbledMarker)
597
+ return;
598
+
599
+ LuggCalloutView *calloutView = _activeNonBubbledMarker.calloutView;
600
+ UIView *contentView = calloutView.contentView;
601
+ CGSize contentSize = contentView.bounds.size;
602
+ if (contentSize.width <= 0 || contentSize.height <= 0)
603
+ return;
604
+
605
+ CGPoint anchor = calloutView.anchor;
606
+
607
+ AppleMarkerAnnotation *annotation =
608
+ (AppleMarkerAnnotation *)_activeNonBubbledMarker.marker;
609
+ MKAnnotationView *annotationView = annotation.annotationView;
610
+
611
+ if (annotationView && contentView.superview == annotationView) {
612
+ CGPoint center = CGPointMake(annotationView.bounds.size.width / 2.0 +
613
+ contentSize.width * (0.5 - anchor.x),
614
+ annotationView.bounds.size.height / 2.0 +
615
+ contentSize.height * (0.5 - anchor.y));
616
+ contentView.center = center;
617
+ } else {
618
+ CGPoint point =
619
+ [_mapView convertCoordinate:_activeNonBubbledMarker.coordinate
620
+ toPointToView:_wrapperView];
621
+ contentView.center =
622
+ CGPointMake(point.x + contentSize.width * (0.5 - anchor.x),
623
+ point.y + contentSize.height * (0.5 - anchor.y));
624
+ }
625
+ }
626
+
627
+ - (void)dismissNonBubbledCallout {
628
+ if (!_activeNonBubbledMarker)
629
+ return;
630
+
631
+ LuggMarkerView *markerView = _activeNonBubbledMarker;
632
+ _activeNonBubbledMarker = nil;
633
+
634
+ markerView.calloutView.delegate = nil;
635
+ [markerView.calloutView.contentView removeFromSuperview];
636
+
637
+ AppleMarkerAnnotation *annotation =
638
+ (AppleMarkerAnnotation *)markerView.marker;
639
+ if (annotation) {
640
+ [_mapView deselectAnnotation:annotation animated:NO];
641
+ }
642
+ }
643
+
644
+ - (void)mapView:(MKMapView *)mapView
645
+ annotationView:(MKAnnotationView *)view
646
+ didChangeDragState:(MKAnnotationViewDragState)newState
647
+ fromOldState:(MKAnnotationViewDragState)oldState {
648
+ if (![view.annotation isKindOfClass:[AppleMarkerAnnotation class]])
649
+ return;
650
+
651
+ AppleMarkerAnnotation *annotation = (AppleMarkerAnnotation *)view.annotation;
652
+ LuggMarkerView *markerView = annotation.markerView;
653
+ if (!markerView)
654
+ return;
655
+
656
+ CLLocationCoordinate2D coord = annotation.coordinate;
657
+ CGPoint point = [_mapView convertCoordinate:coord toPointToView:_mapView];
658
+
659
+ switch (newState) {
660
+ case MKAnnotationViewDragStateStarting:
661
+ [markerView updateCoordinate:coord];
662
+ [markerView emitDragStartEventWithPoint:point];
663
+ [view setDragState:MKAnnotationViewDragStateDragging animated:YES];
664
+ break;
665
+ case MKAnnotationViewDragStateDragging:
666
+ [markerView updateCoordinate:coord];
667
+ [markerView emitDragChangeEventWithPoint:point];
668
+ break;
669
+ case MKAnnotationViewDragStateEnding:
670
+ [markerView updateCoordinate:coord];
671
+ [markerView emitDragEndEventWithPoint:point];
672
+ [view setDragState:MKAnnotationViewDragStateNone animated:YES];
673
+ break;
674
+ case MKAnnotationViewDragStateCanceling:
675
+ [view setDragState:MKAnnotationViewDragStateNone animated:YES];
676
+ break;
677
+ default:
678
+ break;
679
+ }
680
+ }
681
+
682
+ - (void)addCenterTapGesture:(MKAnnotationView *)view {
683
+ UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]
684
+ initWithTarget:self
685
+ action:@selector(handleAnnotationTap:)];
686
+ tap.cancelsTouchesInView = NO;
687
+ [view addGestureRecognizer:tap];
688
+ }
689
+
690
+ - (void)handleAnnotationTap:(UITapGestureRecognizer *)gesture {
691
+ MKAnnotationView *view = (MKAnnotationView *)gesture.view;
692
+ if ([view.annotation isKindOfClass:[AppleMarkerAnnotation class]]) {
693
+ AppleMarkerAnnotation *annotation =
694
+ (AppleMarkerAnnotation *)view.annotation;
695
+ [_mapView setCenterCoordinate:annotation.coordinate animated:YES];
696
+ }
697
+ }
698
+
699
+ - (void)applyCalloutView:(LuggMarkerView *)markerView
700
+ annotationView:(MKAnnotationView *)annotationView {
701
+ LuggCalloutView *calloutView = markerView.calloutView;
702
+ if (!calloutView) {
703
+ annotationView.detailCalloutAccessoryView = nil;
704
+ annotationView.rightCalloutAccessoryView = nil;
705
+ return;
706
+ }
707
+
708
+ annotationView.rightCalloutAccessoryView = nil;
709
+
710
+ if (!calloutView.bubbled) {
711
+ annotationView.canShowCallout = NO;
712
+ annotationView.detailCalloutAccessoryView = nil;
713
+ return;
714
+ }
715
+
716
+ annotationView.detailCalloutAccessoryView =
717
+ calloutView.hasCustomContent ? calloutView.contentView : nil;
718
+ }
719
+
720
+ #pragma mark - MarkerViewDelegate
721
+
722
+ - (void)markerViewDidLayout:(LuggMarkerView *)markerView {
723
+ AppleMarkerAnnotation *annotation =
724
+ (AppleMarkerAnnotation *)markerView.marker;
725
+ if (annotation) {
726
+ [self updateAnnotationViewFrame:annotation];
727
+ }
728
+ }
729
+
730
+ - (void)markerViewDidUpdate:(LuggMarkerView *)markerView {
731
+ AppleMarkerAnnotation *annotation =
732
+ (AppleMarkerAnnotation *)markerView.marker;
733
+
734
+ if (!annotation)
735
+ return;
736
+
737
+ annotation.coordinate = markerView.coordinate;
738
+ annotation.title = markerView.title;
739
+ annotation.subtitle = markerView.markerDescription;
740
+
741
+ MKAnnotationView *annotationView = annotation.annotationView;
742
+ if (annotationView) {
743
+ annotationView.draggable = markerView.draggable;
744
+ annotationView.layer.zPosition = markerView.zIndex;
745
+ annotationView.zPriority = markerView.zIndex;
746
+ [self applyCalloutView:markerView annotationView:annotationView];
747
+ }
748
+
749
+ [self updateAnnotationViewFrame:annotation];
750
+ }
751
+
752
+ #pragma mark - PolylineViewDelegate
753
+
754
+ - (void)polylineViewDidUpdate:(LuggPolylineView *)polylineView {
755
+ [self syncPolylineView:polylineView];
756
+ }
757
+
758
+ #pragma mark - PolygonViewDelegate
759
+
760
+ - (void)polygonViewDidUpdate:(LuggPolygonView *)polygonView {
761
+ [self syncPolygonView:polygonView];
762
+ }
763
+
764
+ #pragma mark - Marker Management
765
+
766
+ - (void)addMarkerView:(LuggMarkerView *)markerView {
767
+ markerView.delegate = self;
768
+
769
+ AppleMarkerAnnotation *annotation = [[AppleMarkerAnnotation alloc] init];
770
+ annotation.markerView = markerView;
771
+ markerView.marker = annotation;
772
+
773
+ if (_mapView) {
774
+ [_mapView addAnnotation:annotation];
775
+ }
776
+
777
+ [self markerViewDidUpdate:markerView];
778
+ }
779
+
780
+ - (void)removeMarkerView:(LuggMarkerView *)markerView {
781
+ markerView.delegate = nil;
782
+
783
+ AppleMarkerAnnotation *annotation =
784
+ (AppleMarkerAnnotation *)markerView.marker;
785
+
786
+ if (annotation) {
787
+ annotation.annotationView.transform = CGAffineTransformIdentity;
788
+ annotation.markerView = nil;
789
+ annotation.annotationView = nil;
790
+ [_mapView removeAnnotation:annotation];
791
+ markerView.marker = nil;
792
+ }
793
+ [markerView resetIconViewTransform];
794
+ }
795
+
796
+ - (void)syncMarkerView:(LuggMarkerView *)markerView {
797
+ [self markerViewDidUpdate:markerView];
798
+ }
799
+
800
+ - (void)applyMarkerStyle:(LuggMarkerView *)markerView
801
+ annotationView:(MKAnnotationView *)annotationView {
802
+ annotationView.transform = CGAffineTransformIdentity;
803
+
804
+ UIView *iconView = markerView.iconView;
805
+ CGRect frame = iconView.frame;
806
+ if (frame.size.width <= 0 || frame.size.height <= 0)
807
+ return;
808
+
809
+ CGFloat scale = markerView.scale;
810
+ CGPoint anchor = markerView.anchor;
811
+
812
+ if (markerView.rasterize) {
813
+ annotationView.image = [markerView createScaledIconImage];
814
+ } else {
815
+ iconView.layer.anchorPoint = anchor;
816
+ iconView.transform = CGAffineTransformMakeScale(scale, scale);
817
+ iconView.frame =
818
+ CGRectMake(frame.size.width * (0.5 - anchor.x) * (scale - 1),
819
+ frame.size.height * (0.5 - anchor.y) * (scale - 1),
820
+ frame.size.width, frame.size.height);
821
+ }
822
+
823
+ annotationView.bounds =
824
+ CGRectMake(0, 0, frame.size.width * scale, frame.size.height * scale);
825
+ annotationView.centerOffset =
826
+ CGPointMake(frame.size.width * scale * (anchor.x - 0.5),
827
+ -frame.size.height * scale * (anchor.y - 0.5));
828
+ annotationView.transform =
829
+ CGAffineTransformMakeRotation(markerView.rotate * M_PI / 180.0);
830
+ }
831
+
832
+ - (void)updateAnnotationViewFrame:(AppleMarkerAnnotation *)annotation {
833
+ MKAnnotationView *annotationView = annotation.annotationView;
834
+ LuggMarkerView *markerView = annotation.markerView;
835
+
836
+ if (!annotationView || !markerView)
837
+ return;
838
+
839
+ [self applyMarkerStyle:markerView annotationView:annotationView];
840
+ }
841
+
842
+ #pragma mark - Polyline Management
843
+
844
+ - (void)addPolylineView:(LuggPolylineView *)polylineView {
845
+ polylineView.delegate = self;
846
+ [self addPolylineOverlayToMap:polylineView];
847
+ }
848
+
849
+ - (void)removePolylineView:(LuggPolylineView *)polylineView {
850
+ polylineView.delegate = nil;
851
+ MKPolyline *polyline = (MKPolyline *)polylineView.polyline;
852
+ if (polyline) {
853
+ [_overlayToPolylineMap removeObjectForKey:polyline];
854
+ [_mapView removeOverlay:polyline];
855
+ polylineView.polyline = nil;
856
+ }
857
+ }
858
+
859
+ - (void)syncPolylineView:(LuggPolylineView *)polylineView {
860
+ if (!_mapView)
861
+ return;
862
+
863
+ MKPolylineAnimator *renderer = (MKPolylineAnimator *)polylineView.renderer;
864
+ MKPolyline *oldPolyline = (MKPolyline *)polylineView.polyline;
865
+
866
+ NSArray<CLLocation *> *coordinates = polylineView.coordinates;
867
+ if (coordinates.count == 0) {
868
+ if (renderer) {
869
+ renderer.animated = NO;
870
+ }
871
+ if (oldPolyline) {
872
+ [_overlayToPolylineMap removeObjectForKey:oldPolyline];
873
+ [_mapView removeOverlay:oldPolyline];
874
+ polylineView.polyline = nil;
875
+ polylineView.renderer = nil;
876
+ }
877
+ return;
878
+ }
879
+
880
+ CLLocationCoordinate2D *coords = (CLLocationCoordinate2D *)malloc(
881
+ sizeof(CLLocationCoordinate2D) * coordinates.count);
882
+ for (NSUInteger i = 0; i < coordinates.count; i++) {
883
+ coords[i] = coordinates[i].coordinate;
884
+ }
885
+ MKPolyline *newPolyline =
886
+ [MKPolyline polylineWithCoordinates:coords count:coordinates.count];
887
+ free(coords);
888
+
889
+ polylineView.polyline = newPolyline;
890
+ [_overlayToPolylineMap setObject:polylineView forKey:newPolyline];
891
+
892
+ if (renderer && oldPolyline) {
893
+ [_overlayToPolylineMap removeObjectForKey:oldPolyline];
894
+ [_mapView removeOverlay:oldPolyline];
895
+ [self insertOverlay:newPolyline withZIndex:polylineView.zIndex];
896
+ [renderer updatePolyline:newPolyline];
897
+ renderer.lineWidth = polylineView.strokeWidth;
898
+ renderer.strokeColor = polylineView.strokeColors.firstObject;
899
+ renderer.strokeColors =
900
+ polylineView.strokeColors.count > 1 ? polylineView.strokeColors : nil;
901
+ renderer.animatedOptions = polylineView.animatedOptions;
902
+ renderer.animated = polylineView.animated;
903
+ return;
904
+ }
905
+
906
+ if (oldPolyline) {
907
+ [_overlayToPolylineMap removeObjectForKey:oldPolyline];
908
+ [_mapView removeOverlay:oldPolyline];
909
+ }
910
+ [self insertOverlay:newPolyline withZIndex:polylineView.zIndex];
911
+ }
912
+
913
+ - (void)addPolylineOverlayToMap:(LuggPolylineView *)polylineView {
914
+ if (!_mapView)
915
+ return;
916
+
917
+ NSArray<CLLocation *> *coordinates = polylineView.coordinates;
918
+ if (coordinates.count == 0)
919
+ return;
920
+
921
+ CLLocationCoordinate2D *coords = (CLLocationCoordinate2D *)malloc(
922
+ sizeof(CLLocationCoordinate2D) * coordinates.count);
923
+ for (NSUInteger i = 0; i < coordinates.count; i++) {
924
+ coords[i] = coordinates[i].coordinate;
925
+ }
926
+
927
+ MKPolyline *polyline = [MKPolyline polylineWithCoordinates:coords
928
+ count:coordinates.count];
929
+ free(coords);
930
+
931
+ polylineView.polyline = polyline;
932
+ [_overlayToPolylineMap setObject:polylineView forKey:polyline];
933
+ [self insertOverlay:polyline withZIndex:polylineView.zIndex];
934
+ }
935
+
936
+ #pragma mark - Polygon Management
937
+
938
+ - (void)addPolygonView:(LuggPolygonView *)polygonView {
939
+ polygonView.delegate = self;
940
+ [self addPolygonOverlayToMap:polygonView];
941
+ }
942
+
943
+ - (void)removePolygonView:(LuggPolygonView *)polygonView {
944
+ polygonView.delegate = nil;
945
+ MKPolygon *polygon = (MKPolygon *)polygonView.polygon;
946
+ if (polygon) {
947
+ [_overlayToPolygonMap removeObjectForKey:polygon];
948
+ [_mapView removeOverlay:polygon];
949
+ polygonView.polygon = nil;
950
+ }
951
+ }
952
+
953
+ - (void)syncPolygonView:(LuggPolygonView *)polygonView {
954
+ if (!_mapView)
955
+ return;
956
+
957
+ MKPolygon *oldPolygon = (MKPolygon *)polygonView.polygon;
958
+
959
+ NSArray<CLLocation *> *coordinates = polygonView.coordinates;
960
+ if (coordinates.count == 0) {
961
+ if (oldPolygon) {
962
+ [_overlayToPolygonMap removeObjectForKey:oldPolygon];
963
+ [_mapView removeOverlay:oldPolygon];
964
+ polygonView.polygon = nil;
965
+ polygonView.renderer = nil;
966
+ }
967
+ return;
968
+ }
969
+
970
+ CLLocationCoordinate2D *coords = (CLLocationCoordinate2D *)malloc(
971
+ sizeof(CLLocationCoordinate2D) * coordinates.count);
972
+ for (NSUInteger i = 0; i < coordinates.count; i++) {
973
+ coords[i] = coordinates[i].coordinate;
974
+ }
975
+ NSArray<MKPolygon *> *interiorPolygons =
976
+ [self interiorPolygonsFromHoles:polygonView.holes];
977
+ MKPolygon *newPolygon = [MKPolygon polygonWithCoordinates:coords
978
+ count:coordinates.count
979
+ interiorPolygons:interiorPolygons];
980
+ free(coords);
981
+
982
+ polygonView.polygon = newPolygon;
983
+ [_overlayToPolygonMap setObject:polygonView forKey:newPolygon];
984
+
985
+ MKPolygonRenderer *renderer = (MKPolygonRenderer *)polygonView.renderer;
986
+ if (renderer && oldPolygon) {
987
+ [_overlayToPolygonMap removeObjectForKey:oldPolygon];
988
+ [_mapView removeOverlay:oldPolygon];
989
+ [self insertOverlay:newPolygon withZIndex:polygonView.zIndex];
990
+ polygonView.renderer = nil;
991
+ return;
992
+ }
993
+
994
+ if (oldPolygon) {
995
+ [_overlayToPolygonMap removeObjectForKey:oldPolygon];
996
+ [_mapView removeOverlay:oldPolygon];
997
+ }
998
+ [self insertOverlay:newPolygon withZIndex:polygonView.zIndex];
999
+ }
1000
+
1001
+ - (void)addPolygonOverlayToMap:(LuggPolygonView *)polygonView {
1002
+ if (!_mapView)
1003
+ return;
1004
+
1005
+ NSArray<CLLocation *> *coordinates = polygonView.coordinates;
1006
+ if (coordinates.count == 0)
1007
+ return;
1008
+
1009
+ CLLocationCoordinate2D *coords = (CLLocationCoordinate2D *)malloc(
1010
+ sizeof(CLLocationCoordinate2D) * coordinates.count);
1011
+ for (NSUInteger i = 0; i < coordinates.count; i++) {
1012
+ coords[i] = coordinates[i].coordinate;
1013
+ }
1014
+
1015
+ NSArray<MKPolygon *> *interiorPolygons =
1016
+ [self interiorPolygonsFromHoles:polygonView.holes];
1017
+ MKPolygon *polygon = [MKPolygon polygonWithCoordinates:coords
1018
+ count:coordinates.count
1019
+ interiorPolygons:interiorPolygons];
1020
+ free(coords);
1021
+
1022
+ polygonView.polygon = polygon;
1023
+ [_overlayToPolygonMap setObject:polygonView forKey:polygon];
1024
+ [self insertOverlay:polygon withZIndex:polygonView.zIndex];
1025
+ }
1026
+
1027
+ - (NSArray<MKPolygon *> *)interiorPolygonsFromHoles:
1028
+ (NSArray<NSArray<CLLocation *> *> *)holes {
1029
+ if (holes.count == 0)
1030
+ return @[];
1031
+
1032
+ NSMutableArray<MKPolygon *> *interiorPolygons = [NSMutableArray array];
1033
+ for (NSArray<CLLocation *> *hole in holes) {
1034
+ if (hole.count == 0)
1035
+ continue;
1036
+ CLLocationCoordinate2D *holeCoords = (CLLocationCoordinate2D *)malloc(
1037
+ sizeof(CLLocationCoordinate2D) * hole.count);
1038
+ for (NSUInteger i = 0; i < hole.count; i++) {
1039
+ holeCoords[i] = hole[i].coordinate;
1040
+ }
1041
+ MKPolygon *interiorPolygon = [MKPolygon polygonWithCoordinates:holeCoords
1042
+ count:hole.count];
1043
+ free(holeCoords);
1044
+ [interiorPolygons addObject:interiorPolygon];
1045
+ }
1046
+ return [interiorPolygons copy];
1047
+ }
1048
+
1049
+ - (void)insertOverlay:(id<MKOverlay>)overlay withZIndex:(NSInteger)zIndex {
1050
+ if (zIndex == 0) {
1051
+ [_mapView addOverlay:overlay];
1052
+ return;
1053
+ }
1054
+
1055
+ NSArray<id<MKOverlay>> *overlays = _mapView.overlays;
1056
+ NSInteger insertIndex = overlays.count;
1057
+
1058
+ for (NSInteger i = 0; i < overlays.count; i++) {
1059
+ NSInteger existingZIndex = 0;
1060
+ LuggPolylineView *existingPolylineView =
1061
+ [_overlayToPolylineMap objectForKey:overlays[i]];
1062
+ LuggPolygonView *existingPolygonView =
1063
+ [_overlayToPolygonMap objectForKey:overlays[i]];
1064
+ if (existingPolylineView) {
1065
+ existingZIndex = existingPolylineView.zIndex;
1066
+ } else if (existingPolygonView) {
1067
+ existingZIndex = existingPolygonView.zIndex;
1068
+ } else {
1069
+ continue;
1070
+ }
1071
+ if (existingZIndex > zIndex) {
1072
+ insertIndex = i;
1073
+ break;
1074
+ }
1075
+ }
1076
+
1077
+ [_mapView insertOverlay:overlay atIndex:insertIndex];
1078
+ }
1079
+
1080
+ #pragma mark - Lifecycle
1081
+
1082
+ - (void)pauseAnimations {
1083
+ for (LuggPolylineView *polylineView in _overlayToPolylineMap
1084
+ .objectEnumerator) {
1085
+ MKPolylineAnimator *renderer = (MKPolylineAnimator *)polylineView.renderer;
1086
+ [renderer pause];
1087
+ }
1088
+ }
1089
+
1090
+ - (void)resumeAnimations {
1091
+ for (LuggPolylineView *polylineView in _overlayToPolylineMap
1092
+ .objectEnumerator) {
1093
+ MKPolylineAnimator *renderer = (MKPolylineAnimator *)polylineView.renderer;
1094
+ [renderer resume];
1095
+ }
1096
+ }
1097
+
1098
+ #pragma mark - Commands
1099
+
1100
+ - (void)moveCamera:(double)latitude
1101
+ longitude:(double)longitude
1102
+ zoom:(double)zoom
1103
+ duration:(double)duration {
1104
+ if (!_mapView)
1105
+ return;
1106
+
1107
+ double targetZoom = zoom > 0 ? zoom : _mapView.zoomLevel;
1108
+
1109
+ if (duration < 0) {
1110
+ [_mapView
1111
+ setCenterCoordinate:CLLocationCoordinate2DMake(latitude, longitude)
1112
+ zoomLevel:targetZoom
1113
+ animated:YES];
1114
+ } else if (duration > 0) {
1115
+ CLLocationCoordinate2D center =
1116
+ CLLocationCoordinate2DMake(latitude, longitude);
1117
+ MKCoordinateRegion region = [_mapView regionForCenterCoordinate:center
1118
+ zoomLevel:targetZoom];
1119
+ [UIView animateWithDuration:duration / 1000.0
1120
+ animations:^{
1121
+ [self->_mapView setRegion:region animated:NO];
1122
+ }];
1123
+ } else {
1124
+ [_mapView
1125
+ setCenterCoordinate:CLLocationCoordinate2DMake(latitude, longitude)
1126
+ zoomLevel:targetZoom
1127
+ animated:NO];
1128
+ }
1129
+ }
1130
+
1131
+ - (void)fitCoordinates:(NSArray *)coordinates
1132
+ edgeInsetsTop:(double)edgeInsetsTop
1133
+ edgeInsetsLeft:(double)edgeInsetsLeft
1134
+ edgeInsetsBottom:(double)edgeInsetsBottom
1135
+ edgeInsetsRight:(double)edgeInsetsRight
1136
+ duration:(double)duration {
1137
+ if (!_mapView || coordinates.count == 0)
1138
+ return;
1139
+
1140
+ CLLocationCoordinate2D *coords = (CLLocationCoordinate2D *)malloc(
1141
+ sizeof(CLLocationCoordinate2D) * coordinates.count);
1142
+ for (NSUInteger i = 0; i < coordinates.count; i++) {
1143
+ NSDictionary *coord = coordinates[i];
1144
+ coords[i] = CLLocationCoordinate2DMake([coord[@"latitude"] doubleValue],
1145
+ [coord[@"longitude"] doubleValue]);
1146
+ }
1147
+
1148
+ MKMapRect mapRect = MKMapRectNull;
1149
+ for (NSUInteger i = 0; i < coordinates.count; i++) {
1150
+ MKMapPoint point = MKMapPointForCoordinate(coords[i]);
1151
+ MKMapRect pointRect = MKMapRectMake(point.x, point.y, 0, 0);
1152
+ mapRect = MKMapRectUnion(mapRect, pointRect);
1153
+ }
1154
+ free(coords);
1155
+
1156
+ UIEdgeInsets insets = UIEdgeInsetsMake(edgeInsetsTop, edgeInsetsLeft,
1157
+ edgeInsetsBottom, edgeInsetsRight);
1158
+
1159
+ if (duration < 0) {
1160
+ [_mapView setVisibleMapRect:mapRect edgePadding:insets animated:YES];
1161
+ } else if (duration > 0) {
1162
+ [UIView animateWithDuration:duration / 1000.0
1163
+ animations:^{
1164
+ [self->_mapView setVisibleMapRect:mapRect
1165
+ edgePadding:insets
1166
+ animated:NO];
1167
+ }];
1168
+ } else {
1169
+ [_mapView setVisibleMapRect:mapRect edgePadding:insets animated:NO];
1170
+ }
1171
+ }
1172
+
1173
+ @end