Skip to content

Instantly share code, notes, and snippets.

@avi-c
Created October 13, 2020 19:30
Show Gist options
  • Save avi-c/65c9879137424791e9b0f60ae8aab6de to your computer and use it in GitHub Desktop.
Save avi-c/65c9879137424791e9b0f60ae8aab6de to your computer and use it in GitHub Desktop.
Mapbox Maps SDK code snippet for a repeating, pulsing animation along a line. Shown here animating a route line from the Mapbox Navigation SDK
// Use runtime styling to animate a repeating pulsing animation on an MGLMapView
class MyAnimationDemoClass {
var animationTimer: Timer?
var lineLayers = [MGLLineStyleLayer]() // Array to hold the Line style layers we created so they can be reused to repeat the animation
// This function will animate a set of line segments and return the duration of the entire animation.
// The duration can be used to set up a repeating timer to trigger the animation again if you want it to loop
private func animateByStep(style: MGLStyle, shapes: [LineString]) -> TimeInterval {
guard shapes.count > 0 else { return 0 }
let fadeDuration = TimeInterval(0.3) // fade in duration
let interSegmentDelay = TimeInterval(0.075) // how much to delay one segment's fade beginning from the start of the previous segment's animation
var animationDuration = TimeInterval(0)
var i = 0
for shape in shapes {
// Create some kind of unique identifier for the layer so we can find it again for reuse
let identifier = "Line-\(shape.coordinates[0].latitude)-\(shape.coordinates[0].longitude)"
let lineLayer: MGLLineStyleLayer
if let existingLineLayer = style.layer(withIdentifier: identifier) as? MGLLineStyleLayer {
lineLayer = existingLineLayer
} else {
// No existing layer was found so we create an MGLShapeSource with the shape and add it to the style
// Then we create a line style layer for this shape
let lineFeature = MGLPolylineFeature(shape)
let linesSource = MGLShapeSource(identifier: identifier, features: [lineFeature], options: nil)
style.addSource(linesSource)
// set some line style properties to whatever we want
lineLayer = MGLLineStyleLayer(identifier: identifier, source: linesSource)
lineLayer.lineColor = NSExpression(forConstantValue: UIColor.white)
lineLayer.lineWidth = NSExpression(forConstantValue: NSNumber(8))
lineLayer.lineOpacity = NSExpression(forConstantValue: 0.0)
lineLayer.lineCap = NSExpression(forConstantValue: "round")
lineLayer.lineOpacityTransition = MGLTransition(duration: fadeDuration, delay: 0)
lineLayer.isVisible = true
style.addLayer(lineLayer)
lineLayers.append(lineLayer)
}
let startTime = DispatchTime.now() + interSegmentDelay * Double(i)
DispatchQueue.main.asyncAfter(deadline: startTime) {
lineLayer.lineOpacity = NSExpression(forConstantValue: 0.95)
DispatchQueue.main.asyncAfter(deadline: startTime + fadeDuration) {
lineLayer.lineOpacity = NSExpression(forConstantValue: 0.0)
}
}
i += 1
animationDuration = TimeInterval(shapes.count) * interSegmentDelay + 2 * fadeDuration
}
return animationDuration
}
// Animate a route line given a Route from the Mapbox Navigation SDK
// Assumes that the passed in MGLStyle is the current style on a visible MGLMapView
func beginAnimatingLine(style: MGLStyle, route: Route) {
if let routeStepShapes = route.legs.first?.steps.compactMap({ $0.shape }) {
let duration = animateByStep(style: style, shapes: routeStepShapes)
if duration > 0 {
animationTimer = Timer.scheduledTimer(withTimeInterval: duration, repeats: true, block: { [weak self] (timer) in
_ = self?.animateByStep(style: style, shapes: routeStepShapes)
})
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment