iT邦幫忙

2022 iThome 鐵人賽

DAY 28
0
Mobile Development

在 iOS 開發路上的大小事2系列 第 28

【在 iOS 開發路上的大小事2-Day28】來自 Apple 爸爸的最新力作 - Swift Charts 之 RuleMark 實作篇

  • 分享至 

  • xImage
  •  

上一篇介紹了 RectangleMark 的實作,今天要來介紹的是 Swift Charts 的 RuleMark

RuleMark 一共提供了六種 init 的方法,讓開發者可以繪製不同樣式的圖表

public init<Y>(xStart: CGFloat? = nil, 
               xEnd: CGFloat? = nil, 
               y: PlottableValue<Y>) where Y : Plottable

public init<X, Y>(xStart: PlottableValue<X>, 
                  xEnd: PlottableValue<X>, 
                  y: PlottableValue<Y>) where X : Plottable, Y : Plottable

public init<X>(xStart: PlottableValue<X>, 
               xEnd: PlottableValue<X>, 
               y: CGFloat? = nil) where X : Plottable

public init<X>(x: PlottableValue<X>, 
               yStart: CGFloat? = nil, 
               yEnd: CGFloat? = nil) where X : Plottable

public init<X, Y>(x: PlottableValue<X>, 
                  yStart: PlottableValue<Y>, 
                  yEnd: PlottableValue<Y>) where X : Plottable, Y : Plottable

public init<Y>(x: CGFloat? = nil, 
               yStart: PlottableValue<Y>, 
               yEnd: PlottableValue<Y>) where Y : Plottable

看了一下 Apple 官方範例後,覺得可以用 RuleMark 來繪製甘特圖
因此下面就用 RuleMark 來繪製甘特圖吧

Model

import SwiftUI

struct EventEntity: Identifiable {
    
    var id = UUID().uuidString
    
    var title: String
    
    var startDate: Date
    
    var endDate: Date
    
    init(year: Int, startMonth: Int, startDay: Int, numMonths: Int, title: String) {
        self.title = title
        let calendar = Calendar.autoupdatingCurrent
        self.startDate = calendar.date(from: DateComponents(year: year, month: startMonth, day: startDay))!
        self.endDate = calendar.date(byAdding: .month, value: numMonths, to: startDate)!
    }
}

ViewModel

import SwiftUI

class EventEntityViewModel {
    
    var eventData: [EventEntity] = [
        .init(year: 2022, startMonth: 1, startDay: 1, numMonths: 2, title: "Development"),
        .init(year: 2022, startMonth: 3, startDay: 1, numMonths: 2, title: "Testing"),
        .init(year: 2022, startMonth: 5, startDay: 1, numMonths: 2, title: "Debug"),
        .init(year: 2022, startMonth: 7, startDay: 1, numMonths: 0, title: "Release")
    ]
}

View

這邊要記得 import Charts,因為我們要顯示 RuleMark 在畫面上

然後這邊宣告了一個 ViewModel 的變數 vm
並在前面加上 @State 修飾字,讓 SwiftUI 來幫我們管理 ViewModel 狀態

接著是 Charts 的語法,語法也是很簡單,像是下面這樣

@State private var vm = EventEntityViewModel()

// 1:vm.eventData,圖表的資料來源
Chart(vm.eventData) {
    RuleMark(
        xStart: .value("Start Date", $0.startDate), // 2:x 軸的起點
        xEnd: .value("End Date", $0.endDate), // 3:x 軸的終點
        y: .value("Event", $0.title) // 4:y 軸要顯示的資料
    )
}
.frame(height: 300)
.padding()

或者你也可以透過 ForEach 來寫,只是就會要讓 Model 繼承 Identifiable
並宣告 UUID() 變數在 Model 裡面,像是這樣 var id = UUID().uuidString

@State private var vm = EventEntityViewModel()

Chart {
    // 1:vm.eventData,圖表的資料來源
    ForEach(vm.eventData) { event in
        RuleMark(
            xStart: .value("Start Date", event.startDate), // 2:x 軸的起點
            xEnd: .value("End Date", event.endDate), // 3:x 軸的終點
            y: .value("Event", event.title) // 4:y 軸要顯示的資料
        )
    }
}
.frame(height: 300)
.padding()

現在的圖,應該會長得像下面這樣

RuleMark 畫甘特圖

RuleMark 還可以搭配下一篇要介紹的 BarMark 來一起繪製具有平均線的柱狀圖

RuleMark + BarMark

Model

import SwiftUI

struct DepartmentEntity: Identifiable {
    
    var id = UUID().uuidString
    
    var department: String
    
    var profit: Double
}

ViewModel

import SwiftUI

class DepartmentEntityViewModel {
    
    var departmentData: [DepartmentEntity] = [
        .init(department: "Production", profit: 15000),
        .init(department: "Marketing", profit: 8000),
        .init(department: "Finance", profit: 10000)
    ]
}

View

@State private var vm = DepartmentEntityViewModel()

Chart {
    ForEach(vm.departmentData) { department in
        BarMark(
            x: .value("Department", department.department),
            y: .value("Profit", department.profit)
        )
    }
    
    RuleMark(
        y: .value("Break Even Threshold", 9000)
    )
    .foregroundStyle(.red)
}
.frame(height: 300)
.padding()

將 RuleMark 跟 BarMark 結合完的圖,應該會長得像下面這樣

RuleMark + BarMark

完整程式碼 (RuleMark)

import SwiftUI
import Charts

struct RuleMarkView: View {
    
    @State private var vm = EventEntityViewModel()
    
    var body: some View {
        Chart {
            ForEach(vm.eventData) { event in
                RuleMark(
                    xStart: .value("Start Date", event.startDate),
                    xEnd: .value("End Date", event.endDate),
                    y: .value("Event", event.title)
                )
            }
        }
        .chartYAxisLabel("2022 Event", alignment: .center)
        .frame(height: 300)
        .padding()
    }
}

struct RuleMarkView_Previews: PreviewProvider {
    static var previews: some View {
        RuleMarkView()
    }
}

完整程式碼 (RuleMark + BarMark)

import SwiftUI
import Charts

struct RuleMark_BarMarkView: View {
    
    @State private var vm = DepartmentEntityViewModel()
    
    var body: some View {
        Chart {
            ForEach(vm.departmentData) { department in
                BarMark(
                    x: .value("Department", department.department),
                    y: .value("Profit", department.profit)
                )
            }
            
            RuleMark(
                y: .value("Break Even Threshold", 9000)
            )
            .foregroundStyle(.red)
        }
        .frame(height: 300)
        .padding()
    }
}

struct RuleMark_BarMarkView_Previews: PreviewProvider {
    static var previews: some View {
        RuleMark_BarMarkView()
    }
}

總結

這篇依照 Apple 官方教學簡單實作了 Swift Charts 中的 RuleMark

明天會來介紹 Swift Charts 系列中的最後一種圖表 BarMark,讓我們繼續看下去吧~

參考資料

  1. https://developer.apple.com/documentation/charts/rulemark

上一篇
【在 iOS 開發路上的大小事2-Day27】來自 Apple 爸爸的最新力作 - Swift Charts 之 RectangleMark 實作篇
下一篇
【在 iOS 開發路上的大小事2-Day29】來自 Apple 爸爸的最新力作 - Swift Charts 之 BarMark 實作篇
系列文
在 iOS 開發路上的大小事230
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言