Reputation: 31
I am writing my first iOS native app. I am trying to load a GeoJSON layer onto a google map in the app (map comes from the google maps sdk) but I can't find any way to do it. I'm proficient in the google maps javascript API but I'm sensing things in Swift are very different.
How can I load a GeoJSON layer onto a map in a native iOS app?
Upvotes: 3
Views: 3762
Reputation: 445
All you have to do is add your geoJSon file in your project, Then add below code:
func addMapView() {
let zoomLevel = locationManager.accuracyAuthorization == .fullAccuracy ? preciseLocationZoomLevel : approximateLocationZoomLevel
let options = GMSMapViewOptions()
options.camera = GMSCameraPosition.camera(withLatitude: defaultLocation.coordinate.latitude, longitude: defaultLocation.coordinate.longitude, zoom: zoomLevel)
options.frame = self.vwMap.bounds
mapView = GMSMapView(options: options)
mapView.settings.myLocationButton = true
mapView.isMyLocationEnabled = true
vwMap.addSubview(mapView)
}
func renderGeoJSON() {
guard let path = Bundle.main.path(forResource: "Wadi Khat", ofType: "geojson") else {
return
}
let url = URL(fileURLWithPath: path)
geoJsonParser = GMUGeoJSONParser(url: url)
geoJsonParser.parse()
renderer = GMUGeometryRenderer(map: mapView, geometries: geoJsonParser.features)
renderer.render()
}
Call both of these methods in ViewDidLoad, Attaching sample geoJSon file: Wadi Khat.geojson
Upvotes: 0
Reputation: 956
First add your geoJSON file to your project. And if you have google maps set up than you can use the following:
let path = Bundle.main.path(forResource: "GeoJSON_sample", ofType: "json")
let url = URL(fileURLWithPath: path!)
geoJsonParser = GMUGeoJSONParser(url: url)
geoJsonParser.parse()
let renderer = GMUGeometryRenderer(map: mapView, geometries: geoJsonParser.features)
renderer.render()
Upvotes: 3
Reputation: 5535
As of today, I have not see any api can parse geojson into google map shapes on ios. Therefor you have to parse it on your own, parse it into array, then loop through array get each feature, get each geometry, properties, and create shape based on feature type(point, line, polygon)
Here is sample from mapbox to draw a line, you have to extend it to point and polygon.
// Perform GeoJSON parsing on a background thread
dispatch_queue_t backgroundQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(backgroundQueue, ^(void)
{
// Get the path for example.geojson in the app's bundle
NSString *jsonPath = [[NSBundle mainBundle] pathForResource:@"example" ofType:@"geojson"];
// Load and serialize the GeoJSON into a dictionary filled with properly-typed objects
NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:[[NSData alloc] initWithContentsOfFile:jsonPath] options:0 error:nil];
// Load the `features` dictionary for iteration
for (NSDictionary *feature in jsonDict[@"features"])
{
// Our GeoJSON only has one feature: a line string
if ([feature[@"geometry"][@"type"] isEqualToString:@"LineString"])
{
// Get the raw array of coordinates for our line
NSArray *rawCoordinates = feature[@"geometry"][@"coordinates"];
NSUInteger coordinatesCount = rawCoordinates.count;
// Create a coordinates array, sized to fit all of the coordinates in the line.
// This array will hold the properly formatted coordinates for our MGLPolyline.
CLLocationCoordinate2D coordinates[coordinatesCount];
// Iterate over `rawCoordinates` once for each coordinate on the line
for (NSUInteger index = 0; index < coordinatesCount; index++)
{
// Get the individual coordinate for this index
NSArray *point = [rawCoordinates objectAtIndex:index];
// GeoJSON is "longitude, latitude" order, but we need the opposite
CLLocationDegrees lat = [[point objectAtIndex:1] doubleValue];
CLLocationDegrees lng = [[point objectAtIndex:0] doubleValue];
CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(lat, lng);
// Add this formatted coordinate to the final coordinates array at the same index
coordinates[index] = coordinate;
}
// Create our polyline with the formatted coordinates array
MGLPolyline *polyline = [MGLPolyline polylineWithCoordinates:coordinates count:coordinatesCount];
// Optionally set the title of the polyline, which can be used for:
// - Callout view
// - Object identification
// In this case, set it to the name included in the GeoJSON
polyline.title = feature[@"properties"][@"name"]; // "Crema to Council Crest"
// Add the polyline to the map, back on the main thread
// Use weak reference to self to prevent retain cycle
__weak typeof(self) weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^(void)
{
[weakSelf.mapView addAnnotation:polyline];
});
}
}
});
here is swift code for line, you have to expend it to point and polygon
// Parsing GeoJSON can be CPU intensive, do it on a background thread
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
// Get the path for example.geojson in the app's bundle
let jsonPath = NSBundle.mainBundle().pathForResource("example", ofType: "geojson")
let jsonData = NSData(contentsOfFile: jsonPath!)
do {
// Load and serialize the GeoJSON into a dictionary filled with properly-typed objects
if let jsonDict = try NSJSONSerialization.JSONObjectWithData(jsonData!, options: []) as? NSDictionary {
// Load the `features` array for iteration
if let features = jsonDict["features"] as? NSArray {
for feature in features {
if let feature = feature as? NSDictionary {
if let geometry = feature["geometry"] as? NSDictionary {
if geometry["type"] as? String == "LineString" {
// Create an array to hold the formatted coordinates for our line
var coordinates: [CLLocationCoordinate2D] = []
if let locations = geometry["coordinates"] as? NSArray {
// Iterate over line coordinates, stored in GeoJSON as many lng, lat arrays
for location in locations {
// Make a CLLocationCoordinate2D with the lat, lng
let coordinate = CLLocationCoordinate2DMake(location[1].doubleValue, location[0].doubleValue)
// Add coordinate to coordinates array
coordinates.append(coordinate)
}
}
let line = MGLPolyline(coordinates: &coordinates, count: UInt(coordinates.count))
// Optionally set the title of the polyline, which can be used for:
// - Callout view
// - Object identification
line.title = "Crema to Council Crest"
// Add the annotation on the main thread
dispatch_async(dispatch_get_main_queue(), {
// Unowned reference to self to prevent retain cycle
[unowned self] in
self.mapView.addAnnotation(line)
})
}
}
}
}
}
}
}
catch
{
print("GeoJSON parsing failed")
}
})
Upvotes: 1