Drawing polyines or routes on a MKMapView (as an MKAnnotationView) – Part 2

It turns out there is a better way to display routes on a map than the last example I gave. The problem with my last example is that the route exists in a layer above the map view, resulting in the line of the route being drawn on top of any annotation views. So pins, photos and anything else expressed as an MKAnnotation would be drawn over by the routes in the layer above the map view.

The solution to this problem then is to draw the lines as usual, but in a custom MKAnnoationView. This view will be set to not clip its own subviews, and will then have a subview that lies outside the frame of the annotation view, and this subview will draw the lines. The route annotation view needs a subview to do the rendering which will always be positioned at the full frame size and origin of the map. This way the MKAnnotationView can be smaller than the route, but it  always draws in the internal subview, which is the size of the map view.

So… long story short: the ability to put a route on a MKMapView via a custom MKAnnotation. You can download the sample code here.

//
// CSRouteView.m
// testMapp
//
// Created by Craig on 8/18/09.
// Copyright Craig Spitzkoff 2009. All rights reserved.
//
#import "CSRouteView.h"
#import "CSRouteAnnotation.h"
// this is an internally used view to CSRouteView. The CSRouteView needs a subview that does not get clipped to always
// be positioned at the full frame size and origin of the map. This way the view can be smaller than the route, but it
// always draws in the internal subview, which is the size of the map view.
@interface CSRouteViewInternal : UIView
{
// route view which added this as a subview.
CSRouteView* _routeView;
}
@property (nonatomic, retain) CSRouteView* routeView;
@end
@implementation CSRouteViewInternal
@synthesize routeView = _routeView;
-(void) drawRect:(CGRect) rect
{
CSRouteAnnotation* routeAnnotation = (CSRouteAnnotation*)self.routeView.annotation;

// only draw our lines if we're not int he moddie of a transition and we
// acutally have some points to draw.
if(!self.hidden && nil != routeAnnotation.points && routeAnnotation.points.count > 0)
{
CGContextRef context = UIGraphicsGetCurrentContext();

if(nil == routeAnnotation.lineColor)
routeAnnotation.lineColor = [UIColor blueColor]; // setting the property instead of the member variable will automatically reatin it.

CGContextSetStrokeColorWithColor(context, routeAnnotation.lineColor.CGColor);
CGContextSetRGBFillColor(context, 0.0, 0.0, 1.0, 1.0);

// Draw them with a 2.0 stroke width so they are a bit more visible.
CGContextSetLineWidth(context, 2.0);

for(int idx = 0; idx < routeAnnotation.points.count; idx++)
{
CLLocation* location = [routeAnnotation.points objectAtIndex:idx];
CGPoint point = [self.routeView.mapView convertCoordinate:location.coordinate toPointToView:self];

NSLog(@"Point: %lf, %lf", point.x, point.y);

if(idx == 0)
{
// move to the first point
CGContextMoveToPoint(context, point.x, point.y);
}
else
{
CGContextAddLineToPoint(context, point.x, point.y);
}
}

CGContextStrokePath(context);

// debug. Draw the line around our view.
/*
CGContextMoveToPoint(context, 0, 0);
CGContextAddLineToPoint(context, 0, self.frame.size.height);
CGContextAddLineToPoint(context, self.frame.size.width, self.frame.size.height);
CGContextAddLineToPoint(context, self.frame.size.width, 0);
CGContextAddLineToPoint(context, 0, 0);
CGContextStrokePath(context);
*/
}

}
-(id) init
{
self = [super init];
self.backgroundColor = [UIColor clearColor];
self.clipsToBounds = NO;

return self;
}
-(void) dealloc
{
self.routeView = nil;

[super dealloc];
}
@end
@implementation CSRouteView
@synthesize mapView = _mapView;
- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
self.backgroundColor = [UIColor clearColor];
// do not clip the bounds. We need the CSRouteViewInternal to be able to render the route, regardless of where the
// actual annotation view is displayed.
self.clipsToBounds = NO;

// create the internal route view that does the rendering of the route.
_internalRouteView = [[CSRouteViewInternal alloc] init];
_internalRouteView.routeView = self;

[self addSubview:_internalRouteView];
}
return self;
}
-(void) setMapView:(MKMapView*) mapView
{
[_mapView release];
_mapView = [mapView retain];

[self regionChanged];
}
-(void) regionChanged
{
NSLog(@"Region Changed");

// move the internal route view.
CGPoint origin = CGPointMake(0, 0);
origin = [_mapView convertPoint:origin toView:self];

_internalRouteView.frame = CGRectMake(origin.x, origin.y, _mapView.frame.size.width, _mapView.frame.size.height);
[_internalRouteView setNeedsDisplay];

}
- (void)dealloc
{
[_mapView release];
[_internalRouteView release];

[super dealloc];
}
@end

Tags: , ,

59 Responses to “Drawing polyines or routes on a MKMapView (as an MKAnnotationView) – Part 2”

  1. Drawing polyines or routes on a MKMapView (Using Map Kit on the iPhone) « The Reluctant Blogger Says:

    [...] 8-19-2009: Another update. This one displays the route as an annotation view, so it does not render on top of other annotations. You can view the update at this link. [...]

  2. Using MKAnnotation, MKPinAnnotationView and creating a custom MKAnnotationView in an MKMapView « The Reluctant Blogger Says:

    [...] Update – 8/19/2009 Another update. This one displays the route as an annotation view, so it does not render on top of other annotations.You can view the update at this link. [...]

  3. Jean-Baptiste LE STANG Says:

    Very nice follow up! This technique is really good when you have really few routes to display. I’m currently working on an application that requires sometimes nearly 500 routes. If you create an MKAnnotationView per route then you’ll get bad performances when executing the application. You can solve this by having only one MKAnnotationView centered on the MKMapView, then you add several routes (as you’re doing with an NSArray for example), then you override the drawRect method and then you can draw all the routes you have. The drawRect method can also be tuned so that you only display routes that will be really visible on the screen.

  4. Shoaib Says:

    Thanks man,

    This is very nice information and it solved my big trouble.

  5. Ben Clayton Says:

    Yeah this is excellent. Thanks! I was really disappointed that 3.0 didn’t have polyline drawing by default :-)

  6. code ninja Says:

    nice work…was working on the same thing, but using my data from google local search….i’m going to use and build off of your MKAnnotationView….in the interim, feel free to join my developer network. Thx.

  7. code ninja Says:

    Interesting code…I liked the switcher code in your mapLinesViewController to detect the pin type–very cool. And the route coordinates converted to CLLocations–good job.

    If you could figure out dynamic route tracking, base it on coordinates, and convert your coordinates on the fly–you can do your own pt-to-pt navigation!

  8. MapKit, Google Maps, iPhone and Drawing Routes or Polylines « Pixelfehler Says:

    [...] more googleing I found this site of Craig who actually proposed the some approach but had posted an update where he suggested to draw the route into a custom annotation-view to solve the problem with the [...]

  9. kish Says:

    hi,

    i have problem in displayind calloutview (bubble) ..i don’t know how to make it customize .i am getting default with title.i tried using leftcallout accessory view
    its adding a view but it looking odd..can any one help??
    thanks in advance

  10. Ed Says:

    I was using this code and ran into a problem with my annotation’s callout accessory buttons not being handled properly. I believe it was due to the internal route view taking the input. Adding this line:

    [self setUserInteractionEnabled:NO];

    to the CSRouteView init method appears to fix the problem.

  11. anand agarwal Says:

    Hi All,

    I want to show user current location on map using this code but when try to do this using
    _mapView.showUserLocation=YES;
    It is giving me error.

    -[MKUserLocation annotationType]: unrecognized selector sent to instance 0x104cf30
    2009-10-01 13:04:41.082 mapLines[1115:20b] *** Terminating app due to uncaught exception ‘NSInvalidArgumentException’, reason: ‘*** -[MKUserLocation annotationType]: unrecognized selector sent to instance 0x104cf30′
    2009-10-01 13:04:41.082 mapLines[1115:20b] Stack: (
    807902715,
    2492227131,
    808284155,
    807854166,
    807706786,
    10205,
    874128122,
    874112507,
    874096995,
    873955568,
    874083280,
    874086305,
    808000523,
    873911044,
    873917914,
    873916994,
    839246475,
    839217747,
    839235858,
    807687328,
    807683624,
    839142449,
    839142646,
    814752238
    )
    So I am not able to do this. If any body have done this. please tell me how can I achieve this.

    Other wise it is really excellent job in new updates.

  12. Rupert Says:

    Well done Craig. Just wanted you to know that I have used your technique and extended it to accomodate polygons as well.

    http://www.gisnotes.com/wordpress/2009/10/iphone-devnote-14-drawing-a-point-line-polygon-on-top-of-mkmapview/

    Best Regards,
    Rupert

  13. Charlie Mezak Says:

    @ Anand: Why don’t you just ask if ([annotation isMemberOfClass:[MKUserLocation class]]) and if so, forgo the rest of the delegate method.

    I have my own problem. The RouteView is initializing with a non-origin frame. When the map appears, the route is cut off at the top. Once the regionChanged method is called, the route draws fine, but I can’t figure out how to get the route to draw correctly the first time. Anyone have some insight on this?

    – Charlie

  14. kish Says:

    I was also curious as to whether its possible to extend CSMapAnnotation to have a bigger popup(callout) view…not just only to include a title, subtitle, accessoryviews, but also a bigger content callout…basically a larger view with more content….does MKAnnotation smart enough to scale that view callout to be bigger? becoz default callout has constant height …

    thsnks in advance

  15. rahulvyas Says:

    from where you are generating csv. is there a way that we can capture the current position and them draw the route from a fixed location.

  16. rahulvyas Says:

    how to create points as you have created in route.csv between two distances

  17. Matt Arturi Says:

    @ Charlie: I had the same problem that you referred to but I came up with this simple workaround that forces the route to be redrawn. Just create a function that nudges the map ever so slightly and have your view controller execute it after an imperceptible delay. Here’s the code:


    - (void) nudgeMap {
    CLLocationCoordinate2D newCenter;
    newCenter.latitude = _mapView.region.center.latitude - .000017;
    newCenter.longitude = _mapView.region.center.longitude;
    [_mapView setCenterCoordinate:newCenter animated:YES];
    }

    And here’s the call from my view controller’s viewWillAppear method:


    [self performSelector:@selector(nudgeMap) withObject:nil afterDelay:.01];

    That’s it. BTW – Great work Craig!

  18. David Manpearl Says:

    Dear Craig,
    First of all, thank you very much for your excellent example for drawing polylines and routes on a MKMapView (as an MKAnnotationView). I am using it to draw routes, icons, annotations, and even Pins on an MKMapView.

    However, I am having a serious problem with the order of my UIAnnotationView objects. I cannot control which objects are displayed on top of each other and the order seems random, perhaps based on the NSMutableDictionary keys and perhaps based on the reuse views controlled by dequeueReusableAnnotationViewWithIdentifier. When I use your example as-is, the view seems correct – the route is on the bottom, the Cleveland Circle image is above that, and callouts are displayed above that. But, as soon as I dramatically change the coordinates of the route allowing it to cross itself and randomly jump around, the object display order seemingly becomes random.

    Please help with some advice to guide my efforts to force my routes to be drawn on the bottom (directly above the map), images on top of that, and of course MKAnnotation callouts on top of everything.
    – Thank you and Best Regards, David

  19. Matej Bukovinski Says:

    David, adding the following lines to regionChanged solved the overlapping problem for me (note that I have only one path annotation visible at a time):

    // Check if path below other annotations and move it below if not
    UIView *parent = self.superview;
    if (parent && [parent.subviews indexOfObject:self] != 0) {
    [self removeFromSuperview];
    [parent insertSubview:self atIndex:0];
    }

    I also noticed that it’s worthwhile removing the delegate methods (regionWillChange, regionDidChange) and do the
    regionChanged call inside CSRouteView:

    - (void)setCenter:(CGPoint)c {
    [super setCenter:c];
    [self regionChanged];
    }

    There is no need to hide the path this way and I and I haven’t noticed any drastic speed decreases. If you increase the _internalRouteView frame to draw a bit off-screen than you can have an even better experience, i.e.:

    #define REGION_INC 500

    _internalRouteView.frame = CGRectMake(origin.x – REGION_INC, origin.y – REGION_INC, _mapView.frame.size.width + 2*REGION_INC, _mapView.frame.size.height + 2*REGION_INC);

  20. iGypsy Says:

    Thanks Matej! The polygon extension to this code provided by Rupert had this problem, I assume because the “route” always overlaps itself when drawing a polygon. I was scratching my head for some time trying to figure out how to make this draw on the bottom.

  21. Matej Bukovinski Says:

    This setCenter override method may not be as good as I firstly thought. On the device (not in the simulator) I noticed that some tiles were failing to load every now and then when scrolling around with a visible path. The console output contained the following line for every failed tile:

    bool GMM::TileResponse::createNextImage(Tile*, CGImage**): ERROR! image is 0

    Has anyone got any ideas what the reason for this could be?

    I tried changing the method in order to delay the drawing after the centering takes place:

    - (void)setCenter:(CGPoint)c {
    [super setCenter:c];
    [self performSelector:@selector(regionChanged) withObject:nil afterDelay:1];
    }

    and it seems to help .

  22. dmanpearl Says:

    Dear Matej,
    Thank you for regionChanged suggestion regarding the drawing order. This method works for me after the user physically moves or zooms the map. However on initialization after viewDidLoad, the annotation orders are initially incorrect. A direct call to regionChanged from within viewDidLoad does not help.
    I was able to implement a kludge work-around with your delay suggestion above by calling regionChanged after a delay from RouteView’s initialization initWithFrame:
    [self performSelector:@selector(regionChanged) withObject:nil afterDelay:0.1];
    This is obviously not an optimal solution.
    How do you suggest solving the order issue on initialization?
    – Thanks, David

  23. Matej Bukovinski Says:

    Hi David,

    I’m well aware that performSelector:withObject:afterDelay: is a submittal solution (or let’s rather call it a workaround). Calling it in setCenter does work fine for mowing along the path but produces a noticeable delay when zooming. I would much rather call the method instantly but then tiles fail to load. I have no idea why.

    CSRouteView’s viewDidLoad method should get called well before it’s inserted to the annotation view hierarchy (you probably call it in the mapView:viewForAnnotation: callback method).

    You could try overriding UIView’s didMoveToSuperview:

    - (void)didMoveToSuperview {
    UIView *parent = self.superview;
    if (parent && [parent.subviews indexOfObject:self] != 0) {
    [self removeFromSuperview];
    [parent insertSubview:self atIndex:0];
    }
    }

    Does this help? I haven’t noticed this since my map gets moved as soon as the path gets drawn.

  24. Cheryl Says:

    Hi

    Thanks for this tutorial it helped me alot. I am successfully drawing annotations on a map using an array of annotations. I can even click on the annotation and change it’s colour or image. My problem arises when the use selects the second annotation and I want to dynamically change the colour or image of the first one back to a non-selected colour/image. I can get the array of all the annotations and work through the array but once I try to set the colour or image ot the array I get a similar error as encountered by anand agarwal above. Any ideas on how best to do this?

    thanks in advance
    Cheryl

  25. Custom callout bubble to MKMapView in iPhone « JAKERI Says:

    [...] solution, inspired by drawing polylines or routes on a MKMapView, has to do with adding a subview (TouchView see code in example) on top of the MKMapView and [...]

  26. dmanpearl Says:

    Dear Craig and Matej,
    Thanks to both of you for your examples and suggestions. I have a related problem that I hope you can help with.

    I must convert the MKMapAnnotationView polylines into buttons. To do this I must trap touch events with something akin to touchesBegan, touchesMoved, and touchesEnded, convert them into latitude/longitude coordinates, test their proximity to each of my line segments, and determine if any is within a reasonable threshold distance to qualify as touched. In order for the MKMapView to continue working, I also have to pass all the touch events into the map view. I have done each of the steps above.

    Unfortunately, it turns out that MKMapView must be the First Responder. I discovered that the map view loses its ability to zoom because it apparently doesn’t receive multi-touch events properly when not receiving them as First Responder. Do you know how to trap touch events AND properly service the MKMapView?
    - Thank you, David

    P.S. Does anyone know how to change my settings to get email notifications when this thread is updated?

  27. Matej Bukovinski Says:

    Hi,

    Instead of trapping the events as they move down the responder chain, you could process them at their origin. All those touches*: methods get called from UIwindow’s sendEvent: method. Basically you create a custom UIWindow subclass and override the sendEvent: method (remember to call super). You can forward the event to your code for processing and the super call will take care of the responder chain.

    This principle was discussed in a WWDC 2009 session (Session 103 – Processing Multi-Touch Events on iPhone). If you have access to those videos, take a look.

    I don’t know about email subscriptions but comment RSS works fine for me.

    Regards,
    Matej

  28. ashwin Says:

    how do i search?
    Drawing polyines or routes on a MKMapView (as an MKAnnotationView) – Part-1

  29. ashwin Says:

    HI, guys
    I am beginner to iphone. pls anyone tell me steps for creating this program.

  30. Chris Van Buskirk Says:

    Has anyone gotten a commercial app approved using this method? Any rejections. I want to show routes in my app, but they are neither walking or driving routes.

  31. admin Says:

    Chris,

    I’ve used this method in several apps, including RunKeeper (pro and free) as well as Walking Cinema: Murder on Beacon Hill

    -Craig

  32. Chris Van Buskirk Says:

    Thanks craig, I will look em up.

  33. Jason Says:

    I have tried using this and I get a mixed bag for results. Sometimes all of my routes are displayed on top of my other annotations and sometimes just a few of them are on top. If the map loads and any of them are on top, none of my callout buttons work (probably because the route views are blocking it)

    Has anyone found a solid way to do this?

  34. Juho Says:

    Jason,

    I’ve found out the same problem, the annotations seem to be in relatively random order, not necessarily in the order they were added. I think this is especially true if they are added in very fast pace. I resolved the solution myself by adding something like:

    - (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views {
    for (int i=0; i<[views count]; i++) {
    MKAnnotationView *view = [views objectAtIndex:i];
    if ([view isKindOfClass:[ViewAnnotation class]]) {
    [[view superview] sendSubviewToBack:view];
    } else {
    [[view superview] bringSubviewToFront:view];
    }
    }
    }

    Where "ViewAnnotation" is the "CSRouteView" of the example. The pins are still in random order relative to each other, but at least they are never under my route. The solution seems to work quite well, tell me if there are issues.

  35. iphone coder Says:

    Hi,

    Still i can not tap on annotation view and it is not going to details view in updated code also.

    Is there any different code.

    Regards,

  36. Daniel Wood Says:

    Juho,

    That code worked for me, however, if you remove the else block the pins stay in the correct order and it just moves the routes to the back behind everything else.

    - (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views {
    for (int i=0; i<[views count]; i++) {
    MKAnnotationView *view = [views objectAtIndex:i];
    if ([view isKindOfClass:[ViewAnnotation class]]) {
    [[view superview] sendSubviewToBack:view];
    }
    }
    }
    }

  37. Vladimir Says:

    Hello,

    thanks for example. I don’t get: how do I add a driving or walking route to my app with MapKit ?

  38. Noam Says:

    Hello Craig and Matej,
    Thank you SO much for your contribution to the iPhone development world.
    I downloaded your source code for this project and I have a problem with the RouteAnnotation. I have the [points] array set up all correctly. When I first enter the application, the line is drawn correctly with my points. However, when I move the map with my finger (RegionChanged is called?), the line appears to extend all the way across the map. Would you guys know why this is happening?

    Thanks,
    Noam.

  39. petem Says:

    Brilliiant. I’ve been wanting to color polyons as annotations on my maps. I incorporated this work and it works very well. My app was pretty ordinary without them. Thanks very much.

  40. petem Says:

    Yes I still love this but I have a little problem. I noted the order of annotation addition, so that the latter ones wouldn’t get covered over. I’d doing this. I’m using both your path annotations and the Apple “pin” annotation on a single map. But the path area is around and very close to the pin location. The pin annotation callout has a right disclosure button. If I include the new path annotations I’m unable to activate the disclosure button action unless I zoom in very close so that the path annotation is off the map. So the path annotations are making my button inaccessible.

    I’d like to solve this problem. Would it make sense to have the path annotations (associated with the pin) respond to the touch event? If so then how? Or can we limit the size of the path annotation “rectangle”?

    Other ideas appreciated. Thanks.,

  41. petem Says:

    I should have read the comments before more carefully. Thank you Daniel Wood, your piece of code does the trick. Thank you.

  42. rhabot Says:

    This piece of code works great!
    The only flaw I could find is the amount of memory leakage…Why is the source code (that you provided) leaking so much?
    Do you know how to fix it?

    Thanks,
    rhabot.

  43. jacobms Says:

    Hi,
    first off thanks to Craig for the original code and Matej for following up with lots of great answers.

    I have a particular problem. I have created a number of annotations to hold polygons different. I want to detect touches inside these polygons. This works fine when listening for touchesEnded inside CSRouteView.

    The problem occurs when I zoom on the map. After a number of zoom ins (4-5) the touchesEnded isn’t called anymore.

    To replicate, use the original code of this post and change the background color in line 103 of CSRouteView.m to e.g. blueColor. Run the app in the simulator and notice how the whole screen is blue. Now try to to zoom once in the right side of the map and some of the map is now shown.

    touchesEnded will be called when clicking on the blue part of the screen, but not the clear part…

    Do you guys have a fix for this? I guess it’s got something to do with the size of the CSRouteView?

    Alternatively, I’ll look into subclassing UIWindow, but it seems silly to do this when it actually works quite well – apart from some details when zooming…

    Thanks in advance,
    Jacob

  44. FMulder Says:

    Hi, thanks a lot for this code.
    I have a question… I’m writing an app that needs a costant update of the overlaying track.
    I thought about two methods that doesn’t need an edit of your code.
    1) Right now, I get this working by removing the annotation, then calculating it again with the new path points and then adding it again to the mapview. But it gets laggy when there are many points and I’m moving the map.
    2) If I add an annotation for every track segment many routes are not showed correctly, and I also think that it would be a waste of memory.

    What do you think about it? do you have other (better) solutions like this or do you think it is better to edit your code for my purpose?

    thank you so much

  45. Philip Says:

    Hi!

    Thank you for providing this elegant solution. I have the same problem as Noam. When moving or zooming the map the methods for redrawing the path isn’t called. Can anyone help?

    Thanks

    Philip

  46. Ian Says:

    This has been a fantastic help – thank you all.

    I’m still struggling with the issue of the view position being wrong the first time the map is shown. It appears to be out by the size of any bars at the top of the display (in the example code – the height of the very top bar with the battery indicator etc in, in my code, that plus the navigation bar I have).

    I’ve tried the “nudge” workaround but it doesn’t seem to do anything. Any ideas ?

    Any thoughts on a fix to the root problem of this ? (If I solve it I’ll post!)

    Best regards to all,

    Ian

  47. Ian Says:

    OK this seems to fix the offset view issue. Change:

    CSRouteView* routeView = [[[CSRouteView alloc] initWithFrame:CGRectMake(0, 0, _mapView.frame.size.width, _mapView.frame.size.height)] autorelease];

    to:

    CSRouteView* routeView = [[[CSRouteView alloc] initWithFrame:CGRectMake(-1, 19, _mapView.frame.size.width, _mapView.frame.size.height)] autorelease];

    in mapLinesViewController.m

    Is there a better way to get the constants for the status bar size without using hard coded numbers like this though ?

    Regards,

    Ian

  48. john Says:

    Hey,

    Where could I get my routing info from?
    Google prohibits the use of it’s api as far as i know. Cloudmade is far too expensive.
    Any ideas?

    Thanks!

  49. john Says:

    There’s a little bug. Problably one knows how to fix that.
    If both Pins (The Userlocation & the saved location) is on the map(visible) the map doesn’t load its content. If one of the pins is outside the view it works. Any suggestions? :)

    thanks a lot.

  50. lee Says:

    Dear
    Thanks ` you for your examples . I have a related problem that I hope you can help with.
    If I changed the code:

    annotation = [[[CSMapAnnotation alloc] initWithCoordinate:[[points objectAtIndex:points.count -1] coordinate]
    annotationType:CSMapAnnotationTypeImage
    title:@”Cleveland Circle”] autorelease];

    then,the image is not on the top of the view.I think this problem is caused due to the drawRect function.But I can not solve this problem until now.Sincerely hope that with your help

  51. Nik Says:

    Hi craig,

    I’am glad there are such good developers to help all of us with less experience.
    Your code was really helpful and very well documented.

    I had a little problem, which i would like to mention.
    When testing my app on a device and navigating on the map the app crashes unexpectedly.

    I use a dictionary to keep the route annotations but i think there is a problem with the autorelease issue…

    I solved the problem by retaining the CSRouteAnnotations and releasing them on the dealloc method manually.

    What do you think about it?

  52. Routes/Lines on a MKMapView (as a MKAnnotationView) – Part 2.5 | Hans Pinckaers Says:

    [...] I should credit Craig for his example of drawing lines on a MKMapView (http://spitzkoff.com/craig/?p=108), that’s where you can find part 1 and part 2. This post is a kind of teaser what I’m [...]

  53. Ankush Says:

    Hi,

    Thanks for creating such a nice application.
    I have used your code for my application and facing a problem i.e. when I plot the route from “San Jose” to “New York”, it works fine but when I try to zoom in or zoom out, then close the application without waiting for the zoom effect. After that I re-launch the application immediately my application crashes!!! :( (

    What I figured out is that when I zoom-in or zoom-out multiple drawRect events are pushed for CSRouteView from setCenter method which are still pending for the execution, when i close the application and relaunch it I somehow gets the same process back again and my application try to handle the remaining events then shuts down.

    Please help me to resolve this issue.

  54. 知识 Says:

    顶~~~~好文章知识分享 我会经常来的252

  55. Vijay Says:

    I am having a problem with dragging pin when overlapped with other pin. It got stuck after lifting the pin.

  56. adriaan Says:

    It sounds like I have the same issues as @Charlie Mezak and @FMulder.
    What I’m trying to do is to display an evolving route. Most of it’s static but the last coordinate is extrapolated based (as if something is moving at a certain speed). I am trying to accomplish this with two routes – one for the static component and one for the extrapolated bit.

    The problem I’m having is as Charlie said that “The RouteView is initializing with a non-origin frame” which is causing the extrapolated route to get cropped in certain situations. And because I keep redrawing/extrapolating this every second, it gets re-cropped every second.

    Does anyone have an idea on how to get the RouteView to initialize correctly, i.e. aligned with the frame of the mapview?

  57. Chris Says:

    Thanks allot for your code.

    Is there anybody out there who managed displaying routes with allot of single points?
    This will be extremely slow – and blocks the mainthread, too.

    Any Ideas?

  58. Merlin Says:

    I’m using the code from Matt Arturi’s comment to fix the clipping problem.

    One thing though – for nudging to work it should move latitude not by 0.00017 (which is fine only at the map scale in this example), but by 1% of the span:

    newCenter.latitude = mapper.region.center.latitude – mapper.region.span.latitudeDelta/100;

    If you move by 0.00017 then in some zoom levels that might be quite visible, and in some zoom levels it might not move at all and not protect the clipping.

  59. Joerg Says:

    You might want to have a look at http://github.com/mobilemelting/nvpolyline
    This solution is especially targeted at iPhone OS versions prior to v.4.0

    Although it can also be used in v.4.0
    Hope this helps.

Leave a Reply