Last active
January 14, 2023 00:41
-
-
Save nkmrh/4e35108f1253343082c62c17fbdc6853 to your computer and use it in GitHub Desktop.
Draw donut pie chart with SwiftUI
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import UIKit | |
import SwiftUI | |
extension FloatingPoint { | |
var degreesToRadians: Self { self * .pi / 180 } | |
var radiansToDegrees: Self { self * 180 / .pi } | |
} | |
struct Donut: Identifiable { | |
var id = UUID() | |
var startValue: Float | |
var endValue: Float | |
var color: Color | |
} | |
struct ScaledArcBezier: Shape { | |
let startValue: Float | |
let endValue: Float | |
static func makeArcPath(startAngle: Float, endAngle: Float) -> UIBezierPath { | |
UIBezierPath(arcCenter: CGPoint(x: 0.5, y: 0.5), | |
radius: 0.5, | |
startAngle: CGFloat(startAngle.degreesToRadians), | |
endAngle: CGFloat(endAngle.degreesToRadians), | |
clockwise: true) | |
} | |
func path(in rect: CGRect) -> Path { | |
let startAngle = 360.0 * startValue | |
let endAngle = 360.0 * endValue | |
let path = Path(Self.makeArcPath(startAngle: startAngle, endAngle: endAngle).cgPath) | |
let multiplier = min(rect.width, rect.height) | |
return path | |
.applying(CGAffineTransform(scaleX: multiplier, y: multiplier)) | |
.applying(CGAffineTransform(translationX: rect.midX, y: rect.midY).inverted()) | |
.applying(CGAffineTransform(rotationAngle: CGFloat(90.0.degreesToRadians)).inverted()) | |
.applying(CGAffineTransform(translationX: rect.midX, y: rect.midY)) | |
} | |
} | |
struct ContentView: View { | |
let dounuts: [Donut] | |
var body: some View { | |
ZStack { | |
ForEach(dounuts, id: \.id) { donut in | |
ScaledArcBezier(startValue: donut.startValue, endValue: donut.endValue) | |
.stroke(style: StrokeStyle(lineWidth: 14, lineCap: .round, lineJoin: .round, miterLimit: 0, dash: [], dashPhase: 0)) | |
.foregroundColor(donut.color) | |
} | |
} | |
.frame(width: 100, height: 100) | |
} | |
} | |
import PlaygroundSupport | |
PlaygroundPage.current.liveView = UIHostingController( | |
rootView: ContentView( | |
dounuts: [ | |
Donut(startValue: 0, endValue: 1, color: Color.gray.opacity(0.5)), | |
Donut(startValue: 0, endValue: 0.27, color: Color.green.opacity(0.5)), | |
Donut(startValue: 0.28, endValue: 0.4, color: Color.purple.opacity(0.5)) | |
] | |
) | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment