How to draw routes on GMSmap view swift (not straight) using google api Swift - swift

I am trying to draw route on mapview using the google direction API . I am using the solution from the stackoverflow itself but i am getting some errors regarding intializers .
Also will the directions route will be same as google map itself or a straight one .
Any help is Appreciated. Also where should i call this methods
I am getting error as
Cannot invoke initializer for type 'GMSCoordinateBounds' with an argument list of type '(coordinate: String, String, coordinate:
String, String)'
Below is the Code .
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=\(lat),\(long)&destination=\(directionlat),\(directionlong)&sensor=false&mode=driving&key=\(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()
}
Function to draw polyline
func drawPath(from polyStr: String){
let mapView: GMSMapView
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: "\(lat)","\(long)", coordinate: "\(directionlat)","\(directionlong)")) as? [String : AnyObject]
mapView.moveCamera(cameraUpdate)
let currentZoom = mapView.camera.zoom
mapView.animate(toZoom: currentZoom - 1.4)
}

GMSCoordinatesBounds takes CLLocationCoordinates2D type as parameter, not String.
replace
let cameraUpdate = GMSCameraUpdate.fit(GMSCoordinateBounds(coordinate: "\(lat)","\(long)", coordinate: "\(directionlat)","\(directionlong)")) as? [String : AnyObject]
with
let cameraUpdate = GMSCameraUpdate.fit(GMSCoordinateBounds(coordinate: CLLocationCoordinate2D(latitude: Double(lat), longitude: Double(long)), coordinate: CLLocationCoordinate2D(latitude: Double(directionlat), longitude: Double(directionlat))))
and once you have added the mapView to your view controller and got the coordinates, call your function
self.getRouteSteps(from source: CLLocationCoordinate2D(latitude: Double(lat), longitude: Double(long)), destination: CLLocationCoordinate2D(latitude: Double(directionlat), longitude: Double(directionlat)))

