Question

I'm trying to create a "mini-map." It's a circle filled with markers, and I want the border of the circle to glow in places to indicate to the user to indicate that more markers are beyond the minimap in a given direction.

I can give the circle a 'glowing' blue border by drawing, below it, a blue circle with a slightly larger radius. I think that I can make this blue border brighter in some places than others by giving its CALayer a mask. (I've tried giving it a gradient mask, and it works.)

Assuming that I can make the proper calculations to determine how bright a given pixel should be (given the position of markers beyond the minimap's viewport), how do I set the individual pixels of a CALayer? Or is there an easier way to accomplish what I'm looking for besides making a complicated alpha value calculation for each pixel in the circle?

Thanks.

Was it helpful?

Solution

Here's my solution. I drew a series of 1-pixel arcs, each with a different stroke color.

void AddGlowArc(CGContextRef context, CGFloat x, CGFloat y, CGFloat radius, CGFloat peakAngle, CGFloat sideAngle, CGColorRef colorRef){
    CGFloat increment = .05;
    for (CGFloat angle = peakAngle - sideAngle; angle < peakAngle + sideAngle; angle+=increment){
        CGFloat alpha = (sideAngle - fabs(angle - peakAngle)) / sideAngle;
        CGColorRef newColor = CGColorCreateCopyWithAlpha(colorRef, alpha);
        CGContextSetStrokeColorWithColor(context, newColor);
        CGContextAddArc(context, x, y, radius, angle, angle + increment, 0);
        CGContextStrokePath(context);
    }
}

And then, in DrawRect,

CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 2.0);
AddGlowArc(context, 160, 160, 160, angle, .2, [UIColor colorWithRed:0 green:.76 blue:.87 alpha:1].CGColor);

OTHER TIPS

This was my [much longer] solution which would allow each glow-point layer to be added and animated individually if needed. The small circle is added on the circumference of a larger one and that larger circle is rotated. Enjoyed getting my head around this even though you answered the question

- (void)viewDidLoad
{
    [super viewDidLoad];
    CGPoint circleCenter = CGPointMake(300.f, 300.f);
    CALayer *outerCircle = [self outerCircleToRotateWithCenter:circleCenter andRadius:100.f];
    [self.view.layer addSublayer:outerCircle];

    CGFloat rotationAngleInDeg = 270.f;
    CGFloat rotationAngle = (M_PI * -rotationAngleInDeg)/180.f;

    CATransform3D transform = CATransform3DIdentity;
    transform = CATransform3DRotate(transform, rotationAngle, 0.f, 0.f, -1.f);
    [outerCircle setTransform:transform];
}

Using method:

- (CALayer *)outerCircleToRotateWithCenter:(CGPoint)circleCenter andRadius:(CGFloat )radius {
    // outer circle
    CAShapeLayer *container = [CAShapeLayer layer];
    UIBezierPath *containerCircle = [UIBezierPath
                            bezierPathWithOvalInRect:CGRectMake(0.f, 0.f, radius, radius)];
    [container setPath:containerCircle.CGPath];
    [container setBounds:CGPathGetBoundingBox(containerCircle.CGPath)];
    [container setPosition:circleCenter];
    [container setAnchorPoint:CGPointMake(0.5f, 0.5f)];
    [container setStrokeColor:[UIColor blackColor].CGColor]; // REMOVE
    [container setFillColor:nil];

    // smaller circle
    CAShapeLayer *circle = [[CAShapeLayer alloc] init];
    [container addSublayer:circle];
    UIBezierPath *circlePath = [UIBezierPath
                            bezierPathWithOvalInRect:CGRectMake(0.f, 0.f, 25.f, 25.f)];
    [circle setPath:circlePath.CGPath];
    [circle setBounds:CGPathGetBoundingBox(circlePath.CGPath)];
    [circle setFillColor:[UIColor orangeColor].CGColor];
    [circle setAnchorPoint:CGPointMake(0.5f, 0.5f)];
    [circle setPosition:CGPointMake(radius/2.f, 0.f)];
    [circle setOpacity:0.4f];

    // shadow
    [circle setShadowOpacity:0.8f];
    [circle setShadowRadius:4.f];
    [circle setShadowOffset:CGSizeMake(0.f, 0.f)];
    [circle setShadowColor:[UIColor orangeColor].CGColor];
    [circle setShadowPath:circlePath.CGPath];

    return container;
}

I'm guessing the smaller circle could be added and rotated in a single transform rather then being a sublayer.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top