Search code examples
swiftwidthmapkit

How can I draw polylines with constant width when in .satelliteFlyover mode?


I have polylines drawn with mapView.mapType set to .satelliteFlyover. Using a generic MKOverlayRenderer method the lines are not a constant width.

enter image description here

ChatGPT came up with some code that actually works.. to a point. I had to modify a few lines but it does what I want it to do. It subclasses MKPolylineRenderer:

class CustomPolylineRenderer: MKPolylineRenderer {
    override func draw(_ mapRect: MKMapRect, zoomScale: MKZoomScale, in context: CGContext) {
        super.draw(mapRect, zoomScale: zoomScale, in: context)
        let path = UIBezierPath(cgPath: self.path)
        context.addPath(path.cgPath)
        context.setStrokeColor(UIColor.green.cgColor)
        let lineWidth: CGFloat = 170
        context.setLineWidth(lineWidth)
        context.strokePath()
    }
}

After creating the polyline it's call with the mapView delegate:

    func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
        let polyline = overlay as? MKPolyline

            return CustomPolylineRenderer(overlay: polyline!)
}

enter image description here

This works great but the issue is that I can't figure out how to change the width or color of the line within the CustomPolylineRenderer class. So really my quesiton is how do you create a polyline that doesn't change width when uing .satelliteFlyover?


Solution

  • MKPolylineRenderer already has fillColor and lineWidth properties (via MKOverlayPathRenderer) so you can make use of those:

    class CustomPolylineRenderer: MKPolylineRenderer {
        override func draw(_ mapRect: MKMapRect, zoomScale: MKZoomScale, in context: CGContext) {
            super.draw(mapRect, zoomScale: zoomScale, in: context)
    
            let path = UIBezierPath(cgPath: self.path)
            context.addPath(path.cgPath)
            context.setStrokeColor((fillColor ?? .green).cgColor)
            context.setLineWidth(lineWidth)
            context.strokePath()
        }
    }
    

    Example usage:

    func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
        let polyline = overlay as? MKPolyline
    
        let renderer = CustomPolylineRenderer(overlay: polyline!)
        renderer.fillColor = .blue
        renderer.lineWidth = 110
        return renderer
    }