【Swift UI】Swift Chartsでラベルをカスタマイズする方法!chartXAxis/chartYAxis/AxisMarks

この記事からわかること

  • Swift UIで使えるSwift Chartsフレームワーク使い方
  • グラフ実装方法
  • ラベルカスタマイズするには?
  • AxisMarks構造体使い方

index

[open]

\ アプリをリリースしました /

みんなの誕生日

友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-

posted withアプリーチ

環境

Swift UIでグラフを実装するためのフレームワークがiOS16から公式より提供されるようになったので実装方法や使い方についてまとめていきたいと思います。

Swift Chartsフレームワークとは?

公式リファレンス:Swift Charts

Swift Charts」はSwift UIで使用できるフレームワークでグラフを簡単に作成、カスタマイズすることが可能です。Apple公式から提供されているので導入作業などは必要なく、import Chartsと記述することで使用できるようになります。

詳細な実装方法などは以下の記事を参考にしてください。

Swift Chartsのラベル

Swift Chartsのラベルは基本的にグラフを実装する際の引数xyに渡した値が自動で反映されます。

Chart {
    ForEach(list) { subject in
        BarMark(
            x: .value("教科名", subject.name),
            y: .value("点数", subject.score)
        ).foregroundStyle(subject.color)
    }
}
【Swift UI】Swift Chartsフレームワークの使い方!グラフの実装方法

X軸のラベルをカスタマイズする方法

X軸のラベルは値に応じて自動的に良い感じに配置してくれます。Date型を渡すと自動でX軸を時間軸にしてくれますが以下のように自動で間引きされるせいで期待通りに表示させられない場合もあります。


struct Record: Identifiable {
    var id: UUID = UUID()
    let date: Date
    let score: Int
}

struct ContentView: View {

    var records: [Record] = [
        Record(date: DateComponents(calendar: .current, year: 2024, month: 2, day: 1).date!, score: 10),
        Record(date: DateComponents(calendar: .current, year: 2024, month: 2, day: 2).date!, score: 30),
        Record(date: DateComponents(calendar: .current, year: 2024, month: 2, day: 3).date!, score: 80),
        Record(date: DateComponents(calendar: .current, year: 2024, month: 2, day: 4).date!, score: 50),
        Record(date: DateComponents(calendar: .current, year: 2024, month: 2, day: 5).date!, score: 14),
        Record(date: DateComponents(calendar: .current, year: 2024, month: 2, day: 6).date!, score: 20),
        Record(date: DateComponents(calendar: .current, year: 2024, month: 2, day: 7).date!, score: 35),
        Record(date: DateComponents(calendar: .current, year: 2024, month: 2, day: 8).date!, score: 70),
        Record(date: DateComponents(calendar: .current, year: 2024, month: 2, day: 9).date!, score: 90)

    ]

    var body: some View {
        Chart(records) { record in
            BarMark(
                x: .value("年月日", record.date),
                y: .value("点数", record.score)
            ).foregroundStyle(.gray)
        }.padding()
    }
}
【Swift UI】Swift Chartsでラベルをカスタマイズする方法!chartXAxis/chartYAxis/AxisMarks

このX軸のラベル周りを調整できるのがchartXAxisモディファイアとAxisMarks構造体です。

chartXAxisモディファイア

公式リファレンス:chartXAxis

func chartXAxis(Visibility) -> some View
func chartXAxis<Content>(@AxisContentBuilder  content: () -> Content) -> some View where Content : AxisContent

chartXAxisグラフのX軸を構成するためのモディファイアです。引数違いで2種類用意されており、Visibilityの方は単に表示/非表示を切り替える役割を持っています。

.chartXAxis(.hidden)  // X軸ラベル非表示

2つ目の方はAxisMarks構造体を引数に渡すことでX軸の構成要素を自由にカスタマイズすることができます。初期値はAxisMarks(values: .automatic)になっており、明示的に以下を指定してもデフォルトの表示と変化はありません。

.chartXAxis {
    AxisMarks(values: .automatic)
}

AxisMarksでカスタマイズする方法

AxisMarksの中に要素を追加することで表示するグラフのUIやラベル数などをコントロールすることができるようになります。AxisMarks構造体の中には表示させたいコンテンツを渡していきます。

.chartXAxis {
    // stride:ラベルの表示間隔
    AxisMarks(values: .stride(by: .day)) {
        // グリッドライン
        AxisGridLine()
        // 目盛り
        AxisTick()
        // ラベルの値
        AxisValueLabel(format: .dateTime.year().month().day())
    }
}
【Swift UI】Swift Chartsでラベルをカスタマイズする方法!chartXAxis/chartYAxis/AxisMarks

ラベルの表示間隔を調整する

データのラベルを間引きせずに全て表示させたい場合はAxisMarksの引数ValuesAxisMarkValues.strideを渡します。引数byには表示させたい年月日をday()month()などで指定します。day()を指定すれば1日ごとに表示されるようになります。

