swiftuiswiftui-animationswiftui-charts

Swift Charts Animation works editing values but not entering one new


I expect the line grow with animation when entering a new entry but the animation only happen when editing existing values

I don't want a canvas resize so I need to scale the canvas before the animation.

import SwiftUI
import Charts

struct Entry: Identifiable {
    var id = UUID()
    var time: Double
    var value: Double
}

struct ContentView: View {
    @State var data: [Entry] = [
        .init(time: 0, value: 0),
        .init(time: 1, value: 1)]
    var body: some View {
        VStack{
            Button("+"){
                withAnimation{
                    data.append(.init(time: 2, value: 2))
                }
            }
            Chart(data){entry in
                LineMark(x: .value("time", entry.time),
                         y: .value("value", entry.value))
            }
            .chartXScale(domain: 0...2)
            .chartYScale(domain: 0...2)
            .padding()
        }
    }
}

Solution

  • Duplicating last entry and editing the values while keeping the entry id generates the desired outcome:

    struct LineChartAnimationPlayground4: View {
        
        struct Playground4Entry: Identifiable {
            let id = UUID()
            var date: Date
            var value: Double
        }
        
        @State private var model: [Playground4Entry]
            
        
        init(){
            model = {
                var output = [0.0,1,2,3,4,5,6,7,8,9]
                    .enumerated()
                    .map{i,value in
                        Playground4Entry(date: Calendar.current.date(byAdding: .day, value: i, to: .now)!,
                                         value: Double.random(in: 0...100))
                    }
                output.append(output.last!)
                return output
            }()
        }
        var body: some View {
            Button("Animate"){          
                withAnimation{
                    model[model.count-1].date = Calendar.current.date(byAdding: .day, value: 1, to:  model[model.count-1].date)!
                    model[model.count-1].value = Double.random(in: 0...100)
                    
                }
            }
            Chart{
                ForEach(model) { entry in
                    LineMark(x: .value("index", entry.date),
                             y: .value("value", entry.value))
                }
            }
        }
    }
    
    #Preview("Add entry animation") {
        LineChartAnimationPlayground4()
    }