is it possible to create a Pie / Donut chart using Apple's new Swift Charts framework?
there are images of a pie chart shown in the WWDC videos. Any help or code sample on how to create the pie chart will be much appreciated.
Thanks
is it possible to create a Pie / Donut chart using Apple's new Swift Charts framework?
there are images of a pie chart shown in the WWDC videos. Any help or code sample on how to create the pie chart will be much appreciated.
Thanks
Swift Charts does not (yet?) support polar geometry, which is what you need to build pie charts.
I would recommend using a Canvas
and drawing the information yourself, something like this:
struct Pie: View {
@State var slices: [(Double, Color)]
var body: some View {
Canvas { context, size in
let total = slices.reduce(0) { $0 + $1.0 }
context.translateBy(x: size.width * 0.5, y: size.height * 0.5)
var pieContext = context
pieContext.rotate(by: .degrees(-90))
let radius = min(size.width, size.height) * 0.48
var startAngle = Angle.zero
for (value, color) in slices {
let angle = Angle(degrees: 360 * (value / total))
let endAngle = startAngle + angle
let path = Path { p in
p.move(to: .zero)
p.addArc(center: .zero, radius: radius, startAngle: startAngle, endAngle: endAngle, clockwise: false)
p.closeSubpath()
}
pieContext.fill(path, with: .color(color))
startAngle = endAngle
}
}
.aspectRatio(1, contentMode: .fit)
}
}
struct Pie_Previews: PreviewProvider {
static var previews: some View {
Pie(slices: [
(2, .red),
(3, .orange),
(4, .yellow),
(1, .green),
(5, .blue),
(4, .indigo),
(2, .purple)
])
}
}
To make a donut chart, clip the canvas as the first thing you do in the rendering closure:
let donut = Path { p in
p.addEllipse(in: CGRect(origin: .zero, size: size))
p.addEllipse(in: CGRect(x: size.width * 0.25, y: size.height * 0.25, width: size.width * 0.5, height: size.height * 0.5))
}
context.clip(to: donut, style: .init(eoFill: true))
iOS 17 and later
As of iOS 17, pie and donut charts are now included in Apple's Charts framework.
Simple pie chart example:
Add a SectorMark to create a pie chart.
import Charts
struct ContentView: View {
var body: some View {
Chart(PieData.data, id: \.id) { element in
SectorMark(
angle: .value("Count", element.count)
)
.foregroundStyle(by: .value("Type", element.type))
}
.frame(width: 350, height: 350)
}
}
Simple doughnut chart:
Add an innerRadius to the SectorMark to create a donut.
struct ContentView: View {
var body: some View {
Chart(PieData.data, id: \.id) { element in
SectorMark(
angle: .value("Count", element.count),
innerRadius: .ratio(0.5)
)
.foregroundStyle(by: .value("Type", element.type))
}
.frame(width: 350, height: 350)
}
}
Pie chart with added features:
Add angularInset to create spacing between sectors.
Add annotation to label the sectors.
Add chartLegend to hide the chart's legend.
struct ContentView: View {
var body: some View {
Chart(data, id: \.id) { element in
SectorMark(
angle: .value("Count", element.count),
angularInset: 2.0
)
.foregroundStyle(by: .value("Type", element.type))
.annotation(position: .overlay, alignment: .center) {
VStack {
Text(element.type)
.font(.caption)
Text("\(element.count, format: .number.precision(.fractionLength(0)))")
.font(.caption)
}
}
}
.chartLegend(.hidden)
.frame(width: 350, height: 350)
}
}
Doughnut chart with added features:
Add angularInset to provide spacing between sectors.
Add cornerRadius to add rounded corners to the sectors.
Add annotation to label sectors.
struct ContentView: View {
var body: some View {
Chart(data, id: \.id) { element in
SectorMark(
angle: .value("Count", element.count),
innerRadius: .ratio(0.5),
angularInset: 2.0
)
.cornerRadius(5)
.foregroundStyle(by: .value("Type", element.type))
.annotation(position: .overlay, alignment: .center) {
Text("\(element.count, format: .number.precision(.fractionLength(0)))")
.font(.caption)
.foregroundColor(.white)
}
}
.frame(width: 350, height: 350)
}
}
Example data used above:
let data = [
ShapeModel(type: "Circle", count: 12),
ShapeModel(type: "Square", count: 10),
ShapeModel(type: "Triangle", count: 21),
ShapeModel(type: "Rectangle", count: 15),
ShapeModel(type: "Hexagon", count: 8)
]
struct ShapeModel: Identifiable {
var type: String
var count: Double
var id = UUID()
}
Yes it is possible in Apple's new swift UI by using charts, swiftUI and foundation libraries