Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>One of the idea I came up is to create a CGPath and stroke it with gradient every time when <code>drawMapRect</code> method been called, since the <code>MKPolylineView</code> is replaced by <code>MKPlolylineRenderer</code> in ios7.</p> <p>I tried to implement this by subclassing a <code>MKOverlayPathRenderer</code> but I failed to pick out individual CGPath, then I find a mysterious method named<code>-(void) strokePath:(CGPathRef)path inContext:(CGContextRef)context</code> which sounds like what I need, but it will not be called if you don't call the super method when you override your <code>drawMapRect</code>. </p> <p>thats what Im working out for now. </p> <p>I'll keep trying so if I work out something I'll come back and update the answer.</p> <p>=========<strong>UPDATE</strong>================================================</p> <p><img src="https://i.stack.imgur.com/iGsrj.jpg" alt="enter image description here"></p> <p>So that is what I'm worked out these days, I almost implemented the basic idea mentioned above but yes, I still cannot pick out an individual PATH according to specific mapRect, so I just draw all paths with gradient at the same time when the boundingBox of all paths intersects with current mapRect. poor trick, but work for now.</p> <p>In the <code>-(void) drawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale inContext:(CGContextRef)context</code> method in render class, I do this:</p> <pre><code>CGMutablePathRef fullPath = CGPathCreateMutable(); BOOL pathIsEmpty = YES; //merging all the points as entire path for (int i=0;i&lt; polyline.pointCount;i++){ CGPoint point = [self pointForMapPoint: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; </code></pre> <p>Then I split the entire path point by point to draw its gradient individually. note that the <code>hues</code> array containing hue value mapping each velocity of location.</p> <pre><code>for (int i=0;i&lt; polyline.pointCount;i++){ CGMutablePathRef path = CGPathCreateMutable(); CGPoint point = [self pointForMapPoint:polyline.points[i]]; ccolor = [UIColor colorWithHue:hues[i] saturation:1.0f brightness:1.0f alpha:1.0f]; if (i==0){ CGPathMoveToPoint(path, nil, point.x, point.y); } else { CGPoint prevPoint = [self pointForMapPoint:polyline.points[i-1]]; CGPathMoveToPoint(path, nil, prevPoint.x, prevPoint.y); CGPathAddLineToPoint(path, nil, point.x, point.y); CGFloat pc_r,pc_g,pc_b,pc_a, cc_r,cc_g,cc_b,cc_a; [pcolor getRed:&amp;pc_r green:&amp;pc_g blue:&amp;pc_b alpha:&amp;pc_a]; [ccolor getRed:&amp;cc_r green:&amp;cc_g blue:&amp;cc_b alpha:&amp;cc_a]; CGFloat gradientColors[8] = {pc_r,pc_g,pc_b,pc_a, cc_r,cc_g,cc_b,cc_a}; CGFloat gradientLocation[2] = {0,1}; CGContextSaveGState(context); CGFloat lineWidth = CGContextConvertSizeToUserSpace(context, (CGSize){self.lineWidth,self.lineWidth}).width; CGPathRef pathToFill = CGPathCreateCopyByStrokingPath(path, NULL, lineWidth, self.lineCap, self.lineJoin, self.miterLimit); CGContextAddPath(context, pathToFill); CGContextClip(context);//&lt;--clip your context after you SAVE it, important! CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, gradientColors, gradientLocation, 2); CGColorSpaceRelease(colorSpace); CGPoint gradientStart = prevPoint; CGPoint gradientEnd = point; CGContextDrawLinearGradient(context, gradient, gradientStart, gradientEnd, kCGGradientDrawsAfterEndLocation); CGGradientRelease(gradient); CGContextRestoreGState(context);//&lt;--Don't forget to restore your context. } pcolor = [UIColor colorWithCGColor:ccolor.CGColor]; } </code></pre> <p>That is all the core drawing method and of course you need <code>points</code>, <code>velocity</code> in your overlay class and feed them with CLLocationManager.</p> <p>the last point is how to get <code>hue</code> value out of velocity, well, I found that if hue ranging from 0.03~0.3 is exactly represent from red to green, so I do some proportionally mapping to hue and velocity.</p> <p>last of the last, here you are this is full source of this demo:<a href="https://github.com/wdanxna/GradientPolyline" rel="nofollow noreferrer">https://github.com/wdanxna/GradientPolyline</a></p> <p>don't panic if can't see the line you draw, I just position the map region on my position :)</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    1. COJust saw your answer. I think this is exactly what I need to achieve in this question : http://stackoverflow.com/questions/20247313/gradient-along-mkpolylineview-mkpolylinerenderer . Basically, if I understand correctly, you recreate the path manually segment by segment and apply a gradient only to the currently added one by clipping each time. Is this optimal/fast enough ?
      singulars
    2. COAt the very first, I tried to draw entire path with one gradient object which has all color values I need in `gradientColors` and each color value mapping one location value in my `gradientLocation`. I thought that should work but its not(weird). and document says we should not draw any thing out of current MapRect, its seems like drawing entire path once for all is not an option? so I think split it into segment is the easiest way... talking about optimal, its running ok in my iPhone :) but there still has something to improve, like: only draw lines that intersects with current MapRect.
      singulars
    3. COI implemented my stuff based on your code and github example and works absolutely great. Only changes I'd suggest is to prepare the path directly in the init and just use in the `drawRect` or simply use `CGRect pointsR = [self rectForMapRect:polyline.boundingMapRect];` and check also for CGRectContains, not only for intersection. My question is still unanswered and has a bounty. You could post your answer above there and I'd accept it happily, it helped me a lot :)
      singulars
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload