How to rotate a CAShapeLayer - ios

I am trying to rotate a CAShapeLayer with respect to a particular anchor point. But when i apply
firstLayer.transform = CATransform3DMakeRotation(CGFloat(M_2_PI), 0, 0, 0)
nothing happens.
i am making a custom UIButton , in which i am adding a layer
import UIKit
#IBDesignable
class CustomButtonTwo: UIButton {
var context = UIGraphicsGetCurrentContext()
#IBInspectable var Thickness : CGFloat = 2
let firstLayer = CAShapeLayer()
var width = CGFloat()
var height = CGFloat()
override func awakeFromNib() {
super.awakeFromNib()
width = self.frame.width
height = self.frame.height
print("\(width) : \(height)")
}
override func drawRect(rect: CGRect) {
super.drawRect(rect)
let afirstStartPoint = CGPointMake(width * 0.1, (height - 3 * Thickness) / 6)
let bfirstStartPoint = CGPointMake(width * 0.1, (height - 3 * Thickness) / 6 + Thickness)
let afirstMiddlePoint = CGPointMake(width * 0.5, (height - 3 * Thickness) / 6 )
let bfirstMiddlePoint = CGPointMake(width * 0.5, (height - 3 * Thickness) / 6 + Thickness)
print(afirstMiddlePoint)
print(afirstStartPoint)
print(bfirstMiddlePoint)
print(bfirstStartPoint)
let firstPath = UIBezierPath()
firstPath.moveToPoint(afirstStartPoint)
firstPath.addLineToPoint(afirstMiddlePoint)
firstPath.addLineToPoint(bfirstMiddlePoint)
firstPath.addLineToPoint(bfirstStartPoint)
firstPath.addLineToPoint(afirstStartPoint)
firstPath.closePath()
firstLayer.frame = self.frame
UIColor.greenColor().setFill()
firstPath.fill()
firstLayer.path = firstPath.CGPath
firstLayer.anchorPoint = afirstStartPoint
firstLayer.transform = CATransform3DMakeRotation(CGFloat(M_2_PI), 0, 0, 1)
layer.addSublayer(firstLayer)
}
}
i want to make a line with a particular thickness and rotate it along a particular point (while animating).
any help appreciated!
simulator Screenshot

Rotating by 2_PI (360) will mean layer will end up back at its original place (0 rotation). Try PI_2 (90) or PI (180) or another angle. Also you need to specify the axis of rotation.
This call rotates by 90 degrees around z-axis:
CATransform3DMakeRotation(CGFloat(M_PI_2), 0, 0, 1.0)

Related

calculate new size and location on a CGRect

