Skip to content

Commit

Permalink
Updates for review feedback. Expose more styling properties of the Ro…
Browse files Browse the repository at this point in the history
…ute Duration Annotations via the Style mechanism. Add more documentation.
  • Loading branch information
avi-c committed Jan 20, 2021
1 parent dec8a5d commit 8a60ad8
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 29 deletions.
15 changes: 9 additions & 6 deletions MapboxNavigation/Array.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,17 @@ extension Array where Element == RouteStep {
func continuousShape(tolerance: CLLocationDistance = 100) -> LineString? {
guard count > 0 else { return nil }
guard count > 1 else { return self[0].shape }
var continuousLine = [CLLocationCoordinate2D]()

for index in 0...count-2 {
if let currentStepFinalCoordinate = self[index].shape?.coordinates.last, currentStepFinalCoordinate.distance(to: self[index+1].maneuverLocation) < tolerance, let coordinates = self[index].shape?.coordinates {
continuousLine.append(contentsOf: coordinates)
}
let filteredStepShapes = zip(compactMap { $0.shape }, suffix(from: 1).compactMap { $0.shape }).filter({
guard let maneuverLocation = $1.coordinates.first else { return false }

return $0.coordinates.last?.distance(to: maneuverLocation) ?? Double.greatestFiniteMagnitude < tolerance
})

let coordinates = filteredStepShapes.flatMap { (firstLine, secondLine) -> [CLLocationCoordinate2D] in
return firstLine.coordinates
}

return LineString(continuousLine)
return LineString(coordinates)
}
}
13 changes: 11 additions & 2 deletions MapboxNavigation/DayStyle.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,12 @@ extension UIColor {
class var defaultBuildingColor: UIColor { get { return #colorLiteral(red: 0.9833194452, green: 0.9843137255, blue: 0.9331936657, alpha: 0.8019049658) } }
class var defaultBuildingHighlightColor: UIColor { get { return #colorLiteral(red: 0.337254902, green: 0.6588235294, blue: 0.9843137255, alpha: 0.949406036) } }

class var defaultRouteDurationAnnotationSelectedColor: UIColor { get { return #colorLiteral(red: 0.337254902, green: 0.6588235294, blue: 0.9843137255, alpha: 1) } }
class var routeDurationAnnotationColor: UIColor { get { return #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1) } }
class var selectedRouteDurationAnnotationColor: UIColor { get { return #colorLiteral(red: 0.337254902, green: 0.6588235294, blue: 0.9843137255, alpha: 1) } }

class var routeDurationAnnotationTextColor: UIColor { get { return #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1) } }
class var selectedRouteDurationAnnotationTextColor: UIColor { get { return #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1) } }

}

extension UIColor {
Expand Down Expand Up @@ -150,7 +155,11 @@ open class DayStyle: Style {
NavigationMapView.appearance().trafficUnknownColor = .trafficUnknown
NavigationMapView.appearance().buildingDefaultColor = .defaultBuildingColor
NavigationMapView.appearance().buildingHighlightColor = .defaultBuildingHighlightColor
NavigationMapView.appearance().routeDurationAnnotationSelectedColor = .defaultRouteDurationAnnotationSelectedColor
NavigationMapView.appearance().routeDurationAnnotationColor = .routeDurationAnnotationColor
NavigationMapView.appearance().routeDurationAnnotationSelectedColor = .selectedRouteDurationAnnotationColor
NavigationMapView.appearance().routeDurationAnnotationFontName = "DIN Pro Medium"
NavigationMapView.appearance().routeDurationAnnotationTextColor = #colorLiteral(red: 0.09803921569, green: 0.09803921569, blue: 0.09803921569, alpha: 1)
NavigationMapView.appearance().routeDurationAnnotationSelectedTextColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
NavigationView.appearance().backgroundColor = #colorLiteral(red: 0.764706, green: 0.752941, blue: 0.733333, alpha: 1)
NextBannerView.appearance().backgroundColor = #colorLiteral(red: 0.9675388083, green: 0.9675388083, blue: 0.9675388083, alpha: 1)
NextBannerView.appearance(whenContainedInInstancesOf:[InstructionsCardContainerView.self]).backgroundColor = #colorLiteral(red: 0.9675388083, green: 0.9675388083, blue: 0.9675388083, alpha: 1)
Expand Down
67 changes: 46 additions & 21 deletions MapboxNavigation/NavigationMapView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ open class NavigationMapView: MGLMapView, UIGestureRecognizerDelegate {
static let instruction = "\(identifierNamespace).instruction"

static let buildingExtrusion = "\(identifierNamespace).buildingExtrusion"
static let routeDurationAnnotations = "\(identifierNamespace).RouteDurationAnnotations"
}

struct StyleLayerIdentifier {
Expand All @@ -99,6 +100,7 @@ open class NavigationMapView: MGLMapView, UIGestureRecognizerDelegate {
static let instructionCircle = "\(identifierNamespace).instructionCircle"

static let buildingExtrusion = "\(identifierNamespace).buildingExtrusion"
static let routeDurationAnnotations = "\(identifierNamespace).RouteDurationAnnotations"
}

enum IdentifierType: Int {
Expand Down Expand Up @@ -129,8 +131,11 @@ open class NavigationMapView: MGLMapView, UIGestureRecognizerDelegate {
}
}

@objc dynamic public var routeDurationAnnotationSelectedColor: UIColor = .defaultRouteDurationAnnotationSelectedColor

@objc dynamic public var routeDurationAnnotationSelectedColor: UIColor = .selectedRouteDurationAnnotationColor
@objc dynamic public var routeDurationAnnotationColor: UIColor = .routeDurationAnnotationColor
@objc dynamic public var routeDurationAnnotationSelectedTextColor: UIColor = .selectedRouteDurationAnnotationTextColor
@objc dynamic public var routeDurationAnnotationTextColor: UIColor = .routeDurationAnnotationTextColor
@objc dynamic public var routeDurationAnnotationFontName: String = "DIN Pro Medium"
var userLocationForCourseTracking: CLLocation?
var animatesUserLocation: Bool = false
var altitude: CLLocationDistance
Expand Down Expand Up @@ -961,35 +966,48 @@ open class NavigationMapView: MGLMapView, UIGestureRecognizerDelegate {
].compactMap { style.source(withIdentifier: $0) }))
}

/**
Shows a callout containing the duration of each route.
Useful as a way to give the user more information when picking between multiple route alternatives.
If the route contains any tolled segments then the callout will specify that as well.
*/
public func showRouteDurationAnnotations(_ routes: [Route]?) {
guard let style = style else { return }
updateAnnotationSymbolImages(style)
updateRouteDurationAnnotations(routes, style: style)
guard let visibleRoutes = self.routes, visibleRoutes.count > 0 else { return }
updateAnnotationSymbolImages()
updateRouteDurationAnnotations(routes)
}

private func updateAnnotationSymbolImages(_ style: MGLStyle) {
guard style.image(forName: "RouteInfoAnnotationLeftHanded") == nil, style.image(forName: "RouteInfoAnnotationRightHanded") == nil else { return }
/**
Updates the image assets in the map style for the route duration annotations. Useful when the desired callout colors change, such as when transitioning between light and dark mode on iOS 13 and later.
*/
private func updateAnnotationSymbolImages() {
guard let style = style, style.image(forName: "RouteInfoAnnotationLeftHanded") == nil, style.image(forName: "RouteInfoAnnotationRightHanded") == nil else { return }
let capInsetHeight = CGFloat(22)
let capInsetWidth = CGFloat(11)
let capInsets = UIEdgeInsets(top: capInsetHeight, left: capInsetWidth, bottom: capInsetHeight, right: capInsetWidth)
if let image = Bundle.mapboxNavigation.image(named: "RouteInfoAnnotationLeftHanded") {
let regularRouteImage = image.tint(UIColor.white).resizableImage(withCapInsets: capInsets, resizingMode: .stretch)
let regularRouteImage = image.tint(routeDurationAnnotationColor).resizableImage(withCapInsets: capInsets, resizingMode: .stretch)
style.setImage(regularRouteImage, forName: "RouteInfoAnnotationLeftHanded")

let selectedRouteImage = image.tint(routeDurationAnnotationSelectedColor).resizableImage(withCapInsets: capInsets, resizingMode: .stretch)
style.setImage(selectedRouteImage, forName: "RouteInfoAnnotationLeftHanded-Selected")
}

if let image = Bundle.mapboxNavigation.image(named: "RouteInfoAnnotationRightHanded") {
let regularRouteImage = image.tint(UIColor.white).resizableImage(withCapInsets: capInsets, resizingMode: .stretch)
let regularRouteImage = image.tint(routeDurationAnnotationColor).resizableImage(withCapInsets: capInsets, resizingMode: .stretch)
style.setImage(regularRouteImage, forName: "RouteInfoAnnotationRightHanded")

let selectedRouteImage = image.tint(routeDurationAnnotationSelectedColor).resizableImage(withCapInsets: capInsets, resizingMode: .stretch)
style.setImage(selectedRouteImage, forName: "RouteInfoAnnotationRightHanded-Selected")
}
}

private func updateRouteDurationAnnotations(_ routes: [Route]?, style: MGLStyle) {
/**
Remove any old route duration callouts and generate new ones for each passed in route.
*/
private func updateRouteDurationAnnotations(_ routes: [Route]?) {
guard let style = style else { return }

// remove any existing route annotation
removeRouteDurationAnnotationsLayerFromStyle(style)

Expand Down Expand Up @@ -1093,24 +1111,25 @@ open class NavigationMapView: MGLMapView, UIGestureRecognizerDelegate {
self.addRouteAnnotationSymbolLayer(features: features)
}

private let annotationLayerIdentifier = "RouteDurationAnnotations"

/**
Add the MGLSymbolStyleLayer for the route duration annotations.
*/
private func addRouteAnnotationSymbolLayer(features: [MGLPointFeature]) {
guard let style = style else { return }
let dataSource: MGLShapeSource
if let source = style.source(withIdentifier: annotationLayerIdentifier + "-source") as? MGLShapeSource {
if let source = style.source(withIdentifier: SourceIdentifier.routeDurationAnnotations) as? MGLShapeSource {
dataSource = source
} else {
dataSource = MGLShapeSource(identifier: annotationLayerIdentifier + "-source", features: features, options: nil)
dataSource = MGLShapeSource(identifier: SourceIdentifier.routeDurationAnnotations, features: features, options: nil)
style.addSource(dataSource)
}

let shapeLayer: MGLSymbolStyleLayer

if let layer = style.layer(withIdentifier: annotationLayerIdentifier + "-shape") as? MGLSymbolStyleLayer {
if let layer = style.layer(withIdentifier: StyleLayerIdentifier.routeDurationAnnotations) as? MGLSymbolStyleLayer {
shapeLayer = layer
} else {
shapeLayer = MGLSymbolStyleLayer(identifier: annotationLayerIdentifier + "-shape", source: dataSource)
shapeLayer = MGLSymbolStyleLayer(identifier: StyleLayerIdentifier.routeDurationAnnotations, source: dataSource)
}

shapeLayer.text = NSExpression(forKeyPath: "text")
Expand All @@ -1121,10 +1140,10 @@ open class NavigationMapView: MGLMapView, UIGestureRecognizerDelegate {
shapeLayer.textFontSize = NSExpression(format: "mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", fontSizeByZoomLevel)

shapeLayer.textColor = NSExpression(forConditional: NSPredicate(format: "selected == true"),
trueExpression: NSExpression(forConstantValue: UIColor.white),
falseExpression: NSExpression(forConstantValue: UIColor.black))
trueExpression: NSExpression(forConstantValue: routeDurationAnnotationSelectedTextColor),
falseExpression: NSExpression(forConstantValue: routeDurationAnnotationTextColor))

shapeLayer.textFontNames = NSExpression(forConstantValue: ["DIN Pro Medium"])
shapeLayer.textFontNames = NSExpression(forConstantValue: [self.routeDurationAnnotationFontName])
shapeLayer.textAllowsOverlap = NSExpression(forConstantValue: true)
shapeLayer.textJustification = NSExpression(forConstantValue: "left")
shapeLayer.symbolZOrder = NSExpression(forConstantValue: NSValue(mglSymbolZOrder: MGLSymbolZOrder.auto))
Expand All @@ -1147,17 +1166,23 @@ open class NavigationMapView: MGLMapView, UIGestureRecognizerDelegate {
style.addLayer(shapeLayer)
}

/**
Removes all visible route duration callouts.
*/
public func removeRouteDurationAnnotations() {
guard let style = style else { return }
removeRouteDurationAnnotationsLayerFromStyle(style)
}

/**
Remove the underlying style layers and data sources for the route duration annotations.
*/
private func removeRouteDurationAnnotationsLayerFromStyle(_ style: MGLStyle) {
if let annotationsLayer = style.layer(withIdentifier: annotationLayerIdentifier + "-shape") {
if let annotationsLayer = style.layer(withIdentifier: StyleLayerIdentifier.routeDurationAnnotations) {
style.removeLayer(annotationsLayer)
}

if let annotationsSource = style.source(withIdentifier: annotationLayerIdentifier + "-source") {
if let annotationsSource = style.source(withIdentifier: SourceIdentifier.routeDurationAnnotations) {
style.removeSource(annotationsSource)
}
}
Expand Down

0 comments on commit 8a60ad8

Please sign in to comment.