3

I need to draw a curved arrow from one point to another. I did manage to get an straight arrow from below extension.

extension UIBezierPath {

static func arrow(from start: CGPoint, to end: CGPoint, tailWidth: CGFloat, headWidth: CGFloat, headLength: CGFloat) -> UIBezierPath {
    let length = hypot(end.x - start.x, end.y - start.y)
    let tailLength = length - headLength

    func p(_ x: CGFloat, _ y: CGFloat) -> CGPoint { return CGPoint(x: x, y: y) }
    let points: [CGPoint] = [
        p(0, tailWidth / 2),
        p(tailLength, tailWidth / 2),
        p(tailLength, headWidth / 2),
        p(length, 0),
        p(tailLength, -headWidth / 2),
        p(tailLength, -tailWidth / 2),
        p(0, -tailWidth / 2)
    ]

    let cosine = (end.x - start.x) / length
    let sine = (end.y - start.y) / length
    let transform = CGAffineTransform(a: cosine, b: sine, c: -sine, d: cosine, tx: start.x, ty: start.y)

    let path = CGMutablePath()
    path.addLines(between: points, transform: transform)


    path.closeSubpath()

    return self.init(cgPath: path)
}}

What I'm currently getting from above code. What I have now

What I need.

What I need

hashB
  • 113
  • 1
  • 12
  • “Curved” is not very specific. How do you want it to curve? Maybe you could post an image showing what you want. – rob mayoff Mar 07 '19 at 08:00
  • @robmayoff will edit my answer – hashB Mar 07 '19 at 08:02
  • try with my 2nd answer, just change radius as per your convenience. let me know if there is issue – Meet Mar 07 '19 at 10:47
  • @MShah couldn't get it working. I need an arrow with a curved line. But it doesn't draw an curved line – hashB Mar 07 '19 at 17:08
  • The code you posted was copied from [this answer](https://stackoverflow.com/a/37985645/77567). I explained the code in detail in [this answer](https://stackoverflow.com/a/13559449/77567). Did you read the explanation? You can use the technique I described there to develop code that draws a curved arrow. – rob mayoff Mar 12 '19 at 07:12

2 Answers2

2

Use addArc method for creating curve line(instead of straight line):-

path.addArc(tangent1End: start, tangent2End: end, radius: 30)

or

path.addArc(center: CGPoint(x: 100, y: 100), radius: 30, startAngle: 270, endAngle: 360, clockwise: true, transform: transform)
Meet
  • 1,196
  • 12
  • 26
1

I have created a curved arrow and used a quadratic bezier path as described here: Core Graphics, Part 4: A Path! A Path!

Quad Curve Animation

path.move(to: firstPoint)
path.addQuadCurve(to: endPoint, control: controlPoint)

I then created the arrow head by finding the angle between the control and end points:

controlPoint.angle(to: endPoint)

Then I found the points to draw the arrow head lines by adding and subtracting from this angle and adding a distance from the end point:

func offset(from point: CGPoint, distance: CGFloat, degrees: CGFloat) -> CGPoint {
    let radians = degrees * .pi / 180
    let vertical = sin(radians) * distance
    let horizontal = cos(radians) * distance
    return point.applying(CGAffineTransform(translationX: horizontal, y: vertical))
}

Finally I just draw lines to these two points.

Leon
  • 3,614
  • 1
  • 33
  • 46