Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Why won't the viewport move to the last X value of my line chart? #3425

Closed
JCMcLovin opened this issue Apr 26, 2018 · 2 comments
Closed

Why won't the viewport move to the last X value of my line chart? #3425

JCMcLovin opened this issue Apr 26, 2018 · 2 comments

Comments

@JCMcLovin
Copy link
Contributor

I've been stuck for 4 days trying to figure out how to fix this and I'm out of ideas. I'm using version 3.1.1. of the framework and I'm having trouble getting the viewport to move far enough to the right to show the last value. If I segue to my ChartViewController and the current selection has data to display, it moves to a point in the chart that leaves 7 datapoints out of view to the right. However, if I then select another item that doesn't have any data and then select the previous item that has data, it correctly moves the chart so the last datapoint is visible:

image

When a selection is made, I fetch the appropriate data:

func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
    let selectedLift = lifts[row]
    
    UserDefaults.setSelectedLiftForChart(selectedLift)
    delegate.fetchLiftEvents()

}

In fetchLiftEvents() I set the chartView.data to nil if there's no data and this appears to be the only difference between what happens when I first segue to the ChartViewController and when select an item with no data and reselect the previous item:

func fetchLiftEvents() {
    
    let liftName = UserDefaults.selectedLiftForChart()
    let liftEvents = dataManager.fetchLiftsEventsOfTypeByName(liftName)
    
    guard liftEvents.count > 0 else {
        chartView.noDataText = "There's no \(liftName) data to display"
        chartView.data = nil
        
        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]
    
    generatexAxisDates(liftEvents: sortedLiftEvents)
    
    generateLineData(liftEvents: sortedLiftEvents)

}

Both generatexAxisDates(liftEvents: sortedLiftEvents) and generateLineData(liftEvents: sortedLiftEvents) are called in viewDidLoad(), my point being that they're called when the view loads and when a new selection with data is chosen. I'm calling setVisibleXRange(minXRange:maxXRange:) in generateLineData(liftEvents:) so it's always getting called as well:

func generateLineData(liftEvents: [LiftEvent]) {

    // generate the array of ChartDataEntry()...
    
    // generate set = LineChartDataSet(values: values, label: "Line DataSet")
                  
    let data = LineChartData(dataSet: set)
    
    chartView.data = data

    chartView.setVisibleXRange(minXRange: 7.0, maxXRange: 7.0)
    chartView.moveViewToX(chartView.chartXMax)

    resetxAxis()
    
    chartView.configureDefaults()
    
    chartView.animate(yAxisDuration: 0.8)
    
}

and resetxAxis() is only doing this:

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

I've searched through the documentation and Issues on Github and looked at many related questions on SO, but I'm not able to get this to work. [This question][2] seems to be addressing the very same problem I'm having but after trying to apply the solution to my problem, it still persists.

Why would the chart not move all the way to the right when it first loads but then correctly move all the way to the right if I change the data and then reselect the very same data that wouldn't work correctly at first?

@liuxuan30
Copy link
Member

liuxuan30 commented May 7, 2018

sorry this is a long text and I cannot read word by word.

To be clear, I'm reading that your question is when your first show the chart, the last data entry is missing its dot and the label? When you feed empty data, and refill the data again, the last entry is displayed, despite the fact that your first image and last image data entries are not the same?

To your code:
I notice that:

  1. you set chart data first and later called resetxAxis() but no notifyDataSetChanged called. This could be an issue that you need to let chart recalculate the axis range when you changed the properties. setting chart data will call notifyDataSetChanged for you, that's why we recommend put chart.data = data at last ine.

  2. You setup the chart in viewDidLoad, while at that moment, the view's frame is not finalized yet, if you are using auto layout, so the frame could possibly impact the axis range calculation and lead to the missing dots/labels, unless you are 100% sure your view's frame is static during the view controller life cycle.

  3. double check chartView.configureDefaults() is not setting anything else to avoid side effects.

@JCMcLovin
Copy link
Contributor Author

Thanks, liuxan30.

I was finally able to figure it out. As you suggested, I am now calling resetxAxis() and then setting chartView.data = data.

Also, I was fetching the data that would be displayed on the charts before setting some of the chart properties that should be set prior to setting chartView.data = data. I now set these default properties before fetching and setting the data and it works:

extension BarLineChartViewBase {
    func configureDefaults() {
    backgroundColor = NSUIColor(red: 35/255.0, green: 43/255.0, blue: 53/255.0, alpha: 1.0)
    
    chartDescription?.enabled = false
    
    legend.enabled = false

    xAxis.labelPosition = .bottom
    xAxis.avoidFirstLastClippingEnabled = false
    xAxis.gridColor.withAlphaComponent(0.9)

    rightAxis.enabled = false // this fixed the extra xAxis grid lines
    rightAxis.drawLabelsEnabled = false
    
    for axis in [xAxis, leftAxis] as [AxisBase] {
        axis.drawAxisLineEnabled = true
        axis.labelTextColor = .white
    }
    
    noDataTextColor = .white
    noDataFont = NSUIFont(name: "HelveticaNeue", size: 16.0)
    
} 

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants