在AppleWatch中使用Charts圖表【2】

1、前言

上一篇介紹了Charts在Watch中的基本使用,這一篇我們介紹個(gè)性化設(shè)置,使得圖表更符合我們的實(shí)際需求和風(fēng)格樣式。

2、修改Y軸范圍

還是使用上一篇的銷售量示例,默認(rèn)情況下Y軸范圍會(huì)根據(jù)實(shí)際數(shù)據(jù)自動(dòng)判斷,如示例中Y軸范圍為0-3000,假設(shè)需求是為了凸顯銷量目標(biāo)為4000,期望Y軸的范圍為0-4000,只需要添加一行代碼

.chartYScale(domain: 0...4000)

完整代碼為:

import SwiftUI
import Charts

struct ContentView: View {
    
    var body: some View {
        
        let gzData:[(day:Date,sales:Int)] = [
            (day:Util.getDate(offset:1),sales:1666),
            (day:Util.getDate(offset:2),sales:1899),
            (day:Util.getDate(offset:3),sales:1254),
            (day:Util.getDate(offset:4),sales:1200),
            (day:Util.getDate(offset:5),sales:983),
            (day:Util.getDate(offset:6),sales:1101),
            (day:Util.getDate(offset:7),sales:801),
        ]
        
        let szData:[(day:Date,sales:Int)] = [
            (day:Util.getDate(offset:1),sales:2287),
            (day:Util.getDate(offset:2),sales:1655),
            (day:Util.getDate(offset:3),sales:1598),
            (day:Util.getDate(offset:4),sales:1067),
            (day:Util.getDate(offset:5),sales:900),
            (day:Util.getDate(offset:6),sales:1201),
            (day:Util.getDate(offset:7),sales:540),
        ]
        
        let sericeData = [
            (city:"廣州",data: gzData),
            (city:"深圳",data: szData)
        ]
        
        Chart {
            ForEach(sericeData,id: \.city) { serice in
                ForEach(serice.data,id: \.day) {
                    LineMark(
                        x: .value("日期", $0.day,unit: .day),
                        y: .value("銷售量", $0.sales)
                    )
                }
                .symbol(.circle)
                .foregroundStyle(by: .value("City", serice.city))
            }
        }
        .chartYScale(domain: 0...4000)
    }
}

class Util {
    static func getDate(offset:Int) -> Date {
            let calendar = Calendar.current
            return calendar.date(byAdding: .day, value: -offset, to: Date()) ?? Date()
        }
}

運(yùn)行效果:


修改Y軸

3、自定義數(shù)據(jù)顏色

上面的示例中,系統(tǒng)自動(dòng)選擇了藍(lán)色和綠色來(lái)區(qū)分廣州和深圳的數(shù)據(jù),如果需求是用紅色和綠色來(lái)表示廣州和深圳,也只需要添加簡(jiǎn)單的代碼:

        Chart {
            ...
        }
        .chartYScale(domain: 0...4000)
        .chartForegroundStyleScale([
            "廣州": .red,
            "深圳": .green
        ])
修改顏色

3、深度自定義

圖表區(qū)域可拆分為:

  • Axes:xy軸
  • Legend:圖例
  • Plot Area:繪圖區(qū)域
Axes和Legend
Plot Area

這三個(gè)部分都可以根據(jù)我們的需求進(jìn)行自定義,我們先看下如果自定義軸和圖例。先上原始代碼:

import SwiftUI
import Charts

struct ContentView: View {
    
    var body: some View {
        
        let data = [
            (month:Util.getDateForMonth(month:1),dailyAverage:939),
            (month:Util.getDateForMonth(month:2),dailyAverage:879),
            (month:Util.getDateForMonth(month:3),dailyAverage:840),
            (month:Util.getDateForMonth(month:4),dailyAverage:823),
            (month:Util.getDateForMonth(month:5),dailyAverage:797),
            (month:Util.getDateForMonth(month:6),dailyAverage:800),
            (month:Util.getDateForMonth(month:7),dailyAverage:820),
            (month:Util.getDateForMonth(month:8),dailyAverage:834),
            (month:Util.getDateForMonth(month:9),dailyAverage:791),
            (month:Util.getDateForMonth(month:10),dailyAverage:801),
            (month:Util.getDateForMonth(month:11),dailyAverage:765),
            (month:Util.getDateForMonth(month:12),dailyAverage:489),
        ]

        Chart(data,id: \.month) {
            BarMark(
                x: .value("月", $0.month, unit: .month),
                y: .value("日均銷量", $0.dailyAverage)
            )
        }
        
    }
}

