@lugg/maps 0.2.0-alpha.17 → 0.2.0-alpha.19

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 (40) hide show
  1. package/android/src/main/java/com/luggmaps/LuggGoogleMapView.kt +16 -17
  2. package/android/src/main/java/com/luggmaps/LuggMapWrapperView.kt +1 -0
  3. package/android/src/main/java/com/luggmaps/LuggMarkerView.kt +129 -13
  4. package/android/src/main/java/com/luggmaps/LuggMarkerViewManager.kt +15 -0
  5. package/android/src/main/java/com/luggmaps/core/PolylineAnimator.kt +8 -0
  6. package/ios/LuggAppleMapView.mm +58 -25
  7. package/ios/LuggGoogleMapView.mm +43 -20
  8. package/ios/LuggMarkerView.h +7 -0
  9. package/ios/LuggMarkerView.mm +66 -0
  10. package/ios/core/GMSPolylineAnimator.h +2 -0
  11. package/ios/core/GMSPolylineAnimator.m +8 -0
  12. package/ios/core/MKPolylineAnimator.h +2 -0
  13. package/ios/core/MKPolylineAnimator.m +8 -0
  14. package/lib/module/MapProvider.web.js +5 -2
  15. package/lib/module/MapProvider.web.js.map +1 -1
  16. package/lib/module/MapView.web.js +14 -11
  17. package/lib/module/MapView.web.js.map +1 -1
  18. package/lib/module/components/Marker.js +6 -0
  19. package/lib/module/components/Marker.js.map +1 -1
  20. package/lib/module/components/Marker.web.js +8 -0
  21. package/lib/module/components/Marker.web.js.map +1 -1
  22. package/lib/module/components/Polyline.web.js +15 -4
  23. package/lib/module/components/Polyline.web.js.map +1 -1
  24. package/lib/module/fabric/LuggMarkerViewNativeComponent.ts +7 -1
  25. package/lib/typescript/src/MapProvider.web.d.ts +8 -2
  26. package/lib/typescript/src/MapProvider.web.d.ts.map +1 -1
  27. package/lib/typescript/src/components/Marker.d.ts +17 -0
  28. package/lib/typescript/src/components/Marker.d.ts.map +1 -1
  29. package/lib/typescript/src/components/Marker.web.d.ts +1 -1
  30. package/lib/typescript/src/components/Marker.web.d.ts.map +1 -1
  31. package/lib/typescript/src/components/Polyline.web.d.ts.map +1 -1
  32. package/lib/typescript/src/fabric/LuggMarkerViewNativeComponent.d.ts +4 -1
  33. package/lib/typescript/src/fabric/LuggMarkerViewNativeComponent.d.ts.map +1 -1
  34. package/package.json +1 -1
  35. package/src/MapProvider.web.tsx +5 -2
  36. package/src/MapView.web.tsx +11 -11
  37. package/src/components/Marker.tsx +32 -2
  38. package/src/components/Marker.web.tsx +9 -0
  39. package/src/components/Polyline.web.tsx +13 -4
  40. package/src/fabric/LuggMarkerViewNativeComponent.ts +7 -1
@@ -146,10 +146,7 @@ class LuggGoogleMapView(private val reactContext: ThemedReactContext) :
146
146
  view.onCreate(null)
147
147
  view.onResume()
148
148
  view.getMapAsync(this)
149
- mapWrapperView?.addView(
150
- view,
151
- LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
152
- )
149
+ mapWrapperView?.addView(view)
153
150
  }
154
151
  }
155
152
 
@@ -176,6 +173,9 @@ class LuggGoogleMapView(private val reactContext: ThemedReactContext) :
176
173
 
177
174
  override fun onCameraMoveStarted(reason: Int) {
178
175
  isDragging = reason == GoogleMap.OnCameraMoveStartedListener.REASON_GESTURE
176
+ if (isDragging) {
177
+ polylineAnimators.values.forEach { it.pause() }
178
+ }
179
179
  }
180
180
 
