title: SwiftUI Pie Chart: glitches when rotating the device
body: <p>I'm trying to implement an animated pie chart in SwiftUI.
  I noticed that my implementation has some glitches on iPad, specifically when the device is rotated.</p>
  <p>As you can see, the pieces are not connected anymore when the device is rotated. Cause: The pieces update their frame size immediately.</p>
  <p><a href="https://i.stack.imgur.com/WRihK.gif" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/WRihK.gif" alt="enter image description here" /></a></p>
  <p>I noticed that everything will work fine when drawingGroup() is used with the chart. Another possible approach is to set the frame of the chart explicitly with a .frame modifier (using GeometryReader for the size) and to animate the frame change with .animation(). However, those options are creating problems in the app switcher. When the app is closed and after that, the device is rotated, the preview of the app in the app switcher looks weird. The chart is not centered and the size is off as well:</p>
  <p><a href="https://i.stack.imgur.com/pj1w6.gif" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/pj1w6.gif" alt="enter image description here" /></a></p>
  <p>So that's not an option unfortunately.</p>
  <p>Also: The pie chart should have different sizes in portrait vs landscape mode (I simulated that with a padding here). Moreover, I want to be able to animate all pieces of the pie chart individually (the start and end angle) just like in the current implementation.</p>
  <p>Hope somebody has an idea how to fix this. Thanks so much for answering!</p>
  <pre><code>
  import SwiftUI
  
  struct ContentView: View {
      @ObservedObject var model = CellModel.sharedInstance
      
      var body: some View {
          PieChart(dataModel: $model.sample)
              //.drawingGroup()
              .aspectRatio(1, contentMode: .fit)
              .padding()
              .padding(.vertical, 200)
      }
  }
  
  struct PieChart: View {
      @Binding var dataModel: [ChartEntry]
      
      var body: some View {
          ZStack{
              ForEach(dataModel) { elem in
                  PieChartWrapper(elem: elem)
              }
          }
      }
  }
  
  struct PieChartWrapper: View {
      @ObservedObject var elem: ChartEntry
      
      var body: some View {
          PieChartCell(start: elem.startAngle, end: elem.endAngle)
              .foregroundColor(elem.color)
      }
  }
  
  let chartCoverage: CGFloat = 0.7
  
  struct PieChartCell: Shape {
      var start: Double
      var end: Double
      
      var animatableData: AnimatablePair&lt;Double, Double&gt; {
          get { .init(start, end) }
          set {
              start = newValue.first
              end = newValue.second
          }
      }
      
      func path(in rect: CGRect) -&gt; Path {
          var p = Path()
          let center =  CGPoint(x: rect.size.width/2, y: rect.size.width/2)
          let radius = rect.size.width/2
          let startAngle = Angle(degrees: start)
          let endAngle = Angle(degrees: end)
          let width = radius * chartCoverage
          
          p.addArc(center: center, radius: abs(width - radius), startAngle: startAngle, endAngle: endAngle, clockwise: false)
          p.addArc(center: center, radius: radius, startAngle: endAngle, endAngle: startAngle, clockwise: true)
          p.closeSubpath()
          return p
      }
  }
  
  
  class CellModel: ObservableObject {
      static let sharedInstance = CellModel()
      @Published var sample =  [ChartEntry(color: .red), ChartEntry(color: .yellow), ChartEntry(color: .green)] {
          didSet{
              calcAngles()
          }
      }
      
      private init() {
          calcAngles()
      }
      
      
      private func calcAngles() {
          for elem in sample {
              withAnimation() {
                  elem.startAngle = getStartAngle(elem: elem, dataModel: sample)
                  elem.endAngle = getEndAngle(elem: elem, dataModel: sample)
              }
          }
      }
      
      private func getStartAngle(elem: ChartEntry, dataModel: [ChartEntry]) -&gt; Double {
          return 360 * (Double(dataModel.firstIndex(of: elem) ?? 0) / Double(dataModel.count))
      }
      
      private func getEndAngle(elem: ChartEntry, dataModel: [ChartEntry]) -&gt; Double {
          return 360 * (Double((dataModel.firstIndex(of: elem) ?? 0) + 1) / Double(dataModel.count))
      }
  }
  
  class ChartEntry: Identifiable, Equatable, ObservableObject{
      static func == (lhs: ChartEntry, rhs: ChartEntry) -&gt; Bool {
          lhs.id == rhs.id
      }
      
      var id = UUID()
      var color: Color
      @Published var startAngle: Double = 360
      @Published var endAngle: Double = 360
      
      init(color: Color) {
          self.color = color
      }
  }
  </code></pre>