Search code examples
swiftios-charts

Allow PieChartView to hide value line for tiny slices in Swift


I'm building a pie chart by chart iOS framework. I'm able to hide the value and label when the the slice is tiny but I can't hide the value line for tiny slice.

enter image description here

If I add this code on setDataCount()

set.valueLineWidth = 0.0

It will hide all the value line. How to hide it by the size of slice?

@IBOutlet weak var myChart: PieChartView!

var valueColors = [UIColor]()
var dataEntries = [PieChartDataEntry]()
var record = [Record]()
var category = [String]()
var categoryTotal : [Double] = []
var categoryArray : [String] = []

func setDataCount() {
    var totalValue = 0.0
    for a in categoryTotal {
        totalValue += a
    }
    UserDefaults.standard.set(totalValue, forKey: "totalValue")
    valueAndColor()

    let set = PieChartDataSet(values: dataEntries, label: nil)

    set.colors = valueColors
    set.valueLinePart1OffsetPercentage = 0.8
    set.valueLinePart1Length = 0.2
    set.valueLinePart2Length = 0.4
    set.xValuePosition = .outsideSlice
    set.yValuePosition = .outsideSlice
    set.selectionShift = 0.0

    let data = PieChartData(dataSet: set)
    let Formatter:ChartFormatter = ChartFormatter()
    data.setValueFormatter(Formatter)
    data.setValueFont(.systemFont(ofSize: 11, weight: .light))
    data.setValueTextColor(.black)

    myChart.data = data
    myChart.highlightValues(nil)
}

func valueAndColor(){
    for i in 0..<categoryArray.count{
        let dataEntry = PieChartDataEntry(value: categoryTotal[i], label: categoryArray[i % categoryArray.count])
        dataEntries.append(dataEntry)

        //I'm using this code to hide the label
        let value = categoryTotal[i]
        let total = UserDefaults.standard.double(forKey: "totalValue")
        var valueToUse = value/total * 100
        valueToUse = Double(round(10*valueToUse)/10)
        let minNumber = 10.0

        if(valueToUse < minNumber) {
            dataEntries[i].label = ""
        }else{
            dataEntries[i].label = categoryArray[i % categoryArray.count]
        }
        if categoryArray[i] == "吃喝" {
            valueColors.append(UIColor.yellow)
        }...
 }

I'm using this code to hide the value %

public class ChartFormatter: NSObject, IValueFormatter{

    public func stringForValue(_ value: Double, entry: ChartDataEntry, dataSetIndex: Int, viewPortHandler: ViewPortHandler?) -> String {
        let total = UserDefaults.standard.double(forKey: "totalValue")
        var valueToUse = value/total * 100
        valueToUse = Double(round(10*valueToUse)/10)
        let minNumber = 10.0

        if(valueToUse < minNumber) {
            return ""
        }
        else {
            let pFormatter = NumberFormatter()
            pFormatter.numberStyle = .percent
            pFormatter.maximumFractionDigits = 1
            pFormatter.multiplier = 1
            pFormatter.percentSymbol = " %"
            let hideValue = pFormatter.string(from: NSNumber(value: value))

            return String(hideValue ?? "0")
        }
    }
}

enter image description here


Solution

  • Inside the file PieChartRenderer change from this:

     if dataSet.valueLineColor != nil        
     {
        context.setStrokeColor(dataSet.valueLineColor!.cgColor)
        context.setLineWidth(dataSet.valueLineWidth)
    
        context.move(to: CGPoint(x: pt0.x, y: pt0.y))
        context.addLine(to: CGPoint(x: pt1.x, y: pt1.y))
        context.addLine(to: CGPoint(x: pt2.x, y: pt2.y))
    
        context.drawPath(using: CGPathDrawingMode.stroke)
    
     }
    

    to this:

     if dataSet.valueLineColor != nil
     {
    
         if(valueText == "") {
             context.setStrokeColor(UIColor.clear.cgColor)
         }
         else {
             context.setStrokeColor(dataSet.valueLineColor!.cgColor)
         }
    
         context.setLineWidth(dataSet.valueLineWidth)
    
         context.move(to: CGPoint(x: pt0.x, y: pt0.y))
         context.addLine(to: CGPoint(x: pt1.x, y: pt1.y))
         context.addLine(to: CGPoint(x: pt2.x, y: pt2.y))
    
         context.drawPath(using: CGPathDrawingMode.stroke)
     }
    

    The change basically checks if the valueText is the empty string, and if so it changes the linecolor to a clear color.