You can try this, use the below to fetch direction:
//This function is used to fetch the directions from origin to destination
private func fetchDirection(destinationLat: CLLocationDegrees, destinationLong: CLLocationDegrees) {
//Here you need to set your origin and destination points and mode
if let location = locationManager.location {
guard let url = URL(string: "\("https://maps.googleapis.com/maps/api/directions/json")?origin=\(location.coordinate.latitude),\(location.coordinate.longitude)&destination=\(destinationLat),\(destinationLong)&key=\(Constants.MapKey)") else { return }
let task = URLSession.shared.dataTask(with: url) { [unowned self](data, response, error) -> Void in
do {
guard let data = data else { return }
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
guard let mapData = try? decoder.decode(MapModel.self, from: data) else { return }
if let points = mapData.routes.first?.overviewPolyline.points {
self.drawRoute(points: points)
}
}
}
task.resume()
}
}
Use this to draw the route on the map:
//This function is used to draw the routes
private func drawRoute(points: String) {
let path = GMSPath.init(fromEncodedPath: points)
let singleLine = GMSPolyline.init(path: path)
self.polylines.append(singleLine)
singleLine.strokeWidth = 6.0
let gradientColor: GMSStrokeStyle = GMSStrokeStyle.gradient(from: .red, to: .blue)
singleLine.spans = [GMSStyleSpan.init(style: gradientColor)]
if self.polylines.count > 0 {
self.polylines.forEach{ $0.map = nil }
}
singleLine.map = self.mapView
}
And, here is the MapModel
struct MapModel: Decodable {
let status: String
let routes: [Routes]
}
struct Routes: Decodable {
let overviewPolyline: OverviewPolyline
}
struct OverviewPolyline: Decodable {
let points: String
}
I hope you are familiar with Codables and also, I have called the drawRoute function when I received the points.

Related

Google maps API Swift; Nil maneuver response

I am trying to get the maneuver data for the given route from Google Maps' API. Running the code gives me nil values.
Here is the code I am running to get the maneuver data:
func getRouteSteps(source: CLLocationCoordinate2D,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=\(APIKey)")!
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 }
guard let duration = leg["duration"] as? [String: Any] else { return }
guard let distance = leg["distance"] as? [String: Any] else { return }
RouteData.append(RouteInfo(Time: String(describing: duration["text"]! as Any), Distance: String(describing: distance["text"]! as Any)))
for item in steps {
guard let step = item as? [String: Any] else { return }
guard let stepTurns = step["html_instructions"] as? String else { return }
guard let stepDistance = step["distance"] as? [String: Any] else { return }
guard let stepTime = step["duration"] as? [String: Any] else { return }
guard let polyline = step["polyline"] as? [String: Any] else { return }
guard let polyLineString = polyline["points"] as? String else { return }
guard let maneuver = step["maneuver"] as? Any else { return }
print(maneuver)
Here are the results:
nil
nil
Optional(turn-right)
Optional(turn-left)
Optional(ramp-left)
Optional(ramp-right)
Optional(straight)
Optional(turn-slight-left)
Optional(turn-slight-left)
Optional(turn-left)

route between two markers in google maps - Swift

I want him to draw the route between the two coordinates and go to the route, but he doesn't draw the route. It prints out success but cannot draw the route. What is the problem? How can I draw two routes on the map and show the details of this route?
func drawPath()
{
let kordinatgetir = keychain.get("uyeKordinat")
let doubleKordinat :Double = Double(kordinatgetir!)!
let kordinatgetir1 = keychain.get("uyeKordinat1")
let doubleKordinat1 :Double = Double(kordinatgetir1!)!
let origin = "\(doubleKordinat),\(doubleKordinat1)"
let destination = "\(doubleKordinat1),\(doubleKordinat)"
let url = "https://maps.googleapis.com/maps/api/directions/json?origin=\(origin)&destination=\(destination)&mode=driving&key=..."
Alamofire.request(url).responseJSON { response in
print(response.request) // original URL request
print(response.response) // HTTP URL response
print(response.data) // server data
print(response.result) // result of response serialization
do {
let json = try 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.init(path: path)
polyline.map = self.mapView
}
} catch {
print(error)
}
}
}
func drowRoute(from source: CLLocationCoordinate2D, to destination: CLLocationCoordinate2D) {
self.mapView.clear()
let origin = "\(source.latitude),\(source.longitude)"
let destinationn = "\(destination.latitude),\(destination.longitude)"
guard let url = URL(string: "https://maps.googleapis.com/maps/api/directions/json?origin=\(origin)&destination=\(destinationn)&mode=driving&key=Your Key") else {
let error = NSError(domain: "LocalDomain", code: 0, userInfo: [NSLocalizedDescriptionKey: "Failed to create object URL"])
print("Error: \(error)")
//completionHandler(nil, error)
return
}
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)
SVProgressHUD.show()
let task = session.dataTask(with: url, completionHandler: {
(data, response, error) in
if error != nil {
print(error!.localizedDescription)
SVProgressHUD.dismiss()
}
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 {
DispatchQueue.main.async {
SVProgressHUD.dismiss()
}
return
}
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
DispatchQueue.main.async {
//
let legs = overview_polyline?["legs"] as! Array<Dictionary<String, AnyObject>>
let distance = legs[0]["distance"] as? NSDictionary
let distanceValue = distance?["value"] as? Int ?? 0
let duration = legs[0]["duration"] as? NSDictionary
let totalDurationInSeconds = duration?["value"] as? Int ?? 0
let miles = Double(distanceValue) / 1609.344
print("\(miles)")
if distanceValue > Int(32186.9){
SVProgressHUD.dismiss()
self.showAlert(title: Appname, message: "Your dropping point is more than 20 miles")
self.txtToLocation.text = ""
self.txtToLocation.becomeFirstResponder()
}else{
self.showPath(polyStr: points!)
let startLocationDictionary = legs[0]["start_location"] as! Dictionary<String, AnyObject>
let originCoordinate = CLLocationCoordinate2DMake(startLocationDictionary["lat"] as! Double, startLocationDictionary["lng"] as! Double)
let endLocationDictionary = legs[legs.count - 1]["end_location"] as! Dictionary<String, AnyObject>
let destinationCoordinate = CLLocationCoordinate2DMake(endLocationDictionary["lat"] as! Double, endLocationDictionary["lng"] as! Double)
let marker1 = GMSMarker()
marker1.position = CLLocationCoordinate2D(latitude:destinationCoordinate.latitude, longitude: destinationCoordinate.longitude)
marker1.icon = UIImage(named: "icn_pin-1")
marker1.map = self.mapView
let marker2 = GMSMarker()
marker2.position = CLLocationCoordinate2D(latitude:originCoordinate.latitude, longitude: originCoordinate.longitude)
marker2.icon = UIImage(named: "icn_pin2")
marker2.map = self.mapView
}
}
}
else {
print(json)
DispatchQueue.main.async {
SVProgressHUD.dismiss()
}
}
}
}
catch {
print("error in JSONSerialization")
DispatchQueue.main.async {
SVProgressHUD.dismiss()
}
}
}
})
task.resume()
}
func showPath(polyStr :String){
SVProgressHUD.dismiss()
let path = GMSPath(fromEncodedPath: polyStr)
let polyline = GMSPolyline(path: path)
polyline.strokeWidth = 5.0
polyline.strokeColor = UIColor.UIColorFromHex(hex: "#F6881F")
polyline.map = mapView
DispatchQueue.main.async {
let bounds = GMSCoordinateBounds(path: path!)
let update = GMSCameraUpdate.fit(bounds, with: UIEdgeInsets(top: 170, left: 30, bottom: 30, right: 30))
self.mapView.moveCamera(update)
}
}

