SwiftUI Adding Text to Path

Viewed 70

I'm looking to add text inside the arc's, but I'm not finding that I can overlay text. For testing I'm just trying to get the angle text in earthyStatsInTonnes. I've tried using GeometryReader but the font just ends up overlapping each other in the center.

enter image description here

struct Shapes: View {

private enum Params {
    static var viewSizeOffset: CGFloat = 100
    static let lineWidth: CGFloat = 20
    static var halfLineWidth: CGFloat {
        lineWidth / 2
    }

    static let animationDuration: CGFloat =
        0.05 // nominal animation to smooth things
    static let circleDegrees: CGFloat = 360
    static let circleRotation: Angle = .init(degrees: -90)
    static let offsetFactor: CGFloat = 0.4
    static let minCircleAngle: CGFloat = 00
    static let maxCircleAngle: CGFloat = 360
    static var minCircleTrim: CGFloat {
        minCircleAngle / circleDegrees
    }

    static var maxCircleTrim: CGFloat {
        maxCircleAngle / circleDegrees
    }

    static let progressColor = Color.red
    static let backgroundColor = Color.blue
    static let arcFrame: CGFloat = 225
}

    @State private var rotation: Double = 0
    @State var earthyStatsInTonnes = [2.6, 3.0, 5.4, 6.75, 0.0]
    @State private var increment = 0
    let arcColor = [Color.red, Color.gray, Color.black, Color.green, Color.purple, Color.blue]


    var body: some View {

        GeometryReader { geo in
            VStack {
                ZStack {
                    Text("Text \(angle)")
                        .position(
                            x: 0,
                            y: 0
                        )
                    Circle()
                        .fill(.red.opacity(0.2))
                        .frame(width: Params.arcFrame + 36, height: Params.arcFrame + 36)
                        ForEach(earthyStatsInTonnes.indices) { stat in
                            VStack {
                                ZStack {
                                    arcView(startAngle: stat == 0 ? 00 : earthyStatsInTonnes[stat],
                                            endAngle: earthyStatsInTonnes[stat],
                                            total: 17.8,
                                            arcColor: arcColor[stat])

                                }
                                .zIndex(-Double(stat))
                            }
                        }
                }
                .frame(width: Params.arcFrame, height: Params.arcFrame)
                .padding(45)
            }
            .position(x: geo.size.width / 2, y: geo.size.height / 2)
        }
    }

    private func arcView(startAngle: Double, endAngle: Double, total: Double, arcColor: Color) -> some View {

        return Arc(startAngle: .degrees(startAngle * total),
                   endAngle: .degrees(startAngle * total + (endAngle * total)),
                   clockwise: true)
        .stroke(arcColor,
                style: .init(lineWidth: 36,
                             lineCap: .round,
                             lineJoin: .miter,
                             miterLimit: 0,
                             dash: [2, 3],
                             dashPhase: 1))
        .frame(width: 226, height: 229)
    }

    func onDrag(value: DragGesture.Value) {
        let circleDegrees = Params.circleDegrees
        // Calculate radians
        let vector = CGVector(dx: value.location.x, dy: value.location.y)
        let radians = atan2(
            vector.dy - Params.halfLineWidth,
            vector.dx - Params.halfLineWidth
        )

        var angle = radians * circleDegrees / 2 / .pi

        // atan2 gives -180 to 180, so set range to 0 to 360
        if angle < 0 {
            angle += circleDegrees
        }

        // constrain angle between desired range
        angle = max(angle, Params.minCircleAngle)
        angle = min(angle, Params.maxCircleAngle)

        withAnimation(Animation.linear(duration: Params.animationDuration)) {
            self.angle = Double(angle)
        }
    }
}


struct Arc: Shape {
    var startAngle: Angle
    var endAngle: Angle
    var clockwise: Bool

    func path(in rect: CGRect) -> Path {
        let rotationAdjustment = Angle.degrees(90)
        let modifiedStart = startAngle - rotationAdjustment
        let modifiedEnd = endAngle - rotationAdjustment

        var path = Path()
        path.addArc(center: CGPoint(x: rect.midX, y: rect.midY),
                    radius: rect.width / 2,
                    startAngle: modifiedStart,
                    endAngle: modifiedEnd,
                    clockwise: !clockwise)

        return path
    }
}
0 Answers
Related