willdale / SwiftUICharts

A charts / plotting library for SwiftUI. Works on macOS, iOS, watchOS, and tvOS and has accessibility features built in.
MIT License
843 stars 105 forks source link

.xAxisLabels sometimes disappeared #196

Closed owenzhao closed 2 years ago

owenzhao commented 2 years ago
import SwiftUI
import SwiftUICharts

struct ContentView: View {
    @State var data:BarChartData?

    var body: some View {
        ScrollView {
            VStack {
                if let data = data {
                    BarChart(chartData: data)
                        .touchOverlay(chartData: data)
                        .xAxisGrid(chartData: data)
                        .yAxisGrid(chartData: data)
                        .xAxisLabels(chartData: data)
                        .yAxisLabels(chartData: data, specifier: "%0.f KGs")
                        .floatingInfoBox(chartData: data)
                        .headerBox(chartData: data)

                    HStack {
                        Button {
                            data.dataSets.dataPoints.removeFirst()
                            data.dataSets.dataPoints.append(getRandomPoint())
                        } label: {
                            Text("Append Item")
                        }

                        Button {
                            changeMaxBarNumber()
                        } label: {
                            Text("Change Max Bar Number")
                        }
                    }
                } else {
                    ProgressView().onAppear {
                        let points = (1...10).map { _ in getEmptyPoint()}
                        let barStyle = BarStyle(barWidth: 0.5, colourFrom: .dataPoints)
                        data = BarChartData(dataSets: BarDataSet(dataPoints: points),
                                            barStyle: barStyle)
                    }
                }
            }
        }
        .padding()
        .frame(minWidth: 800)
    }

    private func getRandomPoint() -> BarChartDataPoint {
        let i = Int.random(in: 50...100)
        return BarChartDataPoint(value: Double(i), xAxisLabel: String(i),
                                 colour: ColourStyle(colour: .green))
    }

    private func getEmptyPoint() -> BarChartDataPoint {
        return BarChartDataPoint(value: 0, xAxisLabel: nil, colour: ColourStyle(colour: .green))
    }

    private func changeMaxBarNumber() {
        let maxBarNumber = Int.random(in: 10...20)
        var points = data!.dataSets.dataPoints.filter { $0.value != 0 }
        let count = points.count

        if count < maxBarNumber {
            let emptyPoints = (1...(maxBarNumber - count)).map { _ in getEmptyPoint() }
            points.insert(contentsOf: emptyPoints, at: 0)

            data = BarChartData(dataSets: BarDataSet(dataPoints: points),
                                barStyle: data!.barStyle)
        } else {
            data = BarChartData(dataSets: BarDataSet(dataPoints: Array(points[(count - maxBarNumber)...])),
                                barStyle: data!.barStyle)
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

When running, sometimes the xAxisLabels disappeared. Any idea why this happened?

https://user-images.githubusercontent.com/2182896/166390706-55489d46-8d18-42a7-9ae5-1370570039ef.mov

willdale commented 2 years ago

The BarChartData should remain constant - don't replace it, update the data points / data sets.

When BarChartData get initialised a UUID gets set which holds the state together. I think this might be the cause.

owenzhao commented 2 years ago

The BarChartData should remain constant - don't replace it, update the data points / data sets.

When BarChartData get initialised a UUID gets set which holds the state together. I think this might be the cause.

Thanks. The issue disappeared with code:

private func changeMaxBarNumber() {
    let maxBarNumber = Int.random(in: 10...20)
    var points = data!.dataSets.dataPoints.filter { $0.value != 0 }
    let count = points.count

    guard let data = data else {
        fatalError()
    }

    if count < maxBarNumber {
        let emptyPoints = (1...(maxBarNumber - count)).map { _ in getEmptyPoint() }
        points.insert(contentsOf: emptyPoints, at: 0)

//            data = BarChartData(dataSets: BarDataSet(dataPoints: points),
//                                barStyle: data!.barStyle)
        data.dataSets = BarDataSet(dataPoints: points)
    } else {
//            data = BarChartData(dataSets: BarDataSet(dataPoints: Array(points[(count - maxBarNumber)...])),
//                                barStyle: data!.barStyle)
        data.dataSets = BarDataSet(dataPoints: Array(points[(count - maxBarNumber)...]))
    }
}