@lugg/maps 0.2.0-alpha.3 → 0.2.0-alpha.30
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 +21 -3
- package/android/src/main/java/com/luggmaps/LuggMapView.kt +265 -0
- package/android/src/main/java/com/luggmaps/{LuggGoogleMapViewManager.kt → LuggMapViewManager.kt} +75 -36
- package/android/src/main/java/com/luggmaps/LuggMapWrapperView.kt +6 -5
- package/android/src/main/java/com/luggmaps/LuggMarkerView.kt +136 -14
- package/android/src/main/java/com/luggmaps/LuggMarkerViewManager.kt +21 -0
- package/android/src/main/java/com/luggmaps/LuggPackage.kt +1 -4
- package/android/src/main/java/com/luggmaps/LuggPolylineView.kt +16 -0
- package/android/src/main/java/com/luggmaps/LuggPolylineViewManager.kt +22 -0
- package/android/src/main/java/com/luggmaps/{LuggGoogleMapView.kt → core/GoogleMapProvider.kt} +251 -241
- package/android/src/main/java/com/luggmaps/core/MapProviderDelegate.kt +55 -0
- package/android/src/main/java/com/luggmaps/core/PolylineAnimator.kt +163 -52
- package/ios/LuggMapView.h +9 -0
- package/ios/LuggMapView.mm +312 -0
- package/ios/LuggMarkerView.h +9 -0
- package/ios/LuggMarkerView.mm +79 -0
- package/ios/LuggPolylineView.h +4 -0
- package/ios/LuggPolylineView.mm +23 -0
- package/ios/core/AppleMapProvider.h +15 -0
- package/ios/core/AppleMapProvider.mm +664 -0
- package/ios/core/GMSPolylineAnimator.h +3 -0
- package/ios/core/GMSPolylineAnimator.m +175 -40
- package/ios/core/GoogleMapProvider.h +13 -0
- package/ios/core/GoogleMapProvider.mm +513 -0
- package/ios/core/MKPolylineAnimator.h +4 -0
- package/ios/core/MKPolylineAnimator.m +224 -68
- package/ios/core/MapProviderDelegate.h +72 -0
- package/ios/core/PolylineAnimatorBase.h +24 -1
- package/ios/core/PolylineAnimatorBase.m +82 -19
- package/ios/extensions/MKMapView+Zoom.h +2 -0
- package/ios/extensions/MKMapView+Zoom.m +14 -4
- 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 +20 -0
- package/lib/module/MapProvider.web.js.map +1 -0
- package/lib/module/MapView.js +29 -16
- package/lib/module/MapView.js.map +1 -1
- package/lib/module/MapView.web.js +290 -0
- package/lib/module/MapView.web.js.map +1 -0
- package/lib/module/components/Marker.js +19 -2
- package/lib/module/components/Marker.js.map +1 -1
- package/lib/module/components/Marker.web.js +33 -0
- package/lib/module/components/Marker.web.js.map +1 -0
- package/lib/module/components/Polyline.js +17 -4
- package/lib/module/components/Polyline.js.map +1 -1
- package/lib/module/components/Polyline.web.js +229 -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/{LuggGoogleMapViewNativeComponent.ts → LuggMapViewNativeComponent.ts} +19 -7
- package/lib/module/fabric/LuggMarkerViewNativeComponent.ts +7 -1
- package/lib/module/fabric/LuggPolylineViewNativeComponent.ts +8 -0
- package/lib/module/index.js +4 -2
- package/lib/module/index.js.map +1 -1
- package/lib/module/index.web.js +7 -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 +11 -0
- package/lib/typescript/src/MapProvider.web.d.ts.map +1 -0
- package/lib/typescript/src/MapView.d.ts +4 -4
- package/lib/typescript/src/MapView.d.ts.map +1 -1
- package/lib/typescript/src/MapView.types.d.ts +23 -7
- package/lib/typescript/src/MapView.types.d.ts.map +1 -1
- package/lib/typescript/src/MapView.web.d.ts +3 -0
- package/lib/typescript/src/MapView.web.d.ts.map +1 -0
- package/lib/typescript/src/components/Marker.d.ts +25 -1
- package/lib/typescript/src/components/Marker.d.ts.map +1 -1
- package/lib/typescript/src/components/Marker.web.d.ts +3 -0
- package/lib/typescript/src/components/Marker.web.d.ts.map +1 -0
- package/lib/typescript/src/components/Polyline.d.ts +36 -1
- package/lib/typescript/src/components/Polyline.d.ts.map +1 -1
- package/lib/typescript/src/components/Polyline.web.d.ts +3 -0
- package/lib/typescript/src/components/Polyline.web.d.ts.map +1 -0
- package/lib/typescript/src/components/index.d.ts +4 -2
- package/lib/typescript/src/components/index.d.ts.map +1 -1
- 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/{LuggGoogleMapViewNativeComponent.d.ts → LuggMapViewNativeComponent.d.ts} +8 -4
- package/lib/typescript/src/fabric/LuggMapViewNativeComponent.d.ts.map +1 -0
- package/lib/typescript/src/fabric/LuggMarkerViewNativeComponent.d.ts +4 -1
- package/lib/typescript/src/fabric/LuggMarkerViewNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/fabric/LuggPolylineViewNativeComponent.d.ts +7 -0
- package/lib/typescript/src/fabric/LuggPolylineViewNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +8 -3
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/index.web.d.ts +10 -0
- package/lib/typescript/src/index.web.d.ts.map +1 -0
- package/lib/typescript/src/types.d.ts +4 -0
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/package.json +17 -3
- package/src/MapProvider.tsx +10 -0
- package/src/MapProvider.types.ts +16 -0
- package/src/MapProvider.web.tsx +14 -0
- package/src/MapView.tsx +28 -26
- package/src/MapView.types.ts +24 -7
- package/src/MapView.web.tsx +364 -0
- package/src/components/Marker.tsx +50 -4
- package/src/components/Marker.web.tsx +33 -0
- package/src/components/Polyline.tsx +51 -2
- package/src/components/Polyline.web.tsx +287 -0
- package/src/components/index.ts +8 -2
- package/src/components/index.web.ts +4 -0
- package/src/fabric/{LuggGoogleMapViewNativeComponent.ts → LuggMapViewNativeComponent.ts} +19 -7
- package/src/fabric/LuggMarkerViewNativeComponent.ts +7 -1
- package/src/fabric/LuggPolylineViewNativeComponent.ts +8 -0
- package/src/index.ts +18 -2
- package/src/index.web.ts +20 -0
- package/src/types.ts +5 -0
- package/ios/LuggAppleMapView.h +0 -16
- package/ios/LuggAppleMapView.mm +0 -580
- package/ios/LuggGoogleMapView.h +0 -13
- package/ios/LuggGoogleMapView.mm +0 -454
- package/lib/module/fabric/LuggAppleMapViewNativeComponent.ts +0 -83
- package/lib/typescript/src/fabric/LuggAppleMapViewNativeComponent.d.ts +0 -54
- package/lib/typescript/src/fabric/LuggAppleMapViewNativeComponent.d.ts.map +0 -1
- package/lib/typescript/src/fabric/LuggGoogleMapViewNativeComponent.d.ts.map +0 -1
- package/src/fabric/LuggAppleMapViewNativeComponent.ts +0 -83
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
package com.luggmaps.core
|
|
2
|
+
|
|
3
|
+
import android.view.View
|
|
4
|
+
import com.luggmaps.LuggMarkerView
|
|
5
|
+
import com.luggmaps.LuggPolylineView
|
|
6
|
+
|
|
7
|
+
data class EdgeInsets(val top: Int = 0, val left: Int = 0, val bottom: Int = 0, val right: Int = 0)
|
|
8
|
+
|
|
9
|
+
interface MapProviderDelegate {
|
|
10
|
+
fun mapProviderDidReady()
|
|
11
|
+
fun mapProviderDidMoveCamera(latitude: Double, longitude: Double, zoom: Float, gesture: Boolean)
|
|
12
|
+
fun mapProviderDidIdleCamera(latitude: Double, longitude: Double, zoom: Float, gesture: Boolean)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface MapProvider {
|
|
16
|
+
var delegate: MapProviderDelegate?
|
|
17
|
+
val isMapReady: Boolean
|
|
18
|
+
|
|
19
|
+
fun initializeMap(wrapperView: View, latitude: Double, longitude: Double, zoom: Float)
|
|
20
|
+
fun destroy()
|
|
21
|
+
|
|
22
|
+
// Props
|
|
23
|
+
fun setZoomEnabled(enabled: Boolean)
|
|
24
|
+
fun setScrollEnabled(enabled: Boolean)
|
|
25
|
+
fun setRotateEnabled(enabled: Boolean)
|
|
26
|
+
fun setPitchEnabled(enabled: Boolean)
|
|
27
|
+
fun setUserLocationEnabled(enabled: Boolean)
|
|
28
|
+
fun setUserLocationButtonEnabled(enabled: Boolean)
|
|
29
|
+
fun setTheme(value: String)
|
|
30
|
+
fun setMinZoom(zoom: Double)
|
|
31
|
+
fun setMaxZoom(zoom: Double)
|
|
32
|
+
fun setEdgeInsets(edgeInsets: EdgeInsets)
|
|
33
|
+
fun setEdgeInsets(edgeInsets: EdgeInsets, duration: Int)
|
|
34
|
+
|
|
35
|
+
// Children
|
|
36
|
+
fun addMarkerView(markerView: LuggMarkerView)
|
|
37
|
+
fun removeMarkerView(markerView: LuggMarkerView)
|
|
38
|
+
fun addPolylineView(polylineView: LuggPolylineView)
|
|
39
|
+
fun removePolylineView(polylineView: LuggPolylineView)
|
|
40
|
+
|
|
41
|
+
// Lifecycle
|
|
42
|
+
fun pauseAnimations()
|
|
43
|
+
fun resumeAnimations()
|
|
44
|
+
|
|
45
|
+
// Commands
|
|
46
|
+
fun moveCamera(latitude: Double, longitude: Double, zoom: Double, duration: Int)
|
|
47
|
+
fun fitCoordinates(
|
|
48
|
+
coordinates: List<Any>,
|
|
49
|
+
edgeInsetsTop: Int,
|
|
50
|
+
edgeInsetsLeft: Int,
|
|
51
|
+
edgeInsetsBottom: Int,
|
|
52
|
+
edgeInsetsRight: Int,
|
|
53
|
+
duration: Int
|
|
54
|
+
)
|
|
55
|
+
}
|
|
@@ -2,20 +2,39 @@ 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
|
|
11
|
+
import com.luggmaps.AnimatedOptions
|
|
10
12
|
import kotlin.math.floor
|
|
11
|
-
import kotlin.math.max
|
|
12
13
|
import kotlin.math.min
|
|
13
14
|
|
|
14
15
|
class PolylineAnimator {
|
|
16
|
+
companion object {
|
|
17
|
+
private const val MAX_ANIMATION_SPANS = 16
|
|
18
|
+
}
|
|
19
|
+
|
|
15
20
|
var polyline: Polyline? = null
|
|
16
21
|
var coordinates: List<LatLng> = emptyList()
|
|
22
|
+
set(value) {
|
|
23
|
+
field = value
|
|
24
|
+
if (animated && animator != null) {
|
|
25
|
+
computeCumulativeDistances()
|
|
26
|
+
}
|
|
27
|
+
}
|
|
17
28
|
var strokeColors: List<Int> = listOf(Color.BLACK)
|
|
18
29
|
var strokeWidth: Float = 1f
|
|
30
|
+
var animatedOptions: AnimatedOptions = AnimatedOptions()
|
|
31
|
+
set(value) {
|
|
32
|
+
if (field == value) return
|
|
33
|
+
field = value
|
|
34
|
+
if (animated) {
|
|
35
|
+
restartAnimation()
|
|
36
|
+
}
|
|
37
|
+
}
|
|
19
38
|
|
|
20
39
|
var animated: Boolean = false
|
|
21
40
|
set(value) {
|
|
@@ -31,6 +50,25 @@ class PolylineAnimator {
|
|
|
31
50
|
|
|
32
51
|
private var animator: ValueAnimator? = null
|
|
33
52
|
private var animationProgress: Float = 0f
|
|
53
|
+
private var cumulativeDistances: FloatArray = floatArrayOf()
|
|
54
|
+
private var totalLength: Float = 0f
|
|
55
|
+
|
|
56
|
+
// Reusable collections to avoid per-frame allocations
|
|
57
|
+
private val reusablePoints = ArrayList<LatLng>()
|
|
58
|
+
private val reusableSpans = ArrayList<StyleSpan>()
|
|
59
|
+
|
|
60
|
+
private fun restartAnimation() {
|
|
61
|
+
stopAnimation()
|
|
62
|
+
startAnimation()
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
private fun applyEasing(t: Float): Float =
|
|
66
|
+
when (animatedOptions.easing) {
|
|
67
|
+
"easeIn" -> t * t
|
|
68
|
+
"easeOut" -> t * (2 - t)
|
|
69
|
+
"easeInOut" -> if (t < 0.5f) 2 * t * t else -1 + (4 - 2 * t) * t
|
|
70
|
+
else -> t
|
|
71
|
+
}
|
|
34
72
|
|
|
35
73
|
fun update() {
|
|
36
74
|
if (animated) return
|
|
@@ -50,8 +88,14 @@ class PolylineAnimator {
|
|
|
50
88
|
private fun startAnimation() {
|
|
51
89
|
if (animator != null) return
|
|
52
90
|
|
|
53
|
-
|
|
54
|
-
|
|
91
|
+
computeCumulativeDistances()
|
|
92
|
+
|
|
93
|
+
val trailLength = animatedOptions.trailLength.coerceIn(0.01f, 1f)
|
|
94
|
+
val maxProgress = if (trailLength < 1f) 1f else 2.15f
|
|
95
|
+
|
|
96
|
+
animator = ValueAnimator.ofFloat(0f, maxProgress).apply {
|
|
97
|
+
duration = (animatedOptions.duration * maxProgress).toLong()
|
|
98
|
+
startDelay = animatedOptions.delay
|
|
55
99
|
repeatCount = ValueAnimator.INFINITE
|
|
56
100
|
interpolator = LinearInterpolator()
|
|
57
101
|
addUpdateListener { animation ->
|
|
@@ -62,83 +106,150 @@ class PolylineAnimator {
|
|
|
62
106
|
}
|
|
63
107
|
}
|
|
64
108
|
|
|
109
|
+
private fun computeCumulativeDistances() {
|
|
110
|
+
if (coordinates.size < 2) {
|
|
111
|
+
cumulativeDistances = floatArrayOf(0f)
|
|
112
|
+
totalLength = 0f
|
|
113
|
+
return
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
val distances = FloatArray(coordinates.size)
|
|
117
|
+
distances[0] = 0f
|
|
118
|
+
var total = 0f
|
|
119
|
+
|
|
120
|
+
for (i in 1 until coordinates.size) {
|
|
121
|
+
val prev = coordinates[i - 1]
|
|
122
|
+
val curr = coordinates[i]
|
|
123
|
+
val results = FloatArray(1)
|
|
124
|
+
Location.distanceBetween(prev.latitude, prev.longitude, curr.latitude, curr.longitude, results)
|
|
125
|
+
total += results[0]
|
|
126
|
+
distances[i] = total
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
cumulativeDistances = distances
|
|
130
|
+
totalLength = total
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
private fun indexForDistance(distance: Float): Int {
|
|
134
|
+
var left = 0
|
|
135
|
+
var right = cumulativeDistances.size - 1
|
|
136
|
+
|
|
137
|
+
while (left < right) {
|
|
138
|
+
val mid = (left + right + 1) / 2
|
|
139
|
+
if (cumulativeDistances[mid] <= distance) {
|
|
140
|
+
left = mid
|
|
141
|
+
} else {
|
|
142
|
+
right = mid - 1
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return left.coerceAtMost(cumulativeDistances.size - 2).coerceAtLeast(0)
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
private fun coordinateAtDistance(distance: Float): LatLng {
|
|
150
|
+
if (distance <= 0f) return coordinates.first()
|
|
151
|
+
if (distance >= totalLength) return coordinates.last()
|
|
152
|
+
|
|
153
|
+
val idx = indexForDistance(distance)
|
|
154
|
+
val segStart = cumulativeDistances[idx]
|
|
155
|
+
val segEnd = cumulativeDistances[idx + 1]
|
|
156
|
+
val segLength = segEnd - segStart
|
|
157
|
+
|
|
158
|
+
val t = if (segLength > 0) (distance - segStart) / segLength else 0f
|
|
159
|
+
val c1 = coordinates[idx]
|
|
160
|
+
val c2 = coordinates[idx + 1]
|
|
161
|
+
|
|
162
|
+
// Reuse existing coordinate if no interpolation needed
|
|
163
|
+
if (t == 0f) return c1
|
|
164
|
+
|
|
165
|
+
return LatLng(
|
|
166
|
+
c1.latitude + (c2.latitude - c1.latitude) * t,
|
|
167
|
+
c1.longitude + (c2.longitude - c1.longitude) * t
|
|
168
|
+
)
|
|
169
|
+
}
|
|
170
|
+
|
|
65
171
|
private fun stopAnimation() {
|
|
66
172
|
animator?.cancel()
|
|
67
173
|
animator = null
|
|
68
174
|
}
|
|
69
175
|
|
|
176
|
+
fun pause() {
|
|
177
|
+
animator?.pause()
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
fun resume() {
|
|
181
|
+
animator?.resume()
|
|
182
|
+
}
|
|
183
|
+
|
|
70
184
|
private fun updateAnimatedPolyline() {
|
|
71
185
|
val poly = polyline ?: return
|
|
72
|
-
if (coordinates.size < 2) {
|
|
186
|
+
if (coordinates.size < 2 || totalLength <= 0f) {
|
|
73
187
|
poly.points = coordinates
|
|
74
188
|
return
|
|
75
189
|
}
|
|
76
190
|
|
|
77
|
-
val
|
|
78
|
-
val
|
|
191
|
+
val trailLength = animatedOptions.trailLength.coerceIn(0.01f, 1f)
|
|
192
|
+
val maxProgress = if (trailLength < 1f) 1f else 2f
|
|
193
|
+
val rawProgress = min(animationProgress, maxProgress)
|
|
194
|
+
val progress = applyEasing(rawProgress / maxProgress) * maxProgress
|
|
79
195
|
|
|
80
|
-
val
|
|
81
|
-
val
|
|
196
|
+
val headDist: Float
|
|
197
|
+
val tailDist: Float
|
|
82
198
|
|
|
83
|
-
if (
|
|
84
|
-
|
|
85
|
-
|
|
199
|
+
if (trailLength < 1f) {
|
|
200
|
+
headDist = progress * totalLength
|
|
201
|
+
tailDist = maxOf(0f, headDist - totalLength * trailLength)
|
|
202
|
+
} else if (progress <= 1f) {
|
|
203
|
+
tailDist = 0f
|
|
204
|
+
headDist = progress * totalLength
|
|
86
205
|
} else {
|
|
87
206
|
val shrinkProgress = progress - 1f
|
|
88
|
-
|
|
89
|
-
|
|
207
|
+
tailDist = shrinkProgress * totalLength
|
|
208
|
+
headDist = totalLength
|
|
90
209
|
}
|
|
91
210
|
|
|
92
|
-
if (
|
|
93
|
-
poly.setSpans(emptyList())
|
|
211
|
+
if (headDist <= tailDist) {
|
|
94
212
|
poly.points = listOf(coordinates.firstOrNull() ?: LatLng(0.0, 0.0))
|
|
213
|
+
poly.color = strokeColors.firstOrNull() ?: Color.BLACK
|
|
95
214
|
return
|
|
96
215
|
}
|
|
97
216
|
|
|
98
|
-
val
|
|
99
|
-
val
|
|
100
|
-
val
|
|
217
|
+
val visibleLength = headDist - tailDist
|
|
218
|
+
val startIndex = indexForDistance(tailDist)
|
|
219
|
+
val endIndex = indexForDistance(headDist)
|
|
101
220
|
|
|
102
|
-
|
|
103
|
-
val spans = mutableListOf<StyleSpan>()
|
|
221
|
+
reusablePoints.clear()
|
|
104
222
|
|
|
105
|
-
|
|
106
|
-
var coord = coordinates[i]
|
|
223
|
+
reusablePoints.add(coordinateAtDistance(tailDist))
|
|
107
224
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
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
|
-
}
|
|
225
|
+
for (i in (startIndex + 1)..endIndex) {
|
|
226
|
+
reusablePoints.add(coordinates[i])
|
|
227
|
+
}
|
|
117
228
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
prev.latitude + (coordinates[i].latitude - prev.latitude) * t,
|
|
124
|
-
prev.longitude + (coordinates[i].longitude - prev.longitude) * t
|
|
125
|
-
)
|
|
126
|
-
}
|
|
229
|
+
val endCoord = coordinateAtDistance(headDist)
|
|
230
|
+
val lastAdded = reusablePoints.lastOrNull()
|
|
231
|
+
if (lastAdded == null || endCoord.latitude != lastAdded.latitude || endCoord.longitude != lastAdded.longitude) {
|
|
232
|
+
reusablePoints.add(endCoord)
|
|
233
|
+
}
|
|
127
234
|
|
|
128
|
-
|
|
235
|
+
if (reusablePoints.size < 2) return
|
|
129
236
|
|
|
130
|
-
|
|
131
|
-
val segStartPos = max(i.toFloat(), tailPos)
|
|
132
|
-
val segEndPos = min((i + 1).toFloat(), headPos)
|
|
133
|
-
val gradientMid = ((segStartPos + segEndPos) / 2f - tailPos) / visibleLength
|
|
134
|
-
val color = colorAtGradientPosition(gradientMid)
|
|
135
|
-
spans.add(StyleSpan(StrokeStyle.colorBuilder(color).build()))
|
|
136
|
-
}
|
|
137
|
-
}
|
|
237
|
+
poly.points = ArrayList(reusablePoints)
|
|
138
238
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
239
|
+
if (strokeColors.size <= 1) {
|
|
240
|
+
poly.color = strokeColors.firstOrNull() ?: Color.BLACK
|
|
241
|
+
} else {
|
|
242
|
+
val segmentCount = reusablePoints.size - 1
|
|
243
|
+
val spanCount = min(segmentCount, MAX_ANIMATION_SPANS)
|
|
244
|
+
val segmentsPerSpan = segmentCount.toDouble() / spanCount
|
|
245
|
+
|
|
246
|
+
reusableSpans.clear()
|
|
247
|
+
for (i in 0 until spanCount) {
|
|
248
|
+
val gradientPos = (i + 0.5f) / spanCount
|
|
249
|
+
val color = colorAtGradientPosition(gradientPos)
|
|
250
|
+
reusableSpans.add(StyleSpan(StrokeStyle.colorBuilder(color).build(), segmentsPerSpan))
|
|
251
|
+
}
|
|
252
|
+
poly.setSpans(reusableSpans)
|
|
142
253
|
}
|
|
143
254
|
}
|
|
144
255
|
|
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
#import "LuggMapView.h"
|
|
2
|
+
#import "LuggMapWrapperView.h"
|
|
3
|
+
#import "LuggMarkerView.h"
|
|
4
|
+
#import "LuggPolylineView.h"
|
|
5
|
+
#import "core/AppleMapProvider.h"
|
|
6
|
+
#import "core/GoogleMapProvider.h"
|
|
7
|
+
#import "core/MapProviderDelegate.h"
|
|
8
|
+
#import "events/CameraIdleEvent.h"
|
|
9
|
+
#import "events/CameraMoveEvent.h"
|
|
10
|
+
#import "events/ReadyEvent.h"
|
|
11
|
+
|
|
12
|
+
#import <react/renderer/components/RNMapsSpec/ComponentDescriptors.h>
|
|
13
|
+
#import <react/renderer/components/RNMapsSpec/EventEmitters.h>
|
|
14
|
+
#import <react/renderer/components/RNMapsSpec/Props.h>
|
|
15
|
+
#import <react/renderer/components/RNMapsSpec/RCTComponentViewHelpers.h>
|
|
16
|
+
|
|
17
|
+
#import "RCTFabricComponentsPlugins.h"
|
|
18
|
+
|
|
19
|
+
using namespace facebook::react;
|
|
20
|
+
using namespace luggmaps::events;
|
|
21
|
+
|
|
22
|
+
@interface LuggMapView () <RCTLuggMapViewViewProtocol, MapProviderDelegate>
|
|
23
|
+
@end
|
|
24
|
+
|
|
25
|
+
@implementation LuggMapView {
|
|
26
|
+
id<MapProvider> _provider;
|
|
27
|
+
LuggMapWrapperView *_mapWrapperView;
|
|
28
|
+
LuggMapViewProvider _providerType;
|
|
29
|
+
NSString *_mapId;
|
|
30
|
+
BOOL _initialized;
|
|
31
|
+
// Cached props to apply after content creation
|
|
32
|
+
BOOL _zoomEnabled;
|
|
33
|
+
BOOL _scrollEnabled;
|
|
34
|
+
BOOL _rotateEnabled;
|
|
35
|
+
BOOL _pitchEnabled;
|
|
36
|
+
BOOL _userLocationEnabled;
|
|
37
|
+
LuggMapViewTheme _theme;
|
|
38
|
+
double _minZoom;
|
|
39
|
+
double _maxZoom;
|
|
40
|
+
UIEdgeInsets _edgeInsets;
|
|
41
|
+
UIEdgeInsets _oldEdgeInsets;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
+ (ComponentDescriptorProvider)componentDescriptorProvider {
|
|
45
|
+
return concreteComponentDescriptorProvider<LuggMapViewComponentDescriptor>();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
- (instancetype)initWithFrame:(CGRect)frame {
|
|
49
|
+
if (self = [super initWithFrame:frame]) {
|
|
50
|
+
static const auto defaultProps = std::make_shared<const LuggMapViewProps>();
|
|
51
|
+
_props = defaultProps;
|
|
52
|
+
|
|
53
|
+
_initialized = NO;
|
|
54
|
+
_mapId = @"";
|
|
55
|
+
_providerType = LuggMapViewProvider::Google;
|
|
56
|
+
_zoomEnabled = YES;
|
|
57
|
+
_scrollEnabled = YES;
|
|
58
|
+
_rotateEnabled = YES;
|
|
59
|
+
_pitchEnabled = YES;
|
|
60
|
+
_userLocationEnabled = NO;
|
|
61
|
+
_theme = LuggMapViewTheme::System;
|
|
62
|
+
_edgeInsets = UIEdgeInsetsZero;
|
|
63
|
+
}
|
|
64
|
+
return self;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
#pragma mark - View Lifecycle
|
|
68
|
+
|
|
69
|
+
- (void)mountChildComponentView:
|
|
70
|
+
(UIView<RCTComponentViewProtocol> *)childComponentView
|
|
71
|
+
index:(NSInteger)index {
|
|
72
|
+
[super mountChildComponentView:childComponentView index:index];
|
|
73
|
+
|
|
74
|
+
if ([childComponentView isKindOfClass:[LuggMapWrapperView class]]) {
|
|
75
|
+
_mapWrapperView = (LuggMapWrapperView *)childComponentView;
|
|
76
|
+
} else if ([childComponentView isKindOfClass:[LuggMarkerView class]]) {
|
|
77
|
+
LuggMarkerView *markerView = (LuggMarkerView *)childComponentView;
|
|
78
|
+
if (_provider) {
|
|
79
|
+
[_provider addMarkerView:markerView];
|
|
80
|
+
}
|
|
81
|
+
} else if ([childComponentView isKindOfClass:[LuggPolylineView class]]) {
|
|
82
|
+
LuggPolylineView *polylineView = (LuggPolylineView *)childComponentView;
|
|
83
|
+
if (_provider) {
|
|
84
|
+
[_provider addPolylineView:polylineView];
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
- (void)unmountChildComponentView:
|
|
90
|
+
(UIView<RCTComponentViewProtocol> *)childComponentView
|
|
91
|
+
index:(NSInteger)index {
|
|
92
|
+
if ([childComponentView isKindOfClass:[LuggMarkerView class]]) {
|
|
93
|
+
LuggMarkerView *markerView = (LuggMarkerView *)childComponentView;
|
|
94
|
+
if (_provider) {
|
|
95
|
+
[_provider removeMarkerView:markerView];
|
|
96
|
+
}
|
|
97
|
+
} else if ([childComponentView isKindOfClass:[LuggPolylineView class]]) {
|
|
98
|
+
LuggPolylineView *polylineView = (LuggPolylineView *)childComponentView;
|
|
99
|
+
if (_provider) {
|
|
100
|
+
[_provider removePolylineView:polylineView];
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
[super unmountChildComponentView:childComponentView index:index];
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
- (void)didMoveToWindow {
|
|
108
|
+
[super didMoveToWindow];
|
|
109
|
+
if (self.window) {
|
|
110
|
+
if (!_provider && _mapWrapperView) {
|
|
111
|
+
[self initializeProvider];
|
|
112
|
+
}
|
|
113
|
+
[_provider resumeAnimations];
|
|
114
|
+
} else {
|
|
115
|
+
[_provider pauseAnimations];
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
- (void)prepareForRecycle {
|
|
120
|
+
[super prepareForRecycle];
|
|
121
|
+
|
|
122
|
+
[_provider destroy];
|
|
123
|
+
_provider = nil;
|
|
124
|
+
_mapWrapperView = nil;
|
|
125
|
+
_initialized = NO;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
#pragma mark - Provider Initialization
|
|
129
|
+
|
|
130
|
+
- (void)initializeProvider {
|
|
131
|
+
if (_provider || !_mapWrapperView)
|
|
132
|
+
return;
|
|
133
|
+
|
|
134
|
+
const auto &viewProps =
|
|
135
|
+
*std::static_pointer_cast<LuggMapViewProps const>(_props);
|
|
136
|
+
|
|
137
|
+
if (_providerType == LuggMapViewProvider::Apple) {
|
|
138
|
+
_provider = [[AppleMapProvider alloc] init];
|
|
139
|
+
} else {
|
|
140
|
+
GoogleMapProvider *google = [[GoogleMapProvider alloc] init];
|
|
141
|
+
google.mapId = _mapId;
|
|
142
|
+
_provider = google;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
_provider.delegate = self;
|
|
146
|
+
|
|
147
|
+
CLLocationCoordinate2D coordinate =
|
|
148
|
+
CLLocationCoordinate2DMake(viewProps.initialCoordinate.latitude,
|
|
149
|
+
viewProps.initialCoordinate.longitude);
|
|
150
|
+
|
|
151
|
+
[_provider initializeMapInView:_mapWrapperView
|
|
152
|
+
initialCoordinate:coordinate
|
|
153
|
+
initialZoom:viewProps.initialZoom];
|
|
154
|
+
|
|
155
|
+
// Apply cached props after map view is created
|
|
156
|
+
[self applyProps];
|
|
157
|
+
[_provider setEdgeInsets:_edgeInsets oldEdgeInsets:UIEdgeInsetsZero];
|
|
158
|
+
|
|
159
|
+
_initialized = YES;
|
|
160
|
+
|
|
161
|
+
// Flush any children that were mounted before content was created
|
|
162
|
+
for (UIView *subview in self.subviews) {
|
|
163
|
+
if ([subview isKindOfClass:[LuggMarkerView class]]) {
|
|
164
|
+
[_provider addMarkerView:(LuggMarkerView *)subview];
|
|
165
|
+
} else if ([subview isKindOfClass:[LuggPolylineView class]]) {
|
|
166
|
+
[_provider addPolylineView:(LuggPolylineView *)subview];
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
#pragma mark - MapProviderDelegate
|
|
172
|
+
|
|
173
|
+
- (void)mapProviderDidReady {
|
|
174
|
+
ReadyEvent::emit<LuggMapViewEventEmitter>(_eventEmitter);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
- (void)mapProviderDidMoveCamera:(double)latitude
|
|
178
|
+
longitude:(double)longitude
|
|
179
|
+
zoom:(double)zoom
|
|
180
|
+
gesture:(BOOL)gesture {
|
|
181
|
+
CameraMoveEvent{latitude, longitude, zoom, static_cast<bool>(gesture)}
|
|
182
|
+
.emit<LuggMapViewEventEmitter>(_eventEmitter);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
- (void)mapProviderDidIdleCamera:(double)latitude
|
|
186
|
+
longitude:(double)longitude
|
|
187
|
+
zoom:(double)zoom
|
|
188
|
+
gesture:(BOOL)gesture {
|
|
189
|
+
CameraIdleEvent{latitude, longitude, zoom, static_cast<bool>(gesture)}
|
|
190
|
+
.emit<LuggMapViewEventEmitter>(_eventEmitter);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
#pragma mark - Property Setters
|
|
194
|
+
|
|
195
|
+
- (void)applyProps {
|
|
196
|
+
[_provider setZoomEnabled:_zoomEnabled];
|
|
197
|
+
[_provider setScrollEnabled:_scrollEnabled];
|
|
198
|
+
[_provider setRotateEnabled:_rotateEnabled];
|
|
199
|
+
[_provider setPitchEnabled:_pitchEnabled];
|
|
200
|
+
[_provider setUserLocationEnabled:_userLocationEnabled];
|
|
201
|
+
[_provider setTheme:(NSInteger)_theme];
|
|
202
|
+
[_provider setMinZoom:_minZoom];
|
|
203
|
+
[_provider setMaxZoom:_maxZoom];
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
- (void)updateProps:(Props::Shared const &)props
|
|
207
|
+
oldProps:(Props::Shared const &)oldProps {
|
|
208
|
+
const auto &newViewProps =
|
|
209
|
+
*std::static_pointer_cast<LuggMapViewProps const>(props);
|
|
210
|
+
const auto &prevViewProps =
|
|
211
|
+
*std::static_pointer_cast<LuggMapViewProps const>(_props);
|
|
212
|
+
|
|
213
|
+
_providerType = newViewProps.provider;
|
|
214
|
+
|
|
215
|
+
NSString *newMapId =
|
|
216
|
+
[NSString stringWithUTF8String:newViewProps.mapId.c_str()];
|
|
217
|
+
if (newMapId.length > 0) {
|
|
218
|
+
_mapId = newMapId;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
if (newViewProps.zoomEnabled != prevViewProps.zoomEnabled) {
|
|
222
|
+
_zoomEnabled = newViewProps.zoomEnabled;
|
|
223
|
+
[_provider setZoomEnabled:_zoomEnabled];
|
|
224
|
+
}
|
|
225
|
+
if (newViewProps.scrollEnabled != prevViewProps.scrollEnabled) {
|
|
226
|
+
_scrollEnabled = newViewProps.scrollEnabled;
|
|
227
|
+
[_provider setScrollEnabled:_scrollEnabled];
|
|
228
|
+
}
|
|
229
|
+
if (newViewProps.rotateEnabled != prevViewProps.rotateEnabled) {
|
|
230
|
+
_rotateEnabled = newViewProps.rotateEnabled;
|
|
231
|
+
[_provider setRotateEnabled:_rotateEnabled];
|
|
232
|
+
}
|
|
233
|
+
if (newViewProps.pitchEnabled != prevViewProps.pitchEnabled) {
|
|
234
|
+
_pitchEnabled = newViewProps.pitchEnabled;
|
|
235
|
+
[_provider setPitchEnabled:_pitchEnabled];
|
|
236
|
+
}
|
|
237
|
+
if (newViewProps.userLocationEnabled != prevViewProps.userLocationEnabled) {
|
|
238
|
+
_userLocationEnabled = newViewProps.userLocationEnabled;
|
|
239
|
+
[_provider setUserLocationEnabled:_userLocationEnabled];
|
|
240
|
+
}
|
|
241
|
+
if (newViewProps.minZoom != prevViewProps.minZoom) {
|
|
242
|
+
_minZoom = newViewProps.minZoom;
|
|
243
|
+
[_provider setMinZoom:_minZoom];
|
|
244
|
+
}
|
|
245
|
+
if (newViewProps.maxZoom != prevViewProps.maxZoom) {
|
|
246
|
+
_maxZoom = newViewProps.maxZoom;
|
|
247
|
+
[_provider setMaxZoom:_maxZoom];
|
|
248
|
+
}
|
|
249
|
+
if (newViewProps.theme != prevViewProps.theme) {
|
|
250
|
+
_theme = newViewProps.theme;
|
|
251
|
+
[_provider setTheme:(NSInteger)_theme];
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
UIEdgeInsets newEdgeInsets = UIEdgeInsetsMake(
|
|
255
|
+
newViewProps.edgeInsets.top, newViewProps.edgeInsets.left,
|
|
256
|
+
newViewProps.edgeInsets.bottom, newViewProps.edgeInsets.right);
|
|
257
|
+
if (!UIEdgeInsetsEqualToEdgeInsets(newEdgeInsets, _edgeInsets)) {
|
|
258
|
+
_oldEdgeInsets = _edgeInsets;
|
|
259
|
+
_edgeInsets = newEdgeInsets;
|
|
260
|
+
[_provider setEdgeInsets:_edgeInsets oldEdgeInsets:_oldEdgeInsets];
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
[super updateProps:props oldProps:oldProps];
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
#pragma mark - Commands
|
|
267
|
+
|
|
268
|
+
- (void)moveCamera:(double)latitude
|
|
269
|
+
longitude:(double)longitude
|
|
270
|
+
zoom:(double)zoom
|
|
271
|
+
duration:(double)duration {
|
|
272
|
+
[_provider moveCamera:latitude
|
|
273
|
+
longitude:longitude
|
|
274
|
+
zoom:zoom
|
|
275
|
+
duration:duration];
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
- (void)fitCoordinates:(NSArray *)coordinates
|
|
279
|
+
edgeInsetsTop:(double)edgeInsetsTop
|
|
280
|
+
edgeInsetsLeft:(double)edgeInsetsLeft
|
|
281
|
+
edgeInsetsBottom:(double)edgeInsetsBottom
|
|
282
|
+
edgeInsetsRight:(double)edgeInsetsRight
|
|
283
|
+
duration:(double)duration {
|
|
284
|
+
[_provider fitCoordinates:coordinates
|
|
285
|
+
edgeInsetsTop:edgeInsetsTop
|
|
286
|
+
edgeInsetsLeft:edgeInsetsLeft
|
|
287
|
+
edgeInsetsBottom:edgeInsetsBottom
|
|
288
|
+
edgeInsetsRight:edgeInsetsRight
|
|
289
|
+
duration:duration];
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
- (void)setEdgeInsets:(double)top
|
|
293
|
+
left:(double)left
|
|
294
|
+
bottom:(double)bottom
|
|
295
|
+
right:(double)right
|
|
296
|
+
duration:(double)duration {
|
|
297
|
+
UIEdgeInsets oldInsets = _edgeInsets;
|
|
298
|
+
_edgeInsets = UIEdgeInsetsMake(top, left, bottom, right);
|
|
299
|
+
[_provider setEdgeInsets:_edgeInsets
|
|
300
|
+
oldEdgeInsets:oldInsets
|
|
301
|
+
duration:duration];
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
- (void)handleCommand:(const NSString *)commandName args:(const NSArray *)args {
|
|
305
|
+
RCTLuggMapViewHandleCommand(self, commandName, args);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
Class<RCTComponentViewProtocol> LuggMapViewCls(void) {
|
|
309
|
+
return LuggMapView.class;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
@end
|
package/ios/LuggMarkerView.h
CHANGED
|
@@ -14,16 +14,25 @@ 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;
|
|
23
|
+
@property(nonatomic, readonly) CLLocationDegrees rotate;
|
|
24
|
+
@property(nonatomic, readonly) CGFloat scale;
|
|
25
|
+
@property(nonatomic, readonly) BOOL rasterize;
|
|
21
26
|
@property(nonatomic, readonly) BOOL hasCustomView;
|
|
22
27
|
@property(nonatomic, readonly) BOOL didLayout;
|
|
23
28
|
@property(nonatomic, readonly) UIView *iconView;
|
|
24
29
|
@property(nonatomic, weak, nullable) id<LuggMarkerViewDelegate> delegate;
|
|
25
30
|
@property(nonatomic, strong, nullable) NSObject *marker;
|
|
26
31
|
|
|
32
|
+
- (nullable UIImage *)createIconImage;
|
|
33
|
+
- (nullable UIImage *)createScaledIconImage;
|
|
34
|
+
- (void)resetIconViewTransform;
|
|
35
|
+
|
|
27
36
|
@end
|
|
28
37
|
|
|
29
38
|
NS_ASSUME_NONNULL_END
|