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

Set values not showing until chart is zoomed #3275

Closed
federicomazzini opened this issue Feb 20, 2018 · 1 comment
Closed

Set values not showing until chart is zoomed #3275

federicomazzini opened this issue Feb 20, 2018 · 1 comment

Comments

@federicomazzini
Copy link

federicomazzini commented Feb 20, 2018

Hi, I have an issue in iOS, with a custom IValueFormatter. I can't get the values on two cubic line charts to show up or the func func stringForValue(_ value: Double, entry: ChartDataEntry, dataSetIndex: Int, viewPortHandler: ViewPortHandler?) to be called. Until the chart is barely zoomed. The zoom gesture seems to make the IValueFormatter to run and the values appear. In this app I only need the first and last values to show up. But the thing is, the IValueFormatter isn't being called at all until I zoom.
Thanks for the support. I'll Add the code:

import Foundation
import Charts

extension KeyStatDetailVC: ChartViewDelegate {

    func setupDoubleChart(unitString: String,
                          chartValues1: [Date : Double],
                          chartValues2: [Date : Double]) {
        
        if chartValues1.count == 0 || chartValues1.count == 0 {
            return
        }
        
        let sortedValues1 = chartValues1.sorted( by: { $1.key > $0.key } )
        let values1 = sortedValues1.map({ ChartDataEntry(x: $0.key.timeIntervalSince1970, y: $0.value) })
        
        let sortedValues2 = chartValues2.sorted( by: { $1.key > $0.key } )
        let values2 = sortedValues2.map({ ChartDataEntry(x: $0.key.timeIntervalSince1970, y: $0.value) })
        
        chartConfig()
        
        let set1 = LineChartDataSet(values: values1, label: "left set")
        let set2 = LineChartDataSet(values: values2, label: "right set")
        
        dataSetConfig(set: set1, isDoubleChart: true)
        dataSetConfig(set: set2, isDoubleChart: true)
        
        set1.setColor( .chartLineColor )
        set2.setColor( .chartLineColor )
        set1.drawFilledEnabled = false
        set2.drawFilledEnabled = false
        
        set1.valueFormatter = MeasuresValueFormatter(valuesRange: values1,
                                                     unitString: unitString,
                                                     left: true)
        set2.valueFormatter = MeasuresValueFormatter(valuesRange: values2,
                                                     unitString: unitString,
                                                     left: false)
        
        let sets = [set1, set2]
        
        let data = LineChartData(dataSets: sets)

        measuresAxisValuesConfig(set1: set1, set2: set2)
        formattingConfig(anySet: set1)
        
        chartView.data = data
    }
    
    // MARK: - Delegate methods
    
        func chartValueNothingSelected(_ chartView: ChartViewBase) {
            chartHighlightedValueLabel.text = ""
        }
    
        func chartValueSelected(_ chartView: ChartViewBase, entry: ChartDataEntry, highlight: Highlight) {
            
            let myText = String(format: "%.2f", entry.y) + " " + unitString
            chartHighlightedValueLabel.text = myText
        }
    
    // MARK: - Dataset base config
    func dataSetConfig(set: LineChartDataSet, isDoubleChart: Bool) {
        set.mode = .horizontalBezier
        set.lineWidth = 1
        
        //highlight
        set.highlightEnabled = true
        set.highlightColor = .black
        set.highlightLineDashPhase = CGFloat(2.0)
        set.highlightLineDashLengths = [CGFloat(2.0)]
        set.drawHorizontalHighlightIndicatorEnabled = false
        
        set.valueFont = isDoubleChart ? .maisonNeueBook(size: 15) : .maisonNeueBook(size: 15)
        set.drawValuesEnabled = true
        set.drawCirclesEnabled = false
        set.axisDependency = .left
    }
    
    // MARK: - Chart config
    func chartConfig() {
        chartView.delegate = self
        chartView.dragEnabled = true
        chartView.setScaleEnabled(true)
        chartView.pinchZoomEnabled = true
        chartView.setViewPortOffsets(left: 8, top: 0, right: 8, bottom: 0)
        
        chartView.highlightPerTapEnabled = true
        
        chartView.legend.enabled = false
        chartView.animate(xAxisDuration: 0.8)
        chartView.backgroundColor = .clear
        
        // X Axis
        let xAxis = chartView.xAxis
        xAxis.labelTextColor = .clear
        xAxis.axisLineColor = .clear
        xAxis.labelPosition = .bottom
        xAxis.drawAxisLineEnabled = false
        xAxis.drawGridLinesEnabled = false
        
        // Y Axis (Left & Right)
        let leftAxis = chartView.leftAxis
        leftAxis.labelTextColor = .clear
        leftAxis.axisLineColor = .clear
        leftAxis.labelPosition = .outsideChart
        leftAxis.drawGridLinesEnabled = false
        
        // Deactivate axes if necessary
        chartView.rightAxis.enabled = false
        
        chartView.chartDescription?.text = ""
    }
    
    // MARK: - Stats Axis Min and Max Settings
    func statsAxisValuesConfig(set: LineChartDataSet) {
        let leftAxis = chartView.leftAxis
        
        // Y scale goes from -%3 of the min value to +%3 of the max value
        let yValueToAdd = set.yMax * KeyStatDetailVC.chartXAxisRangeToAdd
        
        leftAxis.axisMinimum = set.yMin - yValueToAdd
        leftAxis.axisMaximum = set.yMax + yValueToAdd
        
        setXAxis(set: set)
    }
    
    // MARK: - Measures Axis Min and Max Settings
    func measuresAxisValuesConfig(set1: LineChartDataSet, set2: LineChartDataSet) {
        let leftAxis = chartView.leftAxis
        
        let minYValue = set1.yMin < set2.yMin ? set1.yMin : set2.yMin
        let maxYValue = set1.yMax > set2.yMax ? set1.yMax : set2.yMax
        
        // Y scale goes from -%3 of the min value to +%3 of the max value
        let yValueToAdd = maxYValue * KeyStatDetailVC.chartXAxisRangeToAdd
        
        leftAxis.axisMinimum = minYValue - yValueToAdd
        leftAxis.axisMaximum = maxYValue + yValueToAdd
        
        setXAxis(set: set1)
    }
    
    func setXAxis(set: LineChartDataSet) {
        let xAxis = chartView.xAxis
        
        let valueToAdd = (set.xMax - set.xMin) * 0.14
        
        xAxis.axisMinimum = set.xMin - valueToAdd
        xAxis.axisMaximum = set.xMax + valueToAdd
    }
    
    // MARK: - Date Formatting
    func formattingConfig(anySet: LineChartDataSet) {
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "MMM dd"
        var date = dateFormatter.string(from: Date(timeIntervalSince1970: anySet.xMax))
        maxValueLabel.textAlignment = .right
        maxValueLabel.text = date.uppercased()
        
        date = dateFormatter.string(from: Date(timeIntervalSince1970: anySet.xMin))
        minValueLabel.textAlignment = .right
        minValueLabel.text = date.uppercased()
    }
    
}

// The goal of implementing this IValueFormatter subclass is to show only the first and last values of the line

public class MeasuresValueFormatter: NSObject, IValueFormatter {
    
    var valuesRange: [ChartDataEntry]?
    var unitString = ""
    var left = true
    
    convenience init(valuesRange: [ChartDataEntry], unitString: String, left: Bool) {
        self.init()
        
        self.valuesRange = valuesRange
        self.unitString = unitString
        self.left = left
    }
    
    public func stringForValue(_ value: Double, entry: ChartDataEntry, dataSetIndex: Int, viewPortHandler: ViewPortHandler?) -> String {
        
        guard let myValues = valuesRange else { return "" }
        
        let bodySideString = left ? "(L)" : "(R)"
        
        let myText = String(format: "%.2f", entry.y) + " " + unitString + " " + bodySideString
        if entry.x == myValues.first?.x {
            return myText
        }
        else if entry.x == myValues.last?.x {
            return myText
        }
        
        return ""
    }
}

public class DateValueFormatter: NSObject, IAxisValueFormatter {
    private let dateFormatter = DateFormatter()
    
    override init() {
        super.init()
        dateFormatter.dateFormat = "MMM dd"
    }
    
    public func stringForValue(_ value: Double, axis: AxisBase?) -> String {
        let date = dateFormatter.string(from: Date(timeIntervalSince1970: value))
        return date.uppercased()
    }
}
@liuxuan30
Copy link
Member

please refer ChartsDemo, to see what's going on with your value formatter. It usually means your axis labels are not generated because of not enough space or something else.

We are now encouraging people to ask questions on Stack overflow with tag iOS-charts, as we are overwhelmed to read and answer questions and not able to get the real problem solved.

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

No branches or pull requests

2 participants