I am trying to create a half donut chart like the one of the image using the new SectorMark:
So far i just created a normal donut using a sample data fo fullfill it:
struct Score: Identifiable {
let id = UUID()
let type: String
let value: Int
}
@State private var scores: [Score] = [
.init(type: "Hits", value: 1),
.init(type: "Misses", value: 9)
]
Chart(scores) { score in
SectorMark(
angle: .value("Values", score.value),
innerRadius: .ratio(0.9),
outerRadius: .ratio(0.7)
)
.foregroundStyle(
by: .value("Type", score.type)
)
}
In my chart i am trying to create, i use only to sections, to show a score of a person (number of answers he/she answered correct and wrong).
Is it a possible goal to achieve using SectorMark? I discovered this new feature from this Apple video: https://developer.apple.com/videos/play/wwdc2023/10037/
So i decided to use the approach of @Sweeper suggested and it worked for me. Since my chart will only use two values, i used a ZStack with two Circle shapes like this:
ZStack {
Circle()
.trim(from: 0.0, to: 0.7)
.stroke(Color.defaultBlue, style: StrokeStyle(lineWidth: 8, lineCap: .round))
.frame(width: screenSize.width * 0.4, height: screenSize.height * 0.2)
.rotationEffect(.degrees(-215))
Circle()
.trim(from: 0.0, to: CGFloat(-- here you can use a percentage of your choice --) / (100 / 0.7))
.stroke(Color.blue, style: StrokeStyle(lineWidth: 8, lineCap: .round))
.frame(width: screenSize.width * 0.4, height: screenSize.height * 0.2)
.rotationEffect(.degrees(-215))
}
And this was the result for me, exactly what i was looking for:
(I removed the Text view from the code)
But if you want to know if there is a way using SectorMark that is the initial question of the post, yes, there is but not too elegant.
Imagining if you have an sample like me, that is using two values for the chart, you need to:
Here is the code:
struct Score: Identifiable {
let id = UUID()
let type: String
let value: Int
let color: Color
}
struct ContentView: View {
@State private var scores: [Score] = [
.init(type: "Hits", value: 1, color: .blue),
.init(type: "Misses", value: 9, color: .green),
.init(type: "", value: 10, color: .white)
]
var body: some View {
Chart(scores) { score in
SectorMark(
angle: .value("Values", score.value),
innerRadius: .ratio(0.9),
outerRadius: .ratio(0.7)
)
.foregroundStyle(score.color)
.foregroundStyle(
by: .value("Type", score.type)
)
}
.rotationEffect(.degrees(-90))
}
}
And this is will be the result:
You probably will need to add the legend with a VStack using a Text view. Credits to @Claude31 who helped me on Apple Forum (https://developer.apple.com/forums/thread/748142)
SectorMark has a lot of potential, may be Apple can implement half donut approach on next updates.