swiftUI 生成饼状图
//
// RecycleRoundView.swift
// TestUIKitApp
//
// Created by bob bob on 2021/2/23.
//
import SwiftUI
enum Animal:String {
case cat
case dog
case fish
case horse
case hamster
case rabbit
case bird
var color:Color{
switch self {
case .cat:
return .red
case .dog:
return .yellow
case .fish:
return .blue
case .horse:
return .pink
case .hamster:
return .green
case .rabbit:
return .purple
case .bird:
return .orange
default:
return .gray
}
}
}
struct PetData {
let value:Double
let animal:Animal
var color:Color{
animal.color
}
var name:String{
animal.rawValue.capitalized
}
}
struct DataSet1 {
static let dublin: [PetData] = [
.init(value: 2344553, animal: .cat),
.init(value: 1934345, animal: .dog),
.init(value: 323454, animal: .fish),
.init(value: 403400, animal: .rabbit),
.init(value: 1003445, animal: .horse),
.init(value: 1600494, animal: .hamster),
]
static let milan: [PetData] = [
.init(value: 3344553, animal: .cat),
.init(value: 2004345, animal: .dog),
.init(value: 923454, animal: .fish),
.init(value: 803400, animal: .rabbit),
.init(value: 1642345, animal: .bird),
.init(value: 804244, animal: .hamster),
]
static let london: [PetData] = [
.init(value: 3355553, animal: .cat),
.init(value: 4235345, animal: .dog),
.init(value: 1913454, animal: .fish),
.init(value: 1103400, animal: .rabbit),
.init(value: 683445, animal: .horse),
.init(value: 3300494, animal: .hamster),
]
}
struct DataPoint1:Identifiable {
let id = UUID()
let label:String
let value:Double
let color:Color
var percentage:Double = 0
var startAngle:Double = 0
var formattedPercentage:String{
String(format: "%.2f %%", percentage * 100)
}
}
struct DataPoints {
var points = [DataPoint1]()
mutating func add(value:Double,label:String,color:Color){
points.append(DataPoint1(label: label, value: value, color: color))
let total = points.reduce(0.0){
$0 + $1.value
}
points = points.map{
var point = $0
point.percentage = $0.value / total
return point
}
for i in 1..<points.count {
let previous = points[i-1]
let angle = previous.startAngle + previous.value * 360 / total
var current = points[i]
current.startAngle = angle
points[i] = current
}
}
}
//添加一个圆弧形状
struct PieSliceShape:InsettableShape {
var percent:Double
var startAngle:Angle
var insetAmount:CGFloat = 0
func inset(by amount: CGFloat) -> some InsettableShape {
var slice = self
slice.insetAmount += amount
return slice
}
func path(in rect: CGRect) -> Path {
Path(){path in
path.addArc(center: CGPoint(x: rect.size.width/2, y: rect.size.width/2), radius: rect.size.width/2 - insetAmount, startAngle: startAngle, endAngle: startAngle + Angle(degrees: percent * 360), clockwise: false)
}
}
}
//生成圆弧视图
struct PieSlice:View {
var percent:Double
var degree:Double
var color:Color
var body: some View{
GeometryReader{geometry in
PieSliceShape(percent: percent, startAngle: Angle(degrees: degree))
.strokeBorder(color,lineWidth: geometry.size.width/2)
.rotationEffect(.degrees(-90))
.aspectRatio(contentMode: .fit)
}
}
}
//界面布局视图
struct PieChart:View {
var dataPoints:DataPoints
var body: some View{
VStack(alignment: .leading, spacing: 30, content: {
ForEach(dataPoints.points) { p in
HStack( spacing: 16, content: {
Rectangle()
.foregroundColor(p.color)
.frame(width: 16, height: 16)
Text("\(p.label):\(p.formattedPercentage)")
})
}
ZStack{
ForEach(dataPoints.points) { point in
PieSlice(percent: point.percentage, degree: point.startAngle, color: point.color)
}
}.aspectRatio(contentMode: .fill)
})
}
}
//生成数据和显示
struct PieContentView:View {
@State var dataSet:[DataPoints] = [
DataSet1.dublin.reduce(into: DataPoints()){data0,data1 in
data0.add(value: data1.value, label: data1.name, color: data1.color)
},
DataSet1.milan.reduce(into: DataPoints()){data0,data1 in
data0.add(value: data1.value, label: data1.name, color: data1.color)
},
DataSet1.london.reduce(into: DataPoints()){data0,data1 in
data0.add(value: data1.value, label: data1.name, color: data1.color)
}
]
@State var selctedCity = 0
var body: some View{
VStack( spacing: 50, content: {
Text("Most popular Pets")
.font(.system(size: 32))
Picker(selection: self.$selctedCity, label: Text("Most Popular Pets"), content: {
Text("Doublin").tag(0)
Text("Milan").tag(1)
Text("London").tag(2)
})
.pickerStyle(SegmentedPickerStyle())
PieChart(dataPoints: dataSet[selctedCity])
.aspectRatio(1,contentMode: .fit)
Spacer()
}).padding(.horizontal,20)
}
}
struct RecycleRoundView_Previews: PreviewProvider {
static var previews: some View {
PieContentView()
}
}