@lugg/maps 0.2.0-alpha.2 → 0.2.0-alpha.21
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 +31 -37
- 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/LuggPolylineView.kt +16 -0
- package/android/src/main/java/com/luggmaps/LuggPolylineViewManager.kt +22 -0
- package/android/src/main/java/com/luggmaps/core/PolylineAnimator.kt +157 -52
- package/ios/LuggAppleMapView.mm +161 -46
- package/ios/LuggGoogleMapView.mm +52 -22
- 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/GMSPolylineAnimator.h +3 -0
- package/ios/core/GMSPolylineAnimator.m +164 -41
- package/ios/core/MKPolylineAnimator.h +4 -0
- package/ios/core/MKPolylineAnimator.m +162 -43
- package/ios/core/PolylineAnimatorBase.h +14 -0
- package/ios/core/PolylineAnimatorBase.m +33 -0
- 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 +2 -2
- package/lib/module/MapView.js.map +1 -1
- package/lib/module/MapView.web.js +272 -0
- package/lib/module/MapView.web.js.map +1 -0
- package/lib/module/components/Marker.js +10 -1
- 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 +8 -3
- 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/LuggMarkerViewNativeComponent.ts +7 -1
- package/lib/module/fabric/LuggPolylineViewNativeComponent.ts +8 -0
- 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 +11 -0
- package/lib/typescript/src/MapProvider.web.d.ts.map +1 -0
- package/lib/typescript/src/MapView.d.ts +1 -1
- package/lib/typescript/src/MapView.d.ts.map +1 -1
- package/lib/typescript/src/MapView.types.d.ts +2 -2
- 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 +21 -0
- 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 +32 -0
- 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.web.d.ts +5 -0
- package/lib/typescript/src/components/index.web.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 +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 +14 -0
- package/src/MapView.tsx +2 -2
- package/src/MapView.types.ts +2 -2
- package/src/MapView.web.tsx +337 -0
- package/src/components/Marker.tsx +37 -3
- package/src/components/Marker.web.tsx +33 -0
- package/src/components/Polyline.tsx +38 -1
- package/src/components/Polyline.web.tsx +287 -0
- package/src/components/index.web.ts +4 -0
- package/src/fabric/LuggMarkerViewNativeComponent.ts +7 -1
- package/src/fabric/LuggPolylineViewNativeComponent.ts +8 -0
- package/src/index.ts +8 -1
- package/src/index.web.ts +17 -0
|
@@ -1,21 +1,37 @@
|
|
|
1
1
|
package com.luggmaps.core
|
|
2
2
|
|
|
3
|
+
import android.animation.TimeInterpolator
|
|
3
4
|
import android.animation.ValueAnimator
|
|
4
5
|
import android.graphics.Color
|
|
6
|
+
import android.location.Location
|
|
5
7
|
import android.view.animation.LinearInterpolator
|
|
6
8
|
import com.google.android.gms.maps.model.LatLng
|
|
7
9
|
import com.google.android.gms.maps.model.Polyline
|
|
8
10
|
import com.google.android.gms.maps.model.StrokeStyle
|
|
9
11
|
import com.google.android.gms.maps.model.StyleSpan
|
|
12
|
+
import com.luggmaps.AnimatedOptions
|
|
10
13
|
import kotlin.math.floor
|
|
11
|
-
import kotlin.math.max
|
|
12
14
|
import kotlin.math.min
|
|
13
15
|
|
|
14
16
|
class PolylineAnimator {
|
|
15
17
|
var polyline: Polyline? = null
|
|
16
18
|
var coordinates: List<LatLng> = emptyList()
|
|
19
|
+
set(value) {
|
|
20
|
+
field = value
|
|
21
|
+
if (animated && animator != null) {
|
|
22
|
+
computeCumulativeDistances()
|
|
23
|
+
}
|
|
24
|
+
}
|
|
17
25
|
var strokeColors: List<Int> = listOf(Color.BLACK)
|
|
18
26
|
var strokeWidth: Float = 1f
|
|
27
|
+
var animatedOptions: AnimatedOptions = AnimatedOptions()
|
|
28
|
+
set(value) {
|
|
29
|
+
if (field == value) return
|
|
30
|
+
field = value
|
|
31
|
+
if (animated) {
|
|
32
|
+
restartAnimation()
|
|
33
|
+
}
|
|
34
|
+
}
|
|
19
35
|
|
|
20
36
|
var animated: Boolean = false
|
|
21
37
|
set(value) {
|
|
@@ -31,6 +47,30 @@ class PolylineAnimator {
|
|
|
31
47
|
|
|
32
48
|
private var animator: ValueAnimator? = null
|
|
33
49
|
private var animationProgress: Float = 0f
|
|
50
|
+
private var cumulativeDistances: FloatArray = floatArrayOf()
|
|
51
|
+
private var totalLength: Float = 0f
|
|
52
|
+
|
|
53
|
+
// Reusable collections to avoid per-frame allocations
|
|
54
|
+
private val reusablePoints = ArrayList<LatLng>()
|
|
55
|
+
private val reusableSpans = ArrayList<StyleSpan>()
|
|
56
|
+
|
|
57
|
+
private fun restartAnimation() {
|
|
58
|
+
stopAnimation()
|
|
59
|
+
startAnimation()
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
private fun getInterpolator(): TimeInterpolator =
|
|
63
|
+
when (animatedOptions.easing) {
|
|
64
|
+
"easeIn" -> TimeInterpolator { t -> t * t }
|
|
65
|
+
|
|
66
|
+
"easeOut" -> TimeInterpolator { t -> t * (2 - t) }
|
|
67
|
+
|
|
68
|
+
"easeInOut" -> TimeInterpolator { t ->
|
|
69
|
+
if (t < 0.5f) 2 * t * t else -1 + (4 - 2 * t) * t
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
else -> LinearInterpolator()
|
|
73
|
+
}
|
|
34
74
|
|
|
35
75
|
fun update() {
|
|
36
76
|
if (animated) return
|
|
@@ -50,10 +90,16 @@ class PolylineAnimator {
|
|
|
50
90
|
private fun startAnimation() {
|
|
51
91
|
if (animator != null) return
|
|
52
92
|
|
|
53
|
-
|
|
54
|
-
|
|
93
|
+
computeCumulativeDistances()
|
|
94
|
+
|
|
95
|
+
val trailLength = animatedOptions.trailLength.coerceIn(0.01f, 1f)
|
|
96
|
+
val endValue = if (trailLength < 1f) 1f else 2.15f
|
|
97
|
+
|
|
98
|
+
animator = ValueAnimator.ofFloat(0f, endValue).apply {
|
|
99
|
+
duration = animatedOptions.duration
|
|
100
|
+
startDelay = animatedOptions.delay
|
|
55
101
|
repeatCount = ValueAnimator.INFINITE
|
|
56
|
-
interpolator =
|
|
102
|
+
interpolator = getInterpolator()
|
|
57
103
|
addUpdateListener { animation ->
|
|
58
104
|
animationProgress = animation.animatedValue as Float
|
|
59
105
|
updateAnimatedPolyline()
|
|
@@ -62,83 +108,142 @@ class PolylineAnimator {
|
|
|
62
108
|
}
|
|
63
109
|
}
|
|
64
110
|
|
|
111
|
+
private fun computeCumulativeDistances() {
|
|
112
|
+
if (coordinates.size < 2) {
|
|
113
|
+
cumulativeDistances = floatArrayOf(0f)
|
|
114
|
+
totalLength = 0f
|
|
115
|
+
return
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
val distances = FloatArray(coordinates.size)
|
|
119
|
+
distances[0] = 0f
|
|
120
|
+
var total = 0f
|
|
121
|
+
|
|
122
|
+
for (i in 1 until coordinates.size) {
|
|
123
|
+
val prev = coordinates[i - 1]
|
|
124
|
+
val curr = coordinates[i]
|
|
125
|
+
val results = FloatArray(1)
|
|
126
|
+
Location.distanceBetween(prev.latitude, prev.longitude, curr.latitude, curr.longitude, results)
|
|
127
|
+
total += results[0]
|
|
128
|
+
distances[i] = total
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
cumulativeDistances = distances
|
|
132
|
+
totalLength = total
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
private fun indexForDistance(distance: Float): Int {
|
|
136
|
+
var left = 0
|
|
137
|
+
var right = cumulativeDistances.size - 1
|
|
138
|
+
|
|
139
|
+
while (left < right) {
|
|
140
|
+
val mid = (left + right + 1) / 2
|
|
141
|
+
if (cumulativeDistances[mid] <= distance) {
|
|
142
|
+
left = mid
|
|
143
|
+
} else {
|
|
144
|
+
right = mid - 1
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return left.coerceAtMost(cumulativeDistances.size - 2).coerceAtLeast(0)
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
private fun coordinateAtDistance(distance: Float): LatLng {
|
|
152
|
+
if (distance <= 0f) return coordinates.first()
|
|
153
|
+
if (distance >= totalLength) return coordinates.last()
|
|
154
|
+
|
|
155
|
+
val idx = indexForDistance(distance)
|
|
156
|
+
val segStart = cumulativeDistances[idx]
|
|
157
|
+
val segEnd = cumulativeDistances[idx + 1]
|
|
158
|
+
val segLength = segEnd - segStart
|
|
159
|
+
|
|
160
|
+
val t = if (segLength > 0) (distance - segStart) / segLength else 0f
|
|
161
|
+
val c1 = coordinates[idx]
|
|
162
|
+
val c2 = coordinates[idx + 1]
|
|
163
|
+
|
|
164
|
+
// Reuse existing coordinate if no interpolation needed
|
|
165
|
+
if (t == 0f) return c1
|
|
166
|
+
|
|
167
|
+
return LatLng(
|
|
168
|
+
c1.latitude + (c2.latitude - c1.latitude) * t,
|
|
169
|
+
c1.longitude + (c2.longitude - c1.longitude) * t
|
|
170
|
+
)
|
|
171
|
+
}
|
|
172
|
+
|
|
65
173
|
private fun stopAnimation() {
|
|
66
174
|
animator?.cancel()
|
|
67
175
|
animator = null
|
|
68
176
|
}
|
|
69
177
|
|
|
178
|
+
fun pause() {
|
|
179
|
+
animator?.pause()
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
fun resume() {
|
|
183
|
+
animator?.resume()
|
|
184
|
+
}
|
|
185
|
+
|
|
70
186
|
private fun updateAnimatedPolyline() {
|
|
71
187
|
val poly = polyline ?: return
|
|
72
|
-
if (coordinates.size < 2) {
|
|
188
|
+
if (coordinates.size < 2 || totalLength <= 0f) {
|
|
73
189
|
poly.points = coordinates
|
|
74
190
|
return
|
|
75
191
|
}
|
|
76
192
|
|
|
77
|
-
val
|
|
78
|
-
val progress = min(animationProgress, 2f)
|
|
193
|
+
val trailLength = animatedOptions.trailLength.coerceIn(0.01f, 1f)
|
|
194
|
+
val progress = min(animationProgress, if (trailLength < 1f) 1f else 2f)
|
|
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 (
|
|
211
|
+
if (headDist <= tailDist) {
|
|
93
212
|
poly.setSpans(emptyList())
|
|
94
213
|
poly.points = listOf(coordinates.firstOrNull() ?: LatLng(0.0, 0.0))
|
|
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
|
-
|
|
221
|
+
reusablePoints.clear()
|
|
222
|
+
reusableSpans.clear()
|
|
104
223
|
|
|
105
|
-
|
|
106
|
-
var coord = coordinates[i]
|
|
224
|
+
reusablePoints.add(coordinateAtDistance(tailDist))
|
|
107
225
|
|
|
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
|
-
}
|
|
117
|
-
|
|
118
|
-
// Interpolate head
|
|
119
|
-
if (i == endIndex && headPos < endIndex.toFloat() && i > 0) {
|
|
120
|
-
val t = headPos - (endIndex - 1)
|
|
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
|
-
}
|
|
226
|
+
for (i in (startIndex + 1)..endIndex) {
|
|
227
|
+
reusablePoints.add(coordinates[i])
|
|
228
|
+
}
|
|
127
229
|
|
|
128
|
-
|
|
230
|
+
val endCoord = coordinateAtDistance(headDist)
|
|
231
|
+
val lastAdded = reusablePoints.lastOrNull()
|
|
232
|
+
if (lastAdded == null || endCoord.latitude != lastAdded.latitude || endCoord.longitude != lastAdded.longitude) {
|
|
233
|
+
reusablePoints.add(endCoord)
|
|
234
|
+
}
|
|
129
235
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
}
|
|
236
|
+
val pointCount = reusablePoints.size
|
|
237
|
+
for (i in 0 until (pointCount - 1)) {
|
|
238
|
+
val segMidDist = tailDist + visibleLength * (i + 0.5f) / (pointCount - 1)
|
|
239
|
+
val gradientPos = (segMidDist - tailDist) / visibleLength
|
|
240
|
+
val color = colorAtGradientPosition(gradientPos)
|
|
241
|
+
reusableSpans.add(StyleSpan(StrokeStyle.colorBuilder(color).build()))
|
|
137
242
|
}
|
|
138
243
|
|
|
139
|
-
poly.points =
|
|
140
|
-
if (
|
|
141
|
-
poly.setSpans(
|
|
244
|
+
poly.points = reusablePoints
|
|
245
|
+
if (reusableSpans.isNotEmpty()) {
|
|
246
|
+
poly.setSpans(reusableSpans)
|
|
142
247
|
}
|
|
143
248
|
}
|
|
144
249
|
|
package/ios/LuggAppleMapView.mm
CHANGED
|
@@ -44,6 +44,7 @@ using namespace luggmaps::events;
|
|
|
44
44
|
BOOL _isDragging;
|
|
45
45
|
double _minZoom;
|
|
46
46
|
double _maxZoom;
|
|
47
|
+
NSMapTable<id<MKOverlay>, LuggPolylineView *> *_overlayToPolylineMap;
|
|
47
48
|
}
|
|
48
49
|
|
|
49
50
|
+ (ComponentDescriptorProvider)componentDescriptorProvider {
|
|
@@ -56,6 +57,7 @@ using namespace luggmaps::events;
|
|
|
56
57
|
static const auto defaultProps =
|
|
57
58
|
std::make_shared<const LuggAppleMapViewProps>();
|
|
58
59
|
_props = defaultProps;
|
|
60
|
+
_overlayToPolylineMap = [NSMapTable strongToWeakObjectsMapTable];
|
|
59
61
|
}
|
|
60
62
|
|
|
61
63
|
return self;
|
|
@@ -101,16 +103,19 @@ using namespace luggmaps::events;
|
|
|
101
103
|
(AppleMarkerAnnotation *)markerView.marker;
|
|
102
104
|
|
|
103
105
|
if (annotation) {
|
|
106
|
+
annotation.annotationView.transform = CGAffineTransformIdentity;
|
|
104
107
|
annotation.markerView = nil;
|
|
105
108
|
annotation.annotationView = nil;
|
|
106
109
|
[_mapView removeAnnotation:annotation];
|
|
107
110
|
markerView.marker = nil;
|
|
108
111
|
}
|
|
112
|
+
[markerView resetIconViewTransform];
|
|
109
113
|
} else if ([childComponentView isKindOfClass:[LuggPolylineView class]]) {
|
|
110
114
|
LuggPolylineView *polylineView = (LuggPolylineView *)childComponentView;
|
|
111
115
|
polylineView.delegate = nil;
|
|
112
116
|
MKPolyline *polyline = (MKPolyline *)polylineView.polyline;
|
|
113
117
|
if (polyline) {
|
|
118
|
+
[_overlayToPolylineMap removeObjectForKey:polyline];
|
|
114
119
|
[_mapView removeOverlay:polyline];
|
|
115
120
|
polylineView.polyline = nil;
|
|
116
121
|
}
|
|
@@ -167,10 +172,13 @@ using namespace luggmaps::events;
|
|
|
167
172
|
|
|
168
173
|
[_mapWrapperView addSubview:_mapView];
|
|
169
174
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
175
|
+
CLLocationCoordinate2D center =
|
|
176
|
+
CLLocationCoordinate2DMake(viewProps.initialCoordinate.latitude,
|
|
177
|
+
viewProps.initialCoordinate.longitude);
|
|
178
|
+
MKCoordinateRegion region =
|
|
179
|
+
[_mapView regionForCenterCoordinate:center
|
|
180
|
+
zoomLevel:viewProps.initialZoom];
|
|
181
|
+
[_mapView setRegion:region animated:NO];
|
|
174
182
|
|
|
175
183
|
// Add annotations for any markers that were mounted before map was ready
|
|
176
184
|
for (UIView *subview in self.subviews) {
|
|
@@ -230,6 +238,8 @@ using namespace luggmaps::events;
|
|
|
230
238
|
|
|
231
239
|
- (void)updateProps:(Props::Shared const &)props
|
|
232
240
|
oldProps:(Props::Shared const &)oldProps {
|
|
241
|
+
const auto &oldViewProps =
|
|
242
|
+
*std::static_pointer_cast<LuggAppleMapViewProps const>(oldProps);
|
|
233
243
|
const auto &newViewProps =
|
|
234
244
|
*std::static_pointer_cast<LuggAppleMapViewProps const>(props);
|
|
235
245
|
|
|
@@ -239,9 +249,49 @@ using namespace luggmaps::events;
|
|
|
239
249
|
_mapView.rotateEnabled = newViewProps.rotateEnabled;
|
|
240
250
|
_mapView.pitchEnabled = newViewProps.pitchEnabled;
|
|
241
251
|
_mapView.showsUserLocation = newViewProps.userLocationEnabled;
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
252
|
+
|
|
253
|
+
// Check if padding changed
|
|
254
|
+
BOOL paddingChanged =
|
|
255
|
+
oldViewProps.padding.top != newViewProps.padding.top ||
|
|
256
|
+
oldViewProps.padding.left != newViewProps.padding.left ||
|
|
257
|
+
oldViewProps.padding.bottom != newViewProps.padding.bottom ||
|
|
258
|
+
oldViewProps.padding.right != newViewProps.padding.right;
|
|
259
|
+
|
|
260
|
+
if (paddingChanged) {
|
|
261
|
+
// Calculate the offset difference to keep visual center stable
|
|
262
|
+
CGFloat oldOffsetX =
|
|
263
|
+
(oldViewProps.padding.left - oldViewProps.padding.right) / 2.0;
|
|
264
|
+
CGFloat oldOffsetY =
|
|
265
|
+
(oldViewProps.padding.top - oldViewProps.padding.bottom) / 2.0;
|
|
266
|
+
CGFloat newOffsetX =
|
|
267
|
+
(newViewProps.padding.left - newViewProps.padding.right) / 2.0;
|
|
268
|
+
CGFloat newOffsetY =
|
|
269
|
+
(newViewProps.padding.top - newViewProps.padding.bottom) / 2.0;
|
|
270
|
+
|
|
271
|
+
CGFloat deltaX = newOffsetX - oldOffsetX;
|
|
272
|
+
CGFloat deltaY = newOffsetY - oldOffsetY;
|
|
273
|
+
|
|
274
|
+
// Apply new padding first
|
|
275
|
+
_mapView.layoutMargins = UIEdgeInsetsMake(
|
|
276
|
+
newViewProps.padding.top, newViewProps.padding.left,
|
|
277
|
+
newViewProps.padding.bottom, newViewProps.padding.right);
|
|
278
|
+
|
|
279
|
+
// Convert pixel offset to coordinate offset
|
|
280
|
+
if (deltaX != 0 || deltaY != 0) {
|
|
281
|
+
CLLocationCoordinate2D currentCenter = _mapView.centerCoordinate;
|
|
282
|
+
CGPoint centerPoint = [_mapView convertCoordinate:currentCenter
|
|
283
|
+
toPointToView:_mapView];
|
|
284
|
+
CGPoint newPoint =
|
|
285
|
+
CGPointMake(centerPoint.x - deltaX, centerPoint.y - deltaY);
|
|
286
|
+
CLLocationCoordinate2D newCenter = [_mapView convertPoint:newPoint
|
|
287
|
+
toCoordinateFromView:_mapView];
|
|
288
|
+
[_mapView setCenterCoordinate:newCenter animated:NO];
|
|
289
|
+
}
|
|
290
|
+
} else {
|
|
291
|
+
_mapView.layoutMargins = UIEdgeInsetsMake(
|
|
292
|
+
newViewProps.padding.top, newViewProps.padding.left,
|
|
293
|
+
newViewProps.padding.bottom, newViewProps.padding.right);
|
|
294
|
+
}
|
|
245
295
|
|
|
246
296
|
_minZoom = newViewProps.minZoom;
|
|
247
297
|
_maxZoom = newViewProps.maxZoom;
|
|
@@ -253,6 +303,38 @@ using namespace luggmaps::events;
|
|
|
253
303
|
|
|
254
304
|
#pragma mark - Annotation Helpers
|
|
255
305
|
|
|
306
|
+
- (void)applyMarkerStyle:(LuggMarkerView *)markerView
|
|
307
|
+
annotationView:(MKAnnotationView *)annotationView {
|
|
308
|
+
annotationView.transform = CGAffineTransformIdentity;
|
|
309
|
+
|
|
310
|
+
UIView *iconView = markerView.iconView;
|
|
311
|
+
CGRect frame = iconView.frame;
|
|
312
|
+
if (frame.size.width <= 0 || frame.size.height <= 0)
|
|
313
|
+
return;
|
|
314
|
+
|
|
315
|
+
CGFloat scale = markerView.scale;
|
|
316
|
+
CGPoint anchor = markerView.anchor;
|
|
317
|
+
|
|
318
|
+
if (markerView.rasterize) {
|
|
319
|
+
annotationView.image = [markerView createScaledIconImage];
|
|
320
|
+
} else {
|
|
321
|
+
iconView.layer.anchorPoint = anchor;
|
|
322
|
+
iconView.transform = CGAffineTransformMakeScale(scale, scale);
|
|
323
|
+
iconView.frame =
|
|
324
|
+
CGRectMake(frame.size.width * (0.5 - anchor.x) * (scale - 1),
|
|
325
|
+
frame.size.height * (0.5 - anchor.y) * (scale - 1),
|
|
326
|
+
frame.size.width, frame.size.height);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
annotationView.bounds =
|
|
330
|
+
CGRectMake(0, 0, frame.size.width * scale, frame.size.height * scale);
|
|
331
|
+
annotationView.centerOffset =
|
|
332
|
+
CGPointMake(frame.size.width * scale * (anchor.x - 0.5),
|
|
333
|
+
-frame.size.height * scale * (anchor.y - 0.5));
|
|
334
|
+
annotationView.transform =
|
|
335
|
+
CGAffineTransformMakeRotation(markerView.rotate * M_PI / 180.0);
|
|
336
|
+
}
|
|
337
|
+
|
|
256
338
|
- (void)updateAnnotationViewFrame:(AppleMarkerAnnotation *)annotation {
|
|
257
339
|
MKAnnotationView *annotationView = annotation.annotationView;
|
|
258
340
|
LuggMarkerView *markerView = annotation.markerView;
|
|
@@ -261,16 +343,7 @@ using namespace luggmaps::events;
|
|
|
261
343
|
return;
|
|
262
344
|
}
|
|
263
345
|
|
|
264
|
-
|
|
265
|
-
CGRect frame = iconView.frame;
|
|
266
|
-
if (frame.size.width > 0 && frame.size.height > 0) {
|
|
267
|
-
annotationView.frame = frame;
|
|
268
|
-
|
|
269
|
-
CGPoint anchor = markerView.anchor;
|
|
270
|
-
annotationView.centerOffset =
|
|
271
|
-
CGPointMake(frame.size.width * (anchor.x - 0.5),
|
|
272
|
-
-frame.size.height * (anchor.y - 0.5));
|
|
273
|
-
}
|
|
346
|
+
[self applyMarkerStyle:markerView annotationView:annotationView];
|
|
274
347
|
}
|
|
275
348
|
|
|
276
349
|
#pragma mark - PolylineViewDelegate
|
|
@@ -302,7 +375,8 @@ using namespace luggmaps::events;
|
|
|
302
375
|
free(coords);
|
|
303
376
|
|
|
304
377
|
polylineView.polyline = polyline;
|
|
305
|
-
[
|
|
378
|
+
[_overlayToPolylineMap setObject:polylineView forKey:polyline];
|
|
379
|
+
[self insertOverlay:polyline withZIndex:polylineView.zIndex];
|
|
306
380
|
}
|
|
307
381
|
|
|
308
382
|
- (void)syncPolylineView:(LuggPolylineView *)polylineView {
|
|
@@ -316,7 +390,11 @@ using namespace luggmaps::events;
|
|
|
316
390
|
// Build new polyline from coordinates
|
|
317
391
|
NSArray<CLLocation *> *coordinates = polylineView.coordinates;
|
|
318
392
|
if (coordinates.count == 0) {
|
|
393
|
+
if (renderer) {
|
|
394
|
+
renderer.animated = NO;
|
|
395
|
+
}
|
|
319
396
|
if (oldPolyline) {
|
|
397
|
+
[_overlayToPolylineMap removeObjectForKey:oldPolyline];
|
|
320
398
|
[_mapView removeOverlay:oldPolyline];
|
|
321
399
|
polylineView.polyline = nil;
|
|
322
400
|
polylineView.renderer = nil;
|
|
@@ -334,35 +412,54 @@ using namespace luggmaps::events;
|
|
|
334
412
|
free(coords);
|
|
335
413
|
|
|
336
414
|
polylineView.polyline = newPolyline;
|
|
415
|
+
[_overlayToPolylineMap setObject:polylineView forKey:newPolyline];
|
|
337
416
|
|
|
338
417
|
// If we have an existing renderer, update it in place
|
|
339
418
|
if (renderer && oldPolyline) {
|
|
419
|
+
[_overlayToPolylineMap removeObjectForKey:oldPolyline];
|
|
420
|
+
[_mapView removeOverlay:oldPolyline];
|
|
421
|
+
[self insertOverlay:newPolyline withZIndex:polylineView.zIndex];
|
|
340
422
|
[renderer updatePolyline:newPolyline];
|
|
341
423
|
renderer.lineWidth = polylineView.strokeWidth;
|
|
342
424
|
renderer.strokeColor = polylineView.strokeColors.firstObject;
|
|
343
425
|
renderer.strokeColors =
|
|
344
426
|
polylineView.strokeColors.count > 1 ? polylineView.strokeColors : nil;
|
|
427
|
+
renderer.animatedOptions = polylineView.animatedOptions;
|
|
345
428
|
renderer.animated = polylineView.animated;
|
|
346
429
|
return;
|
|
347
430
|
}
|
|
348
431
|
|
|
349
432
|
// Otherwise do full add
|
|
350
433
|
if (oldPolyline) {
|
|
434
|
+
[_overlayToPolylineMap removeObjectForKey:oldPolyline];
|
|
351
435
|
[_mapView removeOverlay:oldPolyline];
|
|
352
436
|
}
|
|
353
|
-
[
|
|
437
|
+
[self insertOverlay:newPolyline withZIndex:polylineView.zIndex];
|
|
354
438
|
}
|
|
355
439
|
|
|
356
|
-
- (
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
440
|
+
- (void)insertOverlay:(id<MKOverlay>)overlay withZIndex:(NSInteger)zIndex {
|
|
441
|
+
if (zIndex == 0) {
|
|
442
|
+
[_mapView addOverlay:overlay];
|
|
443
|
+
return;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
NSArray<id<MKOverlay>> *overlays = _mapView.overlays;
|
|
447
|
+
NSInteger insertIndex = overlays.count;
|
|
448
|
+
|
|
449
|
+
for (NSInteger i = 0; i < overlays.count; i++) {
|
|
450
|
+
LuggPolylineView *existingPolylineView =
|
|
451
|
+
[self findPolylineViewForOverlay:overlays[i]];
|
|
452
|
+
if (existingPolylineView && existingPolylineView.zIndex > zIndex) {
|
|
453
|
+
insertIndex = i;
|
|
454
|
+
break;
|
|
363
455
|
}
|
|
364
456
|
}
|
|
365
|
-
|
|
457
|
+
|
|
458
|
+
[_mapView insertOverlay:overlay atIndex:insertIndex];
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
- (LuggPolylineView *)findPolylineViewForOverlay:(id<MKOverlay>)overlay {
|
|
462
|
+
return [_overlayToPolylineMap objectForKey:overlay];
|
|
366
463
|
}
|
|
367
464
|
|
|
368
465
|
#pragma mark - MarkerViewDelegate
|
|
@@ -388,6 +485,12 @@ using namespace luggmaps::events;
|
|
|
388
485
|
annotation.title = markerView.title;
|
|
389
486
|
annotation.subtitle = markerView.markerDescription;
|
|
390
487
|
|
|
488
|
+
MKAnnotationView *annotationView = annotation.annotationView;
|
|
489
|
+
if (annotationView) {
|
|
490
|
+
annotationView.layer.zPosition = markerView.zIndex;
|
|
491
|
+
annotationView.zPriority = markerView.zIndex;
|
|
492
|
+
}
|
|
493
|
+
|
|
391
494
|
[self updateAnnotationViewFrame:annotation];
|
|
392
495
|
}
|
|
393
496
|
|
|
@@ -395,6 +498,15 @@ using namespace luggmaps::events;
|
|
|
395
498
|
|
|
396
499
|
- (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated {
|
|
397
500
|
_isDragging = [self isUserInteracting:mapView];
|
|
501
|
+
if (_isDragging) {
|
|
502
|
+
for (UIView *subview in self.subviews) {
|
|
503
|
+
if ([subview isKindOfClass:[LuggPolylineView class]]) {
|
|
504
|
+
MKPolylineAnimator *renderer =
|
|
505
|
+
(MKPolylineAnimator *)((LuggPolylineView *)subview).renderer;
|
|
506
|
+
[renderer pause];
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
}
|
|
398
510
|
}
|
|
399
511
|
|
|
400
512
|
- (BOOL)isUserInteracting:(MKMapView *)mapView {
|
|
@@ -418,6 +530,15 @@ using namespace luggmaps::events;
|
|
|
418
530
|
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
|
|
419
531
|
BOOL wasDragging = _isDragging;
|
|
420
532
|
_isDragging = NO;
|
|
533
|
+
if (wasDragging) {
|
|
534
|
+
for (UIView *subview in self.subviews) {
|
|
535
|
+
if ([subview isKindOfClass:[LuggPolylineView class]]) {
|
|
536
|
+
MKPolylineAnimator *renderer =
|
|
537
|
+
(MKPolylineAnimator *)((LuggPolylineView *)subview).renderer;
|
|
538
|
+
[renderer resume];
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
}
|
|
421
542
|
CameraIdleEvent{mapView.centerCoordinate.latitude,
|
|
422
543
|
mapView.centerCoordinate.longitude, mapView.zoomLevel,
|
|
423
544
|
static_cast<bool>(wasDragging)}
|
|
@@ -442,25 +563,16 @@ using namespace luggmaps::events;
|
|
|
442
563
|
reuseIdentifier:nil];
|
|
443
564
|
annotationView.canShowCallout = YES;
|
|
444
565
|
annotationView.displayPriority = MKFeatureDisplayPriorityRequired;
|
|
445
|
-
annotationView.
|
|
446
|
-
|
|
447
|
-
UIView *iconView = markerView.iconView;
|
|
448
|
-
[iconView removeFromSuperview];
|
|
449
|
-
[annotationView addSubview:iconView];
|
|
566
|
+
annotationView.layer.zPosition = markerView.zIndex;
|
|
567
|
+
annotationView.zPriority = markerView.zIndex;
|
|
450
568
|
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
annotationView
|
|
455
|
-
CGRectMake(0, 0, frame.size.width, frame.size.height);
|
|
456
|
-
iconView.frame = CGRectMake(0, 0, frame.size.width, frame.size.height);
|
|
457
|
-
|
|
458
|
-
CGPoint anchor = markerView.anchor;
|
|
459
|
-
annotationView.centerOffset =
|
|
460
|
-
CGPointMake(frame.size.width * (anchor.x - 0.5),
|
|
461
|
-
-frame.size.height * (anchor.y - 0.5));
|
|
569
|
+
if (!markerView.rasterize) {
|
|
570
|
+
UIView *iconView = markerView.iconView;
|
|
571
|
+
[iconView removeFromSuperview];
|
|
572
|
+
[annotationView addSubview:iconView];
|
|
462
573
|
}
|
|
463
574
|
|
|
575
|
+
[self applyMarkerStyle:markerView annotationView:annotationView];
|
|
464
576
|
markerAnnotation.annotationView = annotationView;
|
|
465
577
|
|
|
466
578
|
return annotationView;
|
|
@@ -482,6 +594,7 @@ using namespace luggmaps::events;
|
|
|
482
594
|
if (colors.count > 1) {
|
|
483
595
|
renderer.strokeColors = colors;
|
|
484
596
|
}
|
|
597
|
+
renderer.animatedOptions = polylineView.animatedOptions;
|
|
485
598
|
renderer.animated = polylineView.animated;
|
|
486
599
|
polylineView.renderer = renderer;
|
|
487
600
|
return renderer;
|
|
@@ -504,16 +617,18 @@ using namespace luggmaps::events;
|
|
|
504
617
|
return;
|
|
505
618
|
}
|
|
506
619
|
|
|
620
|
+
double targetZoom = zoom > 0 ? zoom : _mapView.zoomLevel;
|
|
621
|
+
|
|
507
622
|
if (duration < 0) {
|
|
508
623
|
[self setCameraWithLatitude:latitude
|
|
509
624
|
longitude:longitude
|
|
510
|
-
zoom:
|
|
625
|
+
zoom:targetZoom
|
|
511
626
|
animated:YES];
|
|
512
627
|
} else if (duration > 0) {
|
|
513
628
|
CLLocationCoordinate2D center =
|
|
514
629
|
CLLocationCoordinate2DMake(latitude, longitude);
|
|
515
630
|
MKCoordinateRegion region = [_mapView regionForCenterCoordinate:center
|
|
516
|
-
zoomLevel:
|
|
631
|
+
zoomLevel:targetZoom];
|
|
517
632
|
[UIView animateWithDuration:duration / 1000.0
|
|
518
633
|
animations:^{
|
|
519
634
|
[self->_mapView setRegion:region animated:NO];
|
|
@@ -521,7 +636,7 @@ using namespace luggmaps::events;
|
|
|
521
636
|
} else {
|
|
522
637
|
[self setCameraWithLatitude:latitude
|
|
523
638
|
longitude:longitude
|
|
524
|
-
zoom:
|
|
639
|
+
zoom:targetZoom
|
|
525
640
|
animated:NO];
|
|
526
641
|
}
|
|
527
642
|
}
|