포스트

HealthKit (5)

ChartView 분리

현재 DashBoardView의 View를 구성하는 코드가 길어지기에 분리를 해준다.

기존에 DashBoardView에 있던, rawSelectedDate, averageStepCount, selectedHealthMetric을 옮겨준다.

그리고 새롭게

1
2
var selectedStat: HealthMetricContext
var chartData: [HealthMetric]

두 변수를 만들어준다, 위의 두변수는 DashBoardView에서 데이터를 전달한다.

기존에 hkManager.stepData로 받던것들은 chartData로 모두 바꿔주고, annotationView도 가져온다.

이후 DashboardView에서는

1
StepBarChartView(selectedStat: selectedStat, chartData: hkManager.stepData)

Chart가 있던자리에 이렇게 대신하고 값만 전달해준다.

Average pie chart 구현

  1. 요일별로 데이터를 그룹화
  2. 요일별 평균 계산
  3. 요일별 평균을 계산하는 데이터를 새 평일 차트 객체에 넣고 차트에 표시

이 순서대로 진행을 하면 된다.

모델링

1
2
3
4
5
struct WeekdayChartData: Identifiable {
    let id = UUID()
    let date: Date
    let value: Double
}

1. 요일별로 데이터를 그룹화

Extension 구현

각 요일을 수치로 나타내기위해 Date에 새로운 변수를 사용하기위해 Extension을 사용

1
2
3
4
5
extension Date {
    var weekdayInt: Int {
        Calendar.current.component(.weekday, from: self)
    }
}

CleanShot 2024-12-15 at 01 51 58

이렇게 되면 일~토 순으로 각요일이, 1~7로 수치화 된다.

1
2
3
4
5
6
7
8
9
static func averageWeekdayCount(for metric: [HealthMetric]) -> [WeekdayChartData] {
    let sortedByWeekday = metric.sorted { $0.date.weekdayInt < $1.date.weekdayInt }
    
    for metric in sortedByWeekday {
        print(metric.date.weekdayInt)
    }
    
    return []
}

sorted를 사용하여 작은 순대로 오름차순 정렬을 한다.

실행하면 어떻게 나오는지 확인하기 위해 for 문으로 print를 찍어본다.

1
2
3
4
5
.task {
    await hkManager.fetchStepCount()
    ChartMath.averageWeekdayCount(for: hkManager.stepData)
    isShowingPermissionPrimingSheet = !hasSeenPermissionPriming
}

이때 함수를 호출할때 반드시 fetch 다음에 적어야한다.

  • fetch를 해서 값을 가져오기 전에는 함수 호출이 의미가 없다.

실행하면 다음과 같은 결과가 나온다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
1
1
1
1
2
2
2
2
3
3
3
3
4
4
4
4
5
5
5
5
6
6
6
6
7
7
7
7

이제 각 요일별로 데이터의 그룹화가 되었다.


2. 요일별 평균 계산

Swift-algorithms Package 사용

Package를 추가하기위해 Repository를 추가.

CleanShot 2024-12-15 at 02 27 35

이때 우리는 chunk라는 메서드를 사용한다.

먼저 해당 메서드를 사용하기위해

import Algorithms 임포트 하는것 잊지말자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import Algorithms

static func averageWeekdayCount(for metric: [HealthMetric]) -> [WeekdayChartData] {
    let sortedByWeekday = metric.sorted { $0.date.weekdayInt < $1.date.weekdayInt }
    let weekdayArray = sortedByWeekday.chunked { $0.date.weekdayInt == $1.date.weekdayInt }
    
    var weekdayChartData: [WeekdayChartData] = []
    
    for array in weekdayArray {
        guard let firstValue = array.first else { continue }
        let total = array.reduce(0) { $0 + $1.value }
        let avgSteps = total/Double(array.count)
        
        weekdayChartData.append(.init(date: firstValue.date, value: avgSteps))
    }
    
    // Demonstrate
    for metric in sortedByWeekday {
        print("Day: \(metric.date.weekdayInt), value: \(metric.value)")
    }
    
    print("----")
    
    for day in weekdayChartData {
        print("Day: \(day.date.weekdayInt), value: \(day.value)")
    }
    
    return weekdayChartData
}

여기서 firstValue를 사용한 이유는 first로 대표 요일를 가져오기 위함이다.

let weekdayArray = sortedByWeekday.chunked { $0.date.weekdayInt == $1.date.weekdayInt }

  • $0.date.weekdayInt == $1.date.weekdayInt를 통해 같은 요일의 데이터를 배열안에 배열로 만든다.
    • 요일이 달라지면 새롭게 배열을 만들어서 그 요일에 해당하는 요일에 데이터만 새롭게 담는다.
    • 실행 결과
      1
      2
      
        Input 데이터: [월요일(1), 월요일(1), 화요일(2), 화요일(2), 수요일(3)]
        Chunk 결과: [[월요일(1), 월요일(1)], [화요일(2), 화요일(2)], [수요일(3)]]
      

실행하면

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
Day: 1, value: 7785.2535487433415
Day: 1, value: 50162.147187641895
Day: 1, value: 42471.52430555305
Day: 1, value: 36295.063254895074
Day: 2, value: 44028.54182602777
Day: 2, value: 37742.79145187516
Day: 2, value: 47387.79961544836
Day: 2, value: 27168.551298016544
Day: 3, value: 42474.977340623795
Day: 3, value: 32215.292158814344
Day: 3, value: 41597.284353018746
Day: 3, value: 40151.93854547695
Day: 4, value: 39613.873956412725
Day: 4, value: 45595.2528026459
Day: 4, value: 36638.69483201661
Day: 4, value: 36249.68842979061
Day: 5, value: 41009.801312990014
Day: 5, value: 40065.46734613688
Day: 5, value: 32001.438090129075
Day: 5, value: 30650.892971833677
Day: 6, value: 42455.89647019689
Day: 6, value: 28662.235916839494
Day: 6, value: 38682.99549120337
Day: 6, value: 40720.13487827648
Day: 7, value: 38918.49568968225
Day: 7, value: 38450.05031951279
Day: 7, value: 35219.51695299136
Day: 7, value: 36666.9658748508
----
Day: 1, value: 34178.49707420834
Day: 2, value: 39081.921047841955
Day: 3, value: 39109.87309948346
Day: 4, value: 39524.37750521646
Day: 5, value: 35931.89993027241
Day: 6, value: 37630.31568912906
Day: 7, value: 37313.7572092593

이렇게 출력이 된다.


Chunked 메서드 작동 방식

예시 코드 from Repository

1
2
3
let numbers = [10, 20, 30, 10, 40, 40, 10, 20]
let chunks = numbers.chunked(by: { $0 <= $1 })
// [[10, 20, 30], [10, 40, 40], [10, 20]]
  • 현재값과 다음값을 비교해서 현재 값보다 같거나 큰 값을 담는다.
    • 현재 값보다 낮은 값이 나올 경우, 새롭게 배열을 생성 하여 계속 진행

3. 요일별 평균을 계산하는 데이터를 새 평일 차트 객체에 넣고 차트에 표시

Pie Chart

StepPieChartView를 새로 만들어 준다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
    var body: some View {
        VStack(alignment: .leading) {
            VStack(alignment: .leading) {
                Label("Averages", systemImage: "calendar")
                    .font(.title3.bold())
                    .foregroundStyle(.pink)
                
                Text("Last 28 Days")
                    .font(.caption)
                    .foregroundStyle(.secondary)
            }
            .padding(.bottom, 12)
            
            Chart {
                ForEach(chartData) { weekday in
                    SectorMark(angle: .value("Average Steps", weekday.value))
                }
            }
            .frame(height: 240)
        }
        .padding()
        .background(
            RoundedRectangle(cornerRadius: 12)
                .fill(Color(.secondarySystemBackground))
        )
    }

CleanShot 2024-12-15 at 03 26 36

현재는 원하나만 덩그러니 있다.


ForegroundStyle
1
2
3
4
5
6
7
Chart {
    ForEach(chartData) { weekday in
        SectorMark(angle: .value("Average Steps", weekday.value))
            .foregroundStyle(by: .value("Weekday", weekday.value)) // new
    }
}
.frame(height: 240)

CleanShot 2024-12-15 at 03 33 35

우린 보통 foregroundStyle을 사용하여 단순히 색상을 사용하였지만

