dynamically change lineWidth of mkpolyline
Asked Answered
P

3

8

I have Map in my app in which is moving as per user location.I have successfully drawn a polyline for source and destination. Using following code

- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id < MKOverlay >)overlay{
    
    MKPolylineView *view1 = [[MKPolylineView alloc] initWithOverlay:overlay];
    
        view1.lineWidth = 27.0;
        view1.strokeColor = [UIColor colorWithRed:55.0/255.0 green:168.0/255.0 blue:219.0/255.0 alpha:1];
   
    return view1;
}

But my problem is when map is moving , mean i am changing region of map as user moves , then some times polyline is not shown good some time its show thicker than actual size as you can see in below image.

i am attaching the image below, please let me know what can i do for smooth polyline when map is moving.

enter image description here

EDIT

As Matt suggested i create a subclass of MKPolylineRenderer and implement drawMapRect method as below:

-(void)drawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale inContext:(CGContextRef)context{
    
    
    CGMutablePathRef fullPath = CGPathCreateMutable();
    BOOL pathIsEmpty = YES;
    
    //merging all the points as entire path
    for (int i=0;i< self.polyline.pointCount;i++){
        CGPoint point = [self pointForMapPoint:self.polyline.points[i]];
        if (pathIsEmpty){
            CGPathMoveToPoint(fullPath, nil, point.x, point.y);
            pathIsEmpty = NO;
        } else {
            CGPathAddLineToPoint(fullPath, nil, point.x, point.y);
        }
    }
    
    //get bounding box out of entire path.
    CGRect pointsRect = CGPathGetBoundingBox(fullPath);
    CGRect mapRectCG = [self rectForMapRect:mapRect];
    //stop any drawing logic, cuz there is no path in current rect.
    if (!CGRectIntersectsRect(pointsRect, mapRectCG))return;
    
    UIColor *darker = [UIColor blackColor];
    CGFloat baseWidth = 10 / zoomScale;
    
    // draw the dark colour thicker
    CGContextAddPath(context, self.path);
    CGContextSetStrokeColorWithColor(context, darker.CGColor);
    CGContextSetLineWidth(context, baseWidth * 1.5);
    CGContextSetLineCap(context, self.lineCap);
    CGContextStrokePath(context);
    
    // now draw the stroke color with the regular width
    CGContextAddPath(context, self.path);
    CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor);
    CGContextSetLineWidth(context, baseWidth);
    CGContextSetLineCap(context, self.lineCap);
    CGContextStrokePath(context);
    
    [super drawMapRect:mapRect zoomScale:zoomScale inContext:context];
}

But Same problem See below image:

enter image description here

ok, i think i got problem , my polyline is added once, but as user's speed i changing zoom level of MKMapView, zoom level is changed , but polyline width is not refresh,

SO how can i dynamically change lineWidth of mkpolyline ??

Premolar answered 10/11, 2014 at 14:19 Comment(4)
Same problem in iOS 10 using MKPolylineRenderer. Did You found a solution for this?Histamine
I am facing same issue and not finding any solution yet.Mideast
I am also facing same issue any solution find out to manage Polyline width depending on zoom in or zoom out @KumarEventually
As of this writing, iOS 11.3.1 no valid solution is found. I tried several solution suggested on StackOverflow but none worked. Any news?Seen
H
2

The problem is that you are setting your lineWidth at a fixed width (a really big fixed width). This gets larger or smaller as the map is zoomed larger or smaller.

Instead, implement your own MKOverlayRenderer subclass, and override drawMapRect:zoomScale:inContext:. It receives a zoomScale parameter, and so you can adjust the width of your line to look good at what the current scale may be.

Hovercraft answered 10/11, 2014 at 14:37 Comment(3)
Thanks matt for answer,Can you just provide some ref. for implementing that class, i am new in this.Premolar
github.com/mattneub/Programming-iOS-Book-Examples/tree/master/…Hovercraft
:thnaks for providing ref, but still i am getting this type of blur, can you please correct me in this.Premolar
L
2

Subclass MKPolylineRenderer and override applyStrokePropertiesToContext:atZoomScale: so that it ignores the scale, and draws lines at constant width:

@interface ConstantWidthPolylineRenderer : MKPolylineRenderer
@end

@implementation ConstantWidthPolylineRenderer

- (void)applyStrokePropertiesToContext:(CGContextRef)context
                           atZoomScale:(MKZoomScale)zoomScale
{
    [super applyStrokePropertiesToContext:context atZoomScale:zoomScale];
    CGContextSetLineWidth(context, self.lineWidth);
}

@end

Now use it and admire its smooth rendering:

- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay
{
    MKPolyline *polyline = (MKPolyline *)overlay;
    ConstantWidthPolylineRenderer *renderer = [[ConstantWidthPolylineRenderer alloc] initWithPolyline:polyline];
    renderer.strokeColor = [UIColor redColor];
    renderer.lineWidth = 40;
    return renderer;
}
Leslielesly answered 24/8, 2015 at 13:42 Comment(4)
Thanks! That worked but now the problem is- When I am doing zoom in or zoom out. Line width is constant width. and that is a big issue for me.Mideast
I don't know, man. Have your custom renderer aware of the zoom level, maybe? I'm sure you'll figure things out.Ale
Sorry I am not sure how to manage the zoom level with width. But I have tried few customisation in that method but those lineWidth changes reproduce the same issue which was asked in this thread.Mideast
@Kumar Could you find solution to set lineWidth depending on zoom out and zoom in .Eventually
C
1

You need to use MKPolylineRenderer instead of MKPolylineView

- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id < MKOverlay >)overlay {
    @try {

        MKPolylineRenderer *renderer = [[[MKPolylineRenderer alloc] initWithOverlay:overlay];
        renderer.lineWidth = 27.0;
        renderer.strokeColor = [UIColor colorWithRed:55.0/255.0 green:168.0/255.0 blue:219.0/255.0 alpha:1];

        return renderer;
    }
    @catch (NSException *exception) {
        NSLog(@"exception :%@",exception.debugDescription);
    }
}

Read this one:

The MKPolylineRenderer class provides the visual representation for an MKPolyline overlay object. This renderer strokes the line only; it does not fill it. You can change the color and other drawing attributes of the polygon by modifying the properties inherited from the parent class. You typically use this class as is and do not subclass it.

From Apple library

The MKPolylineView class provides the visual representation for an MKPolyline annotation object. This view strokes the path represented by the annotation. (This class does not fill the area enclosed by the path.) You can change the color and other drawing attributes of the path by modifying the properties inherited from the MKOverlayPathView class. This class is typically used as is and not subclassed.

From Apple library

Cecilia answered 10/11, 2014 at 14:27 Comment(5)
Thnks for reply, but i am supporting ios6 also, so i have used that delegate method.Premolar
and i also have use this mkrenderer but it also give me same problem.Premolar
Yes. If you are going to support iOS 6 than MKOverlayRenderer is not available.Cecilia
is there a other way to draw polyline fast, means i have seen many with -()drawMethod(), but i have not implemented so i have no idea, can you tell me is that help me?Premolar
Ok so is there any other way to manage the lineWidth according to the zoom level? From your suggestion we have only a fixed width line on map and as we pinch more it gets disappear because of the width. @KampaiMideast

© 2022 - 2024 — McMap. All rights reserved.