octopus
octopus

Reputation: 31

SwiftCharts extra line running through the bottom of line charts

I have 2 line charts in SwiftCharts that show the user's time asleep and total time in bed. When you first see the chart, it looks normal, but when you click on the different buttons (they are NavigationLinks) a random curved line comes at the bottom of it. It also appears when clicking on the toolbar items.

before

after

The line chart is supposed to look normal, but after pressing buttons, it makes a weird line. I have a chartXSelection which shows an annotation view, and when dragging through the chart, it disappears, but when you stay at the same value for multiple seconds, it appears again (couldn't take a screenshot because it disappears after moving the mouse away)

This is my code, with the annotation view:

var body: some View {
        VStack {
            NavigationLink(value: selectedStat) {
                HStack {
                    VStack(alignment: .leading) {
                        Label("Time Asleep", systemImage: "bed.double.fill")
                            .font(.title3.bold())
                            .foregroundStyle(.cyan)
                        
                        Text("Avg: \(formatTime(seconds: avgSleep, showDecimal: true))")
                            .font(.caption)
                    }
                    
                    Spacer()
                    
                    Image(systemName: "chevron.right")
                }
            }
            .foregroundStyle(.secondary)
            .padding(.bottom, 12)
            
            Chart {
                if let selectedHealthMetric {
                    RuleMark(x: .value("Selected Metric", selectedHealthMetric.date, unit: .day))
                        .foregroundStyle(Color.secondary.opacity(0.3))
                        .offset(y: -10)
                        .annotation(position: .top,
                                    spacing: 0,
                                    overflowResolution: .init(x: .fit(to: .chart), y: .disabled)) { annotationView }
                }
                
                RuleMark(y: .value("Average", avgSleep))
                    .foregroundStyle(.mint)
                    .lineStyle(.init(lineWidth: 1, dash: [5]))
                
                ForEach(chartData) { sleep in
                    LineMark(
                        x: .value("Day", sleep.date, unit: .day),
                        y: .value("Time Asleep", sleep.value)
                    )
                    .foregroundStyle(.cyan)
                    .interpolationMethod(.catmullRom)
                    .symbol(.circle)
                    
                    AreaMark(
                        x: .value("Day", sleep.date, unit: .day),
                        yStart: .value("Value", sleep.value),
                        yEnd: .value("Min Value", minValue)
                    )
                    .foregroundStyle(Gradient(colors: [.cyan.opacity(0.5), .clear]))
                    .interpolationMethod(.catmullRom)
                }
            }
            .frame(height: 150)
            .chartXSelection(value: $rawSelectedDate.animation(.easeInOut))
            .chartXAxis {
                AxisMarks {
                    AxisValueLabel(format: .dateTime.month(.defaultDigits).day())
                }
            }
            .chartYAxis {
                AxisMarks { value in
                    AxisGridLine()
                        .foregroundStyle(Color.secondary.opacity(0.3))
                    
                    AxisValueLabel("\(formatTime(seconds: value.as(Double.self) ?? 0, showDecimal: true))")
                }
            }
            .chartYScale(domain: .automatic(includesZero: false))
        }
        .padding()
        .background(RoundedRectangle(cornerRadius: 12).fill(Color(.secondarySystemBackground)))
    }
    
    var annotationView: some View {
        VStack(alignment: .leading) {
            Text(selectedHealthMetric?.date ?? .now, format: .dateTime.weekday(.abbreviated).month(.abbreviated).day())
                .font(.footnote.bold())
                .foregroundStyle(.secondary)
            
            Text(formatTime(seconds: selectedHealthMetric?.value ?? 0))
                .fontWeight(.heavy)
                .foregroundStyle(.cyan)
        }
        .padding(12)
        .background(
            RoundedRectangle(cornerRadius: 4)
                .fill(Color(.secondarySystemBackground))
                .shadow(color: .secondary.opacity(0.3), radius: 2, x: 2, y: 2)
        )
    }

Upvotes: 1

Views: 91

Answers (1)

octopus
octopus

Reputation: 31

I figured it out, when I get the health data, I am adding to the array instead of updating it, which causes duplicate answers, which messes up the line chart.

Upvotes: 0

Related Questions