For those of us in the U.S. with a geekiness toward math March 15, 2015 at 9:26:53 is going to be the best pi day ever. As the date in the American calendar format is 3/14/15, the closest approximation to pi the mm dd yy hh:mm:ss format can have. To celebrate this, I’m going to add pie wedges to the ring graph I wrote about last Tuesday.
I’m going to assume for this you have completed the ring graph project. If not, take a look at it first.
The key to the ring graph was using arcs in Core Graphics. Arc are lines. Everything else in the app was set up for these few lines of code.
CGContextSetStrokeColorWithColor(context, arcColor.CGColor) CGContextSetLineWidth(context, arcWidth * 0.8 ) CGContextAddArc(context, centerPoint.x, centerPoint.y, radius, start, end, 0) CGContextStrokePath(context)
This code first sets the line color. Then it sets the width of the line. It makes a path for the line drawn, then finally draws the line. What if instead of drawing the line we fill inside of it? Consider this code:
CGContextMoveToPoint(context, centerPoint.x, centerPoint.y) CGContextAddArc(context, centerPoint.x, centerPoint.y, radius, start, end, 0) CGContextFillPath(context)
This code does slightly more. It makes a more complicated path. We move the beginning of the path to the center of the circle. We then make the arc, and Core Graphics draws a straight line path between the center point and the beginning of the path. Core Graphics will connect the two open points for us, so when we call CGContextFillPath(context)
, we get a filled pie wedge.
For our method it would be best to add this as a setting. Replace this code:
//draw the arc CGContextSetStrokeColorWithColor(context, arcColor.CGColor) CGContextSetLineWidth(context, arcWidth * 0.8 ) //CGContextSetLineWidth(context, arcWidth) CGContextAddArc(context, centerPoint.x, centerPoint.y, radius, start, end, 0) CGContextStrokePath(context)
with this code:
if isPie { CGContextSetFillColorWithColor(context, arcColor.CGColor) CGContextMoveToPoint(context, centerPoint.x, centerPoint.y) CGContextAddArc(context, centerPoint.x, centerPoint.y, radius, start, end, 0) CGContextFillPath(context) }else{ CGContextSetStrokeColorWithColor(context, arcColor.CGColor) CGContextSetLineWidth(context, arcWidth * 0.8 ) CGContextAddArc(context, centerPoint.x, centerPoint.y, radius, start, end, 0) CGContextStrokePath(context) }
We will use a new Boolean
property isPie
to decide if we want an arc or a wedge. Add the property to the class, defaulting to an arc graph.
var isPie = false
Changes to the View Controller
Head over to the view controller. Change viewDidLoad
to this:
override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. let backgroundTrackColor = UIColor(white: 0.15, alpha: 1.0) circleGraph.arcBackgroundColor = backgroundTrackColor circleGraph.arcWidth = 35.0 circleGraph.isPie = true circleGraph.endArc = 0.3141592653 // 3/14/15 9:26:53 }
The circleGraph
will now be a pie shape. Build and run and you get this:
We get the background rings for the other two graphs. We can get rid of them by changing the arcBackgroundColor
attribute to UIColor.clearColor()
, or deleting them, but we will add a white ring to the graph, with a new arcBackgroundColor.
Add this to viewDidLoad
:
whiteGraph.arcWidth = 25.0 whiteGraph.arcColor = UIColor.whiteColor() whiteGraph.endArc = 0.5 whiteGraph.arcBackgroundColor = whiteGraph.arcColor.colorWithAlphaComponent(0.75)
Build and run:
The code whiteGraph.arcColor.colorWithAlphaComponent(0.75)
takes our current white foreground color and makes it slightly transparent. This is closer to what they do in the Apple Watch fitness app. Add the redGraph
back in with the wedge with all these changes:
redGraph.endArc = 0.25 redGraph.arcColor = UIColor.redColor() redGraph.arcWidth = 20.0 redGraph.isPie = true redGraph.arcBackgroundColor = redGraph.arcColor.colorWithAlphaComponent(0.35)
Build and run:
Enjoy your Pi Day. Hopefully these are helpful hints on some cool graphics.
The Whole Code
Downloadable Source
The download for this contains the three critical source code files. Download it here: SwiftRingGraph_Source and unzip it. You will find three files.
- ViewController.swift
- Main.Storyboard
- CircleGraphView.swift
In Xcode, Open up a new single view project named SwiftRingGraph using Swift as the language and Universal device. Delete the ViewController.Swift and Main.Storyboard and send them to the trash can. Drag the three files you unzipped to the project’s navigator. In the dialog box that appears, make sure that copy files is checked on, and finish the dialog box. You now have a working copy.
ViewController.swift
// // ViewController.swift // Swift Ring Graph // // Created by Steven Lipton on 3/10/15. // Copyright (c) 2015 MakeAppPie.Com. All rights reserved. // import UIKit class ViewController: UIViewController { @IBOutlet weak var percentLabel: UILabel! @IBOutlet weak var circleGraph: CircleGraphView! @IBOutlet weak var whiteGraph: CircleGraphView! @IBOutlet weak var redGraph: CircleGraphView! @IBAction func slider(sender: UISlider) { circleGraph.endArc = CGFloat(sender.value) percentLabel.text = String(format:" %0.2f %%",sender.value * 100) } @IBAction func whiteSlider(sender: UISlider) { whiteGraph.endArc = CGFloat(sender.value) } @IBAction func redSlider(sender: UISlider) { redGraph.endArc = CGFloat(sender.value) } override func viewDidLoad() { super.viewDidLoad() let backgroundTrackColor = UIColor(white: 0.15, alpha: 1.0) circleGraph.arcBackgroundColor = backgroundTrackColor circleGraph.arcWidth = 35.0 circleGraph.isPie = true circleGraph.endArc = 0.314159 whiteGraph.arcWidth = 25.0 whiteGraph.arcColor = UIColor.whiteColor() whiteGraph.endArc = 0.5 whiteGraph.arcBackgroundColor = whiteGraph.arcColor.colorWithAlphaComponent(0.75) redGraph.endArc = 0.25 redGraph.arcColor = UIColor.redColor() redGraph.arcWidth = 20.0 redGraph.isPie = true redGraph.arcBackgroundColor = redGraph.arcColor.colorWithAlphaComponent(0.35) } }
CircleGraphView.swift
// // CircleGraphView.swift // Swift Ring Graph // // Created by Steven Lipton on 3/10/15. // Copyright (c) 2015 MakeAppPie.Com. All rights reserved. // import UIKit class CircleGraphView: UIView { var endArc:CGFloat = 0.0{ // in range of 0.0 to 1.0 didSet{ setNeedsDisplay() } } var arcWidth:CGFloat = 10.0 var arcColor = UIColor.yellowColor() var arcBackgroundColor = UIColor.blackColor() var isPie = false override func drawRect(rect: CGRect) { //Important constants for circle let fullCircle = 2.0 * CGFloat(M_PI) let start:CGFloat = -0.25 * fullCircle let end:CGFloat = endArc * fullCircle + start //find the centerpoint of the rect var centerPoint = CGPointMake(CGRectGetMidX(rect), CGRectGetMidY(rect)) //define the radius by the smallest side of the view var radius:CGFloat = 0.0 if CGRectGetWidth(rect) > CGRectGetHeight(rect){ radius = (CGRectGetWidth(rect) - arcWidth) / 2.0 }else{ radius = (CGRectGetHeight(rect) - arcWidth) / 2.0 } //starting point for all drawing code is getting the context. let context = UIGraphicsGetCurrentContext() //set colorspace let colorspace = CGColorSpaceCreateDeviceRGB() //set line attributes CGContextSetLineWidth(context, arcWidth) CGContextSetLineCap(context, kCGLineCapRound) //make the circle background CGContextSetStrokeColorWithColor(context, arcBackgroundColor.CGColor) CGContextSetFillColorWithColor(context, arcBackgroundColor.CGColor) CGContextAddArc(context, centerPoint.x, centerPoint.y, radius, 0, fullCircle, 0) CGContextStrokePath(context) //draw the arc or pie if isPie { CGContextSetFillColorWithColor(context, arcColor.CGColor) CGContextMoveToPoint(context, centerPoint.x, centerPoint.y) CGContextAddArc(context, centerPoint.x, centerPoint.y, radius, start, end, 0) CGContextFillPath(context) }else{ CGContextSetStrokeColorWithColor(context, arcColor.CGColor) CGContextSetLineWidth(context, arcWidth * 0.8 ) CGContextAddArc(context, centerPoint.x, centerPoint.y, radius, start, end, 0) CGContextStrokePath(context) } } }
Leave a Reply