The source code of the following can be found at https://github.com/cspnanda/DrawFlag
I have been working on a travel related app where I want to highlight the countries I have visited. Now MKMapView allows you to create a polygon and stroke it with a color fill. It can be achieved with few lines of code in rendererForOverlay.
This will create an image like below. It looked good but not great. I wanted to get something more interesting like the image in right.
I have been working on a travel related app where I want to highlight the countries I have visited. Now MKMapView allows you to create a polygon and stroke it with a color fill. It can be achieved with few lines of code in rendererForOverlay.
MKPolygonRenderer *renderer=[[MKPolygonRenderer alloc] initWithPolygon:overlay];renderer.fillColor = [UIColor colorWithRed:0.93 green:0.35 blue:0.26 alpha:0.7]; renderer.strokeColor = [[UIColor whiteColor] colorWithAlphaComponent:1.0]; renderer.lineWidth = 2; return renderer;
This will create an image like below. It looked good but not great. I wanted to get something more interesting like the image in right.
How do we do that ? It is a combination of following steps.
- Construct a polygon from the map points and add as an overlay to MKMapView.
- Subclass the MKPolygonRenderer and override the drawMapRect
- Create a UIBezierPath from the path property of polygon. Close the path.
- Add clip to path for intersect.
- Draw the overlay image.
Step 1 : Construct the polygon
You need points which will construct the boundary of the country. I loaded the JSON file and constructed the map overlay using
if(overLayDict == Nil) overLayDict = [[NSMutableDictionary alloc] init]; NSString *fileName = [[NSBundle mainBundle] pathForResource:@"gz_2010_us_040_00_500k" ofType:@"json"]; NSData *overlayData = [NSData dataWithContentsOfFile:fileName]; NSArray *countries = [[NSJSONSerialization JSONObjectWithData:overlayData options:NSJSONReadingAllowFragments error:nil] objectForKey:@"features"]; for (NSDictionary *country in countries) { NSMutableArray *overlays = [[NSMutableArray alloc] init]; NSDictionary *geometry = country[@"geometry"]; if ([geometry[@"type"] isEqualToString:@"Polygon"]) { MKPolygon *polygon = [ViewController overlaysFromPolygons:geometry[@"coordinates"] id:country[@"properties"][@"name"]]; if (polygon) { [overlays addObject:polygon]; } } else if ([geometry[@"type"] isEqualToString:@"MultiPolygon"]){ for (NSArray *polygonData in geometry[@"coordinates"]) { MKPolygon *polygon = [ViewController overlaysFromPolygons:polygonData id:country[@"properties"][@"name"]]; if (polygon) { [overlays addObject:polygon]; } } } else { NSLog(@"Unsupported type: %@", geometry[@"type"]); } [overLayDict setObject:overlays forKey:country[@"properties"][@"name"]]; }
Step 2 : Override the drawRect in MKPolygonRenderer
- (void)drawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale inContext:(CGContextRef)context { [super drawMapRect:mapRect zoomScale:zoomScale inContext:context]; MKMapRect theMapRect = [self.overlay boundingMapRect]; CGRect theRect = [self rectForMapRect:theMapRect]; @try { UIGraphicsPushContext(context); UIBezierPath *bpath = [UIBezierPath bezierPath]; MKPolygon *polyGon = self.polygon; MKMapPoint *points = polyGon.points; NSUInteger pointCount = polyGon.pointCount; CGPoint point = [self pointForMapPoint:points[0]]; [bpath moveToPoint:point]; for (int i = 1; i < pointCount; i++) { point = [self pointForMapPoint:points[i]]; [bpath addLineToPoint:point]; } [bpath closePath]; [bpath addClip]; [_overlayImage drawInRect:theRect blendMode:kCGBlendModeMultiply alpha:0.4]; UIGraphicsPopContext(); } @catch (NSException *exception) { NSLog(@"Caught an exception while drawing radar on map - %@",[exception description]); } @finally { } }