Cannot convert value of type '(key: String, value: Any)' to expected argument type '[String : Any]

I'm trying to get JSON but it shows an occurred issue
Line starting with if let deliveryObject
How to get rid of the problem?
code:
struct Tracking {
let receiver: String
let placeOfMail: String
let indexOfMail: Double
init(json:[String:Any]) throws {
guard let receiver = json["name"] as? String else {
throw SerializationError.missing("Receiver data has been missed")
}
guard let placeOfMail = json ["address"] as? String else {
throw SerializationError.missing("Place of delivery has been missed")
}
guard let indexOfMail = json ["postindex"] as? Double else {
throw SerializationError.missing("Index of postmail has been missed")
}
self.receiver = receiver
self.placeOfMail = placeOfMail
self.indexOfMail = indexOfMail
}
static let basePath = "https://track.kazpost.kz/api/v2/"
static func deliveryData (withTrackid trackid:String, completion: #escaping ([Tracking]) -> ()){
let url = basePath + trackid
let request = URLRequest(url: URL(string: url)!)
let task = URLSession.shared.dataTask(with: request) { (data: Data?, response : URLResponse?, error: Error?) in
var deliveryArray: [Tracking] = []
if let data = data {
do {
if let json = try JSONSerialization.jsonObject(with: data, options:[]) as? [String:Any] {
if let deliveryInformation = json ["delivery"] as? [String:Any] {
if let deliveryPlace = deliveryInformation ["address"] as? [String:Any] {
for dataPoint in deliveryPlace {
if let dataPointValue = dataPoint.value as? [String: AnyObject],
let deliveryObject = try Tracking(json: dataPointValue) {
deliveryArray.append(deliveryObject)
}
}
}
}
}
}catch {
print(error.localizedDescription)
}
completion(deliveryArray)
}
}
task.resume()
}
}

how to move marker along polyline in swift

