@lugg/maps 0.2.0-alpha.2 → 0.2.0-alpha.20
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 +154 -42
- 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
|
}
|
|
@@ -230,6 +235,8 @@ using namespace luggmaps::events;
|
|
|
230
235
|
|
|
231
236
|
- (void)updateProps:(Props::Shared const &)props
|
|
232
237
|
oldProps:(Props::Shared const &)oldProps {
|
|
238
|
+
const auto &oldViewProps =
|
|
239
|
+
*std::static_pointer_cast<LuggAppleMapViewProps const>(oldProps);
|
|
233
240
|
const auto &newViewProps =
|
|
234
241
|
*std::static_pointer_cast<LuggAppleMapViewProps const>(props);
|
|
235
242
|
|
|
@@ -239,9 +246,49 @@ using namespace luggmaps::events;
|
|
|
239
246
|
_mapView.rotateEnabled = newViewProps.rotateEnabled;
|
|
240
247
|
_mapView.pitchEnabled = newViewProps.pitchEnabled;
|
|
241
248
|
_mapView.showsUserLocation = newViewProps.userLocationEnabled;
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
249
|
+
|
|
250
|
+
// Check if padding changed
|
|
251
|
+
BOOL paddingChanged =
|
|
252
|
+
oldViewProps.padding.top != newViewProps.padding.top ||
|
|
253
|
+
oldViewProps.padding.left != newViewProps.padding.left ||
|
|
254
|
+
oldViewProps.padding.bottom != newViewProps.padding.bottom ||
|
|
255
|
+
oldViewProps.padding.right != newViewProps.padding.right;
|
|
256
|
+
|
|
257
|
+
if (paddingChanged) {
|
|
258
|
+
// Calculate the offset difference to keep visual center stable
|
|
259
|
+
CGFloat oldOffsetX =
|
|
260
|
+
(oldViewProps.padding.left - oldViewProps.padding.right) / 2.0;
|
|
261
|
+
CGFloat oldOffsetY =
|
|
262
|
+
(oldViewProps.padding.top - oldViewProps.padding.bottom) / 2.0;
|
|
263
|
+
CGFloat newOffsetX =
|
|
264
|
+
(newViewProps.padding.left - newViewProps.padding.right) / 2.0;
|
|
265
|
+
CGFloat newOffsetY =
|
|
266
|
+
(newViewProps.padding.top - newViewProps.padding.bottom) / 2.0;
|
|
267
|
+
|
|
268
|
+
CGFloat deltaX = newOffsetX - oldOffsetX;
|
|
269
|
+
CGFloat deltaY = newOffsetY - oldOffsetY;
|
|
270
|
+
|
|
271
|
+
// Apply new padding first
|
|
272
|
+
_mapView.layoutMargins = UIEdgeInsetsMake(
|
|
273
|
+
newViewProps.padding.top, newViewProps.padding.left,
|
|
274
|
+
newViewProps.padding.bottom, newViewProps.padding.right);
|
|
275
|
+
|
|
276
|
+
// Convert pixel offset to coordinate offset
|
|
277
|
+
if (deltaX != 0 || deltaY != 0) {
|
|
278
|
+
CLLocationCoordinate2D currentCenter = _mapView.centerCoordinate;
|
|
279
|
+
CGPoint centerPoint = [_mapView convertCoordinate:currentCenter
|
|
280
|
+
toPointToView:_mapView];
|
|
281
|
+
CGPoint newPoint =
|
|
282
|
+
CGPointMake(centerPoint.x - deltaX, centerPoint.y - deltaY);
|
|
283
|
+
CLLocationCoordinate2D newCenter = [_mapView convertPoint:newPoint
|
|
284
|
+
toCoordinateFromView:_mapView];
|
|
285
|
+
[_mapView setCenterCoordinate:newCenter animated:NO];
|
|
286
|
+
}
|
|
287
|
+
} else {
|
|
288
|
+
_mapView.layoutMargins = UIEdgeInsetsMake(
|
|
289
|
+
newViewProps.padding.top, newViewProps.padding.left,
|
|
290
|
+
newViewProps.padding.bottom, newViewProps.padding.right);
|
|
291
|
+
}
|
|
245
292
|
|
|
246
293
|
_minZoom = newViewProps.minZoom;
|
|
247
294
|
_maxZoom = newViewProps.maxZoom;
|
|
@@ -253,6 +300,38 @@ using namespace luggmaps::events;
|
|
|
253
300
|
|
|
254
301
|
#pragma mark - Annotation Helpers
|
|
255
302
|
|
|
303
|
+
- (void)applyMarkerStyle:(LuggMarkerView *)markerView
|
|
304
|
+
annotationView:(MKAnnotationView *)annotationView {
|
|
305
|
+
annotationView.transform = CGAffineTransformIdentity;
|
|
306
|
+
|
|
307
|
+
UIView *iconView = markerView.iconView;
|
|
308
|
+
CGRect frame = iconView.frame;
|
|
309
|
+
if (frame.size.width <= 0 || frame.size.height <= 0)
|
|
310
|
+
return;
|
|
311
|
+
|
|
312
|
+
CGFloat scale = markerView.scale;
|
|
313
|
+
CGPoint anchor = markerView.anchor;
|
|
314
|
+
|
|
315
|
+
if (markerView.rasterize) {
|
|
316
|
+
annotationView.image = [markerView createScaledIconImage];
|
|
317
|
+
} else {
|
|
318
|
+
iconView.layer.anchorPoint = anchor;
|
|
319
|
+
iconView.transform = CGAffineTransformMakeScale(scale, scale);
|
|
320
|
+
iconView.frame =
|
|
321
|
+
CGRectMake(frame.size.width * (0.5 - anchor.x) * (scale - 1),
|
|
322
|
+
frame.size.height * (0.5 - anchor.y) * (scale - 1),
|
|
323
|
+
frame.size.width, frame.size.height);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
annotationView.bounds =
|
|
327
|
+
CGRectMake(0, 0, frame.size.width * scale, frame.size.height * scale);
|
|
328
|
+
annotationView.centerOffset =
|
|
329
|
+
CGPointMake(frame.size.width * scale * (anchor.x - 0.5),
|
|
330
|
+
-frame.size.height * scale * (anchor.y - 0.5));
|
|
331
|
+
annotationView.transform =
|
|
332
|
+
CGAffineTransformMakeRotation(markerView.rotate * M_PI / 180.0);
|
|
333
|
+
}
|
|
334
|
+
|
|
256
335
|
- (void)updateAnnotationViewFrame:(AppleMarkerAnnotation *)annotation {
|
|
257
336
|
MKAnnotationView *annotationView = annotation.annotationView;
|
|
258
337
|
LuggMarkerView *markerView = annotation.markerView;
|
|
@@ -261,16 +340,7 @@ using namespace luggmaps::events;
|
|
|
261
340
|
return;
|
|
262
341
|
}
|
|
263
342
|
|
|
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
|
-
}
|
|
343
|
+
[self applyMarkerStyle:markerView annotationView:annotationView];
|
|
274
344
|
}
|
|
275
345
|
|
|
276
346
|
#pragma mark - PolylineViewDelegate
|
|
@@ -302,7 +372,8 @@ using namespace luggmaps::events;
|
|
|
302
372
|
free(coords);
|
|
303
373
|
|
|
304
374
|
polylineView.polyline = polyline;
|
|
305
|
-
[
|
|
375
|
+
[_overlayToPolylineMap setObject:polylineView forKey:polyline];
|
|
376
|
+
[self insertOverlay:polyline withZIndex:polylineView.zIndex];
|
|
306
377
|
}
|
|
307
378
|
|
|
308
379
|
- (void)syncPolylineView:(LuggPolylineView *)polylineView {
|
|
@@ -316,7 +387,11 @@ using namespace luggmaps::events;
|
|
|
316
387
|
// Build new polyline from coordinates
|
|
317
388
|
NSArray<CLLocation *> *coordinates = polylineView.coordinates;
|
|
318
389
|
if (coordinates.count == 0) {
|
|
390
|
+
if (renderer) {
|
|
391
|
+
renderer.animated = NO;
|
|
392
|
+
}
|
|
319
393
|
if (oldPolyline) {
|
|
394
|
+
[_overlayToPolylineMap removeObjectForKey:oldPolyline];
|
|
320
395
|
[_mapView removeOverlay:oldPolyline];
|
|
321
396
|
polylineView.polyline = nil;
|
|
322
397
|
polylineView.renderer = nil;
|
|
@@ -334,35 +409,54 @@ using namespace luggmaps::events;
|
|
|
334
409
|
free(coords);
|
|
335
410
|
|
|
336
411
|
polylineView.polyline = newPolyline;
|
|
412
|
+
[_overlayToPolylineMap setObject:polylineView forKey:newPolyline];
|
|
337
413
|
|
|
338
414
|
// If we have an existing renderer, update it in place
|
|
339
415
|
if (renderer && oldPolyline) {
|
|
416
|
+
[_overlayToPolylineMap removeObjectForKey:oldPolyline];
|
|
417
|
+
[_mapView removeOverlay:oldPolyline];
|
|
418
|
+
[self insertOverlay:newPolyline withZIndex:polylineView.zIndex];
|
|
340
419
|
[renderer updatePolyline:newPolyline];
|
|
341
420
|
renderer.lineWidth = polylineView.strokeWidth;
|
|
342
421
|
renderer.strokeColor = polylineView.strokeColors.firstObject;
|
|
343
422
|
renderer.strokeColors =
|
|
344
423
|
polylineView.strokeColors.count > 1 ? polylineView.strokeColors : nil;
|
|
424
|
+
renderer.animatedOptions = polylineView.animatedOptions;
|
|
345
425
|
renderer.animated = polylineView.animated;
|
|
346
426
|
return;
|
|
347
427
|
}
|
|
348
428
|
|
|
349
429
|
// Otherwise do full add
|
|
350
430
|
if (oldPolyline) {
|
|
431
|
+
[_overlayToPolylineMap removeObjectForKey:oldPolyline];
|
|
351
432
|
[_mapView removeOverlay:oldPolyline];
|
|
352
433
|
}
|
|
353
|
-
[
|
|
434
|
+
[self insertOverlay:newPolyline withZIndex:polylineView.zIndex];
|
|
354
435
|
}
|
|
355
436
|
|
|
356
|
-
- (
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
437
|
+
- (void)insertOverlay:(id<MKOverlay>)overlay withZIndex:(NSInteger)zIndex {
|
|
438
|
+
if (zIndex == 0) {
|
|
439
|
+
[_mapView addOverlay:overlay];
|
|
440
|
+
return;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
NSArray<id<MKOverlay>> *overlays = _mapView.overlays;
|
|
444
|
+
NSInteger insertIndex = overlays.count;
|
|
445
|
+
|
|
446
|
+
for (NSInteger i = 0; i < overlays.count; i++) {
|
|
447
|
+
LuggPolylineView *existingPolylineView =
|
|
448
|
+
[self findPolylineViewForOverlay:overlays[i]];
|
|
449
|
+
if (existingPolylineView && existingPolylineView.zIndex > zIndex) {
|
|
450
|
+
insertIndex = i;
|
|
451
|
+
break;
|
|
363
452
|
}
|
|
364
453
|
}
|
|
365
|
-
|
|
454
|
+
|
|
455
|
+
[_mapView insertOverlay:overlay atIndex:insertIndex];
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
- (LuggPolylineView *)findPolylineViewForOverlay:(id<MKOverlay>)overlay {
|
|
459
|
+
return [_overlayToPolylineMap objectForKey:overlay];
|
|
366
460
|
}
|
|
367
461
|
|
|
368
462
|
#pragma mark - MarkerViewDelegate
|
|
@@ -388,6 +482,12 @@ using namespace luggmaps::events;
|
|
|
388
482
|
annotation.title = markerView.title;
|
|
389
483
|
annotation.subtitle = markerView.markerDescription;
|
|
390
484
|
|
|
485
|
+
MKAnnotationView *annotationView = annotation.annotationView;
|
|
486
|
+
if (annotationView) {
|
|
487
|
+
annotationView.layer.zPosition = markerView.zIndex;
|
|
488
|
+
annotationView.zPriority = markerView.zIndex;
|
|
489
|
+
}
|
|
490
|
+
|
|
391
491
|
[self updateAnnotationViewFrame:annotation];
|
|
392
492
|
}
|
|
393
493
|
|
|
@@ -395,6 +495,15 @@ using namespace luggmaps::events;
|
|
|
395
495
|
|
|
396
496
|
- (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated {
|
|
397
497
|
_isDragging = [self isUserInteracting:mapView];
|
|
498
|
+
if (_isDragging) {
|
|
499
|
+
for (UIView *subview in self.subviews) {
|
|
500
|
+
if ([subview isKindOfClass:[LuggPolylineView class]]) {
|
|
501
|
+
MKPolylineAnimator *renderer =
|
|
502
|
+
(MKPolylineAnimator *)((LuggPolylineView *)subview).renderer;
|
|
503
|
+
[renderer pause];
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
}
|
|
398
507
|
}
|
|
399
508
|
|
|
400
509
|
- (BOOL)isUserInteracting:(MKMapView *)mapView {
|
|
@@ -418,6 +527,15 @@ using namespace luggmaps::events;
|
|
|
418
527
|
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
|
|
419
528
|
BOOL wasDragging = _isDragging;
|
|
420
529
|
_isDragging = NO;
|
|
530
|
+
if (wasDragging) {
|
|
531
|
+
for (UIView *subview in self.subviews) {
|
|
532
|
+
if ([subview isKindOfClass:[LuggPolylineView class]]) {
|
|
533
|
+
MKPolylineAnimator *renderer =
|
|
534
|
+
(MKPolylineAnimator *)((LuggPolylineView *)subview).renderer;
|
|
535
|
+
[renderer resume];
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
}
|
|
421
539
|
CameraIdleEvent{mapView.centerCoordinate.latitude,
|
|
422
540
|
mapView.centerCoordinate.longitude, mapView.zoomLevel,
|
|
423
541
|
static_cast<bool>(wasDragging)}
|
|
@@ -442,25 +560,16 @@ using namespace luggmaps::events;
|
|
|
442
560
|
reuseIdentifier:nil];
|
|
443
561
|
annotationView.canShowCallout = YES;
|
|
444
562
|
annotationView.displayPriority = MKFeatureDisplayPriorityRequired;
|
|
445
|
-
annotationView.
|
|
563
|
+
annotationView.layer.zPosition = markerView.zIndex;
|
|
564
|
+
annotationView.zPriority = markerView.zIndex;
|
|
446
565
|
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
// Set frame and centerOffset based on iconView
|
|
452
|
-
CGRect frame = iconView.frame;
|
|
453
|
-
if (frame.size.width > 0 && frame.size.height > 0) {
|
|
454
|
-
annotationView.frame =
|
|
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));
|
|
566
|
+
if (!markerView.rasterize) {
|
|
567
|
+
UIView *iconView = markerView.iconView;
|
|
568
|
+
[iconView removeFromSuperview];
|
|
569
|
+
[annotationView addSubview:iconView];
|
|
462
570
|
}
|
|
463
571
|
|
|
572
|
+
[self applyMarkerStyle:markerView annotationView:annotationView];
|
|
464
573
|
markerAnnotation.annotationView = annotationView;
|
|
465
574
|
|
|
466
575
|
return annotationView;
|
|
@@ -482,6 +591,7 @@ using namespace luggmaps::events;
|
|
|
482
591
|
if (colors.count > 1) {
|
|
483
592
|
renderer.strokeColors = colors;
|
|
484
593
|
}
|
|
594
|
+
renderer.animatedOptions = polylineView.animatedOptions;
|
|
485
595
|
renderer.animated = polylineView.animated;
|
|
486
596
|
polylineView.renderer = renderer;
|
|
487
597
|
return renderer;
|
|
@@ -504,16 +614,18 @@ using namespace luggmaps::events;
|
|
|
504
614
|
return;
|
|
505
615
|
}
|
|
506
616
|
|
|
617
|
+
double targetZoom = zoom > 0 ? zoom : _mapView.zoomLevel;
|
|
618
|
+
|
|
507
619
|
if (duration < 0) {
|
|
508
620
|
[self setCameraWithLatitude:latitude
|
|
509
621
|
longitude:longitude
|
|
510
|
-
zoom:
|
|
622
|
+
zoom:targetZoom
|
|
511
623
|
animated:YES];
|
|
512
624
|
} else if (duration > 0) {
|
|
513
625
|
CLLocationCoordinate2D center =
|
|
514
626
|
CLLocationCoordinate2DMake(latitude, longitude);
|
|
515
627
|
MKCoordinateRegion region = [_mapView regionForCenterCoordinate:center
|
|
516
|
-
zoomLevel:
|
|
628
|
+
zoomLevel:targetZoom];
|
|
517
629
|
[UIView animateWithDuration:duration / 1000.0
|
|
518
630
|
animations:^{
|
|
519
631
|
[self->_mapView setRegion:region animated:NO];
|
|
@@ -521,7 +633,7 @@ using namespace luggmaps::events;
|
|
|
521
633
|
} else {
|
|
522
634
|
[self setCameraWithLatitude:latitude
|
|
523
635
|
longitude:longitude
|
|
524
|
-
zoom:
|
|
636
|
+
zoom:targetZoom
|
|
525
637
|
animated:NO];
|
|
526
638
|
}
|
|
527
639
|
}
|