Sub-second X AxisMarks in SwiftUI Charts time series line chart

I already have a working app, using SwiftUI Canvas, for charting sensor milliVolt data at a frequency of 130Hz, so thought I'd see how SwiftUI Charts compared for ease of implementation. Charts is much easier to implement, saving the tedium of scaling and label context placement. However, creating the AxisMarks.Values was a problem because the stride-by method with Calendar.Component has .second as the smallest unit, and I need deciSecond. I tried some other inbuillt options, e.g. desiredCount, but no joy.

After a while I realised that I can create my own values array using a function, so here it is (hoping that this helps someone, somewhere, sometime):

struct ChartView: View {
    var chartData : [DataPoint] // An array of CoreData objects with timeStamp and milliVolt attributes
    let xSecStyle = StrokeStyle(lineWidth: 1.0)
    let xDeciSecStyle = StrokeStyle(lineWidth: 0.5)
...

// The .chartAxis code within Chart in body
.chartXAxis {
                AxisMarks(values: deciSecValues) { value in
                    if Double(value.index).remainder(dividingBy: 10.0)  == 0.0 {
                    // show the second-gridline as wider and display the time label
                        AxisGridLine(stroke:xSecStyle)
                                .foregroundStyle(.orange)
                        AxisValueLabel(format: .dateTime.minute().second(),centered: false)
                    } else {
                        AxisGridLine(stroke:xDeciSecStyle)
                                .foregroundStyle(.orange)
                    }
                }
            }
.....
// The func for creating the X Axis Marks
private var deciSecValues : [Date] {
        var xDates = [Date]()
        if chartData.isEmpty { return xDates }
        let deciSecs = (Int(chartData.last!.timeStamp!.timeIntervalSince(chartData.first!.timeStamp!)) + 1) * 10
        for i in stride(from: 0, to: deciSecs, by: 1) {
            let newTime = Double(i) / 10.0
            xDates.append(chartData.first!.timeStamp!.addingTimeInterval(newTime))
        }
        return xDates
    }

Regards, Michaela

Post not yet marked as solved Up vote post of AncientCoder Down vote post of AncientCoder
1.2k views