@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.
Files changed (124) hide show
  1. package/README.md +21 -3
  2. package/android/src/main/java/com/luggmaps/LuggMapView.kt +265 -0
  3. package/android/src/main/java/com/luggmaps/{LuggGoogleMapViewManager.kt → LuggMapViewManager.kt} +75 -36
  4. package/android/src/main/java/com/luggmaps/LuggMapWrapperView.kt +6 -5
  5. package/android/src/main/java/com/luggmaps/LuggMarkerView.kt +136 -14
  6. package/android/src/main/java/com/luggmaps/LuggMarkerViewManager.kt +21 -0
  7. package/android/src/main/java/com/luggmaps/LuggPackage.kt +1 -4
  8. package/android/src/main/java/com/luggmaps/LuggPolylineView.kt +16 -0
  9. package/android/src/main/java/com/luggmaps/LuggPolylineViewManager.kt +22 -0
  10. package/android/src/main/java/com/luggmaps/{LuggGoogleMapView.kt → core/GoogleMapProvider.kt} +251 -241
  11. package/android/src/main/java/com/luggmaps/core/MapProviderDelegate.kt +55 -0
  12. package/android/src/main/java/com/luggmaps/core/PolylineAnimator.kt +163 -52
  13. package/ios/LuggMapView.h +9 -0
  14. package/ios/LuggMapView.mm +312 -0
  15. package/ios/LuggMarkerView.h +9 -0
  16. package/ios/LuggMarkerView.mm +79 -0
  17. package/ios/LuggPolylineView.h +4 -0
  18. package/ios/LuggPolylineView.mm +23 -0
  19. package/ios/core/AppleMapProvider.h +15 -0
  20. package/ios/core/AppleMapProvider.mm +664 -0
  21. package/ios/core/GMSPolylineAnimator.h +3 -0
  22. package/ios/core/GMSPolylineAnimator.m +175 -40
  23. package/ios/core/GoogleMapProvider.h +13 -0
  24. package/ios/core/GoogleMapProvider.mm +513 -0
  25. package/ios/core/MKPolylineAnimator.h +4 -0
  26. package/ios/core/MKPolylineAnimator.m +224 -68
  27. package/ios/core/MapProviderDelegate.h +72 -0
  28. package/ios/core/PolylineAnimatorBase.h +24 -1
  29. package/ios/core/PolylineAnimatorBase.m +82 -19
  30. package/ios/extensions/MKMapView+Zoom.h +2 -0
  31. package/ios/extensions/MKMapView+Zoom.m +14 -4
  32. package/lib/module/MapProvider.js +13 -0
  33. package/lib/module/MapProvider.js.map +1 -0
  34. package/lib/module/MapProvider.types.js +4 -0
  35. package/lib/module/MapProvider.types.js.map +1 -0
  36. package/lib/module/MapProvider.web.js +20 -0
  37. package/lib/module/MapProvider.web.js.map +1 -0
  38. package/lib/module/MapView.js +29 -16
  39. package/lib/module/MapView.js.map +1 -1
  40. package/lib/module/MapView.web.js +290 -0
  41. package/lib/module/MapView.web.js.map +1 -0
  42. package/lib/module/components/Marker.js +19 -2
  43. package/lib/module/components/Marker.js.map +1 -1
  44. package/lib/module/components/Marker.web.js +33 -0
  45. package/lib/module/components/Marker.web.js.map +1 -0
  46. package/lib/module/components/Polyline.js +17 -4
  47. package/lib/module/components/Polyline.js.map +1 -1
  48. package/lib/module/components/Polyline.web.js +229 -0
  49. package/lib/module/components/Polyline.web.js.map +1 -0
  50. package/lib/module/components/index.js +2 -2
  51. package/lib/module/components/index.js.map +1 -1
  52. package/lib/module/components/index.web.js +5 -0
  53. package/lib/module/components/index.web.js.map +1 -0
  54. package/lib/module/fabric/{LuggGoogleMapViewNativeComponent.ts → LuggMapViewNativeComponent.ts} +19 -7
  55. package/lib/module/fabric/LuggMarkerViewNativeComponent.ts +7 -1
  56. package/lib/module/fabric/LuggPolylineViewNativeComponent.ts +8 -0
  57. package/lib/module/index.js +4 -2
  58. package/lib/module/index.js.map +1 -1
  59. package/lib/module/index.web.js +7 -0
  60. package/lib/module/index.web.js.map +1 -0
  61. package/lib/typescript/src/MapProvider.d.ts +8 -0
  62. package/lib/typescript/src/MapProvider.d.ts.map +1 -0
  63. package/lib/typescript/src/MapProvider.types.d.ts +16 -0
  64. package/lib/typescript/src/MapProvider.types.d.ts.map +1 -0
  65. package/lib/typescript/src/MapProvider.web.d.ts +11 -0
  66. package/lib/typescript/src/MapProvider.web.d.ts.map +1 -0
  67. package/lib/typescript/src/MapView.d.ts +4 -4
  68. package/lib/typescript/src/MapView.d.ts.map +1 -1
  69. package/lib/typescript/src/MapView.types.d.ts +23 -7
  70. package/lib/typescript/src/MapView.types.d.ts.map +1 -1
  71. package/lib/typescript/src/MapView.web.d.ts +3 -0
  72. package/lib/typescript/src/MapView.web.d.ts.map +1 -0
  73. package/lib/typescript/src/components/Marker.d.ts +25 -1
  74. package/lib/typescript/src/components/Marker.d.ts.map +1 -1
  75. package/lib/typescript/src/components/Marker.web.d.ts +3 -0
  76. package/lib/typescript/src/components/Marker.web.d.ts.map +1 -0
  77. package/lib/typescript/src/components/Polyline.d.ts +36 -1
  78. package/lib/typescript/src/components/Polyline.d.ts.map +1 -1
  79. package/lib/typescript/src/components/Polyline.web.d.ts +3 -0
  80. package/lib/typescript/src/components/Polyline.web.d.ts.map +1 -0
  81. package/lib/typescript/src/components/index.d.ts +4 -2
  82. package/lib/typescript/src/components/index.d.ts.map +1 -1
  83. package/lib/typescript/src/components/index.web.d.ts +5 -0
  84. package/lib/typescript/src/components/index.web.d.ts.map +1 -0
  85. package/lib/typescript/src/fabric/{LuggGoogleMapViewNativeComponent.d.ts → LuggMapViewNativeComponent.d.ts} +8 -4
  86. package/lib/typescript/src/fabric/LuggMapViewNativeComponent.d.ts.map +1 -0
  87. package/lib/typescript/src/fabric/LuggMarkerViewNativeComponent.d.ts +4 -1
  88. package/lib/typescript/src/fabric/LuggMarkerViewNativeComponent.d.ts.map +1 -1
  89. package/lib/typescript/src/fabric/LuggPolylineViewNativeComponent.d.ts +7 -0
  90. package/lib/typescript/src/fabric/LuggPolylineViewNativeComponent.d.ts.map +1 -1
  91. package/lib/typescript/src/index.d.ts +8 -3
  92. package/lib/typescript/src/index.d.ts.map +1 -1
  93. package/lib/typescript/src/index.web.d.ts +10 -0
  94. package/lib/typescript/src/index.web.d.ts.map +1 -0
  95. package/lib/typescript/src/types.d.ts +4 -0
  96. package/lib/typescript/src/types.d.ts.map +1 -1
  97. package/package.json +17 -3
  98. package/src/MapProvider.tsx +10 -0
  99. package/src/MapProvider.types.ts +16 -0
  100. package/src/MapProvider.web.tsx +14 -0
  101. package/src/MapView.tsx +28 -26
  102. package/src/MapView.types.ts +24 -7
  103. package/src/MapView.web.tsx +364 -0
  104. package/src/components/Marker.tsx +50 -4
  105. package/src/components/Marker.web.tsx +33 -0
  106. package/src/components/Polyline.tsx +51 -2
  107. package/src/components/Polyline.web.tsx +287 -0
  108. package/src/components/index.ts +8 -2
  109. package/src/components/index.web.ts +4 -0
  110. package/src/fabric/{LuggGoogleMapViewNativeComponent.ts → LuggMapViewNativeComponent.ts} +19 -7
  111. package/src/fabric/LuggMarkerViewNativeComponent.ts +7 -1
  112. package/src/fabric/LuggPolylineViewNativeComponent.ts +8 -0
  113. package/src/index.ts +18 -2
  114. package/src/index.web.ts +20 -0
  115. package/src/types.ts +5 -0
  116. package/ios/LuggAppleMapView.h +0 -16
  117. package/ios/LuggAppleMapView.mm +0 -580
  118. package/ios/LuggGoogleMapView.h +0 -13
  119. package/ios/LuggGoogleMapView.mm +0 -454
  120. package/lib/module/fabric/LuggAppleMapViewNativeComponent.ts +0 -83
  121. package/lib/typescript/src/fabric/LuggAppleMapViewNativeComponent.d.ts +0 -54
  122. package/lib/typescript/src/fabric/LuggAppleMapViewNativeComponent.d.ts.map +0 -1
  123. package/lib/typescript/src/fabric/LuggGoogleMapViewNativeComponent.d.ts.map +0 -1
  124. package/src/fabric/LuggAppleMapViewNativeComponent.ts +0 -83
