The Util Designer
SwiftUI 畫統計圓餅圖
xcode 13.3.1, swift 5.5, iOS 15.4
2022-08-08
如何在SwiftUI中畫統計圓餅圖
首先先畫一個寬度為100的藍色的圓圈
import SwiftUI

struct CircleExample: View {
    var body: some View {
        ZStack {
            Color.brown.ignoresSafeArea()
            Circle()
                .inset(by: 50)
                .stroke(lineWidth: 100)
                .foregroundColor(.blue)
                
        }
    }
}
然後可以使用trim(from:to)去設置有畫多少個圓,0至1代表一個完整個圓圈,若0到0.25就只會畫一個4分之1的圓圈,代碼如下
import SwiftUI

struct CircleExample: View {
    var body: some View {
        ZStack {
            Color.gray.opacity(0.2).ignoresSafeArea()
            Circle()
                .inset(by: 50)
                .trim(from: 0.0, to: 0.25)
                .stroke(lineWidth: 100)
                .foregroundColor(.blue)
                
        }
    }
}
4分之1的圓圈
由於trim(from:to)的from和to參數只能為正,而在右邊的水平線是為0度的關係,若我們要畫一個不是從0度開始的圓餅,就需要rotationEffect的方法來幫忙做轉動需要的角度,如比把1/4圓餅的開始角度10度或-10度,代碼如下:
從10度開始的1/4圓餅
import SwiftUI

struct CircleExample: View {
    var body: some View {
        ZStack {
            Color.gray.opacity(0.2).ignoresSafeArea()
            Circle()
                .inset(by: 50)
                .trim(from: 0.0, to: 0.25)
                .stroke(lineWidth: 100)
                .foregroundColor(.blue)
                .rotationEffect(.degrees(10))
                
        }
    }
}
從10度開始的1/4圓餅
從-10度開始的1/4圓餅
import SwiftUI

struct CircleExample: View {
    var body: some View {
        ZStack {
            Color.gray.opacity(0.2).ignoresSafeArea()
            Circle()
                .inset(by: 50)
                .trim(from: 0.0, to: 0.25)
                .stroke(lineWidth: 100)
                .foregroundColor(.blue)
                .rotationEffect(.degrees(-10))
                
        }
    }
}
從-10度開始的1/4圓餅
知道上面的一些方法後,我們可以很容易在SwiftUI去實現一個統計的圓餅圖。假設我們想畫一個學校的男女學生和老師的統計圓餅,老師佔全校人數是4/8=0.5(藍色部分),男同學佔了3/8=0.375(黃色部分),女同學佔了1/8=0.125(綠色部分)。
實作如下:
import SwiftUI

struct CircleExample: View {
    var body: some View {
        ZStack {
            Color.gray.opacity(0.2).ignoresSafeArea()
            Circle()
                .inset(by: 50)
                .trim(from: 0.0, to: 0.5)
                .stroke(lineWidth: 100)
                .foregroundColor(.blue)
            Circle()
                .inset(by: 50)
                .trim(from: 0.5, to: (0.5+0.375))
                .stroke(lineWidth: 100)
                .foregroundColor(.yellow)
            Circle()
                .inset(by: 50)
                .trim(from: (0.5+0.375), to: 1)
                .stroke(lineWidth: 100)
                .foregroundColor(.green)

        }
    }
}
學校的男女學生和老師的統計圓餅
若每次數據改動或增減,都要自己去計算每個from和to的數值就很痛苦,以下代碼改動能輸入原始數據和每種數據的顏色,就可以畫出圓餅圖。
實作如下:
import SwiftUI


struct CircleExample: View {
    var body: some View {
        let nums : [Double] = [10.0, 30.0, 10.0]
        let colors : [Color] = [.blue, .yellow, .green]
        let degress = toDegree(nums)
        
        return ZStack {
            Color.gray.opacity(0.2).ignoresSafeArea()
            ForEach(degress.indices, id:\.self) { i in
                Circle()
                    .inset(by: 50)
                    .trim(from:degress[i].0, to: degress[i].1)
                    .stroke(lineWidth: 100)
                    .foregroundColor(colors[i])
            }
        }
    }
    
    func toDegree(_ nums : [Double]) -> [(Double, Double)] {
        var sum  = 0.0
        var acculate : [Double] = []
        var result : [(Double, Double)] = []
        for i in nums {
            acculate.append(sum)
            sum += Double(i)
        }
        for i in 0..<nums.count {
            result.append((acculate[i]/sum, (acculate[i]+nums[i])/sum))
        }
        return result
    }
    
}