WWDC Quick Look 💓 By SwiftGGTeam
Swift Charts: Raise the bar

Swift Charts: Raise the bar

元の動画を見る

ハイライト

Swift Charts は、基本的なチャートに加えて、豊富なマークの組み合わせ、カスタム軸スタイル、プロット エリアの背景、およびジェスチャ インタラクション機能を提供し、開発者が単純なものから複雑なものまで完全なデータ視覚化エクスペリエンスを構築できるようにします。


主要内容

アプリに棒グラフや折れ線グラフを追加するのは難しくありません。 Hello Swift Charts セッションでは、基本的な使用法がすでに示されています。しかし、実際にデータ ダッシュボードを起動すると、多くの問題に遭遇することになります。同じ画像内で複数の視覚要素をどのように組み合わせるか? X 軸のラベルを四半期ごとにグループ化するにはどうすればよいですか?ユーザーがドラッグ アンド ドロップしてデータ範囲を選択できるようにするにはどうすればよいですか?

これらの要件には、以前は Core Graphics を自分で作成するか、サードパーティのライブラリを導入する必要がありました。 Swift Charts は、基本的な Mark に基づいた一連の組み合わせとカスタマイズのメカニズムを提供し、複雑なチャートの実装コストを大幅に削減します。

このセッションは、同じパンケーキ販売データ セットを使用してゼロから始まり、単一のマークから複数のマークのスタッキング、デフォルト スタイルから完全にカスタマイズされた軸、そしてドラッグ アンド ドロップ操作へと徐々に複雑さを加えていきます。プロセス全体は、Swift Chart の「使いやすい」から「使いやすい」までの完全なパスを示します。


詳細

複数のマークを組み合わせて豊富なデータを表現

(3:48) 水平ヒストグラムは、ランキング データを表示するための古典的な選択肢です。 x と y の値を交換して、水平レイアウトを取得します。

Chart(data, id: \.name) {
    BarMark(
        x: .value("Sales", $0.sales),
        y: .value("Name", $0.name)
    )
    .foregroundStyle(.pink)
    .accessibilityLabel($0.name)
    .accessibilityValue("\($0.sales) sold")
}

キーポイント:

  • BarMark値は x に、カテゴリは y に配置され、自動的に水平方向のヒストグラムにレンダリングされます。 -.foregroundStyle(.pink)色を均一に設定する -.accessibilityLabelそして.accessibilityValueVoiceOver のカスタム説明を入力します

(5:12) 時系列データの場合は、次を使用しますLineMark交換するBarMark型名を変更するだけです。

Chart {
    ForEach(dailySales, id: \.day) {
        BarMark(
            x: .value("Day", $0.day, unit: .day),
            y: .value("Sales", $0.sales)
        )
    }
}

キーポイント:

  • unit: .dayデータの時間粒度をフレームワークに伝え、適切な軸ラベルを自動的に生成します
  • するだろうBarMarkに変更しますLineMarkデータ レイヤーを変更せずにグラフの種類を切り替えることができます。

(6:16) 複数の都市を比較する場合、LineMark協力する.foregroundStyle(by:)異なるシリーズに色を自動的に割り当てます。

Chart {
    ForEach(seriesData, id: \.city) { series in
        ForEach(series.data, id: \.weekday) {
            LineMark(
                x: .value("Weekday", $0.weekday, unit: .day),
                y: .value("Sales", $0.sales)
            )
        }
        .foregroundStyle(by: .value("City", series.city))
        .symbol(by: .value("City", series.city))
        .interpolationMethod(.catmullRom)
    }
}

キーポイント:

  • ネスティングForEach複数の一連のデータを処理します。外側のレイヤーは都市を横断し、内側のレイヤーは都市の毎日のデータを横断します。 -.foregroundStyle(by:)都市ごとに色をグループ化し、凡例を自動的に生成 -.symbol(by:)シリーズごとに異なるデータ ポイント マーカーを使用する -.interpolationMethod(.catmullRom)Catmull-Rom 曲線を使用したスムーズな接続

(7:19) に変更されましたBarMarkグループ化されたヒストグラムを比較するときの主な違いは次のとおりです。.position(by:)

BarMark(
    x: .value("Weekday", $0.weekday, unit: .day),
    y: .value("Sales", $0.sales)
)
.foregroundStyle(by: .value("City", series.city))
.position(by: .value("City", series.city))

キーポイント:

  • .position(by:)同じ x 位置にある列を都市ごとに並べて表示します
  • 追加なし.position(by:)列は互いに積み重ねられます
  • からLineMarkに切り替えるBarMarkタイプ名を変更して追加するだけです.position(by:)

(8:02) 同じ画像に複数のマークを重ねると、データ範囲と平均を同時に表示できます。