@@ -1,10 +1,42 @@
1
1
  #import "MKPolylineAnimator.h"
2
2
  #import <QuartzCore/QuartzCore.h>
3
3
 
4
+ @interface MKDisplayLinkProxy : NSObject
5
+ @property(nonatomic, weak) id target;
6
+ @property(nonatomic, assign) SEL selector;
7
+ @end
8
+
9
+ @implementation MKDisplayLinkProxy
10
+ - (instancetype)initWithTarget:(id)target selector:(SEL)selector {
11
+ if (self = [super init]) {
12
+ _target = target;
13
+ _selector = selector;
14
+ }
15
+ return self;
16
+ }
17
+ - (void)tick:(CADisplayLink *)displayLink {
18
+ if (_target) {
19
+ #pragma clang diagnostic push
20
+ #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
21
+ [_target performSelector:_selector withObject:displayLink];
22
+ #pragma clang diagnostic pop
23
+ } else {
24
+ [displayLink invalidate];
25
+ }
26
+ }
27
+ @end
28
+
4
29
  @implementation MKPolylineAnimator {
5
30
  MKPolyline *_polyline;
6
31
  CADisplayLink *_displayLink;
7
- CGFloat _animationProgress; // 0→1 grow, 1→2 shrink
32
+ MKDisplayLinkProxy *_displayLinkProxy;
33
+ CGFloat _animationProgress;
34
+ CGFloat _delayRemaining;
35
+ NSArray<NSNumber *> *_cumulativeDistances;
36
+ CGFloat _totalLength;
37
+ CGColorSpaceRef _colorSpace;
38
+ RGBAComponents *_colorCache;
39
+ NSUInteger _colorCacheCount;
8
40
  }
