Search code examples
iosswiftmathgeometrypie-chart

Rotating MDRotatingPieChart changes x/y position instead of angle


Screenshot of MDRotatingPieChart

I want to have a rotating piechart in my iOS application. I've found MDRotatingPieChart control that seems to do most of what I need. But when I put it into non-(0,0) origin and start to drag, it changes the X and Y position of the piechart as well. It shouldn't do this. Can someone help me out here?

Here is the code that seems relevant

pieChart = MDRotatingPieChart(frame: CGRect(x: 30, y: 30, width: view.frame.width + 30 , height: view.frame.width + 30 ))

and inside MDRotatingPieChart:

override func continueTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
    hasBeenDraged = true
    let currentPoint = touch.location(in: self)
    let deltaX = currentPoint.x - pieChartCenter.x - 15
    let deltaY = currentPoint.y - pieChartCenter.y - 15
    let ang = atan2(deltaY,deltaX);
    let angleDifference = delta - ang
    self.transform = self.transform.rotated(by: -angleDifference)
    let savedTransform = slicesArray[0].labelObj?.transform
    let savedTransformCenter = labelCenter.transform
    for slice in slicesArray  {
        if(slice.labelObj != nil)  {
            slice.labelObj?.transform = savedTransform!.rotated(by: angleDifference)
        }
    }
    labelCenter.transform = savedTransformCenter.rotated(by: angleDifference)
    return true;
}

Solution

  • First of all, it looks like you should use MDRotatingPieChart.swift from MDRotatingPieChart-Example folder as it is much more modern. Still it contains the bug you described and the source of the bug seems to be that the original developer doesn't know the difference between frame and bounds which are according to the UIView doc:

    The geometry of each view is defined by its frame and bounds properties. The frame property defines the origin and dimensions of the view in the coordinate system of its superview. The bounds property defines the internal dimensions of the view as it sees them and is used almost exclusively in custom drawing code.

    So to fix the issue you can find the following line in createSlice

        mask.frame = self.frame
    

    and replace it with

        mask.frame = self.bounds
    

    P.S. Your code features a line

    pieChart = MDRotatingPieChart(frame: CGRect(x: 30, y: 30, width: view.frame.width + 30 , height: view.frame.width + 30 ))
    

    which is suspicious. You almost never want either width or height of a child to be more than corresponding parent's dimension. You probably want

    pieChart = MDRotatingPieChart(frame: CGRect(x: 30, y: 30,
                 width: view.frame.width - 30 , height: view.frame.width - 30 ))
    

    or even (if you want symmetrical margins in both X and Y)

    pieChart = MDRotatingPieChart(frame: CGRect(x: 30, y: 30, 
                   width: view.frame.width - 2*30 , height: view.frame.width - 2*30 ))
    

    instead.