Jim
Jim

Reputation: 1450

Charts' line chart doesn't render line chart properly

I'm using the Charts framework and I'm experiencing some very weird behavior in my line chart.

When I segue to the ChartViewContoller and the default selection has data, the chart renders normally:

1rm_normal

but if I segue to this view controller when the default selection doesn't have any data and then select an item that has data, it looks like this:

1) segue to this:

1rm_nodatamessage

2) then select an item that has data:

1rm_squished

Of course viewDidLoad is called when I segue to the view controller and as long as the default selection has data when I segue to it, I can select another item that has data or doesn't and the chart will continue to render properly. So the difference appears to be in viewDidLoad but I've tried everything I can think of but nothing fixes the problem. Here's my viewDidLoad:

 override func viewDidLoad() {
    super.viewDidLoad()

    view.backgroundColor = UIColor(hexString: "232B35")

    self.title = "1RM"

    chartView.delegate = self
    chartView.chartDescription?.enabled = false

    let leftAxis = chartView.leftAxis
    leftAxis.axisMinimum = 190
    leftAxis.labelTextColor = NSUIColor.white

    let xAxis = chartView.xAxis
    xAxis.labelPosition = .bottom
    xAxis.axisMinimum = 0
    xAxis.granularity = 1
    xAxis.axisLineWidth = 5
    xAxis.valueFormatter = self
    xAxis.labelTextColor = NSUIColor.white


    chartView.configureDefaults()
    chartView.rightAxis.enabled = false // this fixed the extra xAxis grid lines

    chartView.backgroundColor = NSUIColor(red: 35/255.0, green: 43/255.0, blue: 53/255.0, alpha: 1.0)

    fetchData()

    chartView.setVisibleXRangeMaximum(7)

    chartView.animate(yAxisDuration: 1.0)
}

here's what's happening in fetchData():

func fetchData() {

    chartView.data = nil

    let liftName = UserDefaults.selectedLiftForChart()
    let liftEvents = dataManager.fetchLiftsEventsOfTypeByName(liftName)

    guard liftEvents.count > 0 else {
        chartView.noDataText = "There's no \(liftName) data to display"
        shouldHideData = true

        return }

    // put them into a Dictionary grouped by each unique day
    let groupedEvents = Dictionary(grouping: liftEvents, by: { floor($0.date.timeIntervalSince1970 / 86400) })

    // grab the maximum 1RM from each day
    let dailyMaximums = groupedEvents.map { $1.max(by: { $0.oneRepMax < $1.oneRepMax }) }

    // MARK: - TODO: Fix the silly unwrapping
    sortedLiftEvents = dailyMaximums.sorted(by: { $0?.date.compare(($1?.date)!) == .orderedAscending }) as! [LiftEvent]

    let intervalBetweenDates: TimeInterval = 3600 * 24 // 3600 = 1 hour
    let startDate = (sortedLiftEvents.first?.date)! - intervalBetweenDates
    let lastDate = sortedLiftEvents.last?.date

    let dateFormatter = DateFormatter()
    dateFormatter.dateFormat = "MMM d"
    let dates:[Date] = intervalDates(from: startDate, to: lastDate!, with: intervalBetweenDates)

    days = dates.map {dateFormatter.string(from: $0)}

    generateLineData()

}

and finally, this is the generateLineData method:

func fetchData() {

    chartView.data = nil

    let liftName = UserDefaults.selectedLiftForChart()
    let liftEvents = dataManager.fetchLiftsEventsOfTypeByName(liftName)

    guard liftEvents.count > 0 else {
        chartView.noDataText = "There's no \(liftName) data to display"
        shouldHideData = true

        return }

    // put them into a Dictionary grouped by each unique day
    let groupedEvents = Dictionary(grouping: liftEvents, by: { floor($0.date.timeIntervalSince1970 / 86400) })

    // grab the maximum 1RM from each day
    let dailyMaximums = groupedEvents.map { $1.max(by: { $0.oneRepMax < $1.oneRepMax }) }

    // MARK: - TODO: Fix the silly unwrapping
    sortedLiftEvents = dailyMaximums.sorted(by: { $0?.date.compare(($1?.date)!) == .orderedAscending }) as! [LiftEvent]

    let intervalBetweenDates: TimeInterval = 3600 * 24 // 3600 = 1 hour
    let startDate = (sortedLiftEvents.first?.date)! - intervalBetweenDates
    let lastDate = sortedLiftEvents.last?.date

    let dateFormatter = DateFormatter()
    dateFormatter.dateFormat = "MMM d"
    let dates:[Date] = intervalDates(from: startDate, to: lastDate!, with: intervalBetweenDates)

    days = dates.map {dateFormatter.string(from: $0)}

    generateLineData()

}

I've tried putting chartView.setVisibleXRangeMaximum(7) in the method that sets the chart data and verified that chartView.visibleXRange is 7 each time the chart is rendered but it doesn't make a difference. I've also made sure that the max XRange is being set after the data is set for the chart.

Is there anything else I can try or is this perhaps a bug that hasn't been fixed yet?

Thanks

Upvotes: 0

Views: 573

Answers (1)

Jim
Jim

Reputation: 1450

Well I finally figured it out. I knew from reading the documentation that some properties must be set after the chart data is handed to the chart. It was not entirely clear which properties but through lots of debugging and process of elimination I determined it was the xAxis properties that needed to be reset whenever the data changed.

Now, when the data is changed I call my new function:

func resetxAxis() {
    let xAxis = chartView.xAxis
    xAxis.labelPosition = .bottom
    xAxis.axisMinimum = 0
    xAxis.granularity = 1
    xAxis.axisLineWidth = 5
    xAxis.valueFormatter = self
}

This had been in my viewDidLoad method so I made the above method out of it and can call it any time it's needed.

Upvotes: 1

Related Questions