ContentView.swift
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 | // // 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() } } |