9
41
 
10
42
  - (id)initWithPolyline:(MKPolyline *)polyline {
@@ -12,13 +44,28 @@
12
44
  if (self) {
13
45
  _polyline = polyline;
14
46
  _animationProgress = 0;
47
+ _animatedOptions = [PolylineAnimatedOptions defaultOptions];
48
+ _colorSpace = CGColorSpaceCreateDeviceRGB();
15
49
  [self createPath];
16
50
  }
17
51
  return self;
18
52
  }
19
53
 
54
+ - (void)setAnimatedOptions:(PolylineAnimatedOptions *)animatedOptions {
55
+ _animatedOptions = animatedOptions ?: [PolylineAnimatedOptions defaultOptions];
56
+ if (_animated && _displayLink) {
57
+ [self stopAnimation];
58
+ [self startAnimation];
59
+ }
60
+ }
61
+
20
62
  - (void)dealloc {
21
63
  [self stopAnimation];
64
+ free(_colorCache);
65
+ if (_colorSpace) {
66
+ CGColorSpaceRelease(_colorSpace);
67
+ _colorSpace = NULL;
68
+ }
22
69
  }
23
70
 
24
71
  - (void)setAnimated:(BOOL)animated {
@@ -38,24 +85,91 @@
38
85
  if (_displayLink) {
39
86
  return;
40
87
  }
88
+ [self computeCumulativeDistances];
41
89
  _animationProgress = 0;
42
- _displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(animationTick:)];
90
+ _delayRemaining = _animatedOptions.delay / 1000.0;
91
+ _displayLinkProxy = [[MKDisplayLinkProxy alloc] initWithTarget:self selector:@selector(animationTick:)];
92
+ _displayLink = [CADisplayLink displayLinkWithTarget:_displayLinkProxy selector:@selector(tick:)];
43
93
  [_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
44
94
  }
45
95
 
96
+ - (void)computeCumulativeDistances {
97
+ NSMutableArray<NSNumber *> *distances = [NSMutableArray array];
98
+ CGFloat total = 0;
99
+ [distances addObject:@(0)];
100
+
101
+ for (NSUInteger i = 1; i < _polyline.pointCount; i++) {
102
+ MKMapPoint p1 = _polyline.points[i - 1];
103
+ MKMapPoint p2 = _polyline.points[i];
104
+ total += MKMetersBetweenMapPoints(p1, p2);
105
+ [distances addObject:@(total)];
106
+ }
107
+
108
+ _cumulativeDistances = [distances copy];
109
+ _totalLength = total;
110
+ }
111
+
46
112
  - (void)stopAnimation {
47
113
  [_displayLink invalidate];
48
114
  _displayLink = nil;
115
+ _displayLinkProxy = nil;
116
+ }
117
+
118
+ - (void)pause {
119
+ _displayLink.paused = YES;
120
+ }
121
+
122
+ - (void)resume {
123
+ _displayLink.paused = NO;
124
+ }
125
+
126
+ - (NSUInteger)indexForDistance:(CGFloat)distance {
127
+ NSUInteger left = 0;
128
+ NSUInteger right = _cumulativeDistances.count - 1;
129
+
130
+ while (left < right) {
131
+ NSUInteger mid = (left + right + 1) / 2;
132
+ if (_cumulativeDistances[mid].doubleValue <= distance) {
133
+ left = mid;
134
+ } else {
135
+ right = mid - 1;
136
+ }
137
+ }
138
+
139
+ return MIN(left, _cumulativeDistances.count - 2);
140
+ }
141
+
142
+ - (CGFloat)applyEasing:(CGFloat)t {
143
+ NSString *easing = _animatedOptions.easing ?: @"linear";
144
+
145
+ if ([easing isEqualToString:@"easeIn"]) {
146
+ return t * t;
147
+ } else if ([easing isEqualToString:@"easeOut"]) {
148
+ return t * (2 - t);
149
+ } else if ([easing isEqualToString:@"easeInOut"]) {
150
+ return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
151
+ }
152
+ return t;
49
153
  }