CleanShot 2024-12-15 at 03 35 27

이렇게 하면 값의 분포에 따라 pie chart가 나뉘어 진다.

숫자대신 요일을 사용하기위해 Extension을 만들어 준다.

1
2
3
4
5
6
7
8
9
10
11
// Date Extenstion
var weekdayTitle: String {
    self.formatted(.dateTime.weekday(.wide))
}

Chart {
    ForEach(chartData) { weekday in
        SectorMark(angle: .value("Average Steps", weekday.value))
            .foregroundStyle(by: .value("Weekday", weekday.date.weekdayTitle)) // modified
    }
}

CleanShot 2024-12-15 at 03 40 31

이렇게 하면 요일에 따라 값의 분포가 생기게 된다.

.chartLegend(.hidden) Modifier를 사용하면

CleanShot 2024-12-15 at 03 42 01

더이상 색에 대한 설명이 보이지 않는다.


SectorMark Customizing
1
2
3
4
5
6
7
8
9
10
Chart {
    ForEach(chartData) { weekday in
        SectorMark(angle: .value("Average Steps", weekday.value),
                    innerRadius: .ratio(0.618),
                    angularInset: 1)
        .foregroundStyle(.pink.gradient)
        .cornerRadius(6)
    }
}
.frame(height: 240)

기존에는 angle에만 값을 넣었는데 Customizing을 하기 위해 paramter들을 더 사용한다.

CleanShot 2024-12-15 at 03 45 34

  • angle: 섹터의 각도 크기에 매핑되는 plottable value.
  • innerRadius: 내부 원의 반지름
    • 값이 클수록 내부 원이 커진다.
    • 고정 값을 하거나, 비율로 설정이 가능
  • angularInset: 각 section별 사이 거리
    • 값이 클수록 사이 간격이 멀어진다.

CleanShot 2024-12-15 at 03 46 29

값을 변경하면 다음과 같다.

1
2
3
SectorMark(angle: .value("Average Steps", weekday.value),
            innerRadius: .ratio(0.1), // modified
            angularInset: 10) // modified

CleanShot 2024-12-15 at 03 50 46


annotation

BarChart와 마찬가지로 Annotation추가가 가능하다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Chart {
    ForEach(chartData) { weekday in
        SectorMark(angle: .value("Average Steps", weekday.value),
                    innerRadius: .ratio(0.618),
                    angularInset: 1)
        .foregroundStyle(.pink.gradient)
        .cornerRadius(6)
        .annotation(position: .overlay) { // new
            Text(weekday.value, format: .number.precision(.fractionLength(0)))
                .foregroundStyle(.white)
                .fontWeight(.bold)
        }
    }
}
.frame(height: 240)

CleanShot 2024-12-15 at 03 54 22


Average Pie Chart Interactivity

이번에도 이전글과 같이 onChange를 통해 값이 어떻게 변하는지 알아본다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@State private var rawSelectedChartValue: Double?

    Chart {
        ForEach(chartData) { weekday in
            SectorMark(angle: .value("Average Steps", weekday.value),
                        innerRadius: .ratio(0.618),
                        angularInset: 1)
            .foregroundStyle(.pink.gradient)
            .cornerRadius(6)
        }
    }
    .chartAngleSelection(value: $rawSelectedChartValue) // new
    .frame(height: 240)
}
.padding()
.background(
    RoundedRectangle(cornerRadius: 12)
        .fill(Color(.secondarySystemBackground))
)
.onChange(of: rawSelectedChartValue) { oldValue, newValue in // new
    print(newValue)
}

Dec-15-2024 04-23-44

이렇게 값이 나오게 된다.


출력 관련 정리

  1. Pie Chart와 누적 합계
    • 원형 차트(Pie Chart) 는 데이터를 각도로 변환하여 표시한다. 각 데이터의 비율은 해당 데이터 값이 차지하는 각도로 나타난다.
    • 드래그 동작은 사용자가 차트를 터치하거나 드래그할 때 차트의 특정 각도 위치를 선택하는 것을 의미한다.
    • 이 각도 위치는 차트 데이터를 누적하여 계산한 총합의 일부로 매핑된다.
  2. 차트 드래그의 동작 원리
    • 누적 합계 계산
      • 차트는 데이터를 누적 합계(Cumulative Sum) 방식으로 관리한다.
      • 드래그한 위치에 해당하는 누적 합계 값을 반환하여 사용자가 선택한 데이터와 연관시킨다.
    • 계산 방식
      1. 각 데이터 값(chartData)의 비율(각도)을 계산.
      2. 비율(각도)을 기준으로 각 데이터 값을 누적.
      3. 드래그 위치에 해당하는 각도의 누적 합계 값을 반환.
  3. 출력된 값의 의미
    • 출력된 값은 rawSelectedChartValue의 값으로, 사용자가 선택한 차트의 각도에 해당하는 누적 합계이다.
    • 예를 들어, 주어진 chartData의 값이 다음과 같다고 가정 (현재 chartData를 출력했을 때의 값.)
      1
      2
      3
      4
      5
      6
      7
      8
      9
      
       let chartData = [
        WeekdayChartData(date: ..., value: 34178.49707420834), // 일요일 
        WeekdayChartData(date: ..., value: 39081.921047841955), // 월요일 
        WeekdayChartData(date: ..., value: 39109.87309948346),  // 화요일 
        WeekdayChartData(date: ..., value: 39524.37750521646),  // 수요일 
        WeekdayChartData(date: ..., value: 35931.89993027241),  // 목요일 
        WeekdayChartData(date: ..., value: 37630.31568912906),  // 금요일 
        WeekdayChartData(date: ..., value: 37313.7572092593)    // 토요일 
       ]
      
    • 사용자가 드래그한 위치가 누적 합계 값 80000에 해당한다고 가정하면:
    • rawSelectedChartValue = 80000
    • 누적 합계 값이 80000 이하가 되는 마지막 데이터는 화요일 (112370.3)이다.
    • 부연 설명
      1
      2
      3
      
        WeekdayChartData(date: ..., value: 34178.49707420834), // 일요일 (누적 합계: 34178.5)
        WeekdayChartData(date: ..., value: 39081.921047841955), // 월요일 (누적 합계: 73260.4)
        WeekdayChartData(date: ..., value: 39109.87309948346),  // 화요일 (누적 합계: 112370.3)
      
      • 일요일:
        • total = 34178.5
        • 조건: 80000 <= 34178.5 → False. 다음 요일로 이동.
      • 월요일:
        • total = 34178.5 + 39081.9 = 73260.4 - 조건: 80000 <= 73260.4 → False. 다음 요일로 이동.
      • 화요일:
        • total = 73260.4 + 39109.9 = 112370.3
        • 조건: 80000 <= 112370.3 → True. 화요일 반환.
  4. 사용 이유
    • 이 값들은 사용자가 선택한 차트의 각도에 해당하는 데이터 값을 찾기 위해 사용된다. 즉:
      • rawSelectedChartValue를 이용해 누적 합계와 비교.
      • 사용자가 드래그한 위치와 관련된 데이터를 반환.

이 방식은 차트 상호작용(Interactivity)을 구현하는 데 핵심 역할을 한다.

Pie Chart 요일 확인하기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var selectedWeekday: WeekdayChartData? {
    guard let rawSelectedChartValue else { return nil }
    var total = 0.0
    
    let selectedData = chartData.first {
        total += $0.value
        return rawSelectedChartValue <= total
    }
    return selectedData
}

.onChange(of: rawSelectedChartValue) { oldValue, newValue in // new
    print(selectedWeekday?.date.weekdayTitle)
}

selectedWeekday 에서는

1
2
3
4
let selectedData = chartData.first {
    total += $0.value
    return rawSelectedChartValue <= total
}

이부분만 정리를 하면 될것같다.

  1. 누적 합계 계산:
    • chartData 배열을 순회하며 각 요일 데이터의 value를 total에 더한다.
    • 이때, total은 현재까지 순회한 값들의 합계를 나타낸다.
  2. 조건 만족 시 반환:
    • 누적된 합계(total)가 rawSelectedChartValue와 같거나 클 경우, 해당 데이터를 반환한다.
    • rawSelectedChartValue는 차트에서 선택된 값의 위치를 나타낸다.
    • 이 과정을 통해 현재 선택된 섹터(요일 데이터)를 판별한다.

이때 중요한건 드래그하면서 값을 너무 생각하면 안된다. 헷갈리기 때문.

print(chartData)를 하여 각 요일에 해당하는 걸음수 평균값이 무엇인지를 먼저 떠올리자.

1
2
3
4
5
6
7
Day: 1, value: 34178.49707420834
Day: 2, value: 39081.921047841955
Day: 3, value: 39109.87309948346
Day: 4, value: 39524.37750521646
Day: 5, value: 35931.89993027241
Day: 6, value: 37630.31568912906
Day: 7, value: 37313.7572092593

위의 값이 바로 우리가 담아 두었던 값이다.

  • 드래그 시, 선택된 위치에 따라 total 값이 누적된다.
  • 드래그하지 않고 클릭만 해도, 해당 포인트에서 누적된 값이 계산된다.
  • 선택된 값(rawSelectedChartValue)은 차트 데이터(chartData)의 누적 합계와 비교되며, 조건에 맞는 요일 데이터를 반환한다.
  • rawSelectedChartValue가 특정 요일의 데이터 값보다 크면, 그 다음 요일로 이동하여 조건을 확인한다

그래서 이런 내용을 바탕으로 실행을 했을때 요일이 출력이 되는것이다.

Dec-15-2024 04-31-00


선택한 요일만 강조 (opacity)

1
2
3
4
5
6
7
8
9
10
Chart {
    ForEach(chartData) { weekday in
        SectorMark(angle: .value("Average Steps", weekday.value),
                    innerRadius: .ratio(0.618),
                    angularInset: 1)
        .foregroundStyle(.pink.gradient)
        .cornerRadius(6)
        .opacity(selectedWeekday?.date.weekdayInt == weekday.date.weekdayInt ? 1.0 : 0.3 ) // new
    }
}

이전에 했던것과 방식은 같다.

Dec-15-2024 05-47-45

outerRadius 사용

SectorMark의 Paramter에 대해 언급할떄 저부분은 당시 코드에 들어가지 않아 포함시키지 않았다.

outerRadius: 외부 원의 반지름

  • 클수록 섹터의 크기가 전체적으로 커진다.
  • 내부 반지름(innerRadius)과의 차이로 섹터의 두께를 조정할 수 있다.

outerRadius: 100 CleanShot 2024-12-15 at 05 57 56

outerRadius: 50 CleanShot 2024-12-15 at 05 58 07

이렇게 값을 통해서 전반적인 크기를 설정할 수 있다.

outerRadius: selectedWeekday?.date.weekdayInt == weekday.date.weekdayInt ? 150 : 50 Dec-15-2024 06-00-16

이런식으로 선택 부분에 대해 강조를 할 수 있다. 지금은 너무 동떨어져서 값을 다시 수정한다.

outerRadius: selectedWeekday?.date.weekdayInt == weekday.date.weekdayInt ? 140 : 110 Dec-15-2024 06-02-10

이젠 좀 더 자연스럽게 된걸 확인할 수 있다.

animation 사용

1
2
3
4
5
6
7
8
9
10
11
12
Chart {
    ForEach(chartData) { weekday in
        SectorMark(angle: .value("Average Steps", weekday.value),
                    innerRadius: .ratio(0.618),
                    outerRadius: selectedWeekday?.date.weekdayInt == weekday.date.weekdayInt ? 140 : 110,
                    angularInset: 1)
        .foregroundStyle(.pink.gradient)
        .cornerRadius(6)
        .opacity(selectedWeekday?.date.weekdayInt == weekday.date.weekdayInt ? 1.0 : 0.3 )
    }
}
.chartAngleSelection(value: $rawSelectedChartValue.animation(.easeOut)) // new

실행하면 다음과 같다.

Dec-15-2024 06-04-30

ChartBackground

.chartBackground Modifier를 사용한다.

이때 새로운 ChartProxy가 나타는데 ChartProxy Docs를 읽어보자.

WWDC2023 초반에 간단한 예시가 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
.chartAngleSelection(value: $rawSelectedChartValue.animation(.easeOut))
.frame(height: 240)
.chartBackground { proxy in // new
    GeometryReader { geo in
        if let plotFrame = proxy.plotFrame {
            let frame = geo[plotFrame]
            if let selectedWeekday {
                VStack {
                    Text(selectedWeekday.date.weekdayTitle)
                        .font(.title3.bold())
                    
                    Text(selectedWeekday.value, format: .number.precision(.fractionLength(0)))
                        .fontWeight(.medium)
                        .foregroundStyle(.secondary)
                }
                .position(x: frame.midX, y: frame.midY)
            }
        }
    }
}

여긴 조금 생소한 부분이 많기에 Docs를 기반으로 정리를 해본다.

1. Chart Background

  • chartBackground: 차트 배경에 커스텀 뷰를 추가하기 위한 Modifier.
  • ChartProxy:
    차트의 스케일과 플롯 영역에 접근하기 위해 사용하는 프록시(proxy).
    • 차트 프록시를 사용하여 데이터 값을 화면 좌표로 변환하거나 그 반대로 변환할 수 있다.
  • proxy.plotFrame:
    • 차트의 플롯 영역에 대한 프레임을 나타내는 앵커(anchor) 이며, CGRect 값(Optional).
    • 앵커를 GeometryProxy를 사용하여 프레임으로 변환할 수 있다..

플롯 영역은 실제로 파이 차트, 막대 그래프, 선 그래프 등 데이터 시각화가 그려지는 공간을 말한다. 즉, 차트의 데이터를 시각적으로 나타내는 핵심 영역이다.


2. GeometryReader

  • GeometryReader: 자신의 크기와 좌표 공간을 기반으로 내용을 정의하는 컨테이너 뷰.
  • GeometryProxy: 컨테이너 뷰의 크기와 좌표 공간(앵커를 해석하기 위한)에 접근하기 위한 프록시.
  • geo[plotFrame]:
    • proxy.plotFrameGeometryProxy 객체(geo)와 함께 사용하여 플롯 영역의 실제 좌표와 크기를 계산.
    • 반환값은 차트 배경 내에서의 플롯 영역 위치(CGRect).

이건 예전에 회고 할때 잠깐 나왔었다. GeometryReaderGeometryProxy 를 읽어보는걸 추천

3. 정리

  1. 차트의 배경에 텍스트를 표현하기 위해 chartBackground Modifier 사용.
  2. ChartProxy를 사용하여 차트의 플롯 영역(데이터 시각화가 이루어지는 공간)에 접근.
  3. GeometryReader를 사용하여 좌표 기반으로 내용을 정의하는 컨테이너 뷰를 생성.
  4. GeometryProxy를 사용하여 플롯 영역의 앵커(proxy.plotFrame)를 화면 좌표(CGRect)로 변환.
  5. 선택한 날짜가 있다면(드래그 또는 클릭), 플롯 영역의 중심에 텍스트를 표시.

실행하면 다음과 같다.

Dec-15-2024 06-10-06

Transition 효과

1
2
3
4
5
6
7
8
9
10
11
12
13
if let selectedWeekday {
    VStack {
        Text(selectedWeekday.date.weekdayTitle)
            .font(.title3.bold())
            .contentTransition(.identity) // new
        
        Text(selectedWeekday.value, format: .number.precision(.fractionLength(0)))
            .fontWeight(.medium)
            .foregroundStyle(.secondary)
            .contentTransition(.numericText()) // new
    }
    .position(x: frame.midX, y: frame.midY) 
}

실행하면 다음과 같다.

Dec-15-2024 06-15-22

댓글을 보니

1
2
3
Text(selectedWeekday.date.weekdayTitle)
    .font(.title3.bold())
    .animation(nil)

animation Modifier를 사용하여 요일에는 변화를 주지 않았다.

Dec-15-2024 06-42-16

이게 더 나은듯 하다.

Default Value 설정

@State private var rawSelectedChartValue: Double? = 0

0이라는 초기값을 주면서 일요일을 보여준다.

즉, 사용자가 처음 차트를 볼 때 공백 상태를 방지하기 위함.

아무것도 없으면 유져 입장에선 차트를 어떻게 해야하는지 모를수 있기에 초기값을 주면 유져가 다른 차트의 섹션을 클릭해보거나 드래그를 하게 될것이다.

Dec-15-2024 06-17-10


Github: Step-Tracker Repository

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.