I have a CGRect (let's call it A1) with know size and location that has a parent A of know size. A1 has all sort of CGAffineTransform applied to it.
I need to find the location and size of a second rectangle relative to a parent B of known (but different dimensions) that would look proportional to A1 in relation to A
Basically a "zoom" effect. What would A1 dimensions and position be to look similar when placed in B . Kind of a "scale the CGAffineTransform" ?
visual guide:
From:
To:
Assuming you are transforming the rect like this:
scale it
move it
rotate it
First, you want to calculate the "scaleFactor" between the two sizes. So...
if rect A was 100 x 100
and rect B was 200 x 200
The scaleFactor would be 200 / 100 == 2 ... that is, B is 2x bigger.
For your values:
rect A is 375 x 375
rect B is 1080 x 1080
the scaleFactor is 1080 / 375 == 2.88
So, let's go with values that make the math easy (and obvious):
rect A is 200 x 200
rect A1 origin is x: 30 y: 20
rect A1 size is 50 x 25
rect B is 600 x 600
scaleFactor is 600 / 200 == 3, so
rect B1 origin is x: (30 * 3) y: (20 * 3)
rect B1 size is (50 * 3) x (25 * 3)
If that's all we've done so far, we would get this result:
Next, we need to move (translate) it, and scale the translation. If the original translation is:
CGAffineTransform(translationX: 30, y: 100)
the new translation is:
CGAffineTransform(translationX: 30 * scaleFactor, y: 100 * scaleFactor)
We don't need to scale the rotation, because, well, it's the same rotation.
So, after setting the original frame based on our origin and size calculations, then applying the same scale transform, plus the scaled translation transform, plus the same rotation transform, we get:
Here's example code I used to produce that:
class ViewController: UIViewController {
let viewA: UIView = {
let v = UIView()
v.backgroundColor = .systemYellow
return v
}()
let viewARedView: UIView = {
let v = UIView()
v.backgroundColor = .systemRed
return v
}()
let viewABlueView: UIView = {
let v = UIView()
v.backgroundColor = .systemBlue
return v
}()
let viewB: UIView = {
let v = UIView()
v.backgroundColor = .systemYellow
return v
}()
let viewBRedView: UIView = {
let v = UIView()
v.backgroundColor = .systemRed
return v
}()
let viewBBlueView: UIView = {
let v = UIView()
v.backgroundColor = .systemBlue
return v
}()
override func viewDidLoad() {
super.viewDidLoad()
navigationController?.setNavigationBarHidden(true, animated: false)
view.addSubview(viewA)
view.addSubview(viewB)
viewA.frame = CGRect(x: 20, y: 60, width: 200, height: 200)
viewB.frame = CGRect(x: 20, y: viewA.frame.maxY + 20, width: 600, height: 600)
viewA.addSubview(viewARedView)
viewA.addSubview(viewABlueView)
let origRect: CGRect = CGRect(x: 30, y: 20, width: 50, height: 25)
// set frames of red and blue rect to the same rectangles
// so blue is on top of red
// we're going to transform the blue rect
viewARedView.frame = origRect
viewABlueView.frame = origRect
// scale values
let scX: CGFloat = 2.25
let scY: CGFloat = 1.75
// translate values
let trX: CGFloat = 30.0
let trY: CGFloat = 100.0
// rotation value
let rot: CGFloat = .pi * -0.15
var tx: CGAffineTransform = .identity
// scale it
tx = tx.concatenating(CGAffineTransform(scaleX: scX, y: scY))
// move it
tx = tx.concatenating(CGAffineTransform(translationX: trX, y: trY))
// rotate it
tx = tx.concatenating(CGAffineTransform(rotationAngle: rot))
// apply the transform
viewABlueView.transform = tx
viewB.addSubview(viewBRedView)
viewB.addSubview(viewBBlueView)
// get the scale factor...
// in this case,
// viewA width is 200
// viewB width is 700
// so viewB is 3.5 times bigger (700 / 200)
let scaleFactor: CGFloat = viewB.frame.width / viewA.frame.width
// make the original rect origin and size
// "scaleFactor bigger"
let newRect: CGRect = CGRect(x: origRect.origin.x * scaleFactor,
y: origRect.origin.y * scaleFactor,
width: origRect.width * scaleFactor,
height: origRect.height * scaleFactor)
// set frames of red and blue rect to the same rectangles
// so blue is on top of red
// we're going to transform the blue rect
viewBRedView.frame = newRect
viewBBlueView.frame = newRect
// scale the translation values
let trXb: CGFloat = trX * scaleFactor
let trYb: CGFloat = trY * scaleFactor
var txb: CGAffineTransform = .identity
// we've already changed the initial size of the rectangle,
// so use same scaling values
txb = txb.concatenating(CGAffineTransform(scaleX: scX, y: scY))
// we need to use scaled translation values
txb = txb.concatenating(CGAffineTransform(translationX: trXb, y: trYb))
// rotation doesn't change based on scale
txb = txb.concatenating(CGAffineTransform(rotationAngle: rot))
// apply the transform
viewBBlueView.transform = txb
}
}

How can I layout images/views programmatically in a circle AROUND a central image

I am attempting to plot 8 UIViews in a circle around a central image. I am able to plot the images in a circle, but my center point is not located on the central image.
I have successfully plotted 8 UIViews (will be images) programmatically in a circle using a shared center/origin point. From center.x and center.y I am adding the x and y components for each particular image using trig functions.
let radiusX = center.x + (radius * cos(radians)) .
let radiusY = center.y + (radius * sin(radians))
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var centerImage: UIImageView!{
didSet{
centerImage.clipsToBounds = true
centerImage.layer.cornerRadius =
centerImage.frame.width/2
}
}
#IBOutlet weak var containerView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view,
typically from a nib.
}
override func viewDidLayoutSubviews() {
initSmallPhotos()
}
func initSmallPhotos() {
var radians : CGFloat = 0
let sideOfPic : CGFloat = 65.7
let radius : CGFloat = containerView.frame.width >
containerView.frame.height ?
containerView.frame.height / 2 -
sideOfPic : containerView.frame.width / 2 - sideOfPic
let x = containerView.center.x
let y = containerView.center.y
let center = CGPoint(x: x, y: y)
print(center)
for _ in 0...7 {
let radiusX = center.x + (radius * cos(radians))
let radiusY = center.y + (radius * sin(radians))
let view = UIView()
view.backgroundColor = UIColor.red
view.frame.size = CGSize(width: sideOfPic, height:
sideOfPic)
view.center = CGPoint(x: radiusX, y: radiusY)
view.clipsToBounds = true
view.layer.cornerRadius = sideOfPic / 2
view.layer.masksToBounds = true
view.layer.borderColor = UIColor.white.cgColor
view.layer.borderWidth = 2
view.contentMode = .scaleAspectFit
containerView.addSubview(view)
radians += (CGFloat.pi / 4)
print(radians)
}
}
}
The issue is what to use for my center points. I am able to center the 8 images horizontally by using my center.x = containerView.center.x, but when I use center.y = containerView.center.y, the images are set too low. I also tried center.y = containerView.frame.origin.y and that set the 8 images too high on the screen.
trying to use center points from my centerImage gave me really strange behavior, even though the image is constrained to the center of the container view.
Any help would be appreciated.
Use bounds.midX vs center.x AND bounds.midY vs. center.y.. Check the lines where you set x and y. Using center is giving you the position of the containerView inside of its super view not the center of containerView. Hope that makes sense.
import Foundation
import UIKit
import PlaygroundSupport
class ViewController:UIViewController{
var check = true
var containerView = UIView(frame: CGRect(x: 30, y: 30, width: 400, height: 300))
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .blue
view.addSubview(containerView)
initSmallPhotos()
}
func initSmallPhotos() {
var radians : CGFloat = 0
let sideOfPic : CGFloat = 65.7
let radius : CGFloat = containerView.frame.width >
containerView.frame.height ?
containerView.frame.height / 2 -
sideOfPic : containerView.frame.width / 2 - sideOfPic
let x = containerView.bounds.midX
let y = containerView.bounds.midY
let center = CGPoint(x: x, y: y)
print(center)
for _ in 0...7 {
let radiusX = center.x + (radius * cos(radians))
let radiusY = center.y + (radius * sin(radians))
let view = UIView()
view.backgroundColor = UIColor.red
view.frame.size = CGSize(width: sideOfPic, height:
sideOfPic)
view.center = CGPoint(x: radiusX, y: radiusY)
view.clipsToBounds = true
view.layer.cornerRadius = sideOfPic / 2
view.layer.masksToBounds = true
view.layer.borderColor = UIColor.white.cgColor
view.layer.borderWidth = 2
view.contentMode = .scaleAspectFit
containerView.addSubview(view)
radians += (CGFloat.pi / 4)
print(radians)
}
}
}
let viewController = ViewController()
PlaygroundPage.current.liveView = viewController
PlaygroundPage.current.needsIndefiniteExecution

EXC_BAD_INSTRUCTION when trying to pass data to UIViews

I created a call of a UIView in which I draw a graph. I am trying to pass it new data and have it update.
When I run the app on the simulator and click the tab in which the the controller housing the view is in, I receive this error:
Thread 1: EXC_BAD_INSTRUCTION (code=EXC_1386_INVOP, subcode=0x0)
at the line:
let maxValue = graphPoints.maxElement()
Here is my code for the view:
#IBDesignable class GraphView: UIView {
var graphPoints :[Int]!
override init(frame: CGRect) {
super.init(frame: frame)
}
init(graphPoints: [Int]) {
self.graphPoints = graphPoints
super.init(frame: CGRectZero)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
#IBInspectable var startColor: UIColor = UIColor.redColor()
#IBInspectable var endColor: UIColor = UIColor.greenColor()
override func drawRect(rect: CGRect) {
let width = rect.width
let height = rect.height
//set up background clipping area
let path = UIBezierPath(roundedRect: rect,
byRoundingCorners: UIRectCorner.AllCorners,
cornerRadii: CGSize(width: 8.0, height: 8.0))
path.addClip()
//2 - get the current context
let context = UIGraphicsGetCurrentContext()
let colors = [startColor.CGColor, endColor.CGColor]
//3 - set up the color space
let colorSpace = CGColorSpaceCreateDeviceRGB()
//4 - set up the color stops
let colorLocations:[CGFloat] = [0.0, 1.0]
//5 - create the gradient
let gradient = CGGradientCreateWithColors(colorSpace,
colors,
colorLocations)
//6 - draw the gradient
var startPoint = CGPoint.zeroPoint
var endPoint = CGPoint(x:0, y:self.bounds.height)
CGContextDrawLinearGradient(context,
gradient,
startPoint,
endPoint,
.DrawsBeforeStartLocation)
//calculate the x point
let rightMargin:CGFloat = 40
let leftMargin : CGFloat = 10
let columnXPoint = { (column:Int) -> CGFloat in
//Calculate gap between points
let spacer = (width - rightMargin - leftMargin - 4) /
CGFloat((self.graphPoints.count - 1))
var x:CGFloat = CGFloat(column) * spacer
x += leftMargin + 2
print(x)
return x
}
// calculate the y point
let topBorder:CGFloat = 30
let bottomBorder:CGFloat = 50
let graphHeight = height - topBorder - bottomBorder
let maxValue = graphPoints.maxElement()
let columnYPoint = { (graphPoint:Int) -> CGFloat in
var y:CGFloat = CGFloat(graphPoint) /
CGFloat(maxValue!) * graphHeight
y = graphHeight + topBorder - y // Flip the graph
print(y)
return y
}
// draw the line graph
UIColor.whiteColor().setFill()
UIColor.whiteColor().setStroke()
//set up the points line
let graphPath = UIBezierPath()
//go to start of line
graphPath.moveToPoint(CGPoint(x:columnXPoint(0), y:columnYPoint(graphPoints[0])))
//add points for each item in the graphPoints array
//at the correct (x, y) for the point
for i in 1..<graphPoints.count {
let nextPoint = CGPoint(x:columnXPoint(i),
y:columnYPoint(graphPoints[i]))
graphPath.addLineToPoint(nextPoint)
}
//Create the clipping path for the graph gradient
//1 - save the state of the context (commented out for now)
CGContextSaveGState(context)
//2 - make a copy of the path
let clippingPath = graphPath.copy() as! UIBezierPath
//3 - add lines to the copied path to complete the clip area
clippingPath.addLineToPoint(CGPoint(
x: columnXPoint(graphPoints.count - 1),
y:height))
clippingPath.addLineToPoint(CGPoint(
x:columnXPoint(0),
y:height))
clippingPath.closePath()
//4 - add the clipping path to the context
clippingPath.addClip()
let highestYPoint = columnYPoint(maxValue!)
startPoint = CGPoint(x:leftMargin, y: highestYPoint)
endPoint = CGPoint(x:rightMargin, y:self.bounds.height)
CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, .DrawsBeforeStartLocation)
CGContextRestoreGState(context)
//draw the line on top of the clipped gradient
graphPath.lineWidth = 2.0
graphPath.stroke()
//Draw the circles on top of graph stroke
for i in 0..<graphPoints.count {
var point = CGPoint(x:columnXPoint(i), y:columnYPoint(graphPoints[i]))
point.x -= 5.0/2
point.y -= 5.0/2
let circle = UIBezierPath(ovalInRect:
CGRect(origin: point,
size: CGSize(width: 5.0, height: 5.0)))
circle.fill()
}
//Draw horizontal graph lines on the top of everything
let linePath = UIBezierPath()
//top line
linePath.moveToPoint(CGPoint(x:leftMargin, y: topBorder))
linePath.addLineToPoint(CGPoint(x: width - rightMargin,
y:topBorder))
//center line
linePath.moveToPoint(CGPoint(x:leftMargin,
y: graphHeight/2 + topBorder))
linePath.addLineToPoint(CGPoint(x:width - rightMargin,
y:graphHeight/2 + topBorder))
//bottom line
linePath.moveToPoint(CGPoint(x:leftMargin,
y:height - bottomBorder))
linePath.addLineToPoint(CGPoint(x:width - rightMargin,
y:height - bottomBorder))
let color = UIColor(white: 1.0, alpha: 0.3)
color.setStroke()
linePath.lineWidth = 1.0
linePath.stroke()
}
And here is the code for my view controller in which I pass data to the view.
import UIKit
import QuartzCore
class ProgressViewController: UIViewController {
#IBOutlet weak var graphView: UIView!
var firstGraph : GraphView!
override func viewDidLoad() {
self.graphView = self.firstGraph
self.firstGraph = GraphView(graphPoints: [2240, 1983, 2171, 2017, 1842, 1992, 2347])
I'm new to Swift and I'm stumped on this problem after looking everywhere for an answer. Any help is appreciated.

How can I increase the size of a CGRect by a certain percent value?

How can I increase the size of a CGRect by a certain percent value? Should I use some form of CGRectInset to do it?
Example:
Assume I have a CGRect: {10, 10, 110, 110}
I want to increase its size (retaining the same center point) by 20% to:
{0, 0, 120, 120}
You can use CGRectInset if you like:
double pct = 0.2;
CGRect newRect = CGRectInset(oldRect, -CGRectGetWidth(oldRect)*pct/2, -CGRectGetHeight(oldRect)*pct/2);
To decrease the size, remove the -s.
Side note: A CGRect that is 20% bigger than {10, 10, 100, 100} is {0, 0, 120, 120}.
Edit: If the intention is to increase by area, then this'll do it (even for rectangles that aren't square):
CGFloat width = CGRectGetWidth(oldRect);
CGFloat height = CGRectGetHeight(oldRect);
double pct = 1.2; // 20% increase
double newWidth = sqrt(width * width * pct);
double newHeight = sqrt(height * height * pct);
CGRect newRect = CGRectInset(oldRect, (width-newWidth)/2, (height-newHeight)/2);
In Swift:
func increaseRect(rect: CGRect, byPercentage percentage: CGFloat) -> CGRect {
let startWidth = CGRectGetWidth(rect)
let startHeight = CGRectGetHeight(rect)
let adjustmentWidth = (startWidth * percentage) / 2.0
let adjustmentHeight = (startHeight * percentage) / 2.0
return CGRectInset(rect, -adjustmentWidth, -adjustmentHeight)
}
let rect = CGRectMake(0, 0, 10, 10)
let adjusted = increaseRect(rect, byPercentage: 0.1)
// -0.5, -0.5, 11, 11
In ObjC:
- (CGRect)increaseRect:(CGRect)rect byPercentage:(CGFloat)percentage
{
CGFloat startWidth = CGRectGetWidth(rect);
CGFloat startHeight = CGRectGetHeight(rect);
CGFloat adjustmentWidth = (startWidth * percentage) / 2.0;
CGFloat adjustmentHeight = (startHeight * percentage) / 2.0;
return CGRectInset(rect, -adjustmentWidth, -adjustmentHeight);
}
CGRect rect = CGRectMake(0,0,10,10);
CGRect adjusted = [self increaseRect:rect byPercentage:0.1];
// -0.5, -0.5, 11, 11
Sure, using CGRectInset works:
CGRect someRect = CGRectMake(10, 10, 100, 100);
someRect = CGRectInset(someRect, someRect.size.width * -0.2, someRect.size.height * -0.2);
Swift 4 extension inspired by several of the answers here with simplified calculations:
extension CGRect {
func scaleLinear(amount: Double) -> CGRect {
guard amount != 1.0, amount > 0.0 else { return self }
let ratio = ((1.0 - amount) / 2.0).cgFloat
return insetBy(dx: width * ratio, dy: height * ratio)
}
func scaleArea(amount: Double) -> CGRect {
return scaleLinear(percent: sqrt(amount))
}
func scaleLinear(percent: Double) -> CGRect {
return scaleLinear(amount: percent / 100)
}
func scaleArea(percent: Double) -> CGRect {
return scaleArea(amount: percent / 100)
}
}
Usage is simply:
rect.scaleLinear(percent: 120.0) OR (amount: 1.2)
rect.scaleArea(percent: 120.0) OR (amount: 1.2)
If you are interested in trying my testing methods:
/// Testing
extension CGRect {
var area: CGFloat { return width * height }
var center: CGPoint { return CGPoint(x: origin.x + width/2, y: origin.y + height/2)
}
func compare(_ r: CGRect) {
let centered = center.x == r.center.x && center.y == r.center.y
print("linear = \(r.width / width), area = \(r.area / area) centered \(centered)")
}
static func ScaleTest() {
let rect = CGRect(x: 17, y: 24, width: 200, height: 100)
let percent = 122.6
rect.compare(rect.scaleLinear(percent: percent))
rect.compare(rect.scaleArea(percent: percent))
}
}
I'm using CGRect > insetBy in my Swift code
https://developer.apple.com/documentation/coregraphics/cgrect/1454218-insetby
With this, your percent value will be the scaleX as my example.
let dx = rectWidth*scaleX
let dy = rectHeight*scaleX
let rectangle = CGRect(x: rectX,
y: rectY,
width: rectWidth,
height: rectHeight).insetBy(dx: -dx, dy: -dy)
use positive value to scale down
use negative value to scale up
Using Swift you can retain the center point (relative to the source Rect) and increase/decrease the size as follows using an extension:
extension CGRect {
func centerAndAdjustPercentage(percentage p: CGFloat) -> CGRect {
let x = self.origin.x
let y = self.origin.y
let w = self.width
let h = self.height
let newW = w * p
let newH = h * p
let newX = (w - newW) / 2
let newY = (h - newH) / 2
return CGRect(x: newX, y: newY, width: newW, height: newH)
}
}
let newRect = oldRect.centerAndAdjustPercentage(percentage: 0.25)
let scale = percent / 100
let newRect = oldRect.applying(CGAffineTransform(scaleX: scale, y: scale))
Beware that this approach also will change x and y of rectangle.

iOS Swift Xcode 6: CGAffineTransformRotate with auto-layout anchorpoint

I'm making an app with a rotatable pie chart. However, my pie chart rotates around (0,0) and I can't find a solution to make it rotate around its center.
Some code:
// DRAWING CODE
// Set constants for piePieces
let radius: CGFloat = CGFloat(screen.width * 0.43)
let pi: CGFloat = 3.1415926535
let sliceRad: CGFloat = 2.0 * pi / CGFloat(categoryArray.count)
var currentAngle: CGFloat = -0.5 * sliceRad - 0.5 * pi
let center: CGPoint = CGPoint(x: screen.width / 2.0, y: radius)
println("Center point: \(center)")
//container!.layer.anchorPoint = CGPoint(x: screen.width, y: radius)
// Draw all pie charts, add them to container (chartView)
for category in categoryArray {
let slice = UIView()
slice.frame = self.frame
let shapeLayer = CAShapeLayer()
let scoreIndex = CGFloat(category.calculateScoreIndex())
let sliceRadius: CGFloat = scoreIndex * radius
// Draw the path
var path:UIBezierPath = UIBezierPath()
path.moveToPoint(center)
path.addLineToPoint(CGPoint(x: center.x + sliceRadius * cos(currentAngle), y: center.y + sliceRadius * sin(currentAngle)))
path.addArcWithCenter(center, radius: sliceRadius, startAngle: currentAngle, endAngle: currentAngle + sliceRad, clockwise: true)
path.addLineToPoint(center)
path.closePath()
// For next slice, add 2*pi Rad / n categories
currentAngle += sliceRad
// Add path to shapeLayer
shapeLayer.path = path.CGPath
//shapeLayer.frame = self.frame
shapeLayer.fillColor = SurveyColors().getColor(category.categoryIndex).CGColor
shapeLayer.anchorPoint = center
// Add shapeLayer to sliceView
slice.layer.addSublayer(shapeLayer)
// Add slice to chartView
container!.addSubview(slice)
}
self.addSubview(container!)
//container!.center = center
container!.layer.anchorPoint = center
}
I sheduled a NSTimer to perform a rotation every 2 seconds (for testing purposes):
func rotate() {
let t: CGAffineTransform = CGAffineTransformRotate(container!.transform, -0.78)
container!.transform = t;
}
The pie chart rotates around (0,0). What is going wrong?
I believe a good solution to your problem would be to set a container view:
container = UIView()
container!.frame = CGRect(x: 0.0, y: 0.0, width: screen.width, height: screen.width)
container!.layer.anchorPoint = CGPoint(x: 0.5, y: 0.5)
container!.backgroundColor = UIColor.clearColor()
And then add all slices to this container view:
let slice = UIView()
slice.frame = CGRect(x: 0.0 , y: 0.0 , width: container!.bounds.width, height: container!.bounds.height)
let shapeLayer = CAShapeLayer()
let scoreIndex = CGFloat(category.calculateScoreIndex())
let sliceRadius: CGFloat = scoreIndex * radius
/*
*/
container!.addSubview(slice)
Also, make sure not to add your chart as a subview to a view with auto-layout constraints (which might interfere with you CGAffineTransformRotate).

Resources