AxisMarks(values: .stride(by: .day)) { // コンテンツ }

static func stride(
    by component: Calendar.Component,
    count: Int = 1,
    roundLowerBound: Bool? = nil,
    roundUpperBound: Bool? = nil,
    calendar: Calendar? = nil
) -> AxisMarkValues

2日おきに表示させたい場合はcount2を渡します。

AxisMarks(values: .stride(by: .day, count: 2)) { // コンテンツ }

ラベルの日付を調整する

ラベルに表示させる日付情報AxisValueLabel(format:)dateTimeを指定することで調整することができます。年月日を表示させたければyear().month().day()のように続けて指定すればOKです。

 AxisValueLabel(format: .dateTime.year().month().day())

デフォルトだとFeb 1, 2024と表示されましたが、defaultDigitsなどを指定することで2024/02/01というように表示を変更させることができます。

AxisValueLabel(format: .dateTime.year().month(.defaultDigits).day())

ラベルの表示位置を上に設定する

X軸のラベルはデフォルトではbottomに配置されていますが、上配置に変更したい場合は引数positiontopを渡します。

.chartXAxis {
    AxisMarks(position: .top)
}

X軸のラベルカテゴリ名を指定する

X軸のラベルの大元カテゴリ名を指定するにはchartXAxisLabelモディファイアを使用します。

.chartXAxisLabel("年月日", position: .bottom, alignment: .top, spacing: 10)

また以下のようにViewを指定することも可能です。

.chartXAxisLabel(position: .bottom, alignment: .top, spacing: 10) {
    Text("年月日")
        .foregroundStyle(.brown)
}

Y軸のラベルをカスタマイズする方法

Y軸ラベルのカスタマイズ方法も基本的にはX軸と同じです。Y軸用のchartYAxisモディファイアが用意されているのでそれを使用してカスタマイズしていきます。非表示にする方法も変わりません。

.chartYAxis(.hidden)  // Y軸ラベル非表示
【Swift UI】Swift Chartsでラベルをカスタマイズする方法!chartXAxis/chartYAxis/AxisMarks

ラベルの最小値/最大値を指定する

ラベルの最小値/最大値を指定するにはchartYScale(domain:)を使用します。これはChartから呼び出すので注意してください。例えば最小を0最大を120にしたい場合は以下のようになります。

.chartYScale(domain: 0...120)

ラベルの表示位置を左に設定する

Y軸のラベルはデフォルトではtrailingに配置されていますが、左配置に変更したい場合は引数positionleadingを渡します。

.chartYAxis {
    AxisMarks(position: .leading)
}

Y軸のラベルカテゴリ名を指定する

Y軸のラベルの大元カテゴリ名を指定するにはchartYAxisLabelモディファイアを使用します。

.chartYAxisLabel("点数", position: .trailing, alignment: .center, spacing: 10)

X軸同様にViewを渡すことが可能です。

 .chartYAxisLabel(position: .leading, alignment: .center, spacing: 10) {
    Text("点数")
        .foregroundStyle(.brown)
}

Y軸の値に単位をつける

Y軸に表示させている数値に単位をつけたい場合はAxisMarksの引数からvalueを受け取り以下のように実装することで自由にカスタマイズした文字ラベルを実装することができます。

.chartYAxis {
    AxisMarks(position: .leading) { value in
        AxisValueLabel {
            if let intValue = value.as(Int.self) {
                Text("\(intValue) 点")
            }
        }
    }
}

ラベルやグリッド線の表示間隔を調整する

ラベルやグリッド線の表示間隔を調整するにはAxisMarksの引数valuesに明示的に値を渡すことで実装することができます。

.chartYAxis {
    AxisMarks(position: .leading, values: [0, 20, 40, 60, 80, 100]) { value in
        AxisGridLine()
        AxisValueLabel {
            if let intValue = value.as(Int.self) {
                Text("\(intValue) 点")
            }
        }
    }
}

またAxisMarksを2つ実装することで異なる間隔でのコンテンツの設定を変更することもできます。

.chartYAxis {
    AxisMarks(position: .leading, values: [0, 20, 40, 60, 80, 100]) { value in
        AxisGridLine()
    }
    
    AxisMarks(position: .leading, values: [0, 50, 100]) { value in
        AxisValueLabel {
            if let intValue = value.as(Int.self) {
                Text("\(intValue) 点")
            }
        }
    }
}

まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。

ご覧いただきありがとうございました。

searchbox

スポンサー

ProFile

ame

趣味:読書,プログラミング学習,サイト制作,ブログ

IT嫌いを克服するためにITパスを取得しようと勉強してからサイト制作が趣味に変わりました笑
今はCMSを使わずこのサイトを完全自作でサイト運営中〜

New Article

index