Search code examples
iosswiftchartscore-graphicspie-chart

How can I create a Pie Chart with rounded slice edges?


I want to achieve the following effect, shown below in my iOS app (written in Swift)

piechart-image

So far I have been able to achieve this, using Charts by danielgindi. But I am not able to get the desired effect as I want to. Is there any way to add rounded corners to each Pie Chart slice like in this example image here?:

myimplementation

My Chart setup is as follows:

let data1 = PieChartDataEntry(value: 3)
let data2 = PieChartDataEntry(value: 5)
let data3 = PieChartDataEntry(value: 4)
let data4 = PieChartDataEntry(value: 6)
let data5 = PieChartDataEntry(value: 8)
let values = [data1, data2, data3, data4, data5]
let chartDataSet = PieChartDataSet(entries: values, label: nil)
let chartData = PieChartData(dataSet: chartDataSet)
let colors = [UIColor.fuelTintColor, UIColor.maintenanceTintColor, UIColor.insuranceTintColor, UIColor.fastagTintColor, UIColor.miscTintColor]
chartDataSet.colors = colors as! [NSUIColor]
chartDataSet.sliceSpace = 10
        
pieChart1.data = chartData
        
pieChart1.holeRadiusPercent = 0.8

I think it can be done using the PieChartRenderer but I have no idea how I should proceed.

Also, if you have any suggestions for other ways to implement this do let me know.


Solution

  • Solved it, and here's the output:

    ring-chart-img

    Basically I am using this library, called CircularProgressView (https://cocoapods.org/pods/CircleProgressView) to achieve the individual rings. Since I needed 5 rings, I stacked 5 such views (with clear background) on top of each other and rotated them to achieve my desired effect.

    Cocoapod setup

    First, you have to install the CircularProgressView pod in your project. I am using Cocoapods for importing the library here.

    NOTE: If you do not have Cocoapods setup already then you need to install Cocoapods first using steps here: https://guides.cocoapods.org/using/getting-started.html

    To add it using Cocoapods, add the following line in your Podfile.

    pod 'CircleProgressView'
    

    and run pod install on the Terminal from within your project directory.

    Interface Builder

    In your Storyboard file, go to your View Controller and add a view and set its contents. You can also create this view programmatically but here I will be using the storyboard.

    Create 4 more views and use Auto Layout to stack them on top of one another.

    Select all 5 views and go to the Identity Inspector (right panel in storyboard, 4th item in top bar).

    Set the Class field value (under Custom Class) as 'CircularProgressView'.

    Link all 5 views to your ViewController.swift file.

    I have named them as follows:

    @IBOutlet weak var pieChart1: CircleProgressView!
    @IBOutlet weak var pieChart2: CircleProgressView!
    @IBOutlet weak var pieChart3: CircleProgressView!
    @IBOutlet weak var pieChart4: CircleProgressView!
    @IBOutlet weak var pieChart5: CircleProgressView!
    

    Call the function showRingChart() in viewDidLoad() to setup the views.

    Here is the code for the functions:

    // Function to convert degrees to radian
    func degToRad(_ rotationDegrees: Double) -> CGFloat {
        let rotationAngle = CGFloat(rotationDegrees * .pi/180.0)
        return rotationAngle
    }
    
    // Function to Show Ring Chart
    func showRingChart() {
        
        // Values for the graph, can be changed as per your need
        let val1 = self.val1
        let val2 = self.val2
        let val3 = self.val3
        let val4 = self.val4
        let val5 = self.val5
        let totalVal = (val1 + val2 + val3 + val4 + val5)
        var spacing = 0.05 * totalVal // Spacing is set to 5% (ie. 0.05). Change it according to your needs
        
        print("Spacing: ", spacing)
        let totalSpacing = 5 * spacing //Total spacing value to be added in the chart
        
        let total = totalVal + totalSpacing //Total corresponding to 100% on the chart
        
        if val1 == 0.0
            && val2 == 0.0
            && val3 == 0.0
            && val4 == 0.0
            && val5 == 0.0 {
            
            // NO DATA, HIDE ALL CHARTS
            pieChart1.isHidden = true
            pieChart2.isHidden = true
            pieChart3.isHidden = true
            pieChart4.isHidden = true
            pieChart5.isHidden = true
            
        } else {
    
            // DATA AVAILABLE
    
            // Calculate Percentage of each value in the ring chart (ie. progress)
            let valOnePerc = (val1 / total) 
            let valTwoPerc = (val2 / total)
            let valThreePerc = (val3 / total)
            let valFourPerc = (val4 / total)
            let valFivePerc = (val5 / total)
    
            let spacingPerc = spacing / total
            
            // Angle offsets (in degrees)
            let offset1 = (valOnePerc + spacingPerc) * 360
            let offset2 = (valOnePerc + valTwoPerc + (2 * spacingPerc)) * 360
            let offset3 = (valOnePerc + valTwoPerc + valThreePerc + (3 * spacingPerc)) * 360
            let offset4 = (valOnePerc + valTwoPerc + valThreePerc + valFourPerc + (4 * spacingPerc)) * 360
    
            print("--- PRINTING CHART VALUES HERE ---- ")
            print(total)
            print(valOnePerc)
            print(valTwoPerc)
            print(valThreePerc)
            print(valFourPerc)
            print(valFivePerc)
            print(offset1)
            print(offset2)
            print(offset3)
            print(offset4)
            print("------------------")
            
            // Setup ring chart sections
            pieChart1.trackFillColor = UIColor.tintColorOne
            pieChart1.progress = valOnePerc
            
            pieChart2.trackFillColor = UIColor.tintColorTwo
            pieChart2.progress = valTwoPerc
            pieChart2.transform = CGAffineTransform(rotationAngle: degToRad(offset1))
    
            pieChart3.trackFillColor = UIColor.tintColorThree
            pieChart3.progress = valThreePerc
            pieChart3.transform = CGAffineTransform(rotationAngle: degToRad(offset2))
    
            pieChart4.trackFillColor = UIColor.tintColorFour
            pieChart4.progress = valFourPerc
            pieChart4.transform = CGAffineTransform(rotationAngle: degToRad(offset3))
    
            pieChart5.trackFillColor = UIColor.tintColorFive
            pieChart5.progress = valFivePerc
            pieChart5.transform = CGAffineTransform(rotationAngle: degToRad(offset4))
            
            // Unhide all charts
            pieChart1.isHidden = false
            pieChart2.isHidden = false
            pieChart3.isHidden = false
            pieChart4.isHidden = false
            pieChart5.isHidden = false
    
        }
    }
    
    

    It should do it. Change the (val1, val2, ..., val5) values to change the progress of the rings.