@@ -8,6 +8,7 @@ private let simulatedCoordinate = CLLocationCoordinate2D(latitude: 37.6421, long
88final class DynamicViewAnnotationExample : UIViewController , ExampleProtocol {
99 private var mapView : MapView !
1010 private var cancelables = Set < AnyCancelable > ( )
11+ private var puckRenderCancellable : AnyCancelable ?
1112
1213 private var routes = [ Route] ( ) {
1314 didSet {
@@ -21,8 +22,8 @@ final class DynamicViewAnnotationExample: UIViewController, ExampleProtocol {
2122 self ? . select ( route: route)
2223 }
2324 }
24- if let last = routes. last {
25- select ( route: last , animated: false )
25+ if let first = routes. first {
26+ select ( route: first , animated: false )
2627 }
2728 }
2829 }
@@ -56,13 +57,6 @@ final class DynamicViewAnnotationExample: UIViewController, ExampleProtocol {
5657
5758 updateModeButton ( )
5859
59- mapView. location. override (
60- locationProvider: Signal ( just: [
61- Location (
62- coordinate: simulatedCoordinate,
63- bearing: 168.8 )
64- ] ) ,
65- headingProvider: Signal ( just: Heading ( direction: 180 , accuracy: 0 ) ) )
6660 mapView. location. options = LocationOptions ( puckType: . puck2D( . init( topImage: UIImage ( named: " dash-puck " ) ) ) , puckBearing: . heading, puckBearingEnabled: true )
6761
6862 mapView. viewport. options. usesSafeAreaInsetsAsPadding = true
@@ -101,6 +95,49 @@ final class DynamicViewAnnotationExample: UIViewController, ExampleProtocol {
10195 }
10296 }
10397
98+ private func setupLocationSimulation( route: Route ) {
99+ guard case Turf . Geometry . lineString( let line) = route. feature. geometry! else {
100+ return
101+ }
102+
103+ var coordinates = line. coordinates
104+ var lastLocation : CLLocationCoordinate2D = coordinates. first!
105+
106+ var locationHandler : ( ( [ Location ] ) -> Void ) ?
107+ var headingHandler : ( ( Heading ) -> Void ) ?
108+ var timer : Timer ?
109+ let locationSignal : Signal < [ Location ] > = Signal { handler in
110+ locationHandler = handler
111+ return AnyCancelable {
112+ timer? . invalidate ( )
113+ }
114+ }
115+ let headingSignal : Signal < Heading > = Signal { handler in
116+ headingHandler = handler
117+ return AnyCancelable { }
118+ }
119+
120+ timer = Timer . scheduledTimer ( withTimeInterval: 1 , repeats: true ) { timer in
121+ guard !coordinates. isEmpty else {
122+ timer. invalidate ( )
123+ return
124+ }
125+ let currentLocation = coordinates. removeFirst ( )
126+ let currentDirection = lastLocation. direction ( to: currentLocation)
127+
128+ locationHandler ? ( [ Location ( coordinate: lastLocation) ] )
129+ headingHandler ? ( Heading ( direction: currentDirection, accuracy: 0 ) )
130+
131+ lastLocation = currentLocation
132+ }
133+
134+ mapView. location. override ( locationProvider: locationSignal, headingProvider: headingSignal)
135+
136+ puckRenderCancellable = mapView. location. onPuckRender. observe { data in
137+ route. updateProgress ( with: data. location. coordinate)
138+ }
139+ }
140+
104141 private func select( route: Route , animated: Bool = true ) {
105142 // Move selected route layer on top of unselected route layers
106143 let routeLayersIds = Set ( routes. map ( \. layerId) )
@@ -118,35 +155,36 @@ final class DynamicViewAnnotationExample: UIViewController, ExampleProtocol {
118155 if !driveMode {
119156 updateViewport ( animated: animated)
120157 }
158+ setupLocationSimulation ( route: route)
121159 }
122160
123161 @objc private func changeMode( ) {
124162 self . driveMode. toggle ( )
125163 updateModeButton ( )
126164
127- hideAnnotations ( true )
128165 updateViewport ( animated: true ) { [ weak self] in
129- self ? . hideAnnotations ( false )
130- }
131- routes. forEach {
132- $0. updateProgress ( with: driveMode ? simulatedCoordinate : nil )
166+ guard let self else { return }
167+
168+ self . hideInactiveRoutes ( self . driveMode)
133169 }
134170 }
135171
136172 private func updateModeButton( ) {
137- modeButton. setTitle ( " Mode: \( driveMode ? " Drive " : " Overview " ) " , for: . normal)
173+ modeButton. setTitle ( " Mode: \( driveMode ? " Overview " : " Drive " ) " , for: . normal)
138174 }
139175
140- private func hideAnnotations ( _ hidden: Bool ) {
176+ private func hideInactiveRoutes ( _ hidden: Bool ) {
141177 routes. forEach {
142- $0. etaAnnotation ? . visible = ! hidden
178+ $0. visible = $0 . selected || hidden
143179 }
144180 }
145181
146182 private func updateViewport( animated: Bool , completion: ( ( ) -> Void ) ? = nil ) {
147183 var viewportState : ViewportState ?
148184 if driveMode {
149- viewportState = mapView. viewport. makeFollowPuckViewportState ( options: . init( zoom: 17 , bearing: . course, pitch: 49 ) )
185+ viewportState = mapView. viewport. makeFollowPuckViewportState ( options:
186+ . init( padding: . init( top: 100 , left: 100 , bottom: 100 , right: 100 ) , zoom: 18 , bearing: . heading, pitch: 70 )
187+ )
150188 } else {
151189 if let route = routes. first ( where: \. selected) , let geometry = route. feature. geometry {
152190 let coordPadding = UIEdgeInsets ( allEdges: 20 )
@@ -199,6 +237,9 @@ private final class Route {
199237 var selected : Bool = false {
200238 didSet { updateSelected ( ) }
201239 }
240+ var visible = true {
241+ didSet { updateVisible ( ) }
242+ }
202243 var layerId : String { " route- \( name) " }
203244 private( set) var etaAnnotation : ViewAnnotation ?
204245 private var etaView : ETAView ?
@@ -220,7 +261,7 @@ private final class Route {
220261 case let . lineString( s) = feature. geometry,
221262 let doneDistance = s. distance ( to: coordinate) ,
222263 let length = s. distance ( ) {
223- progress = doneDistance / length + 0.0005
264+ progress = doneDistance / length
224265 }
225266
226267 try ? mapView? . mapboxMap. setLayerProperty ( for: layerId, property: " line-trim-offset " , value: [ 0 , progress] )
@@ -304,6 +345,10 @@ private final class Route {
304345 etaAnnotation? . setNeedsUpdateSize ( )
305346 }
306347
348+ private func updateVisible( ) {
349+ try ? mapView? . mapboxMap. setLayerProperty ( for: layerId, property: " visibility " , value: visible ? " visible " : " none " )
350+ }
351+
307352 static func load( name: String , time: String ) -> Route {
308353 let data = NSDataAsset ( name: name) !. data
309354 let feature = try ! JSONDecoder ( ) . decode ( Feature . self, from: data)
0 commit comments