Draw a line with a CALayer
Asked Answered
A

3

15

I'm trying to draw a line between two points using a CALayer. Here is my code:

//positions a CALayer to be a line between a parent node and its subnodes.

-(void)makeLineLayer:(CALayer *)layer lineFromPointA:(CGPoint)pointA toPointB:(CGPoint)pointB{
    NSLog([NSString stringWithFormat:@"Coordinates: \n Ax: %f Ay: %f Bx: %f By: %f", pointA.x,pointA.y,pointB.x,pointB.y]);

    //find the length of the line:
    CGFloat length = sqrt((pointA.x - pointB.x) * (pointA.x - pointB.x) + (pointA.y -     pointB.y) * (pointA.y - pointB.y));
    layer.frame = CGRectMake(0, 0, 1, length);

    //calculate and set the layer's center:
    CGPoint center = CGPointMake((pointA.x+pointB.x)/2, (pointA.y+pointB.y)/2);
    layer.position = center;

    //calculate the angle of the line and set the layer's transform to match it.
    CGFloat angle = atan2f(pointB.y - pointA.y, pointB.x - pointA.x);
    layer.transform = CATransform3DMakeRotation(angle, 0, 0, 1);
}

I know that the length is being calculated correctly, and I'm am pretty sure that the center is also. When I run it lines are displayed that are the right length and that pass through the center point between the two points, but are not rotated correctly. At first I thought that the line was being rotated around the wrong anchor point, so I did: layer.anchorPoint = center;, but this code fails to show any lines on the screen. What am I doing wrong

Ash answered 2/2, 2014 at 19:56 Comment(2)
The anchor point is in unit coordinate space (both x and y goes from 0 to 1). This means that a centered anchor point is (0.5, 0.5), no matter the size and aspect ratio of the layer.Philipphilipa
Ok, so doing layer.anchorPoint = center; is setting the anchor point to something way off, and the rotation would be somewhere way beyond the bonds of the screen...makes sense that it doesn't display. Do you have any idea what the problem might be though?Ash
K
33

Try This...

-(void)makeLineLayer:(CALayer *)layer lineFromPointA:(CGPoint)pointA toPointB:(CGPoint)pointB
{
    CAShapeLayer *line = [CAShapeLayer layer];
    UIBezierPath *linePath=[UIBezierPath bezierPath];
    [linePath moveToPoint: pointA];
    [linePath addLineToPoint:pointB];
    line.path=linePath.CGPath;
    line.fillColor = nil;
    line.opacity = 1.0;
    line.strokeColor = [UIColor redColor].CGColor;
    [layer addSublayer:line];
}
Kerrin answered 3/2, 2014 at 7:50 Comment(1)
Yes. Don't make a solid CALayer at an angle to represent a line. Use a CAShapeLayer, and set its path.Malissamalissia
M
21

Here's a Swift version based on Rajesh Choudhary's answer:

Swift 2

func drawLine(onLayer layer: CALayer, fromPoint start: CGPoint, toPoint end: CGPoint) {
    let line = CAShapeLayer()
    let linePath = UIBezierPath()
    linePath.moveToPoint(start)
    linePath.addLineToPoint(end)
    line.path = linePath.CGPath
    line.fillColor = nil
    line.opacity = 1.0
    line.strokeColor = UIColor.redColor().CGColor
    layer.addSublayer(line)
}

Swift 3

func drawLine(onLayer layer: CALayer, fromPoint start: CGPoint, toPoint end: CGPoint) {
    let line = CAShapeLayer()
    let linePath = UIBezierPath()
    linePath.move(to: start)
    linePath.addLine(to: end)
    line.path = linePath.cgPath
    line.fillColor = nil
    line.opacity = 1.0
    line.strokeColor = UIColor.red.cgColor
    layer.addSublayer(line)
}
Magdeburg answered 6/7, 2016 at 2:2 Comment(1)
It's better to return the layer, and let the caller insert it themselves (above or below another layer, as they find fit), rather than inserting it for them.Folse
U
0

Here's a Swift 3 version based on Rajesh Choudhary's answer:

func drawLine(onLayer layer: CALayer, fromPoint start: CGPoint, toPoint end:CGPoint) {
        let line = CAShapeLayer()
        let linePath = UIBezierPath()
        linePath.move(to: start)
        linePath.addLine(to: end)
        line.path = linePath.cgPath
        line.fillColor = nil
        line.opacity = 1.0
        line.strokeColor = UIColor.green.cgColor
        layer.addSublayer(line)
    }
Unhallowed answered 25/4, 2017 at 4:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.