i had obtained the start and end locations through the json, but when i loop through to draw the animation ,it takes only last point of the loop and the marker moves in a straight line
func playAnimation() {
let origin = "\(self.locationManager.location?.coordinate.latitude ?? 0),\(self.locationManager.location?.coordinate.longitude ?? 0)"
let destination = "\(latitude),\(longitude)"
let url = "https://maps.googleapis.com/maps/api/directions/json?origin=\(origin)&destination=\(destination)&mode=driving&key=googleApi"
print(url)
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)
guard let requestUrl = URL(string :url) else { return }
let request = URLRequest(url:requestUrl)
let task = session.dataTask(with: request, completionHandler: {
(data, response, error) in
DispatchQueue.main.async {
if error != nil {
print(error!.localizedDescription)
}else{
do {
if let json : [String:Any] = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String: Any]{
if let routes = json["routes"] as? [Any] {
//print(routes)
if let route = routes[0] as? [String: Any] {
//print(route)
if let legs = route["legs"] as? [Any]{
// print(legs)
if let leg = legs[0] as? [String: Any]{
// print(leg)
if let steps = leg["steps"] as? [Any]{
// print("steps:\(steps)")
for step in steps {
//print(step)
let endLocation:NSDictionary = (step as! NSDictionary).value(forKey: "end_location") as! NSDictionary
print("endLocation is : \(endLocation)")
let endLocationLatitude = endLocation.object(forKey: "lat") as! CLLocationDegrees
print(endLocationLatitude)
let endLocationLongitude = endLocation.object(forKey: "lng") as! CLLocationDegrees
print(endLocationLongitude)
let startLocation:NSDictionary = (step as! NSDictionary).value(forKey: "start_location") as! NSDictionary
print("startLocation is : \(startLocation)")
let startLocationLatitude = startLocation.object(forKey: "lat") as! CLLocationDegrees
print(startLocationLatitude)
let startLocationLongitude = startLocation.object(forKey: "lng") as! CLLocationDegrees
print(startLocationLongitude)
// let destinationLocation = CLLocationCoordinate2DMake(19.0178967, 72.8558875)
let destinationLocation = CLLocationCoordinate2DMake(endLocationLatitude,endLocationLongitude)
print("destinationLocation:\(destinationLocation)")
let startLocationDestination = CLLocationCoordinate2DMake(startLocationLatitude, startLocationLongitude)
//self.updateMarker(startlocation: startLocationDestination, endlocation: destinationLocation)
//self.updateMarker(coordinates: destinationLocation)
CATransaction.begin()
CATransaction.setAnimationDuration(5.0)
self.marker.position = destinationLocation
self.marker.map = self.mapView
self.delay(2, closure: {})
// Center Map View
let camera = GMSCameraUpdate.setTarget(destinationLocation)
self.mapView.animate(with: camera)
CATransaction.commit()
}
}
}
}
}
}
}
}catch{
print("error in JSONSerialization")
DispatchQueue.main.async {
self.activityIndicator.stopAnimating()
}
}
}
}
})
task.resume()
}
You can move your marker using below code. You need to pass the position and the marker has to be present on the map. If marker is not there you first need to create it and then move
let position = CLLocationCoordinate2D(latitude:
self.locationManager.location?.coordinate.latitude ?? 0.0, longitude: self.locationManager.location?.coordinate.longitude ?? 0.0)
CATransaction.begin()
CATransaction.setAnimationDuration(1.0)
myMarker?.position = position
myMarker?.map = mapView
myMarker?.appearAnimation = .pop
CATransaction.commit()

How to set google map zoom level according to path & markers in swift

I am trying to show path in google maps from one place to another place I am getting something like this. but I need to show like this. Which means the whole path need to show & according to path on map, the zooming level should adjust
Here is the code which I tried to draw path from API. and here in let settingCam am setting camera to adjust to one of the location
func showingPathFromPickupLocToDropLoc(dropLat: Double, dropLong: Double){
let origin = "\(dropLat),\(dropLong)"
let destination = "\(dropLatitude),\(dropLongitude)"
let settingCam: CLLocationCoordinate2D = CLLocationCoordinate2D(latitude: CLLocationDegrees(dropLat), longitude: CLLocationDegrees(dropLong))
let url = URL(string: "https://maps.googleapis.com/maps/api/directions/json?origin=\(origin)&destination=\(destination)&key=\(NEWAPI.GOOGLE_APIKEY)")
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]
if json["status"] as! String == "OK"{
let routes = json["routes"] as! [[String:AnyObject]]
OperationQueue.main.addOperation({
for route in routes{
let routeOverviewPolyline = route["overview_polyline"] as! [String:String]
let points = routeOverviewPolyline["points"]
let path = GMSPath.init(fromEncodedPath: points!)
self.PathFromPickupLocToDropLoc = GMSPolyline(path: path)
self.PathFromPickupLocToDropLoc.strokeColor = .gray
self.PathFromPickupLocToDropLoc.strokeWidth = 3.0
self.PathFromPickupLocToDropLoc.map = self.mapView
let camera = GMSCameraPosition.camera(withTarget: settingCam, zoom: 16.0)
self.mapView.animate(toLocation: settingCam)
self.mapView.animate(to: camera)
self.insertingMarkersFromPickupLocToDropLoc(dropLat: dropLat, dropLong: dropLong)
}
})
}
}catch let error as NSError{
print(error)
}
}
}).resume()
}
You need to do like this
DispatchQueue.main.async
{
if self.googleMap != nil
{
let bounds = GMSCoordinateBounds(path: path!)
self.googleMap!.animate(with: GMSCameraUpdate.fit(bounds, withPadding: 50.0))
}
}