Код: Выделить всё
import SwiftUI
import Charts
struct Product: Identifiable {
let id = UUID()
let title: String
let revenue: Double
}
struct FirstView: View {
@State private var animateChart: Bool = false
@State private var products: [Product] = [
.init(title: "Annual", revenue: 0.1),
.init(title: "Monthly", revenue: 0.2),
.init(title: "Lifetime", revenue: 0.7)
]
@State private var selectedProduct: Product?
@State private var isDetailLocked: Bool = false
@State private var touchLocation: CGPoint?
var body: some View {
VStack {
// Refresh button
Button(action: {
// Reset the animation
withAnimation(.easeInOut(duration: 0.5)) {
animateChart = false
}
// Trigger the animation after a slight delay for reset effect
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
withAnimation(.easeInOut(duration: 1.5)) {
animateChart = true
}
}
}) {
Text("Refresh Chart")
.padding()
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(10)
}
.padding()
ZStack {
// Doughnut Chart section with smaller size
Chart(products) { product in
SectorMark(
angle: .value(
Text(verbatim: product.title),
animateChart ? product.revenue : 0 // Start from 0
),
innerRadius: .ratio(0.6),
angularInset: 2
)
.cornerRadius(6)
.foregroundStyle(
by: .value(
Text(verbatim: product.title),
product.title
)
)
}
.rotationEffect(.degrees(animateChart ? 0 : -180))
.frame(width: 200, height: 200) // Smaller chart size
// Adding an overlay to handle taps
GeometryReader { geometry in
Color.clear
.contentShape(Rectangle())
.gesture(
DragGesture(minimumDistance: 0)
.onChanged { value in
guard !isDetailLocked else { return }
let touchLocation = value.location
self.touchLocation = touchLocation
let center = CGPoint(
x: geometry.size.width / 2,
y: geometry.size.height / 2
)
let touchAngle = angleFromPoint(center: center, point: touchLocation)
let totalRevenue = products.map(\.revenue).reduce(0, +)
var currentAngle: Double = 0
for product in products {
let productAngle = 360 * (product.revenue / totalRevenue)
if touchAngle >= currentAngle && touchAngle Double {
let deltaX = point.x - center.x
let deltaY = point.y - center.y
let radians = atan2(deltaY, deltaX)
var degrees = radians * 180 / .pi
if degrees < 0 {
degrees += 360
}
// Adjust for the 90-degree rotation of the chart
degrees += 90
if degrees >= 360 {
degrees -= 360
}
return degrees
}
}
Подробнее здесь: https://stackoverflow.com/questions/791 ... -the-chart