50
154
 
51
155
  - (void)animationTick:(CADisplayLink *)displayLink {
52
- // ~1.75s per phase (grow or shrink), matching JS duration
53
- CGFloat speed = displayLink.duration / 1.75;
156
+ if (_delayRemaining > 0) {
157
+ _delayRemaining -= displayLink.duration;
158
+ return;
159
+ }
160
+
161
+ CGFloat duration = _animatedOptions.duration / 1000.0;
162
+ if (duration <= 0) duration = 2.15;
163
+
164
+ CGFloat trailLength = MAX(0.01, MIN(1.0, _animatedOptions.trailLength));
165
+ CGFloat maxProgress = (trailLength < 1.0) ? 1.0 : 2.15;
166
+
167
+ CGFloat speed = displayLink.duration / duration;
54
168
  _animationProgress += speed;
55
169
 
56
- // 0→1 grow, 1→2 shrink, then reset with small pause
57
- if (_animationProgress >= 2.15) { // 2.0 + 0.15 pause (~300ms at this speed)
170
+ if (_animationProgress >= maxProgress) {
58
171
  _animationProgress = 0;
172
+ _delayRemaining = _animatedOptions.delay / 1000.0;
59
173
  }
60
174
 
61
175
  MKMapRect bounds = _polyline.boundingMapRect;
@@ -67,6 +181,9 @@
67
181
  _polyline = polyline;
68
182
  [self invalidatePath];
69
183
  [self createPath];
184
+ if (_animated) {
185
+ [self computeCumulativeDistances];
186
+ }
70
187
  [self setNeedsDisplay];
71
188
  }
72
189
 
@@ -85,34 +202,60 @@
85
202
  self.path = path;
86
203
  }
87
204
 
