Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@erica
Created October 20, 2016 15:26
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save erica/fe785645fb28a783e0f851b24d37dd6d to your computer and use it in GitHub Desktop.
Save erica/fe785645fb28a783e0f851b24d37dd6d to your computer and use it in GitHub Desktop.
import UIKit
func pushDraw(in context: UIGraphicsImageRendererContext,
applying actions: () -> Void)
{
context.cgContext.saveGState()
actions()
context.cgContext.restoreGState()
}
let π = CGFloat(Double.pi)
let size = CGSize(width: 200, height: 200)
let renderer = UIGraphicsImageRenderer(size: size)
// Enable kerning
let attributes: [String: Any] = [
NSFontAttributeName: UIFont.boldSystemFont(ofSize: 14.0),
NSForegroundColorAttributeName: UIColor.black,
NSKernAttributeName: 8
]
// Textkit layout
let manager = NSLayoutManager()
let container = NSTextContainer(size: CGSize(width: .max, height: .max))
manager.addTextContainer(container)
let attributedString = NSTextStorage(string: "ABCDEFGHIJKLMNOPQRSTUVWXYZ", attributes: attributes)
manager.textStorage = attributedString
let fullSize = manager.boundingRect(forGlyphRange: NSMakeRange(0, 26), in: container).size.width
let lettersAndSizes = Array(0 ..< 26).lazy
.map({ NSMakeRange($0, 1) })
.map({ (attributedString.attributedSubstring(from: $0),
manager.boundingRect(forGlyphRange: $0, in: container).size.width) })
var consumedSize: CGFloat = 0
let image = renderer.image { context in
let bounds = context.format.bounds
let (centerX, centerY) = (bounds.midX, bounds.midY)
// Start by adjusting the context origin
// This affects all subsequent operations
context.cgContext.translateBy(x: centerX, y: centerY)
// Offset by half of the first character
let firstHalfSize = lettersAndSizes.first!.1 / 2.0
let theta = 2 * π * firstHalfSize / fullSize
context.cgContext.rotate(by: -theta)
// Set the radius to draw at
let r: CGFloat = 70
// Draw each letter proportionally
for (letter, letterSize) in lettersAndSizes
{
let halfWidth = letterSize / 2.0
consumedSize = consumedSize + halfWidth;
defer { consumedSize += halfWidth }
pushDraw(in: context) {
// Rotate the context
let theta = 2 * π * consumedSize / fullSize
context.cgContext.rotate(by: theta)
// Translate up to the edge of the radius and
// move left by half the letter width.
context.cgContext.translateBy(x: -halfWidth, y: -r)
letter.draw(at: .zero)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment