@lugg/maps 0.2.0-alpha.1 → 0.2.0-alpha.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -4
- package/android/src/main/java/com/luggmaps/LuggGoogleMapView.kt +30 -8
- package/android/src/main/java/com/luggmaps/LuggGoogleMapViewManager.kt +10 -2
- package/android/src/main/java/com/luggmaps/LuggMarkerView.kt +7 -1
- package/android/src/main/java/com/luggmaps/LuggMarkerViewManager.kt +6 -0
- package/android/src/main/java/com/luggmaps/LuggPolylineView.kt +7 -0
- package/android/src/main/java/com/luggmaps/LuggPolylineViewManager.kt +6 -0
- package/android/src/main/java/com/luggmaps/core/PolylineAnimator.kt +89 -43
- package/ios/LuggAppleMapView.mm +45 -5
- package/ios/LuggGoogleMapView.mm +18 -6
- package/ios/LuggMarkerView.h +2 -0
- package/ios/LuggMarkerView.mm +13 -0
- package/ios/LuggPolylineView.h +1 -0
- package/ios/LuggPolylineView.mm +6 -1
- package/ios/core/GMSPolylineAnimator.m +85 -36
- package/ios/core/MKPolylineAnimator.m +63 -32
- package/lib/module/MapProvider.js +13 -0
- package/lib/module/MapProvider.js.map +1 -0
- package/lib/module/MapProvider.types.js +4 -0
- package/lib/module/MapProvider.types.js.map +1 -0
- package/lib/module/MapProvider.web.js +14 -0
- package/lib/module/MapProvider.web.js.map +1 -0
- package/lib/module/MapView.js +8 -2
- package/lib/module/MapView.js.map +1 -1
- package/lib/module/MapView.web.js +266 -0
- package/lib/module/MapView.web.js.map +1 -0
- package/lib/module/components/Marker.js +4 -1
- package/lib/module/components/Marker.js.map +1 -1
- package/lib/module/components/Marker.web.js +34 -0
- package/lib/module/components/Marker.web.js.map +1 -0
- package/lib/module/components/Polyline.js +5 -2
- package/lib/module/components/Polyline.js.map +1 -1
- package/lib/module/components/Polyline.web.js +177 -0
- package/lib/module/components/Polyline.web.js.map +1 -0
- package/lib/module/components/index.js +2 -2
- package/lib/module/components/index.js.map +1 -1
- package/lib/module/components/index.web.js +5 -0
- package/lib/module/components/index.web.js.map +1 -0
- package/lib/module/fabric/LuggAppleMapViewNativeComponent.ts +4 -1
- package/lib/module/fabric/LuggGoogleMapViewNativeComponent.ts +4 -1
- package/lib/module/index.js +3 -2
- package/lib/module/index.js.map +1 -1
- package/lib/module/index.web.js +6 -0
- package/lib/module/index.web.js.map +1 -0
- package/lib/typescript/src/MapProvider.d.ts +8 -0
- package/lib/typescript/src/MapProvider.d.ts.map +1 -0
- package/lib/typescript/src/MapProvider.types.d.ts +16 -0
- package/lib/typescript/src/MapProvider.types.d.ts.map +1 -0
- package/lib/typescript/src/MapProvider.web.d.ts +3 -0
- package/lib/typescript/src/MapProvider.web.d.ts.map +1 -0
- package/lib/typescript/src/MapView.d.ts.map +1 -1
- package/lib/typescript/src/MapView.types.d.ts +1 -2
- package/lib/typescript/src/MapView.types.d.ts.map +1 -1
- package/lib/typescript/src/MapView.web.d.ts +12 -0
- package/lib/typescript/src/MapView.web.d.ts.map +1 -0
- package/lib/typescript/src/components/Marker.d.ts +4 -0
- package/lib/typescript/src/components/Marker.d.ts.map +1 -1
- package/lib/typescript/src/components/Marker.web.d.ts +6 -0
- package/lib/typescript/src/components/Marker.web.d.ts.map +1 -0
- package/lib/typescript/src/components/Polyline.d.ts +4 -0
- package/lib/typescript/src/components/Polyline.d.ts.map +1 -1
- package/lib/typescript/src/components/Polyline.web.d.ts +6 -0
- package/lib/typescript/src/components/Polyline.web.d.ts.map +1 -0
- package/lib/typescript/src/components/index.web.d.ts +5 -0
- package/lib/typescript/src/components/index.web.d.ts.map +1 -0
- package/lib/typescript/src/fabric/LuggAppleMapViewNativeComponent.d.ts +1 -1
- package/lib/typescript/src/fabric/LuggAppleMapViewNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/fabric/LuggGoogleMapViewNativeComponent.d.ts +1 -1
- package/lib/typescript/src/fabric/LuggGoogleMapViewNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +3 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/index.web.d.ts +7 -0
- package/lib/typescript/src/index.web.d.ts.map +1 -0
- package/package.json +15 -2
- package/src/MapProvider.tsx +10 -0
- package/src/MapProvider.types.ts +16 -0
- package/src/MapProvider.web.tsx +6 -0
- package/src/MapView.tsx +11 -2
- package/src/MapView.types.ts +1 -2
- package/src/MapView.web.tsx +319 -0
- package/src/components/Marker.tsx +6 -2
- package/src/components/Marker.web.tsx +32 -0
- package/src/components/Polyline.tsx +6 -1
- package/src/components/Polyline.web.tsx +222 -0
- package/src/components/index.web.ts +4 -0
- package/src/fabric/LuggAppleMapViewNativeComponent.ts +4 -1
- package/src/fabric/LuggGoogleMapViewNativeComponent.ts +4 -1
- package/src/index.ts +8 -1
- package/src/index.web.ts +17 -0
package/README.md
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
# @lugg/maps
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
- Google Maps (iOS & Android)
|
|
6
|
-
- Apple Maps (iOS only)
|
|
3
|
+
Universal maps for your React Native apps 📍
|
|
7
4
|
|
|
8
5
|
## Installation
|
|
9
6
|
|
|
@@ -56,6 +53,22 @@ Add your Google Maps API key to `AndroidManifest.xml`:
|
|
|
56
53
|
</application>
|
|
57
54
|
```
|
|
58
55
|
|
|
56
|
+
### Web
|
|
57
|
+
|
|
58
|
+
Wrap your app with `MapProvider` and pass your Google Maps API key:
|
|
59
|
+
|
|
60
|
+
```tsx
|
|
61
|
+
import { MapProvider } from '@lugg/maps';
|
|
62
|
+
|
|
63
|
+
function App() {
|
|
64
|
+
return (
|
|
65
|
+
<MapProvider apiKey="YOUR_WEB_API_KEY">
|
|
66
|
+
{/* Your app */}
|
|
67
|
+
</MapProvider>
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
59
72
|
## Usage
|
|
60
73
|
|
|
61
74
|
```tsx
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
package com.luggmaps
|
|
2
2
|
|
|
3
3
|
import android.annotation.SuppressLint
|
|
4
|
-
import android.util.Log
|
|
5
4
|
import android.view.View
|
|
6
5
|
import android.view.ViewGroup
|
|
7
6
|
import com.facebook.react.uimanager.PixelUtil.dpToPx
|
|
@@ -103,7 +102,6 @@ class LuggGoogleMapView(private val reactContext: ThemedReactContext) :
|
|
|
103
102
|
override fun removeViewAt(index: Int) {
|
|
104
103
|
val view = getChildAt(index)
|
|
105
104
|
if (view is LuggMarkerView) {
|
|
106
|
-
Log.d(TAG, "removing markerView: ${view.name}")
|
|
107
105
|
view.marker?.remove()
|
|
108
106
|
view.marker = null
|
|
109
107
|
} else if (view is LuggPolylineView) {
|
|
@@ -123,7 +121,6 @@ class LuggGoogleMapView(private val reactContext: ThemedReactContext) :
|
|
|
123
121
|
}
|
|
124
122
|
|
|
125
123
|
fun onDropViewInstance() {
|
|
126
|
-
Log.d(TAG, "dropping mapView instance")
|
|
127
124
|
pendingMarkerViews.clear()
|
|
128
125
|
pendingPolylineViews.clear()
|
|
129
126
|
polylineAnimators.values.forEach { it.destroy() }
|
|
@@ -282,6 +279,7 @@ class LuggGoogleMapView(private val reactContext: ThemedReactContext) :
|
|
|
282
279
|
title = markerView.title
|
|
283
280
|
snippet = markerView.description
|
|
284
281
|
setAnchor(markerView.anchorX, markerView.anchorY)
|
|
282
|
+
zIndex = markerView.zIndex
|
|
285
283
|
if (!markerView.hasCustomView) {
|
|
286
284
|
iconView = null
|
|
287
285
|
}
|
|
@@ -291,7 +289,6 @@ class LuggGoogleMapView(private val reactContext: ThemedReactContext) :
|
|
|
291
289
|
private fun processPendingMarkers() {
|
|
292
290
|
if (googleMap == null) return
|
|
293
291
|
|
|
294
|
-
Log.d(TAG, "processing pending markers ${pendingMarkerViews.size}")
|
|
295
292
|
pendingMarkerViews.forEach { addMarkerViewToMap(it) }
|
|
296
293
|
pendingMarkerViews.clear()
|
|
297
294
|
}
|
|
@@ -311,15 +308,14 @@ class LuggGoogleMapView(private val reactContext: ThemedReactContext) :
|
|
|
311
308
|
.position(position)
|
|
312
309
|
.title(markerView.title)
|
|
313
310
|
.snippet(markerView.description)
|
|
314
|
-
.collisionBehavior(CollisionBehavior.REQUIRED)
|
|
315
311
|
|
|
316
|
-
Log.d(TAG, "adding marker: ${markerView.name} customview: ${markerView.hasCustomView}")
|
|
317
312
|
if (markerView.hasCustomView) {
|
|
318
313
|
options.iconView(iconView)
|
|
319
314
|
}
|
|
320
315
|
|
|
321
316
|
val marker = map.addMarker(options) as AdvancedMarker
|
|
322
317
|
marker.setAnchor(markerView.anchorX, markerView.anchorY)
|
|
318
|
+
marker.zIndex = markerView.zIndex
|
|
323
319
|
|
|
324
320
|
markerView.marker = marker
|
|
325
321
|
}
|
|
@@ -342,6 +338,7 @@ class LuggGoogleMapView(private val reactContext: ThemedReactContext) :
|
|
|
342
338
|
}
|
|
343
339
|
|
|
344
340
|
polylineView.polyline?.width = polylineView.strokeWidth.dpToPx()
|
|
341
|
+
polylineView.polyline?.zIndex = polylineView.zIndex
|
|
345
342
|
|
|
346
343
|
polylineAnimators[polylineView]?.apply {
|
|
347
344
|
coordinates = polylineView.coordinates
|
|
@@ -364,6 +361,7 @@ class LuggGoogleMapView(private val reactContext: ThemedReactContext) :
|
|
|
364
361
|
|
|
365
362
|
val options = PolylineOptions()
|
|
366
363
|
.width(polylineView.strokeWidth.dpToPx())
|
|
364
|
+
.zIndex(polylineView.zIndex)
|
|
367
365
|
|
|
368
366
|
val polyline = map.addPolyline(options)
|
|
369
367
|
polylineView.polyline = polyline
|
|
@@ -466,7 +464,14 @@ class LuggGoogleMapView(private val reactContext: ThemedReactContext) :
|
|
|
466
464
|
}
|
|
467
465
|
}
|
|
468
466
|
|
|
469
|
-
fun fitCoordinates(
|
|
467
|
+
fun fitCoordinates(
|
|
468
|
+
coordinates: List<LatLng>,
|
|
469
|
+
paddingTop: Int,
|
|
470
|
+
paddingLeft: Int,
|
|
471
|
+
paddingBottom: Int,
|
|
472
|
+
paddingRight: Int,
|
|
473
|
+
duration: Int
|
|
474
|
+
) {
|
|
470
475
|
val map = googleMap ?: return
|
|
471
476
|
if (coordinates.isEmpty()) return
|
|
472
477
|
|
|
@@ -474,12 +479,29 @@ class LuggGoogleMapView(private val reactContext: ThemedReactContext) :
|
|
|
474
479
|
coordinates.forEach { boundsBuilder.include(it) }
|
|
475
480
|
val bounds = boundsBuilder.build()
|
|
476
481
|
|
|
477
|
-
val
|
|
482
|
+
val top = paddingTop.toFloat().dpToPx().toInt()
|
|
483
|
+
val left = paddingLeft.toFloat().dpToPx().toInt()
|
|
484
|
+
val bottom = paddingBottom.toFloat().dpToPx().toInt()
|
|
485
|
+
val right = paddingRight.toFloat().dpToPx().toInt()
|
|
486
|
+
|
|
487
|
+
// Set padding before camera update, then restore after
|
|
488
|
+
map.setPadding(
|
|
489
|
+
this.paddingLeft + left,
|
|
490
|
+
this.paddingTop + top,
|
|
491
|
+
this.paddingRight + right,
|
|
492
|
+
this.paddingBottom + bottom
|
|
493
|
+
)
|
|
494
|
+
|
|
495
|
+
val cameraUpdate = CameraUpdateFactory.newLatLngBounds(bounds, 0)
|
|
496
|
+
|
|
478
497
|
when {
|
|
479
498
|
duration < 0 -> map.animateCamera(cameraUpdate)
|
|
480
499
|
duration > 0 -> map.animateCamera(cameraUpdate, duration, null)
|
|
481
500
|
else -> map.moveCamera(cameraUpdate)
|
|
482
501
|
}
|
|
502
|
+
|
|
503
|
+
// Restore base padding
|
|
504
|
+
map.setPadding(this.paddingLeft, this.paddingTop, this.paddingRight, this.paddingBottom)
|
|
483
505
|
}
|
|
484
506
|
|
|
485
507
|
// endregion
|
|
@@ -144,7 +144,15 @@ class LuggGoogleMapViewManager :
|
|
|
144
144
|
view.moveCamera(latitude, longitude, zoom, duration.toInt())
|
|
145
145
|
}
|
|
146
146
|
|
|
147
|
-
override fun fitCoordinates(
|
|
147
|
+
override fun fitCoordinates(
|
|
148
|
+
view: LuggGoogleMapView,
|
|
149
|
+
coordinates: ReadableArray?,
|
|
150
|
+
paddingTop: Double,
|
|
151
|
+
paddingLeft: Double,
|
|
152
|
+
paddingBottom: Double,
|
|
153
|
+
paddingRight: Double,
|
|
154
|
+
duration: Double
|
|
155
|
+
) {
|
|
148
156
|
val coords = mutableListOf<LatLng>()
|
|
149
157
|
coordinates?.let {
|
|
150
158
|
for (i in 0 until it.size()) {
|
|
@@ -154,7 +162,7 @@ class LuggGoogleMapViewManager :
|
|
|
154
162
|
coords.add(LatLng(lat, lng))
|
|
155
163
|
}
|
|
156
164
|
}
|
|
157
|
-
view.fitCoordinates(coords,
|
|
165
|
+
view.fitCoordinates(coords, paddingTop.toInt(), paddingLeft.toInt(), paddingBottom.toInt(), paddingRight.toInt(), duration.toInt())
|
|
158
166
|
}
|
|
159
167
|
|
|
160
168
|
companion object {
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
package com.luggmaps
|
|
2
2
|
|
|
3
3
|
import android.content.Context
|
|
4
|
-
import android.util.Log
|
|
5
4
|
import android.view.View
|
|
6
5
|
import androidx.core.view.isNotEmpty
|
|
7
6
|
import com.facebook.react.views.view.ReactViewGroup
|
|
@@ -34,6 +33,9 @@ class LuggMarkerView(context: Context) : ReactViewGroup(context) {
|
|
|
34
33
|
var anchorY: Float = 1.0f
|
|
35
34
|
private set
|
|
36
35
|
|
|
36
|
+
var zIndex: Float = 0f
|
|
37
|
+
private set
|
|
38
|
+
|
|
37
39
|
var didLayout: Boolean = false
|
|
38
40
|
private set
|
|
39
41
|
|
|
@@ -114,6 +116,10 @@ class LuggMarkerView(context: Context) : ReactViewGroup(context) {
|
|
|
114
116
|
anchorY = y.toFloat()
|
|
115
117
|
}
|
|
116
118
|
|
|
119
|
+
fun setZIndex(zIndex: Float) {
|
|
120
|
+
this.zIndex = zIndex
|
|
121
|
+
}
|
|
122
|
+
|
|
117
123
|
fun setName(name: String?) {
|
|
118
124
|
this.name = name
|
|
119
125
|
}
|
|
@@ -63,6 +63,12 @@ class LuggMarkerViewManager :
|
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
+
@ReactProp(name = "zIndex", defaultFloat = 0f)
|
|
67
|
+
override fun setZIndex(view: LuggMarkerView, zIndex: Float) {
|
|
68
|
+
super.setZIndex(view, zIndex)
|
|
69
|
+
view.setZIndex(zIndex)
|
|
70
|
+
}
|
|
71
|
+
|
|
66
72
|
companion object {
|
|
67
73
|
const val NAME = "LuggMarkerView"
|
|
68
74
|
}
|
|
@@ -25,6 +25,9 @@ class LuggPolylineView(context: Context) : ReactViewGroup(context) {
|
|
|
25
25
|
var animated: Boolean = false
|
|
26
26
|
private set
|
|
27
27
|
|
|
28
|
+
var zIndex: Float = 0f
|
|
29
|
+
private set
|
|
30
|
+
|
|
28
31
|
var cachedSpans: List<StyleSpan>? = null
|
|
29
32
|
private set
|
|
30
33
|
|
|
@@ -55,6 +58,10 @@ class LuggPolylineView(context: Context) : ReactViewGroup(context) {
|
|
|
55
58
|
animated = value
|
|
56
59
|
}
|
|
57
60
|
|
|
61
|
+
fun setZIndex(value: Float) {
|
|
62
|
+
zIndex = value
|
|
63
|
+
}
|
|
64
|
+
|
|
58
65
|
fun getOrCreateSpans(): List<StyleSpan> {
|
|
59
66
|
cachedSpans?.let { return it }
|
|
60
67
|
|
|
@@ -65,6 +65,12 @@ class LuggPolylineViewManager :
|
|
|
65
65
|
view.setAnimated(value)
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
+
@ReactProp(name = "zIndex", defaultFloat = 0f)
|
|
69
|
+
override fun setZIndex(view: LuggPolylineView, value: Float) {
|
|
70
|
+
super.setZIndex(view, value)
|
|
71
|
+
view.setZIndex(value)
|
|
72
|
+
}
|
|
73
|
+
|
|
68
74
|
companion object {
|
|
69
75
|
const val NAME = "LuggPolylineView"
|
|
70
76
|
}
|
|
@@ -2,18 +2,24 @@ package com.luggmaps.core
|
|
|
2
2
|
|
|
3
3
|
import android.animation.ValueAnimator
|
|
4
4
|
import android.graphics.Color
|
|
5
|
+
import android.location.Location
|
|
5
6
|
import android.view.animation.LinearInterpolator
|
|
6
7
|
import com.google.android.gms.maps.model.LatLng
|
|
7
8
|
import com.google.android.gms.maps.model.Polyline
|
|
8
9
|
import com.google.android.gms.maps.model.StrokeStyle
|
|
9
10
|
import com.google.android.gms.maps.model.StyleSpan
|
|
10
11
|
import kotlin.math.floor
|
|
11
|
-
import kotlin.math.max
|
|
12
12
|
import kotlin.math.min
|
|
13
13
|
|
|
14
14
|
class PolylineAnimator {
|
|
15
15
|
var polyline: Polyline? = null
|
|
16
16
|
var coordinates: List<LatLng> = emptyList()
|
|
17
|
+
set(value) {
|
|
18
|
+
field = value
|
|
19
|
+
if (animated && animator != null) {
|
|
20
|
+
computeCumulativeDistances()
|
|
21
|
+
}
|
|
22
|
+
}
|
|
17
23
|
var strokeColors: List<Int> = listOf(Color.BLACK)
|
|
18
24
|
var strokeWidth: Float = 1f
|
|
19
25
|
|
|
@@ -31,6 +37,8 @@ class PolylineAnimator {
|
|
|
31
37
|
|
|
32
38
|
private var animator: ValueAnimator? = null
|
|
33
39
|
private var animationProgress: Float = 0f
|
|
40
|
+
private var cumulativeDistances: FloatArray = floatArrayOf()
|
|
41
|
+
private var totalLength: Float = 0f
|
|
34
42
|
|
|
35
43
|
fun update() {
|
|
36
44
|
if (animated) return
|
|
@@ -50,8 +58,10 @@ class PolylineAnimator {
|
|
|
50
58
|
private fun startAnimation() {
|
|
51
59
|
if (animator != null) return
|
|
52
60
|
|
|
61
|
+
computeCumulativeDistances()
|
|
62
|
+
|
|
53
63
|
animator = ValueAnimator.ofFloat(0f, 2.15f).apply {
|
|
54
|
-
duration =
|
|
64
|
+
duration = 2150
|
|
55
65
|
repeatCount = ValueAnimator.INFINITE
|
|
56
66
|
interpolator = LinearInterpolator()
|
|
57
67
|
addUpdateListener { animation ->
|
|
@@ -62,6 +72,58 @@ class PolylineAnimator {
|
|
|
62
72
|
}
|
|
63
73
|
}
|
|
64
74
|
|
|
75
|
+
private fun computeCumulativeDistances() {
|
|
76
|
+
if (coordinates.size < 2) {
|
|
77
|
+
cumulativeDistances = floatArrayOf(0f)
|
|
78
|
+
totalLength = 0f
|
|
79
|
+
return
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
val distances = FloatArray(coordinates.size)
|
|
83
|
+
distances[0] = 0f
|
|
84
|
+
var total = 0f
|
|
85
|
+
|
|
86
|
+
for (i in 1 until coordinates.size) {
|
|
87
|
+
val prev = coordinates[i - 1]
|
|
88
|
+
val curr = coordinates[i]
|
|
89
|
+
val results = FloatArray(1)
|
|
90
|
+
Location.distanceBetween(prev.latitude, prev.longitude, curr.latitude, curr.longitude, results)
|
|
91
|
+
total += results[0]
|
|
92
|
+
distances[i] = total
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
cumulativeDistances = distances
|
|
96
|
+
totalLength = total
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
private fun indexForDistance(distance: Float): Int {
|
|
100
|
+
for (i in 1 until cumulativeDistances.size) {
|
|
101
|
+
if (cumulativeDistances[i] >= distance) {
|
|
102
|
+
return i - 1
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return (cumulativeDistances.size - 2).coerceAtLeast(0)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
private fun coordinateAtDistance(distance: Float): LatLng {
|
|
109
|
+
if (distance <= 0f) return coordinates.first()
|
|
110
|
+
if (distance >= totalLength) return coordinates.last()
|
|
111
|
+
|
|
112
|
+
val idx = indexForDistance(distance)
|
|
113
|
+
val segStart = cumulativeDistances[idx]
|
|
114
|
+
val segEnd = cumulativeDistances[idx + 1]
|
|
115
|
+
val segLength = segEnd - segStart
|
|
116
|
+
|
|
117
|
+
val t = if (segLength > 0) (distance - segStart) / segLength else 0f
|
|
118
|
+
val c1 = coordinates[idx]
|
|
119
|
+
val c2 = coordinates[idx + 1]
|
|
120
|
+
|
|
121
|
+
return LatLng(
|
|
122
|
+
c1.latitude + (c2.latitude - c1.latitude) * t,
|
|
123
|
+
c1.longitude + (c2.longitude - c1.longitude) * t
|
|
124
|
+
)
|
|
125
|
+
}
|
|
126
|
+
|
|
65
127
|
private fun stopAnimation() {
|
|
66
128
|
animator?.cancel()
|
|
67
129
|
animator = null
|
|
@@ -69,71 +131,55 @@ class PolylineAnimator {
|
|
|
69
131
|
|
|
70
132
|
private fun updateAnimatedPolyline() {
|
|
71
133
|
val poly = polyline ?: return
|
|
72
|
-
if (coordinates.size < 2) {
|
|
134
|
+
if (coordinates.size < 2 || totalLength <= 0f) {
|
|
73
135
|
poly.points = coordinates
|
|
74
136
|
return
|
|
75
137
|
}
|
|
76
138
|
|
|
77
|
-
val segmentCount = coordinates.size - 1
|
|
78
139
|
val progress = min(animationProgress, 2f)
|
|
79
140
|
|
|
80
|
-
val
|
|
81
|
-
val
|
|
141
|
+
val headDist: Float
|
|
142
|
+
val tailDist: Float
|
|
82
143
|
|
|
83
144
|
if (progress <= 1f) {
|
|
84
|
-
|
|
85
|
-
|
|
145
|
+
tailDist = 0f
|
|
146
|
+
headDist = progress * totalLength
|
|
86
147
|
} else {
|
|
87
148
|
val shrinkProgress = progress - 1f
|
|
88
|
-
|
|
89
|
-
|
|
149
|
+
tailDist = shrinkProgress * totalLength
|
|
150
|
+
headDist = totalLength
|
|
90
151
|
}
|
|
91
152
|
|
|
92
|
-
if (
|
|
153
|
+
if (headDist <= tailDist) {
|
|
93
154
|
poly.setSpans(emptyList())
|
|
94
155
|
poly.points = listOf(coordinates.firstOrNull() ?: LatLng(0.0, 0.0))
|
|
95
156
|
return
|
|
96
157
|
}
|
|
97
158
|
|
|
98
|
-
val
|
|
99
|
-
val
|
|
100
|
-
val
|
|
159
|
+
val visibleLength = headDist - tailDist
|
|
160
|
+
val startIndex = indexForDistance(tailDist)
|
|
161
|
+
val endIndex = indexForDistance(headDist)
|
|
101
162
|
|
|
102
163
|
val points = mutableListOf<LatLng>()
|
|
103
164
|
val spans = mutableListOf<StyleSpan>()
|
|
104
165
|
|
|
105
|
-
|
|
106
|
-
var coord = coordinates[i]
|
|
107
|
-
|
|
108
|
-
// Interpolate tail
|
|
109
|
-
if (i == startIndex && tailPos > startIndex.toFloat() && i + 1 < coordinates.size) {
|
|
110
|
-
val t = tailPos - startIndex
|
|
111
|
-
val next = coordinates[i + 1]
|
|
112
|
-
coord = LatLng(
|
|
113
|
-
coord.latitude + (next.latitude - coord.latitude) * t,
|
|
114
|
-
coord.longitude + (next.longitude - coord.longitude) * t
|
|
115
|
-
)
|
|
116
|
-
}
|
|
166
|
+
points.add(coordinateAtDistance(tailDist))
|
|
117
167
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
val prev = coordinates[i - 1]
|
|
122
|
-
coord = LatLng(
|
|
123
|
-
prev.latitude + (coordinates[i].latitude - prev.latitude) * t,
|
|
124
|
-
prev.longitude + (coordinates[i].longitude - prev.longitude) * t
|
|
125
|
-
)
|
|
126
|
-
}
|
|
168
|
+
for (i in (startIndex + 1)..endIndex) {
|
|
169
|
+
points.add(coordinates[i])
|
|
170
|
+
}
|
|
127
171
|
|
|
128
|
-
|
|
172
|
+
val endCoord = coordinateAtDistance(headDist)
|
|
173
|
+
val lastAdded = points.lastOrNull()
|
|
174
|
+
if (lastAdded == null || endCoord.latitude != lastAdded.latitude || endCoord.longitude != lastAdded.longitude) {
|
|
175
|
+
points.add(endCoord)
|
|
176
|
+
}
|
|
129
177
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
spans.add(StyleSpan(StrokeStyle.colorBuilder(color).build()))
|
|
136
|
-
}
|
|
178
|
+
for (i in 0 until (points.size - 1)) {
|
|
179
|
+
val segMidDist = tailDist + visibleLength * (i + 0.5f) / (points.size - 1)
|
|
180
|
+
val gradientPos = (segMidDist - tailDist) / visibleLength
|
|
181
|
+
val color = colorAtGradientPosition(gradientPos)
|
|
182
|
+
spans.add(StyleSpan(StrokeStyle.colorBuilder(color).build()))
|
|
137
183
|
}
|
|
138
184
|
|
|
139
185
|
poly.points = points
|
package/ios/LuggAppleMapView.mm
CHANGED
|
@@ -161,6 +161,10 @@ using namespace luggmaps::events;
|
|
|
161
161
|
_maxZoom = viewProps.maxZoom;
|
|
162
162
|
[self applyZoomRange];
|
|
163
163
|
|
|
164
|
+
_mapView.layoutMargins =
|
|
165
|
+
UIEdgeInsetsMake(viewProps.padding.top, viewProps.padding.left,
|
|
166
|
+
viewProps.padding.bottom, viewProps.padding.right);
|
|
167
|
+
|
|
164
168
|
[_mapWrapperView addSubview:_mapView];
|
|
165
169
|
|
|
166
170
|
[self setCameraWithLatitude:viewProps.initialCoordinate.latitude
|
|
@@ -298,7 +302,7 @@ using namespace luggmaps::events;
|
|
|
298
302
|
free(coords);
|
|
299
303
|
|
|
300
304
|
polylineView.polyline = polyline;
|
|
301
|
-
[
|
|
305
|
+
[self insertOverlay:polyline withZIndex:polylineView.zIndex];
|
|
302
306
|
}
|
|
303
307
|
|
|
304
308
|
- (void)syncPolylineView:(LuggPolylineView *)polylineView {
|
|
@@ -312,6 +316,9 @@ using namespace luggmaps::events;
|
|
|
312
316
|
// Build new polyline from coordinates
|
|
313
317
|
NSArray<CLLocation *> *coordinates = polylineView.coordinates;
|
|
314
318
|
if (coordinates.count == 0) {
|
|
319
|
+
if (renderer) {
|
|
320
|
+
renderer.animated = NO;
|
|
321
|
+
}
|
|
315
322
|
if (oldPolyline) {
|
|
316
323
|
[_mapView removeOverlay:oldPolyline];
|
|
317
324
|
polylineView.polyline = nil;
|
|
@@ -333,6 +340,8 @@ using namespace luggmaps::events;
|
|
|
333
340
|
|
|
334
341
|
// If we have an existing renderer, update it in place
|
|
335
342
|
if (renderer && oldPolyline) {
|
|
343
|
+
[_mapView removeOverlay:oldPolyline];
|
|
344
|
+
[self insertOverlay:newPolyline withZIndex:polylineView.zIndex];
|
|
336
345
|
[renderer updatePolyline:newPolyline];
|
|
337
346
|
renderer.lineWidth = polylineView.strokeWidth;
|
|
338
347
|
renderer.strokeColor = polylineView.strokeColors.firstObject;
|
|
@@ -346,7 +355,28 @@ using namespace luggmaps::events;
|
|
|
346
355
|
if (oldPolyline) {
|
|
347
356
|
[_mapView removeOverlay:oldPolyline];
|
|
348
357
|
}
|
|
349
|
-
[
|
|
358
|
+
[self insertOverlay:newPolyline withZIndex:polylineView.zIndex];
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
- (void)insertOverlay:(id<MKOverlay>)overlay withZIndex:(NSInteger)zIndex {
|
|
362
|
+
if (zIndex == 0) {
|
|
363
|
+
[_mapView addOverlay:overlay];
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
NSArray<id<MKOverlay>> *overlays = _mapView.overlays;
|
|
368
|
+
NSInteger insertIndex = overlays.count;
|
|
369
|
+
|
|
370
|
+
for (NSInteger i = 0; i < overlays.count; i++) {
|
|
371
|
+
LuggPolylineView *existingPolylineView =
|
|
372
|
+
[self findPolylineViewForOverlay:overlays[i]];
|
|
373
|
+
if (existingPolylineView && existingPolylineView.zIndex > zIndex) {
|
|
374
|
+
insertIndex = i;
|
|
375
|
+
break;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
[_mapView insertOverlay:overlay atIndex:insertIndex];
|
|
350
380
|
}
|
|
351
381
|
|
|
352
382
|
- (LuggPolylineView *)findPolylineViewForOverlay:(id<MKOverlay>)overlay {
|
|
@@ -384,6 +414,12 @@ using namespace luggmaps::events;
|
|
|
384
414
|
annotation.title = markerView.title;
|
|
385
415
|
annotation.subtitle = markerView.markerDescription;
|
|
386
416
|
|
|
417
|
+
MKAnnotationView *annotationView = annotation.annotationView;
|
|
418
|
+
if (annotationView) {
|
|
419
|
+
annotationView.layer.zPosition = markerView.zIndex;
|
|
420
|
+
annotationView.zPriority = markerView.zIndex;
|
|
421
|
+
}
|
|
422
|
+
|
|
387
423
|
[self updateAnnotationViewFrame:annotation];
|
|
388
424
|
}
|
|
389
425
|
|
|
@@ -438,7 +474,8 @@ using namespace luggmaps::events;
|
|
|
438
474
|
reuseIdentifier:nil];
|
|
439
475
|
annotationView.canShowCallout = YES;
|
|
440
476
|
annotationView.displayPriority = MKFeatureDisplayPriorityRequired;
|
|
441
|
-
annotationView.
|
|
477
|
+
annotationView.layer.zPosition = markerView.zIndex;
|
|
478
|
+
annotationView.zPriority = markerView.zIndex;
|
|
442
479
|
|
|
443
480
|
UIView *iconView = markerView.iconView;
|
|
444
481
|
[iconView removeFromSuperview];
|
|
@@ -523,7 +560,10 @@ using namespace luggmaps::events;
|
|
|
523
560
|
}
|
|
524
561
|
|
|
525
562
|
- (void)fitCoordinates:(NSArray *)coordinates
|
|
526
|
-
|
|
563
|
+
paddingTop:(double)paddingTop
|
|
564
|
+
paddingLeft:(double)paddingLeft
|
|
565
|
+
paddingBottom:(double)paddingBottom
|
|
566
|
+
paddingRight:(double)paddingRight
|
|
527
567
|
duration:(double)duration {
|
|
528
568
|
if (!_mapView || coordinates.count == 0) {
|
|
529
569
|
return;
|
|
@@ -546,7 +586,7 @@ using namespace luggmaps::events;
|
|
|
546
586
|
free(coords);
|
|
547
587
|
|
|
548
588
|
UIEdgeInsets edgePadding =
|
|
549
|
-
UIEdgeInsetsMake(
|
|
589
|
+
UIEdgeInsetsMake(paddingTop, paddingLeft, paddingBottom, paddingRight);
|
|
550
590
|
|
|
551
591
|
if (duration < 0) {
|
|
552
592
|
[_mapView setVisibleMapRect:mapRect edgePadding:edgePadding animated:YES];
|
package/ios/LuggGoogleMapView.mm
CHANGED
|
@@ -168,6 +168,10 @@ static NSString *const kDemoMapId = @"DEMO_MAP_ID";
|
|
|
168
168
|
[_mapView setMinZoom:_mapView.minZoom maxZoom:(float)viewProps.maxZoom];
|
|
169
169
|
}
|
|
170
170
|
|
|
171
|
+
_mapView.padding =
|
|
172
|
+
UIEdgeInsetsMake(viewProps.padding.top, viewProps.padding.left,
|
|
173
|
+
viewProps.padding.bottom, viewProps.padding.right);
|
|
174
|
+
|
|
171
175
|
[_mapWrapperView addSubview:_mapView];
|
|
172
176
|
|
|
173
177
|
_isMapReady = YES;
|
|
@@ -238,14 +242,15 @@ static NSString *const kDemoMapId = @"DEMO_MAP_ID";
|
|
|
238
242
|
marker.position = markerView.coordinate;
|
|
239
243
|
marker.title = markerView.title;
|
|
240
244
|
marker.snippet = markerView.markerDescription;
|
|
241
|
-
marker.
|
|
242
|
-
|
|
245
|
+
marker.zIndex = (int)markerView.zIndex;
|
|
243
246
|
if (markerView.hasCustomView) {
|
|
244
247
|
UIView *iconView = markerView.iconView;
|
|
245
248
|
[iconView removeFromSuperview];
|
|
246
249
|
marker.iconView = iconView;
|
|
250
|
+
marker.groundAnchor = markerView.anchor;
|
|
247
251
|
} else {
|
|
248
252
|
marker.iconView = nil;
|
|
253
|
+
marker.groundAnchor = CGPointMake(0.5, 1);
|
|
249
254
|
}
|
|
250
255
|
}
|
|
251
256
|
|
|
@@ -273,13 +278,13 @@ static NSString *const kDemoMapId = @"DEMO_MAP_ID";
|
|
|
273
278
|
marker.position = markerView.coordinate;
|
|
274
279
|
marker.title = markerView.title;
|
|
275
280
|
marker.snippet = markerView.markerDescription;
|
|
276
|
-
marker.collisionBehavior = GMSCollisionBehaviorRequired;
|
|
277
281
|
|
|
278
282
|
if (markerView.hasCustomView) {
|
|
279
283
|
marker.iconView = iconView;
|
|
284
|
+
marker.groundAnchor = markerView.anchor;
|
|
280
285
|
}
|
|
281
286
|
|
|
282
|
-
marker.
|
|
287
|
+
marker.zIndex = (int)markerView.zIndex;
|
|
283
288
|
marker.map = _mapView;
|
|
284
289
|
|
|
285
290
|
markerView.marker = marker;
|
|
@@ -302,6 +307,7 @@ static NSString *const kDemoMapId = @"DEMO_MAP_ID";
|
|
|
302
307
|
|
|
303
308
|
GMSPolyline *polyline = (GMSPolyline *)polylineView.polyline;
|
|
304
309
|
polyline.strokeWidth = polylineView.strokeWidth;
|
|
310
|
+
polyline.zIndex = (int)polylineView.zIndex;
|
|
305
311
|
|
|
306
312
|
GMSPolylineAnimator *animator =
|
|
307
313
|
[_polylineAnimators objectForKey:polylineView];
|
|
@@ -331,6 +337,7 @@ static NSString *const kDemoMapId = @"DEMO_MAP_ID";
|
|
|
331
337
|
|
|
332
338
|
GMSPolyline *polyline = [GMSPolyline polylineWithPath:[GMSMutablePath path]];
|
|
333
339
|
polyline.strokeWidth = polylineView.strokeWidth;
|
|
340
|
+
polyline.zIndex = (int)polylineView.zIndex;
|
|
334
341
|
polyline.map = _mapView;
|
|
335
342
|
polylineView.polyline = polyline;
|
|
336
343
|
|
|
@@ -406,7 +413,10 @@ static NSString *const kDemoMapId = @"DEMO_MAP_ID";
|
|
|
406
413
|
}
|
|
407
414
|
|
|
408
415
|
- (void)fitCoordinates:(NSArray *)coordinates
|
|
409
|
-
|
|
416
|
+
paddingTop:(double)paddingTop
|
|
417
|
+
paddingLeft:(double)paddingLeft
|
|
418
|
+
paddingBottom:(double)paddingBottom
|
|
419
|
+
paddingRight:(double)paddingRight
|
|
410
420
|
duration:(double)duration {
|
|
411
421
|
if (!_mapView || coordinates.count == 0) {
|
|
412
422
|
return;
|
|
@@ -419,8 +429,10 @@ static NSString *const kDemoMapId = @"DEMO_MAP_ID";
|
|
|
419
429
|
bounds = [bounds includingCoordinate:CLLocationCoordinate2DMake(lat, lng)];
|
|
420
430
|
}
|
|
421
431
|
|
|
432
|
+
UIEdgeInsets edgePadding =
|
|
433
|
+
UIEdgeInsetsMake(paddingTop, paddingLeft, paddingBottom, paddingRight);
|
|
422
434
|
GMSCameraUpdate *cameraUpdate = [GMSCameraUpdate fitBounds:bounds
|
|
423
|
-
|
|
435
|
+
withEdgeInsets:edgePadding];
|
|
424
436
|
|
|
425
437
|
if (duration < 0) {
|
|
426
438
|
[_mapView animateWithCameraUpdate:cameraUpdate];
|
package/ios/LuggMarkerView.h
CHANGED
|
@@ -14,10 +14,12 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
14
14
|
|
|
15
15
|
@interface LuggMarkerView : RCTViewComponentView
|
|
16
16
|
|
|
17
|
+
@property(nonatomic, readonly, nullable) NSString *name;
|
|
17
18
|
@property(nonatomic, readonly) CLLocationCoordinate2D coordinate;
|
|
18
19
|
@property(nonatomic, readonly, nullable) NSString *title;
|
|
19
20
|
@property(nonatomic, readonly, nullable) NSString *markerDescription;
|
|
20
21
|
@property(nonatomic, readonly) CGPoint anchor;
|
|
22
|
+
@property(nonatomic, readonly) NSInteger zIndex;
|
|
21
23
|
@property(nonatomic, readonly) BOOL hasCustomView;
|
|
22
24
|
@property(nonatomic, readonly) BOOL didLayout;
|
|
23
25
|
@property(nonatomic, readonly) UIView *iconView;
|