HelloEarth is looking good, but it’s still a bit plain. Almost all map or globe apps have some sort of overlay which adds additional information or context. Let’s add some country outlines to get a taste of what’s involved when adding vector data in WhirlyGlobe-Maply.
This tutorial depends on at least the local image layer tutorial. Go ahead and open your HelloEarth project.
If you haven’t got one here is a suitable ViewController (for Objective-C or Swift) file to start with. This version is from the previous tutorial for a remote image layer.
We need some vector data to overlay on the globe. Conveniently, you’ve already got some. Go to the resources directory from earlier. Look for vectors/country_json_50m. That’s a directory full of country outlines from the Natural Earth Data project.
You can drag all of these .geojson files into your project or just your favorites. They’re organized by country code. What, you don’t know your ISO country codes? Fine, drag them all in. Be sure you’re adding them to the HelloEarth target so they get copied to the bundle.
Great, we’ve got files. Now let’s do something with them.
Here’s how you add those vectors to the display. Open ViewController and add a private method. In Objective-C, this is done in the ViewController.m, modifying the @interface section. In Swift it’s just a method with private modifier.
@interface ViewController ()
- (void) addCountries;
@end
class ViewController: UIViewController {
...
private func addCountries() {
}
...
}
The WG-Maply toolkit likes to specify many of its arguments as an NSDictionary (or Dictionary in Swift). So let’s add a private dictionary member, to set our default vector characteristics.
@interface ViewController ()
...
NSDictionary *vectorDict;
@end
class ViewController: UIViewController {
...
private var vectorDict: [String:AnyObject]?
...
}
Next, add some code to set the vector properties and call the addCountries method at the end of viewDidLoad.
// set the vector characteristics to be pretty and selectable
vectorDict = @{
kMaplyColor: [UIColor whiteColor],
kMaplySelectable: @(true),
kMaplyVecWidth: @(4.0)};
// add the countries
[self addCountries];
vectorDict = [
kMaplyColor: UIColor.white,
kMaplySelectable: true,
kMaplyVecWidth: 4.0]
// add the countries
addCountries()
Finally, fill in the addCountries method itself after viewDidLoad.
- (void)addCountries
{
// handle this in another thread
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),
^{
NSArray *allOutlines = [[NSBundle mainBundle] pathsForResourcesOfType:@"geojson" inDirectory:nil];
for (NSString *outlineFile in allOutlines)
{
NSData *jsonData = [NSData dataWithContentsOfFile:outlineFile];
if (jsonData)
{
MaplyVectorObject *wgVecObj = [MaplyVectorObject VectorObjectFromGeoJSON:jsonData];
// the admin tag from the country outline geojson has the country name save
NSString *vecName = [[wgVecObj attributes] objectForKey:@"ADMIN"];
wgVecObj.userObject = vecName;
// add the outline to our view
MaplyComponentObject *compObj = [theViewC addVectors:[NSArray arrayWithObject:wgVecObj] desc:vectorDict];
// If you ever intend to remove these, keep track of the MaplyComponentObjects above.
}
}
});
}
private func addCountries() {
// handle this in another thread
let queue = DispatchQueue.global()
queue.async {
let bundle = Bundle.main
let allOutlines = bundle.paths(forResourcesOfType: "geojson", inDirectory: nil) as! [String]
for outline in allOutlines {
if let jsonData = NSData(contentsOfFile: outline),
let wgVecObj = MaplyVectorObject(fromGeoJSON: jsonData as Data) {
// the admin tag from the country outline geojson has the country name save
if let attrs = wgVecObj.attributes,
let vecName = attrs.objectForKey("ADMIN") as? NSObject {
wgVecObj.userObject = vecName
}
// add the outline to our view
let compObj = self.theViewC?.addVectors([wgVecObj], desc: self.vectorDict)
// If you ever intend to remove these, keep track of the MaplyComponentObjects above.
}
}
}
}
Build and run the app. You should see the outlines of the countries you included in HelloEarth.
Neat! That’s the country outlines right on top of the globe with its base layer. But there’s a lot going on here so let’s unpack it.
First up, let’s look at the dispatch_async() call. That’s an asychronous request to run a block of code in another thread.
WhirlyGlobe-Maply is very thread safe and very threaded. For the user, this means you can call all the add methods from other threads and you probably should. Whenever you’ve got a bunch of work to do, like loading all these files, do it on another thread.
The code block itself is pretty simple. We’re doing the following.
The view controller returns a MaplyComponentObject. If you ever want to remove or modify these, you’ll need that object.
You might notice we’re pulling a string called “ADMIN” out of each vector. This will be handly later if we want to know which country it was.
Next up, let’s do some vector selection.