Chart {
    ForEach(data, id: \.month) {
        AreaMark(
            x: .value("Month", $0.month, unit: .month),
            yStart: .value("Daily Min", $0.dailyMin),
            yEnd: .value("Daily Max", $0.dailyMax)
        )
        .opacity(0.3)
        LineMark(
            x: .value("Month", $0.month, unit: .month),
            y: .value("Daily Average", $0.dailyAverage)
        )
    }
}

キーポイント:

  • AreaMark使用yStartそしてyEnd地域範囲を定義し、月間最小売上高から最大売上高までの範囲を表示します。 -LineMarkエリア上に重ねて日次平均傾向を表示 -.opacity(0.3)ポリラインがはっきり見えるように領域を半透明にします。

(8:46) 別の組み合わせ:BarMark + RectangleMark

BarMark(
    x: .value("Month", $0.month, unit: .month),
    yStart: .value("Daily Min", $0.dailyMin),
    yEnd: .value("Daily Max", $0.dailyMax),
    width: .ratio(0.6)
)
.opacity(0.3)
RectangleMark(
    x: .value("Month", $0.month, unit: .month),
    y: .value("Daily Average", $0.dailyAverage),
    width: .ratio(0.6),
    height: 2
)

キーポイント:

  • BarMarkwidth: .ratio(0.6)列幅を利用可能なスペースの 60% に制御します -RectangleMarkここでは「平均的な水平線」として機能します。height: 2線のように見せる
  • 2 つのマークは同じデータを共有し、異なる次元で情報を表示します

9:19RuleMark参照線と注釈を図に追加できます。

RuleMark(
    y: .value("Average", averageValue)
)
.lineStyle(StrokeStyle(lineWidth: 3))
.annotation(position: .top, alignment: .leading) {
    Text("Average: \(averageValue, format: .number)")
        .font(.headline)
        .foregroundStyle(.blue)
}

キーポイント:

  • RuleMarky 軸上の指定された値に水平の基準線を描画します -.lineStyle(StrokeStyle(lineWidth: 3))線幅の設定 -.annotation(position: .top, alignment: .leading)ガイドの上にテキスト注釈を追加する

軸のスタイルをカスタマイズする

(13:54) チャート修飾子を使用してチャートのスケールとカラー マッピングを制御します。

Chart {
    // ... LineMark 定义 ...
}
.chartYScale(domain: 0 ... 200)
.chartForegroundStyleScale([
    "San Francisco": .orange,
    "Cupertino": .pink
])

キーポイント:

  • .chartYScale(domain:)異なるグラフ間の比較が困難になる自動スケーリングを避けるために、Y 軸の範囲を手動で設定します。 -.chartForegroundStyleScale([:])辞書による各シリーズのマッピングされたカラーの正確な制御

(15:16) X 軸のスケールとラベルの形式をカスタマイズします。

.chartXAxis {
    AxisMarks(values: .stride(by: .month)) { value in
        AxisGridLine()
        AxisTick()
        AxisValueLabel(
            format: .dateTime.month(.narrow)
        )
    }
}

キーポイント:

  • AxisMarks(values: .stride(by: .month))毎月のステップでティックを生成する -AxisGridLine()グリッド線を描く -AxisTick()目盛りを描く -AxisValueLabel(format:)使用.dateTime.month(.narrow)ラベルを短縮月 (J、A、S など) でフォーマットします。

(16:17)AxisMarksクロージャで条件判断を行い、四半期マーキングを実装します。

.chartXAxis {
    AxisMarks(values: .stride(by: .month)) { value in
        if value.as(Date.self)!.isFirstMonthOfQuarter {
            AxisGridLine().foregroundStyle(.black)
            AxisTick().foregroundStyle(.black)
            AxisValueLabel(
                format: .dateTime.month(.narrow)
            )
        } else {
            AxisGridLine()
        }
    }
}

キーポイント:

  • value.as(Date.self)軸の値を日付型に変換する
  • カスタマイズすることでisFirstMonthOfQuarter四半期の最初の月かどうかを判断するために拡張されます
  • 四半期の最初の月には完全なマーカー (グリッド線、目盛りマーク、ラベル) が表示され、他の月にはグリッド線のみが表示されます。
  • このモードは、「インターバル強調表示」のニーズに適しています。

(17:00) Y 軸をカスタマイズします。

.chartYAxis {
    AxisMarks(preset: .extended, position: .leading)
}

キーポイント:

  • preset: .extended軸ラベルの範囲を拡張する -position: .leadingY軸を左側に置きます

描画領域のスタイルをカスタマイズする

(18:26).chartPlotStyle描画領域の外観を変更します。

.chartPlotStyle { plotArea in
    plotArea.frame(height: 60 * 6)
            .background(.pink.opacity(0.2))
            .border(.pink, width: 1)
}

キーポイント:

  • plotAreaSwiftUI モディファイアを直接適用できる描画エリア ビューのプロキシです -.frame(height: 60 * 6)高さを手動で設定、60ptの各行が6つのデータに対応
  • 背景色、境界線などの任意の SwiftUI スタイルを設定できます。