88
- - (UIColor *)colorAtGradientPosition:(CGFloat)position {
89
- if (!_strokeColors || _strokeColors.count == 0) {
90
- return self.strokeColor;
205
+ - (void)setStrokeColors:(NSArray<UIColor *> *)strokeColors {
206
+ _strokeColors = strokeColors;
207
+ [self rebuildColorCache];
208
+ }
209
+
210
+ - (void)rebuildColorCache {
211
+ free(_colorCache);
212
+ _colorCache = NULL;
213
+ _colorCacheCount = _strokeColors.count;
214
+ if (_colorCacheCount == 0) return;
215
+
216
+ _colorCache = (RGBAComponents *)malloc(sizeof(RGBAComponents) * _colorCacheCount);
217
+ for (NSUInteger i = 0; i < _colorCacheCount; i++) {
218
+ [_strokeColors[i] getRed:&_colorCache[i].r
219
+ green:&_colorCache[i].g
220
+ blue:&_colorCache[i].b
221
+ alpha:&_colorCache[i].a];
91
222
  }
92
- if (_strokeColors.count == 1) {
93
- return _strokeColors[0];
223
+ }
224
+
225
+ - (void)colorAtGradientPosition:(CGFloat)position rgba:(RGBAComponents *)out {
226
+ if (_colorCacheCount == 0) {
227
+ CGFloat r, g, b, a;
228
+ [self.strokeColor getRed:&r green:&g blue:&b alpha:&a];
229
+ *out = (RGBAComponents){r, g, b, a};
230
+ return;
231
+ }
232
+ if (_colorCacheCount == 1) {
233
+ *out = _colorCache[0];
234
+ return;
94
235
  }
95
236
 
96
237
  position = MAX(0, MIN(1, position));
97
- CGFloat scaledPos = position * (_strokeColors.count - 1);
98
- NSUInteger index = (NSUInteger)floor(scaledPos);
238
+ CGFloat scaledPos = position * (_colorCacheCount - 1);
239
+ NSUInteger index = (NSUInteger)scaledPos;
99
240
  CGFloat t = scaledPos - index;
100
241
 
101
- if (index >= _strokeColors.count - 1) {
102
- return _strokeColors.lastObject;
242
+ if (index >= _colorCacheCount - 1) {
243
+ *out = _colorCache[_colorCacheCount - 1];
244
+ return;
103
245
  }
104
246
 
105
- UIColor *c1 = _strokeColors[index];
106
- UIColor *c2 = _strokeColors[index + 1];
107
-
108
- CGFloat r1, g1, b1, a1, r2, g2, b2, a2;
109
- [c1 getRed:&r1 green:&g1 blue:&b1 alpha:&a1];
110
- [c2 getRed:&r2 green:&g2 blue:&b2 alpha:&a2];
247
+ RGBAComponents c1 = _colorCache[index];
248
+ RGBAComponents c2 = _colorCache[index + 1];
249
+ out->r = c1.r + (c2.r - c1.r) * t;
250
+ out->g = c1.g + (c2.g - c1.g) * t;
251
+ out->b = c1.b + (c2.b - c1.b) * t;
252
+ out->a = c1.a + (c2.a - c1.a) * t;
253
+ }
111
254
 
112
- return [UIColor colorWithRed:r1 + (r2 - r1) * t
113
- green:g1 + (g2 - g1) * t
114
- blue:b1 + (b2 - b1) * t
115
- alpha:a1 + (a2 - a1) * t];
255
+ - (UIColor *)colorAtGradientPosition:(CGFloat)position {
256
+ RGBAComponents rgba;
257
+ [self colorAtGradientPosition:position rgba:&rgba];
258
+ return [UIColor colorWithRed:rgba.r green:rgba.g blue:rgba.b alpha:rgba.a];
116
259
  }
117
260
 
118
261
  - (void)drawMapRect:(MKMapRect)mapRect
@@ -135,65 +278,77 @@
135
278
  }
136
279
 
137
280
  // Snake animation: grow from start, then shrink from start
138
- if (_animated && _polyline.pointCount > 1) {
139
- CGFloat progress = MIN(_animationProgress, 2.0);
140
- CGFloat headPos, tailPos;
141
-
142
- if (progress <= 1.0) {
143
- // Phase 1: grow from start to end
144
- tailPos = 0;
145
- headPos = progress * segmentCount;
281
+ if (_animated && _polyline.pointCount > 1 && _totalLength > 0) {
282
+ CGFloat trailLength = MAX(0.01, MIN(1.0, _animatedOptions.trailLength));
283
+ CGFloat maxProgress = (trailLength < 1.0) ? 1.0 : 2.0;
284
+ CGFloat progress = MIN(_animationProgress, maxProgress);
285
+ CGFloat easedProgress = [self applyEasing:progress / maxProgress] * maxProgress;
286
+
287
+ CGFloat headDist, tailDist;
288
+
289
+ if (trailLength < 1.0) {
290
+ headDist = easedProgress * _totalLength;
291
+ tailDist = MAX(0, headDist - _totalLength * trailLength);
292
+ } else if (easedProgress <= 1.0) {
293
+ tailDist = 0;
294
+ headDist = easedProgress * _totalLength;
146
295
  } else {
147
- // Phase 2: shrink from start
148
- CGFloat shrinkProgress = progress - 1.0;
149
- tailPos = shrinkProgress * segmentCount;
150
- headPos = segmentCount;
296
+ CGFloat shrinkProgress = easedProgress - 1.0;
297
+ tailDist = shrinkProgress * _totalLength;
298
+ headDist = _totalLength;
151
299
  }
152
300
 
153
- if (headPos <= tailPos) {
301
+ if (headDist <= tailDist) {
154
302
  return;
155
303
  }
156
304
 
157
- NSUInteger startIndex = (NSUInteger)floor(tailPos);
158
- NSUInteger endIndex = (NSUInteger)ceil(headPos);
159
- CGFloat visibleLength = headPos - tailPos;
305
+ CGFloat visibleLength = headDist - tailDist;
306
+ NSUInteger startIndex = [self indexForDistance:tailDist];
307
+ NSUInteger endIndex = [self indexForDistance:headDist];
308
+
309
+ for (NSUInteger i = startIndex; i <= endIndex && i < segmentCount; i++) {
310
+ CGFloat segStartDist = _cumulativeDistances[i].doubleValue;
311
+ CGFloat segEndDist = _cumulativeDistances[i + 1].doubleValue;
312
+
313
+ if (segEndDist <= tailDist || segStartDist >= headDist) {
314
+ continue;
315
+ }
160
316
 
161
- for (NSUInteger i = startIndex; i < endIndex && i < segmentCount; i++) {
162
317
  CGPoint segStart = [self pointForMapPoint:_polyline.points[i]];
163
318
  CGPoint segEnd = [self pointForMapPoint:_polyline.points[i + 1]];
164
319
 
165
320
  CGPoint drawStart = segStart;
166
321
  CGPoint drawEnd = segEnd;
167
- CGFloat segStartPos = (CGFloat)i;
168
- CGFloat segEndPos = (CGFloat)(i + 1);
322
+ CGFloat drawStartDist = segStartDist;
323
+ CGFloat drawEndDist = segEndDist;
324
+ CGFloat segLength = segEndDist - segStartDist;
169
325
 
170
- // Interpolate tail (partial segment at start)
171
- if (segStartPos < tailPos) {
172
- CGFloat t = tailPos - segStartPos;
326
+ if (segStartDist < tailDist && segLength > 0) {
327
+ CGFloat t = (tailDist - segStartDist) / segLength;
173
328
  drawStart.x = segStart.x + (segEnd.x - segStart.x) * t;
174
329
  drawStart.y = segStart.y + (segEnd.y - segStart.y) * t;
175
- segStartPos = tailPos;
330
+ drawStartDist = tailDist;
176
331
  }
177
332
 
178
- // Interpolate head (partial segment at end)
179
- if (segEndPos > headPos) {
180
- CGFloat t = headPos - (CGFloat)i;
333
+ if (segEndDist > headDist && segLength > 0) {
334
+ CGFloat t = (headDist - segStartDist) / segLength;
181
335
  drawEnd.x = segStart.x + (segEnd.x - segStart.x) * t;
182
336
  drawEnd.y = segStart.y + (segEnd.y - segStart.y) * t;
183
- segEndPos = headPos;
337
+ drawEndDist = headDist;
184
338
  }
185
339
 
186
- // Calculate gradient position (0-1) within visible portion
187
- CGFloat gradientStart = (segStartPos - tailPos) / visibleLength;
188
- CGFloat gradientEnd = (segEndPos - tailPos) / visibleLength;
340
+ CGFloat gradientStart = (drawStartDist - tailDist) / visibleLength;
341
+ CGFloat gradientEnd = (drawEndDist - tailDist) / visibleLength;
189
342
 
190
- UIColor *startColor = [self colorAtGradientPosition:gradientStart];
191
- UIColor *endColor = [self colorAtGradientPosition:gradientEnd];
343
+ RGBAComponents startRGBA, endRGBA;
344
+ [self colorAtGradientPosition:gradientStart rgba:&startRGBA];
345
+ [self colorAtGradientPosition:gradientEnd rgba:&endRGBA];
192
346
 
193
- // Draw gradient line segment
194
- CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
195
- NSArray *colors = @[(__bridge id)startColor.CGColor, (__bridge id)endColor.CGColor];
196
- CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)colors, NULL);
347
+ CGFloat components[] = {
348
+ startRGBA.r, startRGBA.g, startRGBA.b, startRGBA.a,
349
+ endRGBA.r, endRGBA.g, endRGBA.b, endRGBA.a
350
+ };
351
+ CGGradientRef gradient = CGGradientCreateWithColorComponents(_colorSpace, components, NULL, 2);
197
352
 
198
353
  CGContextSaveGState(context);
199
354
  CGContextBeginPath(context);
@@ -206,7 +361,6 @@
206
361
 
207
362
  CGContextRestoreGState(context);
208
363
  CGGradientRelease(gradient);
209
- CGColorSpaceRelease(colorSpace);
210
364
  }
211
365
  return;
212
366
  }
@@ -220,12 +374,15 @@
220
374
  CGFloat gradientStart = (CGFloat)i / segmentCount;
221
375
  CGFloat gradientEnd = (CGFloat)(i + 1) / segmentCount;
222
376
 
223
- UIColor *startColor = [self colorAtGradientPosition:gradientStart];
224
- UIColor *endColor = [self colorAtGradientPosition:gradientEnd];
377
+ RGBAComponents startRGBA, endRGBA;
378
+ [self colorAtGradientPosition:gradientStart rgba:&startRGBA];
379
+ [self colorAtGradientPosition:gradientEnd rgba:&endRGBA];
225
380
 
226
- CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
227
- NSArray *colors = @[(__bridge id)startColor.CGColor, (__bridge id)endColor.CGColor];
228
- CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)colors, NULL);
381
+ CGFloat components[] = {
382
+ startRGBA.r, startRGBA.g, startRGBA.b, startRGBA.a,
383
+ endRGBA.r, endRGBA.g, endRGBA.b, endRGBA.a
384
+ };
385
+ CGGradientRef gradient = CGGradientCreateWithColorComponents(_colorSpace, components, NULL, 2);
229
386
 
230
387
  CGContextSaveGState(context);
231
388
  CGContextBeginPath(context);
@@ -238,7 +395,6 @@
238
395
 
239
396
  CGContextRestoreGState(context);
240
397
  CGGradientRelease(gradient);
241
- CGColorSpaceRelease(colorSpace);
242
398
  }
243
399
  return;
244
400
  }
@@ -0,0 +1,72 @@
1
+ #import <CoreLocation/CoreLocation.h>
2
+ #import <UIKit/UIKit.h>
3
+
4
+ NS_ASSUME_NONNULL_BEGIN
5
+
6
+ @class LuggMarkerView;
7
+ @class LuggPolylineView;
8
+
9
+ @protocol MapProviderDelegate <NSObject>
10
+ - (void)mapProviderDidReady;
11
+ - (void)mapProviderDidMoveCamera:(double)latitude
12
+ longitude:(double)longitude
13
+ zoom:(double)zoom
14
+ gesture:(BOOL)gesture;
15
+ - (void)mapProviderDidIdleCamera:(double)latitude
16
+ longitude:(double)longitude
17
+ zoom:(double)zoom
18
+ gesture:(BOOL)gesture;
19
+ @end
20
+
21
+ @protocol MapProvider <NSObject>
22
+
23
+ @property(nonatomic, weak, nullable) id<MapProviderDelegate> delegate;
24
+ @property(nonatomic, readonly) BOOL isMapReady;
25
+
26
+ - (void)initializeMapInView:(UIView *)wrapperView
27
+ initialCoordinate:(CLLocationCoordinate2D)coordinate
28
+ initialZoom:(double)zoom;
29
+ - (void)destroy;
30
+
31
+ // Props
32
+ - (void)setZoomEnabled:(BOOL)enabled;
33
+ - (void)setScrollEnabled:(BOOL)enabled;
34
+ - (void)setRotateEnabled:(BOOL)enabled;
35
+ - (void)setPitchEnabled:(BOOL)enabled;
36
+ - (void)setUserLocationEnabled:(BOOL)enabled;
37
+ - (void)setTheme:(NSInteger)theme;
38
+ - (void)setMinZoom:(double)minZoom;
39
+ - (void)setMaxZoom:(double)maxZoom;
40
+ - (void)setEdgeInsets:(UIEdgeInsets)edgeInsets
41
+ oldEdgeInsets:(UIEdgeInsets)oldEdgeInsets;
42
+ - (void)setEdgeInsets:(UIEdgeInsets)edgeInsets
43
+ oldEdgeInsets:(UIEdgeInsets)oldEdgeInsets
44
+ duration:(double)duration;
45
+
46
+ // Children
47
+ - (void)addMarkerView:(LuggMarkerView *)markerView;
48
+ - (void)removeMarkerView:(LuggMarkerView *)markerView;
49
+ - (void)syncMarkerView:(LuggMarkerView *)markerView;
50
+ - (void)addPolylineView:(LuggPolylineView *)polylineView;
51
+ - (void)removePolylineView:(LuggPolylineView *)polylineView;
52
+ - (void)syncPolylineView:(LuggPolylineView *)polylineView;
53
+
54
+ // Lifecycle
55
+ - (void)pauseAnimations;
56
+ - (void)resumeAnimations;
57
+
58
+ // Commands
59
+ - (void)moveCamera:(double)latitude
60
+ longitude:(double)longitude
61
+ zoom:(double)zoom
62
+ duration:(double)duration;
63
+ - (void)fitCoordinates:(NSArray *)coordinates
64
+ edgeInsetsTop:(double)edgeInsetsTop
65
+ edgeInsetsLeft:(double)edgeInsetsLeft
66
+ edgeInsetsBottom:(double)edgeInsetsBottom
67
+ edgeInsetsRight:(double)edgeInsetsRight
68
+ duration:(double)duration;
69
+
70
+ @end
71
+
72
+ NS_ASSUME_NONNULL_END
@@ -2,21 +2,44 @@
2
2
  #import <Foundation/Foundation.h>
3
3
  #import <UIKit/UIKit.h>
4
4
 
5
+ @interface PolylineAnimatedOptions : NSObject
6
+
7
+ @property(nonatomic, assign) NSTimeInterval duration;
8
+ @property(nonatomic, copy) NSString *easing;
9
+ @property(nonatomic, assign) CGFloat trailLength;
10
+ @property(nonatomic, assign) NSTimeInterval delay;
11
+
12
+ + (instancetype)defaultOptions;
13
+
14
+ @end
15
+
5
16
  @protocol PolylineAnimator <NSObject>
6
17
 
7
18
  @property(nonatomic, strong) NSArray<CLLocation *> *coordinates;
8
19
  @property(nonatomic, strong) NSArray<UIColor *> *strokeColors;
9
20
  @property(nonatomic, assign) BOOL animated;
21
+ @property(nonatomic, strong) PolylineAnimatedOptions *animatedOptions;
10
22
 
11
23
  - (void)update;
12
24
 
13
25
  @end
14
26
 
15
- @interface PolylineAnimatorBase : NSObject
27
+ typedef struct {
28
+ CGFloat r, g, b, a;
29
+ } RGBAComponents;
30
+
31
+ @interface PolylineAnimatorBase : NSObject {
32
+ @protected
33
+ RGBAComponents *_colorCache;
34
+ NSUInteger _colorCacheCount;
35
+ }
16
36
 
17
37
  @property(nonatomic, strong) NSArray<CLLocation *> *coordinates;
18
38
  @property(nonatomic, strong) NSArray<UIColor *> *strokeColors;
39
+ @property(nonatomic, strong) PolylineAnimatedOptions *animatedOptions;
19
40
 
20
41
  - (UIColor *)colorAtGradientPosition:(CGFloat)position;
42
+ - (void)colorAtGradientPosition:(CGFloat)position rgba:(RGBAComponents *)out;
43
+ - (CGFloat)applyEasing:(CGFloat)t;
21
44
 
22
45
  @end
@@ -1,35 +1,98 @@
1
1
  #import "PolylineAnimatorBase.h"
2
2
 
3
+ @implementation PolylineAnimatedOptions
4
+
5
+ + (instancetype)defaultOptions {
6
+ PolylineAnimatedOptions *options = [[PolylineAnimatedOptions alloc] init];
7
+ options.duration = 2.15;
8
+ options.easing = @"linear";
9
+ options.trailLength = 1.0;
10
+ options.delay = 0;
11
+ return options;
12
+ }
13
+
14
+ @end
15
+
3
16
  @implementation PolylineAnimatorBase
4
17
 
5
- - (UIColor *)colorAtGradientPosition:(CGFloat)position {
6
- if (!_strokeColors || _strokeColors.count == 0) {
7
- return [UIColor blackColor];
18
+ - (instancetype)init {
19
+ if (self = [super init]) {
20
+ _animatedOptions = [PolylineAnimatedOptions defaultOptions];
21
+ _colorCache = NULL;
22
+ _colorCacheCount = 0;
23
+ }
24
+ return self;
25
+ }
26
+
27
+ - (void)dealloc {
28
+ free(_colorCache);
29
+ }
30
+
31
+ - (void)setStrokeColors:(NSArray<UIColor *> *)strokeColors {
32
+ _strokeColors = strokeColors;
33
+ [self rebuildColorCache];
34
+ }
35
+
36
+ - (void)rebuildColorCache {
37
+ free(_colorCache);
38
+ _colorCache = NULL;
39
+ _colorCacheCount = _strokeColors.count;
40
+ if (_colorCacheCount == 0) return;
41
+
42
+ _colorCache = (RGBAComponents *)malloc(sizeof(RGBAComponents) * _colorCacheCount);
43
+ for (NSUInteger i = 0; i < _colorCacheCount; i++) {
44
+ [_strokeColors[i] getRed:&_colorCache[i].r
45
+ green:&_colorCache[i].g
46
+ blue:&_colorCache[i].b
47
+ alpha:&_colorCache[i].a];
48
+ }
49
+ }
50
+
51
+ - (CGFloat)applyEasing:(CGFloat)t {
52
+ NSString *easing = self.animatedOptions.easing ?: @"linear";
53
+
54
+ if ([easing isEqualToString:@"easeIn"]) {
55
+ return t * t;
56
+ } else if ([easing isEqualToString:@"easeOut"]) {
57
+ return t * (2 - t);
58
+ } else if ([easing isEqualToString:@"easeInOut"]) {
59
+ return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
8
60
  }
9
- if (_strokeColors.count == 1) {
10
- return _strokeColors[0];
61
+ return t;
62
+ }
63
+
64
+ - (void)colorAtGradientPosition:(CGFloat)position rgba:(RGBAComponents *)out {
65
+ if (_colorCacheCount == 0) {
66
+ *out = (RGBAComponents){0, 0, 0, 1};
67
+ return;
68
+ }
69
+ if (_colorCacheCount == 1) {
70
+ *out = _colorCache[0];
71
+ return;
11
72
  }
12
73
 
13
74
  position = MAX(0, MIN(1, position));
14
- CGFloat scaledPos = position * (_strokeColors.count - 1);
15
- NSUInteger index = (NSUInteger)floor(scaledPos);
75
+ CGFloat scaledPos = position * (_colorCacheCount - 1);
76
+ NSUInteger index = (NSUInteger)scaledPos;
16
77
  CGFloat t = scaledPos - index;
17
78
 
18
- if (index >= _strokeColors.count - 1) {
19
- return _strokeColors.lastObject;
79
+ if (index >= _colorCacheCount - 1) {
80
+ *out = _colorCache[_colorCacheCount - 1];
81
+ return;
20
82
  }
21
83
 
22
- UIColor *c1 = _strokeColors[index];
23
- UIColor *c2 = _strokeColors[index + 1];
24
-
25
- CGFloat r1, g1, b1, a1, r2, g2, b2, a2;
26
- [c1 getRed:&r1 green:&g1 blue:&b1 alpha:&a1];
27
- [c2 getRed:&r2 green:&g2 blue:&b2 alpha:&a2];
84
+ RGBAComponents c1 = _colorCache[index];
85
+ RGBAComponents c2 = _colorCache[index + 1];
86
+ out->r = c1.r + (c2.r - c1.r) * t;
87
+ out->g = c1.g + (c2.g - c1.g) * t;
88
+ out->b = c1.b + (c2.b - c1.b) * t;
89
+ out->a = c1.a + (c2.a - c1.a) * t;
90
+ }
28
91
 
29
- return [UIColor colorWithRed:r1 + (r2 - r1) * t
30
- green:g1 + (g2 - g1) * t
31
- blue:b1 + (b2 - b1) * t
32
- alpha:a1 + (a2 - a1) * t];
92
+ - (UIColor *)colorAtGradientPosition:(CGFloat)position {
93
+ RGBAComponents rgba;
94
+ [self colorAtGradientPosition:position rgba:&rgba];
95
+ return [UIColor colorWithRed:rgba.r green:rgba.g blue:rgba.b alpha:rgba.a];
33
96
  }
34
97
 
35
98
  @end
@@ -12,6 +12,8 @@ NS_ASSUME_NONNULL_BEGIN
12
12
  (CLLocationCoordinate2D)centerCoordinate
13
13
  zoomLevel:(double)zoomLevel;
14
14
 
15
+ /// Returns the zoom level based on the full map region, not affected by
16
+ /// layoutMargins
15
17
  - (double)zoomLevel;
16
18
 
17
19
  @end