I want to show path in google map. But i am unable to show my path. Please help me . This is my code. I am try lot of time in swift. Any help would be appreciated. Thanks in advance.
let camera = GMSCameraPosition.camera(withLatitude: 48.4843822562792, longitude: 35.0635632500052, zoom: 6)
let mapView = GMSMapView.map(withFrame: .zero, camera: camera)
self.view = mapView
let manager = AFHTTPSessionManager()
manager.requestSerializer = AFJSONRequestSerializer()
manager.responseSerializer.acceptableContentTypes = nil
let urlString = "https://maps.googleapis.com/maps/api/directions/json?origin=48.4843822562792,35.0635632500052&destination=48.4893899423081,35.0640017911792&waypoints=48.4833428800255,35.0710221379995|48.4887622031403,35.0573639944196&key=AIzaSyDvS9TbaQ1WzP_3YX6TBrjoTNGhnFa0MBY"
let urlwithPercentEscapes = urlString.addingPercentEncoding( withAllowedCharacters: .urlQueryAllowed)
manager.get(urlwithPercentEscapes!, parameters: nil, success: { (operation, response) in
let parsedData = JSON(response)
var path = GMSPath.init(fromEncodedPath: parsedData["routes"][0]["overview_polyline"]["points"].string!)
//GMSPath.fromEncodedPath(parsedData["routes"][0]["overview_polyline"]["points"].string!)
print(path!)
var singleLine = GMSPolyline.init(path: path)
singleLine.strokeWidth = 7
singleLine.strokeColor = UIColor.green
singleLine.map = self.mapView
}, failure: { (operation, error) in
})
Related
I do a JSON Request and get some information.
func parseJSON(poiData: Data) {
let decoder = JSONDecoder()
do {
let decodedData = try decoder.decode(POIData.self, from: poiData)
POIManager.POIname_One = decodedData.results[0].name
POIManager.POIplaceid_One = decodedData.results[4].place_id
POIManager.POIvicinity_One = decodedData.results[4].vicinity
POIManager.POIlong_One = decodedData.results[0].geometry.location.lat
POIManager.POIlat_One = decodedData.results[0].geometry.location.lng
POIManager.POIname_Two = decodedData.results[1].name
POIManager.POIplaceid_Two = decodedData.results[1].place_id
POIManager.POIvicinity_Two = decodedData.results[1].vicinity
POIManager.POIlong_Two = decodedData.results[1].geometry.location.lat
POIManager.POIlat_Two = decodedData.results[1].geometry.location.lng
POIManager.POIname_Three = decodedData.results[2].name
POIManager.POIplaceid_Three = decodedData.results[2].place_id
POIManager.POIvicinity_Three = decodedData.results[2].vicinity
POIManager.POIlong_Three = decodedData.results[2].geometry.location.lat
POIManager.POIlat_Three = decodedData.results[2].geometry.location.lng
} catch {
print(error)
}
}
In a different Swift file it put the results from the request in a list like this:
#IBAction func kategorieEins(_ sender: UIButton) {
//Eigene Standort soll hier gezeigt werden/aktualisierter Standort
locationManager.delegate=self
let marker1 = GMSMarker()
marker1.position = CLLocationCoordinate2D(latitude: POIManager.POIlong_One, longitude: POIManager.POIlat_One)
marker1.title = POIManager.POIname_One
marker1.snippet = "Marker1_0"
marker1.map = mapView
let marker2 = GMSMarker()
marker2.position = CLLocationCoordinate2D(latitude: POIManager.POIlong_Two, longitude: POIManager.POIlat_Two)
marker2.title = POIManager.POIname_Two
marker2.snippet = "Marker2_0"
marker2.map = mapView
let marker3 = GMSMarker()
marker3.position = CLLocationCoordinate2D(latitude: POIManager.POIlong_Three, longitude: POIManager.POIlat_Three)
marker3.title = POIManager.POIname_Three
marker3.snippet = "Marker3_0"
marker3.map = mapView
}
As you can see this whole thing is not dynamic it is static. I write down how many markers i want to have created.
Is there a way to do this automatically? Especially when I dont know how much information there is in the json file and how many markers should be created.
I solved it now.
I tried:
decodedData.results.forEach {
print($0.name)
print($0.place_id)
}
I tried to implement differents solutions for draw polyLines between markers on my GMSMapView but is not working. Do you have others solutions or maybe do you know what's wrong in my code ?
override func viewDidLoad() {
super.viewDidLoad()
let path = GMSMutablePath()
_data = _modelDelivery.getGarageFromDeliver(refDelivery: _delivery._ref)
let camera = GMSCameraPosition.camera(withLatitude: 48.853183, longitude: 2.369144, zoom: 13.0)
self._mapView.camera = camera
let marker = GMSMarker()
marker.position = CLLocationCoordinate2D(latitude: 48.8531827, longitude: 2.3691443000000163)
path.add(marker.position)
marker.title = "Ma position"
marker.icon = GMSMarker.markerImage(with: UIColor.blue)
marker.map = self._mapView
for elem in _data {
let address = elem._adress + ", " + elem._city + ", " + String(elem._zipCode) + ", France"
let geocoder = CLGeocoder()
geocoder.geocodeAddressString(address) {
placemarks, error in
let placemark = placemarks?.first
let lat = placemark?.location?.coordinate.latitude
let lon = placemark?.location?.coordinate.longitude
let marker = GMSMarker()
marker.position = CLLocationCoordinate2D(latitude: lat!, longitude: lon!)
path.add(marker.position)
marker.title = elem._nameOfGarage
marker.snippet = elem._adress + "\nOrdre de passege : "
marker.map = self._mapView
}
}
let rectangle = GMSPolyline(path: path)
rectangle.strokeWidth = 4
rectangle.strokeColor = UIColor.red
rectangle.map = self._mapView
}
I believe you have configured everything fine in https://console.developers.google.com.
We can draw a polyline between two coordinates. You need to create your ServerKey on https://console.developers.google.com where you have created your project for GoogleMaps and then use that Server Key in the URL below.
This draws polyline between two coordinates.
func drawPath() {
//Taken two source and destinations coordinates. Take the coordinates in this way. "Lat,Long" in a String
let sourceString = "28.6562,77.2410"
let destinationString = "27.1750,78.0422"
//GoogleMaps Web API to draw the polyline
let combinedUrl : String = "https://maps.googleapis.com/maps/api/directions/json?" + "origin=\(sourceString)&destination=\(destinationString)&key=YOUR_SERVER_KEY"
let url = URL(string:combinedUrl)
let task = URLSession.shared.dataTask(with: url!) { (data:Data?, response:URLResponse?, error:Error?) in
if error != nil {
print(error.debugDescription)
return
}
do {
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! NSDictionary
//We need to get to the points key in overview_polyline object in order to pass the points to GMSPath.
let route = (((json.object(forKey: "routes") as! NSArray).object(at: 0) as! NSDictionary).object(forKey: "overview_polyline") as! NSDictionary).value(forKey: "points") as! String
//Draw on main thread always else it will crash
DispatchQueue.main.async {
let path = GMSPath(fromEncodedPath:route)!
let polyline = GMSPolyline(path: path)
polyline.strokeColor = UIColor.green
polyline.strokeWidth = 5.0
//mapView is your GoogleMaps Object i.e. _mapView in your case
polyline.map = self.mapView
}
} catch {
}
}
task.resume()
}
JSON points key data required.
Later on you can animate to the drawn region first coordinate using the GMSCameraPosition.
Similarly for multiple points, just pass the respective coordinates in a for loop and call drawPath function.
You can have a look at this Video Tutorial too.
I'm making the GMSPolyline in the GoogleMap. When I want to remove the GMSPolyline by coding polyline.map = nil, but it can not working for me. I'm copy some coding in the below.
(added the marker before, I need remove the polyline only)
Thank you for your help!!!
my coding:
func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool {
//MARK: create the GMSPolyline
let polyline = GMSPolyline()
//MARK: remove the old polyline from the GoogleMap
polyline.map = nil
let origin = "\(mapView.myLocation!.coordinate.latitude),\(mapView.myLocation!.coordinate.longitude)"
let destination = "\(marker.position.latitude),\(marker.position.longitude)"
let url = "https://maps.googleapis.com/maps/api/directions/json?origin=\(origin)&destination=\(destination)&mode=driving"
Alamofire.request(url).responseJSON { response in
let json = JSON(data: response.data!)
let routes = json["routes"].arrayValue
//MARK: print route using Polyline
for route in routes
{
let routeOverviewPolyline = route["overview_polyline"].dictionary
let points = routeOverviewPolyline?["points"]?.stringValue
let path = GMSPath(fromEncodedPath: points!)
polyline = GMSPolyline(path: path)
polyline.strokeWidth = 4
polyline.strokeColor = UIColor.yellow
polyline.isTappable = true
polyline.map = self.mapView
}
}
return false
}
you should clear the map before adding new polyline on the map.
clear() function of GMSMapView
/**
Clears all markup that has been added to the map, including markers, polylines and ground overlays.
This will not clear the visible location dot or reset the current mapType.
*/
Try this
func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool {
//MARK: create the GMSPolyline
let polyline = GMSPolyline()
//MARK: remove the old polyline from the GoogleMap
mapView.clear()
//TODO:- Redraw all marker here.
let origin = "\(mapView.myLocation!.coordinate.latitude),\(mapView.myLocation!.coordinate.longitude)"
let destination = "\(marker.position.latitude),\(marker.position.longitude)"
let url = "https://maps.googleapis.com/maps/api/directions/json?origin=\(origin)&destination=\(destination)&mode=driving"
Alamofire.request(url).responseJSON { response in
let json = JSON(data: response.data!)
let routes = json["routes"].arrayValue
//MARK: print route using Polyline
for route in routes
{
let routeOverviewPolyline = route["overview_polyline"].dictionary
let points = routeOverviewPolyline?["points"]?.stringValue
let path = GMSPath(fromEncodedPath: points!)
polyline = GMSPolyline(path: path)
polyline.strokeWidth = 4
polyline.strokeColor = UIColor.yellow
polyline.isTappable = true
polyline.map = self.mapView
}
}
return false
}
Declare polyline outside the function as a class property.
var routePolyline: GMSPolyline? = nil
Then to clear old polyline before adding new one, use-
self.routePolyline?.map = nil
This will work as expected!
for poll in mapkit.overlays {
mapkit.removeOverlay(poll)
}
var polyline: GMSPolyline?
func drawPathOnMap() {
if polyline != nil {
//remove existing the gmspoly line from your map
polyline!.map = nil
}
let points = //Your Point
let path = GMSPath(fromEncodedPath: points)
polyline = GMSPolyline(path: path)
polyline?.strokeWidth = 5.0
polyline?.strokeColor = UIColor.init(rgb: 0x7688ED)
polyline!.map = mapView
}
Im new to Swift and I'm trying to use the Google Directions API. I have modified a function to get a Polyline and put the Google directions into an array. The array of directions I declared as a property of the class I'm working in so I can display the results in a table. I have checked and the array is be properly populated with the directions inside the closure. However when I try to use it outside the closure in the CellForTableAT function it is empty. I'm probably not getting the data out of the closures correctly but I cant figure it out. I begin building my array at //MARK: Start Building Directions Array using swiftyJason
func getDirections(currentDestination: GMSMarker, origin: String!, destination: String!, waypoints: Array<String>!, mode: String!, completionHandler: ((_ status: String, _ success: Bool) -> Void)?) {
if let originLocation = origin {
if let destinationLocation = destination {
var directionsURLString = baseURLDirections + "origin=" + originLocation + "&destination=" + destinationLocation + "&mode=" + mode
if let routeWaypoints = waypoints {
directionsURLString += "&waypoints=optimize:true"
for waypoint in routeWaypoints {
directionsURLString += "|" + waypoint
}
}
directionsURLString = ("\(directionsURLString)&sensor=true&key=???????????????")
print("directons*******")
print(directionsURLString)
directionsURLString = directionsURLString.addingPercentEscapes(using: String.Encoding.utf8)!
let directionsURL = NSURL(string: directionsURLString)
DispatchQueue.main.async( execute: { () -> Void in
let directionsData = NSData(contentsOf: directionsURL! as URL)
do{
let dictionary: Dictionary<String, AnyObject> = try JSONSerialization.jsonObject(with: directionsData! as Data, options: JSONSerialization.ReadingOptions.mutableContainers) as! Dictionary<String, AnyObject>
let status = dictionary["status"] as! String
let json = JSON(data: directionsData as! Data)
if status == "OK" {
self.selectedRoute = (dictionary["routes"] as! Array<Dictionary<String, AnyObject>>)[0]
self.overviewPolyline = self.selectedRoute["overview_polyline"] as! Dictionary<String, AnyObject>
let legs = self.selectedRoute["legs"] as! Array<Dictionary<String, AnyObject>>
let startLocationDictionary = legs[0]["start_location"] as! Dictionary<String, AnyObject>
self.originCoordinate = CLLocationCoordinate2DMake(startLocationDictionary["lat"] as! Double, startLocationDictionary["lng"] as! Double)
let endLocationDictionary = legs[legs.count - 1]["end_location"] as! Dictionary<String, AnyObject>
self.destinationCoordinate = CLLocationCoordinate2DMake(endLocationDictionary["lat"] as! Double, endLocationDictionary["lng"] as! Double)
let originAddress = legs[0]["start_address"] as! String
let destinationAddress = legs[legs.count - 1]["end_address"] as! String
for (index, leg) in json["routes"][0]["legs"].arrayValue.enumerated() {
var count = 0
//MARK: Start Building Directions Array
for (stepIndex, step) in json["routes"][0]["legs"][index]["steps"].arrayValue.enumerated() {
count += 1
let htmlInstructions = json["routes"][0]["legs"][index]["steps"][stepIndex]["html_instructions"].string
let distance = json["routes"][0]["legs"][index]["steps"][stepIndex]["distance"]["text"].string
let duration = json["routes"][0]["legs"][index]["steps"][stepIndex]["duration"]["text"].string
let direction:Direction = Direction(index: count, htmlInstructions: htmlInstructions, distance: distance, duration: duration)
self.directions.append(direction)
}
self.tableView.reloadData()
}
//end of stepts to get writtine directions
//NOT Plotting markers endpoins
//position markers for ployline endpoints
//let originMarker = GMSMarker(position: self.originCoordinate)
// originMarker.map = self.mapView
//originMarker.icon = UIImage(named: "mapIcon")
// originMarker.title = originAddress
self.destinationMarker = currentDestination
// destinationMarker.map = self.mapView
// destinationMarker.icon = UIImage(named: "mapIcon")
// destinationMarker.title = destinationAddress
// destinationMarker.icon = GMSMarker.markerImage(with: UIColor.green)
if waypoints != nil && waypoints.count > 0 {
for waypoint in waypoints {
let lat: Double = (waypoint.components(separatedBy: ",")[0] as NSString).doubleValue
let lng: Double = (waypoint.components(separatedBy: ",")[1] as NSString).doubleValue
let marker = GMSMarker(position: CLLocationCoordinate2DMake(lat, lng))
marker.map = self.mapView
marker.icon = UIImage(named: "mapIcon")
}
}
self.routePolyline.map = nil
let route = self.overviewPolyline["points"] as! String
let path: GMSPath = GMSPath(fromEncodedPath: route)!
self.routePolyline = GMSPolyline(path: path)
self.routePolyline.map = self.mapView
self.routePolyline.strokeColor = UIColor.red
self.routePolyline.strokeWidth = 3.0
//Fit map to entire polyline
var bounds = GMSCoordinateBounds()
for index in 1...path.count() {
bounds = bounds.includingCoordinate(path.coordinate(at: index))
}
self.mapView.animate(with: GMSCameraUpdate.fit(bounds))
// end of fit map to ployline
}
else {
print("status of poly draw")
//completionHandler(status: status, success: false)
}
}
catch {
print("catch")
// completionHandler(status: "", success: false)
}
})
}
else {
print("Destination is nil.")
//completionHandler(status: "Destination is nil.", success: false)
}
}
else {
print("Origin is nil")
//completionHandler(status: "Origin is nil", success: false)
}
}
I added a return (->([Direction]))to the closure and was able to access the data outside of it.
func getDirections(currentDestination: GMSMarker, origin: String!, destination: String!, waypoints: Array<String>!, mode: String!, completionHandler: ((_ status: String, _ success: Bool) -> Void)?) -> ([Direction])
I'm new so not sure if its best practice to do it that way, but I needed data to display in a table.
I'm using the google places api to search for nearby places. However, I only want places of specific types. The code (seen below) works when I specify just one type, but when I add a second my code runs and promptly give me a EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0) error on this line:
session.dataTaskWithURL(url!, completionHandler: { (data : NSData!, response : NSURLResponse!, error : NSError!) -> Void in
I know the url is valid. I can plug it into the browser and see the json, so I don't understand what the problem is.
func search(location : CLLocationCoordinate2D, radius : Int, callback : (items : [Attraction]?, errorDescription : String?) -> Void) {
var urlString = "https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=37.7873589,-122.408227&radius=4000&types=aquarium|art_gallery&key=YOURKEY"
var url = NSURL(string: urlString)
var session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())
session.dataTaskWithURL(url!, completionHandler: { (data : NSData!, response : NSURLResponse!, error : NSError!) -> Void in
if error != nil {
callback(items: nil, errorDescription: error.localizedDescription)
}
if let statusCode = response as? NSHTTPURLResponse {
if statusCode.statusCode != 200 {
callback(items: nil, errorDescription: "Could not continue. HTTP Status Code was \(statusCode)")
}
}
NSOperationQueue.mainQueue().addOperationWithBlock({ () -> Void in
callback(items: GooglePlaces.parseFromData(data), errorDescription: nil)
})
}).resume()
}
class func parseFromData(data : NSData) -> [Attraction] {
var attractions = [Attraction]()
var json = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as NSDictionary
var results = json["results"] as? [NSDictionary]
for result in results! {
var placeId = result["place_id"] as String
var image = result["icon"] as String
var name = result["name"] as String
var ratingString = ""
var types = result["types"] as [String]
println(types)
if result["rating"] != nil {
var rating = result["rating"] as Double
ratingString = "\(rating)"
}
var coordinate : CLLocationCoordinate2D!
if let geometry = result["geometry"] as? NSDictionary {
if let location = geometry["location"] as? NSDictionary {
var lat = location["lat"] as CLLocationDegrees
var long = location["lng"] as CLLocationDegrees
coordinate = CLLocationCoordinate2D(latitude: lat, longitude: long)
var placemark = MKPlacemark(coordinate: coordinate, addressDictionary: nil)
var attraction = Attraction(id: placeId, imageUrl: "image url", locationName: name, ratingAvg: "\(ratingString)", types: types, placemarker: placemark)
attractions.append(attraction)
}
}
}
return attractions
}
I know the url is valid
The URL is not valid. You do not know what you think you know. Listen to the runtime. It knows more than you do.
Just try this code alone (in a playground, for instance):
var urlString = "https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=37.7873589,-122.408227&radius=4000&types=aquarium|art_gallery&key=YOURKEY"
let url = NSURL(string:urlString)
url is nil. And that's your problem. You cannot force-unwrap nil; you will crash if you do.
Once you acknowledge this, you can start to think about why the URL is not valid. (It's pretty obvious why that might be.) Learning to believe the compiler and the runtime is key to successful programming.
HINT: Form your URL like this and all is well:
let url2 = NSURL(scheme: "https", host: "maps.googleapis.com", path: "/maps/api/place/nearbysearch/json?location=37.7873589,-122.408227&radius=4000&types=aquarium|art_gallery&key=YOURKEY")
Why do you suppose that is? Look at the docs and see what this initializer does for you...
I would use .stringByAddingPercentEscapesUsingEncoding()
var urlString = "http://example.com/?foo=bar|baz"
if var escapedURLString = urlString.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding) {
NSURL(string: escapedURLString)
}
Returns: http://example.com/?foo=bar%7Cbaz