ContentView.swift
//
// ContentView.swift
// swiftuidev
//
// Created by Cairocoders
//
import SwiftUI
struct PieChartCell: Shape {
let startAngle: Angle
let endAngle: Angle
func path(in rect: CGRect) -> Path {
let center = CGPoint.init(x: (rect.origin.x + rect.width)/2, y: (rect.origin.y + rect.height)/2)
let radii = min(center.x, center.y)
let path = Path { p in
p.addArc(center: center,
radius: radii,
startAngle: startAngle,
endAngle: endAngle,
clockwise: true)
p.addLine(to: center)
}
return path
}
}
struct PieChart: View {
@State private var selectedCell: UUID = UUID()
let dataModel: ChartDataModel
let onTap: (ChartCellModel?) -> ()
var body: some View {
ZStack {
ForEach(dataModel.chartCellModel) { dataSet in
PieChartCell(startAngle: self.dataModel.angle(for: dataSet.value), endAngle: self.dataModel.startingAngle)
.foregroundColor(dataSet.color)
.onTapGesture {
withAnimation {
if self.selectedCell == dataSet.id {
self.onTap(nil)
self.selectedCell = UUID()
} else {
self.selectedCell = dataSet.id
self.onTap(dataSet)
}
}
}.scaleEffect((self.selectedCell == dataSet.id) ? 1.05 : 1.0)
}
}
}
}
struct ContentView: View {
@State var selectedPie: String = ""
@State var selectedDonut: String = ""
var body: some View {
ScrollView {
VStack {
HStack(spacing: 20) {
PieChart(dataModel: ChartDataModel.init(dataModel: sample), onTap: {
dataModel in
if let dataModel = dataModel {
self.selectedPie = "Programming Language: \(dataModel.name)\nPercent: \(dataModel.value)"
} else {
self.selectedPie = ""
}
})
.frame(width: 150, height: 150, alignment: .center)
.padding()
Text(selectedPie)
.font(.footnote)
.multilineTextAlignment(.leading)
Spacer()
}
Spacer()
HStack {
ForEach(sample) { dataSet in
VStack {
Circle().foregroundColor(dataSet.color)
Text(dataSet.name).font(.footnote)
}
}
}
}
}
}
}
struct ChartCellModel: Identifiable {
let id = UUID()
let color: Color
let value: CGFloat
let name: String
}
final class ChartDataModel: ObservableObject {
var chartCellModel: [ChartCellModel]
var startingAngle = Angle(degrees: 0)
private var lastBarEndAngle = Angle(degrees: 0)
init(dataModel: [ChartCellModel]) {
chartCellModel = dataModel
}
var totalValue: CGFloat {
chartCellModel.reduce(CGFloat(0)) { (result, data) -> CGFloat in
result + data.value
}
}
func angle(for value: CGFloat) -> Angle {
if startingAngle != lastBarEndAngle {
startingAngle = lastBarEndAngle
}
lastBarEndAngle += Angle(degrees: Double(value / totalValue) * 360 )
print(lastBarEndAngle.degrees)
return lastBarEndAngle
}
}
let sample = [ ChartCellModel(color: Color.red, value: 11, name: "Javascript"),
ChartCellModel(color: Color.yellow, value: 10, name: "Swift"),
ChartCellModel(color: Color.gray, value: 24, name: "Python"),
ChartCellModel(color: Color.blue, value: 31, name: "Java"),
ChartCellModel(color: Color.green, value: 12, name: "PHP")]
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