class Util {
    static func getDateForMonth(month: Int, year: Int = Calendar.current.component(.year, from: Date())) -> Date {
        // 創(chuàng)建一個(gè) DateComponents 對(duì)象
        var components = DateComponents()
        components.year = year
        components.month = month
        components.day = 1 // 設(shè)置為該月的第一天

        // 使用 Calendar 將 DateComponents 轉(zhuǎn)換為 Date
        let calendar = Calendar.current
        return calendar.date(from: components) ?? Date()
    }
}

原始代碼運(yùn)行效果:


原始代碼效果

Charts會(huì)自動(dòng)生成X抽數(shù)據(jù),我們希望能完整顯示每個(gè)月,并且使用首字母作為月份標(biāo)簽,這時(shí)我們就可以使用.chartXAxis來(lái)實(shí)現(xiàn)自定義了,給Chart添加修飾器:

Chart(data,id: \.month) {
    //...
}
.chartXAxis{
    AxisMarks(values: .stride(by: .month))
}
顯示所有月份

AxisMarks()如果不帶參數(shù),x軸創(chuàng)建的就是默認(rèn)樣式

此時(shí)雖然顯示了所有月份,但是空間不夠全部被壓縮了,此時(shí)我們來(lái)完全自定義X軸樣式:

.chartXAxis{
    AxisMarks(values: .stride(by: .month)) { value in
        AxisGridLine()
        AxisTick()
        AxisValueLabel(
            format: .dateTime.month(.narrow)
        )
    }
}
顯示所有月份首字母

嘗試分別刪除AxisGridLine()和AxisTick(),看它們分別代表什么?

其中參數(shù)值value為當(dāng)前的軸的值,本例中為數(shù)據(jù)中month,類型為Date,此時(shí)我們可以根據(jù)Date的值,x軸只顯示每個(gè)季度的首月:

.chartXAxis{
    AxisMarks(values: .stride(by: .month)) { value in
        if value.as(Date.self)!.isFirstMonthOfQuarter() {
            AxisGridLine().foregroundStyle(.white.opacity(0.3))
            AxisTick().foregroundStyle(.white.opacity(0.3))
            AxisValueLabel(
                format: .dateTime.year().quarter()
            )
        }else {
            AxisGridLine().foregroundStyle(.white.opacity(0.1))
        }
    }
}

其中isFirstMonthOfQuarter方法如下:

extension Date {
    func isFirstMonthOfQuarter() -> Bool {
        let calendar = Calendar.current
        let month = calendar.component(.month, from: self)
        return [1,4,7,10].contains(month)
    }
}

季度

我們?cè)賮?lái)看下Y軸,可以將Y軸移動(dòng)到左邊:

.chartYAxis() {
    AxisMarks(position: .leading)
}
Y軸前移

可以通過(guò)以下代碼分別隱藏X軸、Y軸、圖例:

.chartXAxis(.hidden)
.chartYAxis(.hidden)
.chartLegend(.hidden)

通過(guò) .chartPlotStyle可以拿到繪制區(qū)域上下文,進(jìn)行定制化:

.chartPlotStyle { ploatAr in
      return ploatAr
}

例如固定設(shè)置繪制區(qū)的高度為100,添加背景色和邊框:

.chartPlotStyle { ploatAr in
    ploatAr
        .frame(height: 100)
        .background(.pink.opacity(0.2))
        .border(.pink,width: 1)
}
修改繪制區(qū)高度和顏色

這篇先介紹到這里,下一篇將舉個(gè)??,將Charts應(yīng)用到實(shí)際開(kāi)發(fā)中。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容