181
181
  override fun onCameraMove() {
@@ -188,6 +188,9 @@ class LuggGoogleMapView(private val reactContext: ThemedReactContext) :
188
188
  val map = googleMap ?: return
189
189
  val position = map.cameraPosition
190
190
  eventDelegate?.onCameraIdle(this, position.target.latitude, position.target.longitude, position.zoom, isDragging)
191
+ if (isDragging) {
192
+ polylineAnimators.values.forEach { it.resume() }
193
+ }
191
194
  isDragging = false
192
195
  }
193
196
 
@@ -241,9 +244,7 @@ class LuggGoogleMapView(private val reactContext: ThemedReactContext) :
241
244
  }
242
245
 
243
246
  if (markerView.hasCustomView) {
244
- // Recreate marker with custom view
245
- markerView.marker?.remove()
246
- addMarkerViewToMap(markerView)
247
+ markerView.updateIcon { addMarkerViewToMap(markerView) }
247
248
  } else {
248
249
  syncMarkerView(markerView)
249
250
  }
@@ -276,9 +277,12 @@ class LuggGoogleMapView(private val reactContext: ThemedReactContext) :
276
277
  snippet = markerView.description
277
278
  setAnchor(markerView.anchorX, markerView.anchorY)
278
279
  zIndex = markerView.zIndex
279
- if (!markerView.hasCustomView) {
280
- iconView = null
281
- }
280
+ rotation = markerView.rotate
281
+ }
282
+
283
+ if (markerView.hasCustomView && markerView.scaleChanged) {
284
+ markerView.applyScaleToMarker()
285
+ markerView.clearScaleChanged()
282
286
  }
283
287
  }
284
288
 
@@ -296,24 +300,19 @@ class LuggGoogleMapView(private val reactContext: ThemedReactContext) :
296
300
  }
297
301
 
298
302
  val position = LatLng(markerView.latitude, markerView.longitude)
299
- val iconView = markerView.iconView
300
-
301
- (iconView.parent as? ViewGroup)?.removeView(iconView)
302
303
 
303
304
  val options = AdvancedMarkerOptions()
304
305
  .position(position)
305
306
  .title(markerView.title)
306
307
  .snippet(markerView.description)
307
308
 
308
- if (markerView.hasCustomView) {
309
- options.iconView(iconView)
310
- }
311
-
312
309
  val marker = map.addMarker(options) as AdvancedMarker
313
310
  marker.setAnchor(markerView.anchorX, markerView.anchorY)
314
311
  marker.zIndex = markerView.zIndex
312
+ marker.rotation = markerView.rotate
315
313
 
316
314
  markerView.marker = marker
315
+ markerView.applyIconToMarker()
317
316
  }
318
317
 
319
318
  // endregion
@@ -1,6 +1,7 @@
1
1
  package com.luggmaps
2
2
 
3
3
  import android.annotation.SuppressLint
4
+ import android.util.Log
4
5
  import com.facebook.react.uimanager.ThemedReactContext
5
6
  import com.facebook.react.views.view.ReactViewGroup
6
7
 
@@ -1,10 +1,16 @@
1
1
  package com.luggmaps
2
2
 
3
3
  import android.content.Context
4
+ import android.graphics.Bitmap
5
+ import android.graphics.Canvas
4
6
  import android.view.View
7
+ import android.view.ViewGroup
8
+ import androidx.core.graphics.createBitmap
5
9
  import androidx.core.view.isNotEmpty
6
10
  import com.facebook.react.views.view.ReactViewGroup
7
11
  import com.google.android.gms.maps.model.AdvancedMarker
12
+ import com.google.android.gms.maps.model.BitmapDescriptor
13
+ import com.google.android.gms.maps.model.BitmapDescriptorFactory
8
14
 
9
15
  interface LuggMarkerViewDelegate {
10
16
  fun markerViewDidUpdate(markerView: LuggMarkerView)
@@ -12,6 +18,8 @@ interface LuggMarkerViewDelegate {
12
18
  }
13
19
 
14
20
  class LuggMarkerView(context: Context) : ReactViewGroup(context) {
21
+ private var scaleUpdateRunnable: Runnable? = null
22
+
15
23
  var name: String? = null
16
24
  private set
17
25
 
@@ -36,23 +44,115 @@ class LuggMarkerView(context: Context) : ReactViewGroup(context) {
36
44
  var zIndex: Float = 0f
37
45
  private set
38
46
 
47
+ var rotate: Float = 0f
48
+ private set
49
+
50
+ var scale: Float = 1f
51
+ private set
52
+
53
+ var scaleChanged: Boolean = false
54
+ private set
55
+
56
+ var rasterize: Boolean = true
57
+ private set
58
+
39
59
  var didLayout: Boolean = false
40
60
  private set
41
61
 
42
62
  val hasCustomView: Boolean
43
63
  get() = iconView.isNotEmpty()
44
64
 
45
- val iconView: ReactViewGroup = object : ReactViewGroup(context) {
46
- override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
47
- var maxWidth = 0
48
- var maxHeight = 0
49
- for (i in 0 until childCount) {
50
- val child = getChildAt(i)
51
- if (child.width > maxWidth) maxWidth = child.width
52
- if (child.height > maxHeight) maxHeight = child.height
65
+ val iconView: ReactViewGroup = ReactViewGroup(context)
66
+
67
+ private fun measureIconViewBounds(): Pair<Int, Int> {
68
+ var maxWidth = 0
69
+ var maxHeight = 0
70
+ for (i in 0 until iconView.childCount) {
71
+ val child = iconView.getChildAt(i)
72
+ val childRight = child.left + child.width
73
+ val childBottom = child.top + child.height
74
+ if (childRight > maxWidth) maxWidth = childRight
75
+ if (childBottom > maxHeight) maxHeight = childBottom
76
+ }
77
+ return Pair(maxWidth, maxHeight)
78
+ }
79
+
80
+ private fun createIconBitmap(): BitmapDescriptor? {
81
+ val (width, height) = measureIconViewBounds()
82
+ if (width <= 0 || height <= 0) return null
83
+
84
+ val scaledWidth = (width * scale).toInt()
85
+ val scaledHeight = (height * scale).toInt()
86
+
87
+ val bitmap = createBitmap(scaledWidth, scaledHeight)
88
+ val canvas = Canvas(bitmap)
89
+ canvas.scale(scale, scale)
90
+ iconView.draw(canvas)
91
+ return BitmapDescriptorFactory.fromBitmap(bitmap)
92
+ }
93
+
94
+ private fun createIconViewWrapper(): View {
95
+ val (width, height) = measureIconViewBounds()
96
+ val scaledWidth = (width * scale).toInt()
97
+ val scaledHeight = (height * scale).toInt()
98
+
99
+ (iconView.parent as? ViewGroup)?.removeView(iconView)
100
+ iconView.scaleX = scale
101
+ iconView.scaleY = scale
102
+ iconView.pivotX = 0f
103
+ iconView.pivotY = 0f
104
+
105
+ return object : ReactViewGroup(context) {
106
+ init {
107
+ addView(iconView)
108
+ }
109
+
110
+ override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
111
+ setMeasuredDimension(scaledWidth, scaledHeight)
112
+ }
113
+ }
114
+ }
115
+
116
+ fun applyIconToMarker() {
117
+ val m = marker ?: return
118
+ if (!hasCustomView) return
119
+
120
+ if (rasterize) {
121
+ createIconBitmap()?.let { m.setIcon(it) }
122
+ } else {
123
+ m.iconView = createIconViewWrapper()
124
+ }
125
+ }
126
+
127
+ fun applyScaleToMarker() {
128
+ val m = marker ?: return
129
+ if (!hasCustomView) return
130
+
131
+ scaleUpdateRunnable?.let { removeCallbacks(it) }
132
+ scaleUpdateRunnable = Runnable {
133
+ if (rasterize) {
134
+ createIconBitmap()?.let { m.setIcon(it) }
135
+ } else {
136
+ m.iconView = createIconViewWrapper()
53
137
  }
138
+ }
139
+ post(scaleUpdateRunnable)
140
+ }
54
141
 
55
- setMeasuredDimension(maxWidth, maxHeight)
142
+ fun updateIcon(onAddMarker: () -> Unit) {
143
+ if (!hasCustomView) return
144
+ if (rasterize) {
145
+ post {
146
+ if (marker == null) {
147
+ onAddMarker()
148
+ } else {
149
+ applyIconToMarker()
150
+ }
151
+ }
152
+ } else {
153
+ marker?.remove()
154
+ marker = null
155
+ post { onAddMarker() }
56
156
  }
57
157
  }
58
158
 
@@ -92,6 +192,7 @@ class LuggMarkerView(context: Context) : ReactViewGroup(context) {
92
192
  bottom: Int
93
193
  ) {
94
194
  super.onLayout(changed, left, top, right, bottom)
195
+
95
196
  if (changed && !didLayout) {
96
197
  didLayout = true
97
198
  delegate?.markerViewDidLayout(this)
@@ -120,6 +221,23 @@ class LuggMarkerView(context: Context) : ReactViewGroup(context) {
120
221
  this.zIndex = zIndex
121
222
  }
122
223
 
224
+ fun setRotate(rotate: Float) {
225
+ this.rotate = rotate
226
+ }
227
+
228
+ fun setScale(scale: Float) {
229
+ scaleChanged = this.scale != scale
230
+ this.scale = scale
231
+ }
232
+
233
+ fun clearScaleChanged() {
234
+ scaleChanged = false
235
+ }
236
+
237
+ fun setRasterize(rasterize: Boolean) {
238
+ this.rasterize = rasterize
239
+ }
240
+
123
241
  fun setName(name: String?) {
124
242
  this.name = name
125
243
  }
@@ -129,12 +247,10 @@ class LuggMarkerView(context: Context) : ReactViewGroup(context) {
129
247
  }
130
248
 
131
249
  fun onDropViewInstance() {
250
+ scaleUpdateRunnable?.let { removeCallbacks(it) }
251
+ scaleUpdateRunnable = null
132
252
  didLayout = false
133
253
  delegate = null
134
254
  iconView.removeAllViews()
135
255
  }
136
-
137
- companion object {
138
- private const val TAG = "Lugg"
139
- }
140
256
  }
@@ -69,6 +69,21 @@ class LuggMarkerViewManager :
69
69
  view.setZIndex(zIndex)
70
70
  }
71
71
 
72
+ @ReactProp(name = "rotate", defaultDouble = 0.0)
73
+ override fun setRotate(view: LuggMarkerView, value: Double) {
74
+ view.setRotate(value.toFloat())
75
+ }
76
+
77
+ @ReactProp(name = "scale", defaultDouble = 1.0)
78
+ override fun setScale(view: LuggMarkerView, value: Double) {
79
+ view.setScale(value.toFloat())
80
+ }
81
+
82
+ @ReactProp(name = "rasterize", defaultBoolean = true)
83
+ override fun setRasterize(view: LuggMarkerView, value: Boolean) {
84
+ view.setRasterize(value)
85
+ }
86
+
72
87
  companion object {
73
88
  const val NAME = "LuggMarkerView"
74
89
  }
@@ -143,6 +143,14 @@ class PolylineAnimator {
143
143
  animator = null
144
144
  }
145
145
 
146
+ fun pause() {
147
+ animator?.pause()
148
+ }
149
+
150
+ fun resume() {
151
+ animator?.resume()
152
+ }
153
+
146
154
  private fun updateAnimatedPolyline() {
147
155
  val poly = polyline ?: return
148
156
  if (coordinates.size < 2 || totalLength <= 0f) {
@@ -103,11 +103,13 @@ using namespace luggmaps::events;
103
103
  (AppleMarkerAnnotation *)markerView.marker;
104
104
 
105
105
  if (annotation) {
106
+ annotation.annotationView.transform = CGAffineTransformIdentity;
106
107
  annotation.markerView = nil;
107
108
  annotation.annotationView = nil;
108
109
  [_mapView removeAnnotation:annotation];
109
110
  markerView.marker = nil;
110
111
  }
112
+ [markerView resetIconViewTransform];
111
113
  } else if ([childComponentView isKindOfClass:[LuggPolylineView class]]) {
112
114
  LuggPolylineView *polylineView = (LuggPolylineView *)childComponentView;
113
115
  polylineView.delegate = nil;
@@ -256,6 +258,38 @@ using namespace luggmaps::events;
256
258
 
257
259
  #pragma mark - Annotation Helpers
258
260
 
261
+ - (void)applyMarkerStyle:(LuggMarkerView *)markerView
262
+ annotationView:(MKAnnotationView *)annotationView {
263
+ annotationView.transform = CGAffineTransformIdentity;
264
+
265
+ UIView *iconView = markerView.iconView;
266
+ CGRect frame = iconView.frame;
267
+ if (frame.size.width <= 0 || frame.size.height <= 0)
268
+ return;
269
+
270
+ CGFloat scale = markerView.scale;
271
+ CGPoint anchor = markerView.anchor;
272
+
273
+ if (markerView.rasterize) {
274
+ annotationView.image = [markerView createScaledIconImage];
275
+ } else {
276
+ iconView.layer.anchorPoint = anchor;
277
+ iconView.transform = CGAffineTransformMakeScale(scale, scale);
278
+ iconView.frame =
279
+ CGRectMake(frame.size.width * (0.5 - anchor.x) * (scale - 1),
280
+ frame.size.height * (0.5 - anchor.y) * (scale - 1),
281
+ frame.size.width, frame.size.height);
282
+ }
283
+
284
+ annotationView.bounds =
285
+ CGRectMake(0, 0, frame.size.width * scale, frame.size.height * scale);
286
+ annotationView.centerOffset =
287
+ CGPointMake(frame.size.width * scale * (anchor.x - 0.5),
288
+ -frame.size.height * scale * (anchor.y - 0.5));
289
+ annotationView.transform =
290
+ CGAffineTransformMakeRotation(markerView.rotate * M_PI / 180.0);
291
+ }
292
+
259
293
  - (void)updateAnnotationViewFrame:(AppleMarkerAnnotation *)annotation {
260
294
  MKAnnotationView *annotationView = annotation.annotationView;
261
295
  LuggMarkerView *markerView = annotation.markerView;
@@ -264,16 +298,7 @@ using namespace luggmaps::events;
264
298
  return;
265
299
  }
266
300
 
267
- UIView *iconView = markerView.iconView;
268
- CGRect frame = iconView.frame;
269
- if (frame.size.width > 0 && frame.size.height > 0) {
270
- annotationView.frame = frame;
271
-
272
- CGPoint anchor = markerView.anchor;
273
- annotationView.centerOffset =
274
- CGPointMake(frame.size.width * (anchor.x - 0.5),
275
- -frame.size.height * (anchor.y - 0.5));
276
- }
301
+ [self applyMarkerStyle:markerView annotationView:annotationView];
277
302
  }
278
303
 
279
304
  #pragma mark - PolylineViewDelegate
@@ -427,6 +452,15 @@ using namespace luggmaps::events;
427
452
 
428
453
  - (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated {
429
454
  _isDragging = [self isUserInteracting:mapView];
455
+ if (_isDragging) {
456
+ for (UIView *subview in self.subviews) {
457
+ if ([subview isKindOfClass:[LuggPolylineView class]]) {
458
+ MKPolylineAnimator *renderer =
459
+ (MKPolylineAnimator *)((LuggPolylineView *)subview).renderer;
460
+ [renderer pause];
461
+ }
462
+ }
463
+ }
430
464
  }
431
465
 
432
466
  - (BOOL)isUserInteracting:(MKMapView *)mapView {
@@ -450,6 +484,15 @@ using namespace luggmaps::events;
450
484
  - (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
451
485
  BOOL wasDragging = _isDragging;
452
486
  _isDragging = NO;
487
+ if (wasDragging) {
488
+ for (UIView *subview in self.subviews) {
489
+ if ([subview isKindOfClass:[LuggPolylineView class]]) {
490
+ MKPolylineAnimator *renderer =
491
+ (MKPolylineAnimator *)((LuggPolylineView *)subview).renderer;
492
+ [renderer resume];
493
+ }
494
+ }
495
+ }
453
496
  CameraIdleEvent{mapView.centerCoordinate.latitude,
454
497
  mapView.centerCoordinate.longitude, mapView.zoomLevel,
455
498
  static_cast<bool>(wasDragging)}
@@ -477,23 +520,13 @@ using namespace luggmaps::events;
477
520
  annotationView.layer.zPosition = markerView.zIndex;
478
521
  annotationView.zPriority = markerView.zIndex;
479
522
 
480
- UIView *iconView = markerView.iconView;
481
- [iconView removeFromSuperview];
482
- [annotationView addSubview:iconView];
483
-
484
- // Set frame and centerOffset based on iconView
485
- CGRect frame = iconView.frame;
486
- if (frame.size.width > 0 && frame.size.height > 0) {
487
- annotationView.frame =
488
- CGRectMake(0, 0, frame.size.width, frame.size.height);
489
- iconView.frame = CGRectMake(0, 0, frame.size.width, frame.size.height);
490
-
491
- CGPoint anchor = markerView.anchor;
492
- annotationView.centerOffset =
493
- CGPointMake(frame.size.width * (anchor.x - 0.5),
494
- -frame.size.height * (anchor.y - 0.5));
523
+ if (!markerView.rasterize) {
524
+ UIView *iconView = markerView.iconView;
525
+ [iconView removeFromSuperview];
526
+ [annotationView addSubview:iconView];
495
527
  }
496
528
 
529
+ [self applyMarkerStyle:markerView annotationView:annotationView];
497
530
  markerAnnotation.annotationView = annotationView;
498
531
 
499
532
  return annotationView;
@@ -89,6 +89,7 @@ static NSString *const kDemoMapId = @"DEMO_MAP_ID";
89
89
  marker.map = nil;
90
90
  markerView.marker = nil;
91
91
  }
92
+ [markerView resetIconViewTransform];
92
93
  } else if ([childComponentView isKindOfClass:[LuggPolylineView class]]) {
93
94
  LuggPolylineView *polylineView = (LuggPolylineView *)childComponentView;
94
95
  [_polylineAnimators removeObjectForKey:polylineView];
@@ -189,6 +190,11 @@ static NSString *const kDemoMapId = @"DEMO_MAP_ID";
189
190
 
190
191
  - (void)mapView:(GMSMapView *)mapView willMove:(BOOL)gesture {
191
192
  _isDragging = gesture;
193
+ if (_isDragging) {
194
+ for (GMSPolylineAnimator *animator in _polylineAnimators.objectEnumerator) {
195
+ [animator pause];
196
+ }
197
+ }
192
198
  }
193
199
 
194
200
  - (void)mapView:(GMSMapView *)mapView
@@ -202,6 +208,11 @@ static NSString *const kDemoMapId = @"DEMO_MAP_ID";
202
208
  idleAtCameraPosition:(GMSCameraPosition *)position {
203
209
  BOOL wasDragging = _isDragging;
204
210
  _isDragging = NO;
211
+ if (wasDragging) {
212
+ for (GMSPolylineAnimator *animator in _polylineAnimators.objectEnumerator) {
213
+ [animator resume];
214
+ }
215
+ }
205
216
  CameraIdleEvent{position.target.latitude, position.target.longitude,
206
217
  position.zoom, static_cast<bool>(wasDragging)}
207
218
  .emit<LuggGoogleMapViewEventEmitter>(_eventEmitter);
@@ -225,6 +236,35 @@ static NSString *const kDemoMapId = @"DEMO_MAP_ID";
225
236
 
226
237
  #pragma mark - Marker Management
227
238
 
239
+ - (void)applyMarkerStyle:(LuggMarkerView *)markerView
240
+ marker:(GMSAdvancedMarker *)marker {
241
+ if (markerView.hasCustomView) {
242
+ if (markerView.rasterize) {
243
+ marker.iconView = nil;
244
+ marker.icon = [markerView createScaledIconImage];
245
+ marker.rotation = markerView.rotate;
246
+ } else {
247
+ UIView *iconView = markerView.iconView;
248
+ if (marker.iconView != iconView) {
249
+ [iconView removeFromSuperview];
250
+ marker.iconView = iconView;
251
+ }
252
+ CGFloat scale = markerView.scale;
253
+ CGFloat radians = markerView.rotate * M_PI / 180.0;
254
+ iconView.transform =
255
+ CGAffineTransformConcat(CGAffineTransformMakeScale(scale, scale),
256
+ CGAffineTransformMakeRotation(radians));
257
+ marker.rotation = 0;
258
+ }
259
+ marker.groundAnchor = markerView.anchor;
260
+ } else {
261
+ marker.iconView = nil;
262
+ marker.icon = nil;
263
+ marker.rotation = markerView.rotate;
264
+ marker.groundAnchor = CGPointMake(0.5, 1);
265
+ }
266
+ }
267
+
228
268
  - (void)syncMarkerView:(LuggMarkerView *)markerView caller:(NSString *)caller {
229
269
  if (!_mapView) {
230
270
  if (![_pendingMarkerViews containsObject:markerView]) {
@@ -243,17 +283,7 @@ static NSString *const kDemoMapId = @"DEMO_MAP_ID";
243
283
  marker.title = markerView.title;
244
284
  marker.snippet = markerView.markerDescription;
245
285
  marker.zIndex = (int)markerView.zIndex;
246
- if (markerView.hasCustomView) {
247
- UIView *iconView = markerView.iconView;
248
- if (marker.iconView != iconView) {
249
- [iconView removeFromSuperview];
250
- marker.iconView = iconView;
251
- }
252
- marker.groundAnchor = markerView.anchor;
253
- } else {
254
- marker.iconView = nil;
255
- marker.groundAnchor = CGPointMake(0.5, 1);
256
- }
286
+ [self applyMarkerStyle:markerView marker:marker];
257
287
  }
258
288
 
259
289
  - (void)processPendingMarkers {
@@ -273,22 +303,15 @@ static NSString *const kDemoMapId = @"DEMO_MAP_ID";
273
303
  return;
274
304
  }
275
305
 
276
- UIView *iconView = markerView.iconView;
277
- [iconView removeFromSuperview];
278
-
279
306
  GMSAdvancedMarker *marker = [[GMSAdvancedMarker alloc] init];
280
307
  marker.position = markerView.coordinate;
281
308
  marker.title = markerView.title;
282
309
  marker.snippet = markerView.markerDescription;
310
+ marker.zIndex = (int)markerView.zIndex;
283
311
 
284
- if (markerView.hasCustomView) {
285
- marker.iconView = iconView;
286
- marker.groundAnchor = markerView.anchor;
287
- }
312
+ [self applyMarkerStyle:markerView marker:marker];
288
313
 
289
- marker.zIndex = (int)markerView.zIndex;
290
314
  marker.map = _mapView;
291
-
292
315
  markerView.marker = marker;
293
316
  }
294
317
 
@@ -20,12 +20,19 @@ NS_ASSUME_NONNULL_BEGIN
20
20
  @property(nonatomic, readonly, nullable) NSString *markerDescription;
21
21
  @property(nonatomic, readonly) CGPoint anchor;
22
22
  @property(nonatomic, readonly) NSInteger zIndex;
23
+ @property(nonatomic, readonly) CLLocationDegrees rotate;
24
+ @property(nonatomic, readonly) CGFloat scale;
25
+ @property(nonatomic, readonly) BOOL rasterize;
23
26
  @property(nonatomic, readonly) BOOL hasCustomView;
24
27
  @property(nonatomic, readonly) BOOL didLayout;
25
28
  @property(nonatomic, readonly) UIView *iconView;
26
29
  @property(nonatomic, weak, nullable) id<LuggMarkerViewDelegate> delegate;
27
30
  @property(nonatomic, strong, nullable) NSObject *marker;
28
31
 
32
+ - (nullable UIImage *)createIconImage;
33
+ - (nullable UIImage *)createScaledIconImage;
34
+ - (void)resetIconViewTransform;
35
+
29
36
  @end
30
37
 
31
38
  NS_ASSUME_NONNULL_END
@@ -19,6 +19,9 @@ using namespace facebook::react;
19
19
  NSString *_markerDescription;
20
20
  CGPoint _anchor;
21
21
  NSInteger _zIndex;
22
+ CLLocationDegrees _rotate;
23
+ CGFloat _scale;
24
+ BOOL _rasterize;
22
25
  BOOL _didLayout;
23
26
  UIView *_iconView;
24
27
  }
@@ -37,6 +40,9 @@ using namespace facebook::react;
37
40
  _coordinate = CLLocationCoordinate2DMake(0, 0);
38
41
  _anchor = CGPointMake(0.5, 1.0);
39
42
  _zIndex = 0;
43
+ _rotate = 0;
44
+ _scale = 1;
45
+ _rasterize = YES;
40
46
  _didLayout = NO;
41
47
 
42
48
  _iconView = [[UIView alloc] init];
@@ -63,6 +69,9 @@ using namespace facebook::react;
63
69
  [NSString stringWithUTF8String:newViewProps.description.c_str()];
64
70
  _anchor = CGPointMake(newViewProps.anchor.x, newViewProps.anchor.y);
65
71
  _zIndex = newViewProps.zIndex.value_or(0);
72
+ _rotate = newViewProps.rotate;
73
+ _scale = newViewProps.scale;
74
+ _rasterize = newViewProps.rasterize;
66
75
  }
67
76
 
68
77
  - (void)finalizeUpdates:(RNComponentViewUpdateMask)updateMask {
@@ -138,6 +147,18 @@ using namespace facebook::react;
138
147
  return _zIndex;
139
148
  }
140
149
 
150
+ - (CLLocationDegrees)rotate {
151
+ return _rotate;
152
+ }
153
+
154
+ - (CGFloat)scale {
155
+ return _scale;
156
+ }
157
+
158
+ - (BOOL)rasterize {
159
+ return _rasterize;
160
+ }
161
+
141
162
  - (BOOL)hasCustomView {
142
163
  return _iconView.subviews.count > 0;
143
164
  }
@@ -150,11 +171,56 @@ using namespace facebook::react;
150
171
  return _iconView;
151
172
  }
152
173
 
174
+ - (UIImage *)createIconImage {
175
+ CGSize size = _iconView.bounds.size;
176
+ if (size.width <= 0 || size.height <= 0) {
177
+ return nil;
178
+ }
179
+
180
+ UIGraphicsImageRendererFormat *format =
181
+ [UIGraphicsImageRendererFormat defaultFormat];
182
+ format.scale = [UIScreen mainScreen].scale;
183
+ UIGraphicsImageRenderer *renderer =
184
+ [[UIGraphicsImageRenderer alloc] initWithSize:size format:format];
185
+
186
+ return [renderer imageWithActions:^(UIGraphicsImageRendererContext *context) {
187
+ [self->_iconView.layer renderInContext:context.CGContext];
188
+ }];
189
+ }
190
+
191
+ - (UIImage *)createScaledIconImage {
192
+ CGSize size = _iconView.bounds.size;
193
+ if (size.width <= 0 || size.height <= 0) {
194
+ return nil;
195
+ }
196
+
197
+ CGSize scaledSize = CGSizeMake(size.width * _scale, size.height * _scale);
198
+
199
+ UIGraphicsImageRendererFormat *format =
200
+ [UIGraphicsImageRendererFormat defaultFormat];
201
+ format.scale = [UIScreen mainScreen].scale;
202
+ UIGraphicsImageRenderer *renderer =
203
+ [[UIGraphicsImageRenderer alloc] initWithSize:scaledSize format:format];
204
+
205
+ return [renderer imageWithActions:^(UIGraphicsImageRendererContext *context) {
206
+ CGContextScaleCTM(context.CGContext, self->_scale, self->_scale);
207
+ [self->_iconView.layer renderInContext:context.CGContext];
208
+ }];
209
+ }
210
+
211
+ - (void)resetIconViewTransform {
212
+ _iconView.transform = CGAffineTransformIdentity;
213
+ _iconView.layer.anchorPoint = CGPointMake(0.5, 0.5);
214
+ _iconView.frame = CGRectMake(0, 0, _iconView.bounds.size.width,
215
+ _iconView.bounds.size.height);
216
+ }
217
+
153
218
  - (void)prepareForRecycle {
154
219
  [super prepareForRecycle];
155
220
  _didLayout = NO;
156
221
  self.marker = nil;
157
222
  self.delegate = nil;
223
+ [self resetIconViewTransform];
158
224
  for (UIView *subview in _iconView.subviews) {
159
225
  [subview removeFromSuperview];
160
226
  }
@@ -7,5 +7,7 @@
7
7
  @property(nonatomic, assign) BOOL animated;
8
8
 
9
9
  - (void)update;
10
+ - (void)pause;
11
+ - (void)resume;
10
12
 
11
13
  @end