Created
October 13, 2020 19:30
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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