Want to draw a PolyLine from userLocation to multiple marker. In my code already added markers coordinates in a array then added userLocation into 0th position of that array. Now I want to draw a route polyLine between array elements. My code is given below...
self.coods.append(self.currentLocation)
let jsonResponse = response.data
do{
let json = try JSON(data: jsonResponse!)
self.dictXYZ = [json]
print("JsonResponse printed \(json["data"][0]["lattitude"])")
if let array = json["data"].array{
for i in 0..<array.count{
var coordinate = CLLocationCoordinate2D()
coordinate.latitude = array[i]["lattitude"].doubleValue
coordinate.longitude = array[i]["longitude"].doubleValue
self.coods.append(coordinate)
}
for j in self.coods {
let marker = GMSMarker()
marker.position = j
let camera = GMSCameraPosition.camera(withLatitude: j.latitude, longitude: j.longitude, zoom: 12)
self.mapView.camera = camera
marker.map = self.mapView
}
let path = GMSMutablePath()
for j in self.coods {
path.add(j)
}
let polyline = GMSPolyline(path: path)
polyline.map = mapView
In the Google Developer Docs.
Waypoints - Specifies an array of intermediate locations to include along the route between the origin and destination points as
pass through or stopover locations. Waypoints alter a route by
directing it through the specified location(s). The API supports
waypoints for these travel modes: driving, walking and bicycling; not
transit.
First you need to create a waypoints for all intermediate locations to add the route between the source and destination. With that polyline you can create a GMSPath and then draw the route by using GMSPolyline. I hope below solution can help you to draw a route for multiple locations.
func getPolylineRoute(from source: CLLocationCoordinate2D, to destinations: [CLLocationCoordinate2D], completionHandler: #escaping (Bool, String) -> ()) {
guard let destination = destinations.last else {
return
}
var wayPoints = ""
for (index, point) in destinations.enumerated() {
if index == 0 { // Skipping first location that is current location.
continue.
}
wayPoints = wayPoints.count == 0 ? "\(point.latitude),\(point.longitude)" : "\(wayPoints)%7C\(point.latitude),\(point.longitude)"
}
let url = URL(string: "https://maps.googleapis.com/maps/api/directions/json?origin=\(source.latitude),\(source.longitude)&destination=\(destination.latitude),\(destination.longitude)&sensor=true&mode=driving&waypoints=\(wayPoints)&key=\(GOOGLE_API_KEY)")!
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
if error != nil {
print("Failed : \(String(describing: error?.localizedDescription))")
return
} else {
do {
if let json: [String: Any] = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String: Any] {
guard let routes = json["routes"] as? [[String: Any]] else { return }
if (routes.count > 0) {
let overview_polyline = routes[0]
let dictPolyline = overview_polyline["overview_polyline"] as? NSDictionary
let points = dictPolyline?.object(forKey: "points") as? String
completionHandler(true, points!)
} else {
completionHandler(false, "")
}
}
} catch {
print("Error : \(error)")
}
}
}
task.resume()
}
Pass the current location and destination array of locations to getPolylineRoute method. Then call the drawPolyline method with polyline points from main thread.
getPolylineRoute(from: coods[0], to: coods) { (isSuccess, polylinePoints) in
if isSuccess {
DispatchQueue.main.async {
self.drawPolyline(withMapView: self.mapView, withPolylinePoints: polylinePoints)
}
} else {
print("Falied to draw polyline")
}
}
func drawPolyline(withMapView googleMapView: GMSMapView, withPolylinePoints polylinePoints: String){
path = GMSPath(fromEncodedPath: polylinePoints)!
let polyline = GMSPolyline(path: path)
polyline.strokeWidth = 3.0
polyline.strokeColor = .lightGray
polyline.map = googleMapView
}
First create GMSPath object
let path = GMSMutablePath()
self.coods.forEach {
path.add(coordinate: $0)
}
https://developers.google.com/maps/documentation/ios-sdk/reference/interface_g_m_s_mutable_path.html#af62038ea1a9da3faa7807b8d22e72ffb
Then Create GMSPolyline object using path
let pathLine = GMSPolyline.with(path: path)
pathLine.map = self.mapView
https://developers.google.com/maps/documentation/ios-sdk/reference/interface_g_m_s_polyline.html#ace1dd6e6bab9295b3423712d2eed90a4
Related
Basically, I have searched a lot but mostly answer are for javaScrip and I want some code example in swift and according to google we can not use more than 25 way points in a single request
I already have seen, the links blow.
StackOverFlow.
Documentation
How to draw polyline using more than hundred waypoints (may be more than 300) swift 5?
I am using GoogleMaps.
My code and api.
func getDotsToDrawRoute(positions: [CLLocationCoordinate2D]) {
if positions.count > 0 {
let origin = positions.first
let destination = positions.last
var wayPoint = ""
var wayPoints: [String] = []
for point in positions {
wayPoint = wayPoint.count == 0 ? "\(point.latitude), \(point.longitude)" : "\(wayPoint)|\(point.latitude), \(point.longitude)"
wayPoints.append(wayPoint)
}
print("exactWayPoint:\(wayPoint)")
print("exactWayPoint:\(wayPoints)")
let stringURL = "https://maps.googleapis.com/maps/api/directions/json?origin=\(origin!.latitude),\(origin!.longitude)&destination=\(destination!.latitude),\(destination!.longitude)&wayPoints=\(wayPoints)&key=\(Google_API_Key)&sensor=false&mode=walking&waypoints"
let url = URL(string: stringURL.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!)!
let task = URLSession.shared.dataTask(with: url, completionHandler: { (data, response, error) in
if error != nil {
print("error in task: \(error!.localizedDescription)")
} else {
do {
if let dictionary: [String: Any] = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String: Any] {
print("Dictionary: \(dictionary)")
if let routes = dictionary["routes"] as? [[String: Any]] {
if routes.count > 0 {
let first = routes.first
if let legs = first!["legs"] as? [[String: Any]] {
let fullPath: GMSMutablePath = GMSMutablePath()
for leg in legs {
if let steps = leg["steps"] as? [[String: Any]] {
for step in steps {
if let polyline = step["polyline"] as? [String: Any] {
if let points = polyline["points"] as? String {
fullPath.appendPath(path: GMSMutablePath(fromEncodedPath: points))
self.drawRoutes(polyStr: points)
}
}
}
}
}
}
}
}
}
} catch let parseError {
print("JSON Error: \(parseError.localizedDescription)")
}
}
})
task.resume()
} else {
showAlert(title: "OOps!", message: "No data found")
}
}
func drawRoutes(polyStr: String) {
if let path = GMSPath.init(fromEncodedPath: polyStr) {
let polyline = GMSPolyline.init(path: path)
polyline.path = path
polyline.strokeWidth = 4.0
polyline.strokeColor = .blue
polyline.geodesic = true
self.mapView?.isMyLocationEnabled = true
polyline.map = self.mapView
} else {
print("path is nill")
}
}
// MARK - PATHDelegate
extension GMSMutablePath {
func appendPath(path: GMSPath?) {
if let path = path {
for i in 0..<path.count() {
self.add(path.coordinate(at: i))
}
}
}
}
I'm using an API to get latitude and longitude coordinates and place them on a map with the name of the place it corresponds to. I'm able to put one place's lat and long coordinates but I'm not too sure how to add all of them to a map. I can't get my head around how to do it. I've tried to use a for loop to do it but I'm too sure on how I would implement it. This is what I've got so far:
func getData() {
let url = "https://www.givefood.org.uk/api/2/foodbanks/"
let task = URLSession.shared.dataTask(with: URL(string: url)!, completionHandler: { [self] data, response, error in
guard let data = data, error == nil else {
print("Wrong")
return
}
var result: [Info]?
do {
result = try JSONDecoder().decode([Info].self, from: data)
}
catch {
print("Failed to convert: \(error.localizedDescription)")
}
guard let json = result else {
return
}
for each in json {
var each = 0
each += 1
let comp = json[each].lat_lng?.components(separatedBy: ",")
let latString = comp![each]
let lonString = comp![each]
let lat = Double(latString)
let lon = Double(lonString)
let locationPin: CLLocationCoordinate2D = CLLocationCoordinate2DMake(lat!, lon!)
let location: CLLocationCoordinate2D = CLLocationCoordinate2DMake(51.55573, -0.108312)
let region = MKCoordinateRegion.init(center: location, latitudinalMeters: regionInMetres, longitudinalMeters: regionInMetres)
mapView.setRegion(region, animated: true)
let myAn1 = MapPin(title: json[each].name!, locationName: json[each].name!, coordinate: locationPin)
mapView.addAnnotations([myAn1])
}
})
task.resume()
}
Your loop is wrong, each after for is one Info item. The Int index each is pointless and you set it in each iteration to zero so you get always the same coordinate (at index 1).
First of all declare name and lat_lng as non-optional. All records contain both fields.
struct Info : Decodable {
let lat_lng : String
let name : String
}
Second of all for convenience reasons extend CLLocationCoordinate2D to create a coordinate from a string
extension CLLocationCoordinate2D {
init?(string: String) {
let comp = string.components(separatedBy: ",")
guard comp.count == 2, let lat = Double(comp[0]), let lon = Double(comp[1]) else { return nil }
self.init(latitude: lat, longitude: lon )
}
}
Third of all put all good code into the do scope instead of dealing with optionals and set the region once before the loop
func getData() {
let url = "https://www.givefood.org.uk/api/2/foodbanks/"
let task = URLSession.shared.dataTask(with: URL(string: url)!, completionHandler: { [self] data, response, error in
if let error = error { print(error); return }
do {
let result = try JSONDecoder().decode([Info].self, from: data!)
let location = CLLocationCoordinate2D(latitude: 51.55573, longitude: -0.108312)
let region = MKCoordinateRegion.init(center: location, latitudinalMeters: regionInMetres, longitudinalMeters: regionInMetres)
mapView.setRegion(region, animated: true)
var pins = [MapPin]()
for info in result {
if let coordinate = CLLocationCoordinate2D(string: info.lat_lng) {
pins.append(MapPin(title: info.name, locationName: info.name, coordinate: coordinate))
}
}
DispatchQueue.main.async {
self.mapView.addAnnotations(pins)
}
}
catch {
print("Failed to convert: \(error)")
}
})
task.resume()
}
I have this code but for some reason it's just drawing a rout between 2 points (first, and last points) ignoring all other points which is [index == 1 to index == n-1 ]
output : route between only 2 markers
expected output : route between all markers (5 markers)
Is any body knows what is the wrong with my code ?
func getDotsToDrawRoute(positions : [CLLocationCoordinate2D], completion: #escaping(_ path : GMSPath) -> Void) {
if positions.count > 1 {
let origin = positions.first
let destination = positions.last
var wayPoints = ""
for point in positions {
wayPoints = wayPoints.characters.count == 0 ? "\(point.latitude),\(point.longitude)" : "\(wayPoints)|\(point.latitude),\(point.longitude)"
}
print("this is fullPath :: \(wayPoints)")
let request = "https://maps.googleapis.com/maps/api/directions/json"
let parameters : [String : String] = ["origin" : "\(origin!.latitude),\(origin!.longitude)", "destination" : "\(destination!.latitude),\(destination!.longitude)", "wayPoints" : wayPoints, "stopover": "true", "key" : kyes.google_map]
Alamofire.request(request, method:.get, parameters : parameters).responseJSON(completionHandler: { response in
guard let dictionary = response.result.value as? [String : AnyObject]
else {
return
}
print ("route iss ::: \(dictionary["routes"])")
if let routes = dictionary["routes"] as? [[String : AnyObject]] {
if routes.count > 0 {
var first = routes.first
if let legs = first!["legs"] as? [[String : AnyObject]] {
let fullPath : GMSMutablePath = GMSMutablePath()
for leg in legs {
if let steps = leg["steps"] as? [[String : AnyObject]] {
for step in steps {
if let polyline = step["polyline"] as? [String : AnyObject] {
if let points = polyline["points"] as? String {
fullPath.appendPath(path: GMSMutablePath(fromEncodedPath: points))
}
}
}
let polyline = GMSPolyline.init(path: fullPath)
polyline.path = fullPath
polyline.strokeWidth = 4.0
polyline.map = self._map }
}
}
}
}
})
}
}
Check out this solution working fine with me
func drawpath(positions: [CLLocationCoordinate2D]) {
let origin = positions.first!
let destination = positions.last!
var wayPoints = ""
for point in positions {
wayPoints = wayPoints.characters.count == 0 ? "\(point.latitude),\(point.longitude)" : "\(wayPoints)%7C\(point.latitude),\(point.longitude)"
}
let url = "https://maps.googleapis.com/maps/api/directions/json?origin=\(origin!.latitude),\(origin!.longitude)&destination=\(destination.latitude),\(destination.longitude)&mode=driving&waypoints=\(wayPoints)&key=KEY"
Alamofire.request(url).responseJSON { response in
print(response.request as Any) // original URL request
print(response.response as Any) // HTTP URL response
print(response.data as Any) // server data
print(response.result as Any) // result of response serialization
let json = try! JSON(data: response.data!)
let routes = json["routes"][0]["overview_polyline"]["points"].stringValue
let path = GMSPath.init(fromEncodedPath: routes)
let polyline = GMSPolyline.init(path: path)
polyline.strokeWidth = 4
polyline.strokeColor = UIColor.red
polyline.map = self._map
}
}
try with:
func getPolylineRoute(from source: CLLocationCoordinate2D, to destination: CLLocationCoordinate2D){
self.mapView.clear()
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)
let url = URL(string: "https://maps.googleapis.com/maps/api/directions/json?origin=\(source.latitude),\(source.longitude)&destination=\(destination.latitude),\(destination.longitude)&sensor=true&mode=driving&key=YOUR_API_KEY")!
let task = session.dataTask(with: url, completionHandler: {
(data, response, error) in
if error != nil {
print("Error" + error!.localizedDescription)
}else {
do {
if let json : [String:Any] = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String: Any]{
guard let routes = json["routes"] as? NSArray else {
return
}
print(routes)
if (routes.count > 0) {
let overview_polyline = routes[0] as? NSDictionary
let dictPolyline = overview_polyline?["overview_polyline"] as? NSDictionary
let points = dictPolyline?.object(forKey: "points") as? String
self.showPath(polyStr: points!)
let distancia = overview_polyline?["legs"] as? NSArray
let prueba = distancia![0] as? NSDictionary
let distancia2 = prueba?["distance"] as? NSDictionary
let control = distancia2?.object(forKey: "text") as! String
DispatchQueue.main.async {
let bounds = GMSCoordinateBounds(coordinate: source, coordinate: destination)
let update = GMSCameraUpdate.fit(bounds, with: UIEdgeInsetsMake(170, 30, 30, 30))
self.mapView!.moveCamera(update)
}
}
}
}
catch {
print("error in JSONSerialization")
}
}
})
task.resume()
}
You call the method with
self.getPolylineRoute(from: origin, to: destination)
Remember in the google url to put your api key where it says YOUR_API_KEY
You can use this function for drawing the polyline which covers your waypoints.
Make sure that positions doesn't have same waypoint coordinates. If
so, it will just draw the polylines from source to destination
func drawPolyLine(for positions: [CLLocationCoordinate2D]) {
let origin = positions.first!
let destination = positions.last!
var wayPoints = ""
for point in positions {
wayPoints = wayPoints.count == 0 ? "\(point.latitude),\(point.longitude)" : "\(wayPoints)%7C\(point.latitude),\(point.longitude)"
}
let url = "https://maps.googleapis.com/maps/api/directions/json?origin=\(origin.latitude),\(origin.longitude)&destination=\(destination.latitude),\(destination.longitude)&mode=driving&waypoints=\(wayPoints)&key=\(YOUR_GOOLE_MAP_API_KEY)"
Alamofire.request(url).responseJSON { response in
do {
let json = try JSONSerialization.jsonObject(with: response.data!, options: .allowFragments) as? [String: Any]
guard let routes = json?["routes"] as? NSArray else {
return
}
for route in routes {
let routeOverviewPolyline: NSDictionary = ((route as? NSDictionary)!.value(forKey: "overview_polyline") as? NSDictionary)!
let points = routeOverviewPolyline.object(forKey: "points")
let path = GMSPath.init(fromEncodedPath: (points! as? String)!)
let polyline = GMSPolyline.init(path: path)
polyline.strokeWidth = 4
polyline.strokeColor = UIColor(red: 95/255.0, green: 233/255.0, blue: 188/255.0, alpha: 1.0)
polyline.map = self.mapView
}
} catch {
print("Unexpected Error")
}
}
}
I am trying to draw route between two places using Google Maps on a custom UIView but not able to get it correctly implemented. My custom view is mapViewX. I've installed google sdk using pods which includes pod 'GoogleMaps' and pod 'GooglePlaces'. I made custom-view Class as 'GMSMapView'. my code is :
#IBOutlet weak var mapViewX: GMSMapView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let path = GMSMutablePath()
path.add(CLLocationCoordinate2D(latitude: 37.778483, longitude: -122.513960))
path.add(CLLocationCoordinate2D(latitude: 37.706753, longitude: -122.418677))
let polyline = GMSPolyline(path: path)
polyline.strokeColor = .black
polyline.strokeWidth = 10.0
polyline.map = mapViewX
}
Please help!
It works fine here. Make sure you're setting correct coordinates of GMSCameraPosition.
EDIT
To draw the route between two coordinate, use Google Maps Direction API
Something like :
let origin = "\(37.778483),\(-122.513960)"
let destination = "\(37.706753),\(-122.418677)"
let url = "https://maps.googleapis.com/maps/api/directions/json?origin=\(origin)&destination=\(destination)&mode=driving&key=[YOUR-API-KEY]"
Alamofire.request(url).responseJSON { response in
let json = JSON(data: response.data!)
let routes = json["routes"].arrayValue
for route in routes
{
let routeOverviewPolyline = route["overview_polyline"].dictionary
let points = routeOverviewPolyline?["points"]?.stringValue
let path = GMSPath.init(fromEncodedPath: points!)
let polyline = GMSPolyline(path: path)
polyline.strokeColor = .black
polyline.strokeWidth = 10.0
polyline.map = mapViewX
}
}
For more info - Directions API Developer's Guide
To draw a route between 2 coordinates you need to make a request to the Google Maps Directions API and parse its response. Therefore you firstly need to get an API key for your request. You can get one here, by creating a project and also enabling the Google Maps Directions API in this project.
Assuming you have the Google Maps SDK installed, you need to make a request to the directions API and then parse its response. Once you have parsed the response JSON, you can create a GMSPath object. I prefer to do that with a function that has two inputs, start & end CLLocationCoordinate2D objects and that returns the GMSPath on success or an error if something failed. The code below is in Swift 3.
My class and its function look like this:
import Foundation
import CoreLocation
import GoogleMaps
class SessionManager {
let GOOGLE_DIRECTIONS_API_KEY = "INSERT_YOUR_API_KEY_HERE"
func requestDirections(from start: CLLocationCoordinate2D, to end: CLLocationCoordinate2D, completionHandler: #escaping ((_ response: GMSPath?, _ error: Error?) -> Void)) {
guard let url = URL(string: "https://maps.googleapis.com/maps/api/directions/json?origin=\(start.latitude),\(start.longitude)&destination=\(end.latitude),\(end.longitude)&key=\(GOOGLE_DIRECTIONS_API_KEY)") else {
let error = NSError(domain: "LocalDomain", code: 0, userInfo: [NSLocalizedDescriptionKey: "Failed to create object URL"])
print("Error: \(error)")
completionHandler(nil, error)
return
}
// Set up the session
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)
let task = session.dataTask(with: url) { (data, response, error) in
// Check if there is an error.
guard error == nil else {
DispatchQueue.main.async {
print("Google Directions Request Error: \((error!)).")
completionHandler(nil, error)
}
return
}
// Make sure data was received.
guard let data = data else {
DispatchQueue.main.async {
let error = NSError(domain: "GoogleDirectionsRequest", code: 0, userInfo: [NSLocalizedDescriptionKey: "Failed to receive data"])
print("Error: \(error).")
completionHandler(nil, error)
}
return
}
do {
// Convert data to dictionary.
guard let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] else {
DispatchQueue.main.async {
let error = NSError(domain: "GoogleDirectionsRequest", code: 2, userInfo: [NSLocalizedDescriptionKey: "Failed to convert JSON to Dictionary"])
print("Error: \(error).")
completionHandler(nil, error)
}
return
}
// Check if the the Google Direction API returned a status OK response.
guard let status: String = json["status"] as? String, status == "OK" else {
DispatchQueue.main.async {
let error = NSError(domain: "GoogleDirectionsRequest", code: 3, userInfo: [NSLocalizedDescriptionKey: "Google Direction API did not return status OK"])
print("Error: \(error).")
completionHandler(nil, error)
}
return
}
print("Google Direction API response:\n\(json)")
// We only need the 'points' key of the json dictionary that resides within.
if let routes: [Any] = json["routes"] as? [Any], routes.count > 0, let routes0: [String: Any] = routes[0] as? [String: Any], let overviewPolyline: [String: Any] = routes0["overview_polyline"] as? [String: Any], let points: String = overviewPolyline["points"] as? String {
// We need the get the first object of the routes array (route0), then route0's overview_polyline and finally overview_polyline's points object.
if let path: GMSPath = GMSPath(fromEncodedPath: points) {
DispatchQueue.main.async {
completionHandler(path, nil)
}
return
} else {
DispatchQueue.main.async {
let error = NSError(domain: "GoogleDirections", code: 5, userInfo: [NSLocalizedDescriptionKey: "Failed to create GMSPath from encoded points string."])
completionHandler(nil, error)
}
return
}
} else {
DispatchQueue.main.async {
let error = NSError(domain: "GoogleDirections", code: 4, userInfo: [NSLocalizedDescriptionKey: "Failed to parse overview polyline's points"])
completionHandler(nil, error)
}
return
}
} catch let error as NSError {
DispatchQueue.main.async {
completionHandler(nil, error)
}
return
}
}
task.resume()
}
}
Then you can use that in your viewDidLoad like that:
#IBOutlet weak var mapView: GMSMapView!
override func viewDidLoad() {
super.viewDidLoad()
let sessionManager = SessionManager()
let start = CLLocationCoordinate2D(latitude: 37.778483, longitude: -122.513960)
let end = CLLocationCoordinate2D(latitude: 37.706753, longitude: -122.418677)
sessionManager.requestDirections(from: start, to: end, completionHandler: { (path, error) in
if let error = error {
print("Something went wrong, abort drawing!\nError: \(error)")
} else {
// Create a GMSPolyline object from the GMSPath
let polyline = GMSPolyline(path: path!)
// Add the GMSPolyline object to the mapView
polyline.map = self.mapView
// Move the camera to the polyline
let bounds = GMSCoordinateBounds(path: path!)
let cameraUpdate = GMSCameraUpdate.fit(bounds, with: UIEdgeInsets(top: 40, left: 15, bottom: 10, right: 15))
self.mapView.animate(with: cameraUpdate)
}
})
}
Hope you find it useful.
Swift 4
Create global variables.
var sourceLat = 0.0
var sourceLong = 0.0
var DestinationLat = 0.0
var DestinationLong = 0.0
var startLOC = CLLocation()
var endLOC = CLLocation()
Install Pod Alamofire and SwiftJSON.
pod 'Alamofire', '~> 4.5'
pod 'SwiftyJSON'
Make a function for draw route between source and destination.
func drawPath(startLocation: CLLocation, endLocation: CLLocation)
{
let origin = "\(startLocation.coordinate.latitude),\(startLocation.coordinate.longitude)"
let destination = "\(endLocation.coordinate.latitude),\(endLocation.coordinate.longitude)"
let url = "https://maps.googleapis.com/maps/api/directions/json?origin=\(origin)&destination=\(destination)&mode=driving"
Alamofire.request(url).responseJSON { response in
//print(response.request as Any) // original URL request
//print(response.response as Any) // HTTP URL response
//print(response.data as Any) // server data
//print(response.result as Any) // result of response serialization
let json = JSON(data: response.data!)
let routes = json["routes"].arrayValue
print(json)
// print route using Polyline
DispatchQueue.global(qos: .default).async(execute: {() -> Void in
// Do something...
DispatchQueue.main.async(execute: {() -> Void in
// self.hideHUD()
})
})
for route in routes
{
let routeOverviewPolyline = route["overview_polyline"].dictionary
let points = routeOverviewPolyline?["points"]?.stringValue
let path = GMSPath.init(fromEncodedPath: points!)
let polyline = GMSPolyline.init(path: path)
polyline.strokeWidth = 4
polyline.strokeColor = UIColor.black
polyline.map = self.mapViewBus
}
}
}
Create button action provide it source route and destination route. Giving Latitude and Longitude. After that paste the code.
// Route Source & Destination
self.startLOC = CLLocation(latitude: sourceLat, longitude: sourceLong)
self.endLOC = CLLocation(latitude: DestinationLat, longitude: DestinationLong)
drawPath(startLocation: startLOC, endLocation: endLOC)
let marker = GMSMarker()
marker.position = CLLocationCoordinate2D(latitude: sourceLat, longitude: sourceLong)
// marker.icon = userImage.af_imageScaled(to: CGSize(width: 50, height: 50)).af_imageRoundedIntoCircle()
marker.title = "Source"
marker.map = mapViewBus
let markerr = GMSMarker()
markerr.position = CLLocationCoordinate2D(latitude: DestinationLat, longitude: DestinationLong)
// markerr.icon = washerImage.af_imageScaled(to: CGSize(width: 50, height: 50)).af_imageRoundedIntoCircle()
markerr.title = "Desintation"
markerr.map = mapViewBus
let camera = GMSCameraPosition.camera(withLatitude: sourceLat, longitude: sourceLong, zoom: 14.0)
self.mapViewBus.camera = camera
self.mapViewBus.animate(to: camera)
I'm using google maps in my iOS swift project. I want to draw a path between two locations on the map (Not straight line). Any idea how to do that ?
To draw polyline between two locations on Google Map in Swift.
//Pass your source and destination coordinates in this method.
func fetchRoute(from source: CLLocationCoordinate2D, to destination: CLLocationCoordinate2D) {
let session = URLSession.shared
let url = URL(string: "http://maps.googleapis.com/maps/api/directions/json?origin=\(source.latitude),\(source.longitude)&destination=\(destination.latitude),\(destination.longitude)&sensor=false&mode=driving")!
let task = session.dataTask(with: url, completionHandler: {
(data, response, error) in
guard error == nil else {
print(error!.localizedDescription)
return
}
guard let jsonResponse = try? JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String: Any] else {
print("error in JSONSerialization")
return
}
guard let routes = jsonResponse["routes"] as? [Any] else {
return
}
guard let route = routes[0] as? [String: Any] else {
return
}
guard let overview_polyline = route["overview_polyline"] as? [String: Any] else {
return
}
guard let polyLineString = overview_polyline["points"] as? String else {
return
}
//Call this method to draw path on map
self.drawPath(from: polyLineString)
})
task.resume()
}
To draw polyline on map .
func drawPath(from polyStr: String){
let path = GMSPath(fromEncodedPath: polyStr)
let polyline = GMSPolyline(path: path)
polyline.strokeWidth = 3.0
polyline.map = mapView // Google MapView
}
Showing Multiple-routes between two locations in google maps in swift 3.0 with camera zoom:
let origin = "\(startLocation.coordinate.latitude),\(startLocation.coordinate.longitude)"
let destination = "\(destinationLocation.coordinate.latitude),\(destinationLocation.coordinate.longitude)"
let urlString = "https://maps.googleapis.com/maps/api/directions/json?origin=\(origin)&destination=\(destination)&mode=driving&key=API_KEY"
let url = URL(string: urlString)
URLSession.shared.dataTask(with: url!, completionHandler: {
(data, response, error) in
if(error != nil){
print("error")
}else{
do{
let json = try JSONSerialization.jsonObject(with: data!, options:.allowFragments) as! [String : AnyObject]
let routes = json["routes"] as! NSArray
self.mapView.clear()
OperationQueue.main.addOperation({
for route in routes
{
let routeOverviewPolyline:NSDictionary = (route as! NSDictionary).value(forKey: "overview_polyline") as! NSDictionary
let points = routeOverviewPolyline.object(forKey: "points")
let path = GMSPath.init(fromEncodedPath: points! as! String)
let polyline = GMSPolyline.init(path: path)
polyline.strokeWidth = 3
let bounds = GMSCoordinateBounds(path: path!)
self.mapView!.animate(with: GMSCameraUpdate.fit(bounds, withPadding: 30.0))
polyline.map = self.mapView
}
})
}catch let error as NSError{
print("error:\(error)")
}
}
}).resume()
Above all answers can draw routes but there is a way that you can draw accurate route using directions API.Here is the code hopefully it will help for you.
func getRouteSteps(from source: CLLocationCoordinate2D, to destination: CLLocationCoordinate2D) {
let session = URLSession.shared
let url = URL(string: "https://maps.googleapis.com/maps/api/directions/json?origin=\(source.latitude),\(source.longitude)&destination=\(destination.latitude),\(destination.longitude)&sensor=false&mode=driving&key=\(Your_API_Key)")!
let task = session.dataTask(with: url, completionHandler: {
(data, response, error) in
guard error == nil else {
print(error!.localizedDescription)
return
}
guard let jsonResult = try? JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String: Any] else {
print("error in JSONSerialization")
return
}
guard let routes = jsonResult["routes"] as? [Any] else {
return
}
guard let route = routes[0] as? [String: Any] else {
return
}
guard let legs = route["legs"] as? [Any] else {
return
}
guard let leg = legs[0] as? [String: Any] else {
return
}
guard let steps = leg["steps"] as? [Any] else {
return
}
for item in steps {
guard let step = item as? [String: Any] else {
return
}
guard let polyline = step["polyline"] as? [String: Any] else {
return
}
guard let polyLineString = polyline["points"] as? String else {
return
}
//Call this method to draw path on map
DispatchQueue.main.async {
self.drawPath(from: polyLineString)
}
}
})
task.resume()
}
And then
//MARK:- Draw Path line
func drawPath(from polyStr: String){
let path = GMSPath(fromEncodedPath: polyStr)
let polyline = GMSPolyline(path: path)
polyline.strokeWidth = 3.0
polyline.map = mapView // Google MapView
let cameraUpdate = GMSCameraUpdate.fit(GMSCoordinateBounds(coordinate: sourceLocationCordinates, coordinate: destinationLocationCordinates))
mapView.moveCamera(cameraUpdate)
let currentZoom = mapView.camera.zoom
mapView.animate(toZoom: currentZoom - 1.4)
}
Note: I have added sourcesLocationCordinates and destinationLocationCordinates variables.Don't forget to replace them with your source and destination.Hopefully this will help you making perfect route line.
Create a new Swift file copy this code, that's it call then drawPolygon() method from map view for polygon line.
import GoogleMaps
private struct MapPath : Decodable{
var routes : [Route]?
}
private struct Route : Decodable{
var overview_polyline : OverView?
}
private struct OverView : Decodable {
var points : String?
}
extension GMSMapView {
//MARK:- Call API for polygon points
func drawPolygon(from source: CLLocationCoordinate2D, to destination: CLLocationCoordinate2D){
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)
guard let url = URL(string: "https://maps.googleapis.com/maps/api/directions/json?origin=\(source.latitude),\(source.longitude)&destination=\(destination.latitude),\(destination.longitude)&sensor=false&mode=driving") else {
return
}
DispatchQueue.main.async {
session.dataTask(with: url) { (data, response, error) in
guard data != nil else {
return
}
do {
let route = try JSONDecoder().decode(MapPath.self, from: data!)
if let points = route.routes?.first?.overview_polyline?.points {
self.drawPath(with: points)
}
print(route.routes?.first?.overview_polyline?.points)
} catch let error {
print("Failed to draw ",error.localizedDescription)
}
}.resume()
}
}
//MARK:- Draw polygon
private func drawPath(with points : String){
DispatchQueue.main.async {
let path = GMSPath(fromEncodedPath: points)
let polyline = GMSPolyline(path: path)
polyline.strokeWidth = 3.0
polyline.strokeColor = .red
polyline.map = self
}
}
}
This piece of code will work right for you. Don't forget to change your API key and mode (walking, driving).
func draw(src: CLLocationCoordinate2D, dst: CLLocationCoordinate2D){
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)
let url = URL(string: "https://maps.googleapis.com/maps/api/directions/json?origin=\(src.latitude),\(src.longitude)&destination=\(dst.latitude),\(dst.longitude)&sensor=false&mode=walking&key=**YOUR_KEY**")!
let task = session.dataTask(with: url, completionHandler: {
(data, response, error) in
if error != nil {
print(error!.localizedDescription)
} else {
do {
if let json : [String:Any] = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String: Any] {
let preRoutes = json["routes"] as! NSArray
let routes = preRoutes[0] as! NSDictionary
let routeOverviewPolyline:NSDictionary = routes.value(forKey: "overview_polyline") as! NSDictionary
let polyString = routeOverviewPolyline.object(forKey: "points") as! String
DispatchQueue.main.async(execute: {
let path = GMSPath(fromEncodedPath: polyString)
let polyline = GMSPolyline(path: path)
polyline.strokeWidth = 5.0
polyline.strokeColor = UIColor.green
polyline.map = mapView
})
}
} catch {
print("parsing error")
}
}
})
task.resume()
}