ドラッグ選択インタラクション

(20:03) 合格.chartOverlayジェスチャ インタラクションを追加してブラッシング機能を実装します。

struct InteractiveBrushingChart: View {
    @State var range: (Date, Date)? = nil

    var body: some View {
        Chart {
            ForEach(data, id: \.day) {
                LineMark(
                    x: .value("Month", $0.day, unit: .day),
                    y: .value("Sales", $0.sales)
                )
                .interpolationMethod(.catmullRom)
                .symbol(Circle().strokeBorder(lineWidth: 2))
            }
            if let (start, end) = range {
                RectangleMark(
                    xStart: .value("Selection Start", start),
                    xEnd: .value("Selection End", end)
                )
                .foregroundStyle(.gray.opacity(0.2))
            }
        }
        .chartOverlay { proxy in
            GeometryReader { nthGeoItem in
                Rectangle().fill(.clear).contentShape(Rectangle())
                    .gesture(DragGesture()
                        .onChanged { value in
                            let xStart = value.startLocation.x - nthGeoItem[proxy.plotAreaFrame].origin.x
                            let xCurrent = value.location.x - nthGeoItem[proxy.plotAreaFrame].origin.x
                            if let dateStart: Date = proxy.value(atX: xStart),
                               let dateCurrent: Date = proxy.value(atX: xCurrent) {
                                range = (dateStart, dateCurrent)
                            }
                        }
                        .onEnded { _ in range = nil }
                    )
            }
        }
    }
}

キーポイント:

  • .chartOverlayチャートの上に SwiftUI ビューをオーバーレイして、ジェスチャ認識をサポートします -proxy.plotAreaFrame座標変換用の描画領域の座標枠を取得します。 -proxy.value(atX:)画面の X 座標をチャート データ フィールドの日付値に変換します。 -GeometryReaderスクリーン座標系におけるオーバーレイビューの位置を取得するために使用されます。 -RectangleMark使用xStartそしてxEnd選択した領域のハイライトをレンダリングする
  • ジェスチャーの終了時range = nil選択状態をクリア -.contentShape(Rectangle())透明な領域もジェスチャーに反応するようにする

重要ポイント

データかんばんアプリの「インターバルハイライト」機能

  • エクスプロイトAreaMark + LineMark日次変動幅と平均トレンドを重ねて表示し通過RuleMark業界のベースラインを追加
  • 使用する.chartOverlay + DragGesture時間間隔のドラッグ アンド ドロップ選択を実装するには、次を使用します。RectangleMark選択したハイライトをレンダリングする
  • からproxy.value(atX:)選択した日付範囲を取得した後、以下の統計カードがリンクされ、間隔の概要データが表示されます。

スポーツデータの視覚化

  • 使用するBarMark + .position(by:)毎週のさまざまなスポーツの継続時間を比較し、横棒グラフにスポーツのランキングが表示されます。
  • 使用する.chartYScale(domain:)異なる週の間で視覚的に誤解を招くのを避けるために、y 軸の範囲を修正しました
  • 使用する.chartXAxis各週の最初の日のみをマークするようにスケールをカスタマイズします

財務動向チャート

  • 使用するLineMark + .interpolationMethod(.catmullRom)スムーズな資産の動きを描く
  • 使用するAreaMarkyStart/yEnd月々の収入・支出の範囲を表示
  • 使用する.chartForegroundStyleScale支出/収入の配色をカスタマイズする
  • 使用するRuleMark予算ラインをマークし、予算を超過した場合に注釈の色を変更します

気象データの比較

  • 使用するLineMark協力する.foregroundStyle(by:)複数の都市の気温曲線を表示
  • 使用する.symbol(by:)各都市に異なる形状のデータ ポイント マーカーを割り当てる
  • 使用する.chartPlotStyle描画領域に水色の背景を追加して、「天気」の視覚的認識を強化します。

リーダーボードアニメーション

  • SwiftUI のデータ駆動型機能を利用して、データ変更時に連携します.animation()ランキング変動のスムーズな移行を実現
  • 風景を使用するBarMark + .foregroundStyleグラデーション表示の順位、順位が高いほど色が濃くなります
  • 使用する.chartPlotStyleデータ量が変化したときにチャートの高さが急上昇しないように、固定の高さを設定します。

関連セッション

  • Hello Swift Charts — say hello to swift charts — a flexible framework that helps you create charts entirely in swiftui that look and feel right at home on all apple platforms
  • Design an effective chart — learn how to design focused, approachable, and accessible charts with clear marks, axes, descriptions, interaction, and color
  • What’s new in SwiftUI — join us as we share the latest updates and a glimpse into the future of ui framework design including swift charts

コメント

GitHub Issues · utterances