I have 3 function where Im drawing text on Image. The text includes attribute paragraphStyle = .right, but the text always getting aligned to left.
These are my function :
Function Name drawText() :
private func drawText(file: String = #file , line: Int = #line, function: String = #function) {
var myInflectionRate = inflectionRate
let EPS = 0.00000001
if myInflectionRate >= 0 {
myInflectionRate = max(EPS,myInflectionRate)
}else if myInflectionRate < 0{
myInflectionRate = min(-EPS,myInflectionRate)
}
let attributedText = NSAttributedString(string: text, attributes: textAttributes)
var rect = attributedText.boundingRect(with: CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude), options: .usesLineFragmentOrigin, context: nil)
let nsText = text as NSString
let textSize = nsText.size(withAttributes: textAttributes)
let angle = myInflectionRate*2*Double.pi
let arcLength = textSize.width
let r = arcLength / angle
let min_r = arcLength/(2*Double.pi)
let angleB = (Double.pi - angle) / 2.0
let widthOfRect = max(abs(angle) < Double.pi ? r * (sin(angle)/sin(angleB)) : abs(2*r), 2.0*min_r)
let positiveR = abs(r)
let positiveAngle = abs(angle)
let heightOfRect = max( positiveAngle < Double.pi ? positiveR - sqrt(positiveR*positiveR - (widthOfRect/2)*(widthOfRect/2)) : positiveR + positiveR*sin((positiveAngle-Double.pi)/2.0), 2.0*0)
rect.size = CGSize(width: widthOfRect + textSize.height, height: heightOfRect + 2.0*textSize.height)
if text.isEmpty {
rect.size = CGSize(width: 80, height: 80)
}
UIGraphicsBeginImageContextWithOptions(rect.size, false, 0.0)
guard let context = UIGraphicsGetCurrentContext() else {
return
}
if myInflectionRate >= EPS {
context.translateBy (x: rect.size.width / 2, y: textSize.height + r )
}else if myInflectionRate <= -EPS{
context.translateBy (x: rect.size.width / 2, y: rect.size.height - textSize.height + r )
}else{
context.translateBy (x: rect.size.width / 2, y: rect.size.height/2)
}
context.scaleBy(x: 1, y: -1)
context.setFillColor(UIColor.clear.cgColor)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
imageViewForText?.image = image
imageViewForText?.contentMode = .scaleAspectFit
imageViewForText?.frame = self.bounds.insetBy(dx: globalInset!, dy: globalInset!)
imageViewForText?.backgroundColor = textBackgroundColor?.withAlphaComponent(textBackgroundAlpha ?? 1)
refresh()
}
Function Name centreArcPerpendicular() :
func centreArcPerpendicular(text str: String, context: CGContext, radius r: CGFloat, angle theta: CGFloat, attributes: [NSAttributedString.Key: AnyObject], clockwise: Bool, size: CGSize){
let characters: [String] = str.map { String($0) } // An array of single character strings, each character in str
let l = characters.count
var arcs: [CGFloat] = [] // This will be the arcs subtended by each character
var totalArc: CGFloat = 0 // ... and the total arc subtended by the string
for i in 0 ..< l {
arcs += [chordToArc(characters[i].size(withAttributes: attributes).width, radius: r)]
totalArc += arcs[i]
}
let direction: CGFloat = clockwise ? -1 : 1
let slantCorrection: CGFloat = clockwise ? -.pi / 2 : .pi / 2
var thetaI = theta - direction * totalArc / 2
var modifiedAttributes = attributes
for i in 0 ..< l {
thetaI += direction * arcs[i] / 2
let ColorArraySize = CurrentTextConfiguration.shared.textConfiguration.textureTextColor.count
let offset = characters[i].size(withAttributes: attributes)
modifiedAttributes[NSAttributedString.Key.foregroundColor] = CurrentTextConfiguration.shared.textConfiguration.textureTextColor[i%ColorArraySize].getColor(bounds: CGRect(origin: .zero, size: offset))
thetaI += direction * arcs[i] / 2
}
centre(text: str, context: context, radius: r, angle: theta, attributes: modifiedAttributes, slantAngle: thetaI + slantCorrection,size : size)
}
func chordToArc(_ chord: CGFloat, radius: CGFloat) -> CGFloat {
if (chord/(2*radius)) > 1 {
return 2 * asin(1)
}else if (chord/(2*radius)) < -1 {
return 2 * asin(-1)
}
return 2 * asin(chord / (2 * radius))
}
Function name center() :
func centre(text str: String, context: CGContext, radius r: CGFloat, angle theta: CGFloat, attributes: [NSAttributedString.Key: AnyObject], slantAngle: CGFloat, size : CGSize) {
NSAttributedString.Key.font: font]
context.saveGState()
context.scaleBy(x: 1, y: -1)
context.translateBy(x: r * cos(theta), y: -(r * sin(theta)))
context.rotate(by: -slantAngle)
let offset = str.size(withAttributes: attributes)
context.translateBy (x: -offset.width / 2, y: -offset.height / 2) // Move the origin to the centre of the text (negating the y-axis manually)
str.draw(at: CGPoint(x: 0, y: 0), withAttributes: attributes)
context.restoreGState()
}
I want to align my text from right , not left
Related
I have a label which I want to make curve up and curve down using slider. I achieve this using following code:
func drawCurvedString(on layer: CALayer, text: NSAttributedString, angle: CGFloat, radius: CGFloat) {
var radAngle = angle.radians
let textSize = text.boundingRect(
with: CGSize(width: .max, height: .max),
options: [.usesLineFragmentOrigin, .usesFontLeading],
context: nil)
.integral
.size
let perimeter: CGFloat = 2 * .pi * radius
let textAngle: CGFloat = textSize.width / perimeter * 2 * .pi
var textRotation: CGFloat = 0
var textDirection: CGFloat = 0
if angle > CGFloat(10).radians, angle < CGFloat(170).radians {
// bottom string
textRotation = 0.5 * .pi
textDirection = -2 * .pi
radAngle += textAngle / 2
} else {
// top string
textRotation = 1.5 * .pi
textDirection = 2 * .pi
radAngle -= textAngle / 2
}
for c in 0..<text.length {
let letter = text.attributedSubstring(from: NSRange(c..<c+1))
let charSize = letter.boundingRect(
with: CGSize(width: .max, height: .max),
options: [.usesLineFragmentOrigin, .usesFontLeading],
context: nil)
.integral
.size
let letterAngle = (charSize.width / perimeter) * textDirection
let x = radius * cos(radAngle + (letterAngle / 2))
let y = radius * sin(radAngle + (letterAngle / 2))
let singleChar = drawText(
on: layer,
text: letter,
frame: CGRect(
x: (layer.frame.size.width / 2) - (charSize.width / 2) + x,
y: (layer.frame.size.height / 2) - (charSize.height / 2) + y,
width: charSize.width,
height: charSize.height))
layer.addSublayer(singleChar)
singleChar.transform = CATransform3DMakeAffineTransform(CGAffineTransform(rotationAngle: radAngle - textRotation))
radAngle += letterAngle
}
}
func drawText(on layer: CALayer, text: NSAttributedString, frame: CGRect) -> CATextLayer {
let textLayer = CATextLayer()
textLayer.frame = frame
textLayer.string = text
textLayer.alignmentMode = kCAAlignmentCenter
textLayer.contentsScale = UIScreen.main.scale
return textLayer
}
But the problem is its add a sublayer of text. All I want to make existing text curve using slider value. There is some code available but that is in objective-c so can anyone help how to achieve this without adding sublayer in swift.
Thanks in advance.
Here is a complete example...
View Controller
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let testLabel = UILabelX()
testLabel.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(testLabel)
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
// constrain original image view Top / Leading / Trailing
testLabel.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
testLabel.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
testLabel.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
// let's use the image's aspect ratio
testLabel.heightAnchor.constraint(equalToConstant: 300.0),
])
testLabel.backgroundColor = .yellow
testLabel.text = "This is a test of the UILabelX subclass."
}
}
UILabel subclass - from: https://stackoverflow.com/a/69056167/6257435
#IBDesignable
class UILabelX: UILabel {
#IBInspectable var angle: CGFloat = 1.6
#IBInspectable var clockwise: Bool = true
override func draw(_ rect: CGRect) {
centreArcPerpendicular()
}
/**
This draws the self.text around an arc of radius r,
with the text centred at polar angle theta
*/
func centreArcPerpendicular() {
guard let context = UIGraphicsGetCurrentContext() else { return }
let str = self.text ?? ""
let size = self.bounds.size
context.translateBy(x: size.width / 2, y: size.height / 2)
let radius = getRadiusForLabel()
let l = str.count
// let attributes: [String : Any] = [NSAttributedString.Key: self.font]
let attributes : [NSAttributedString.Key : Any] = [.font : self.font]
let characters: [String] = str.map { String($0) } // An array of single character strings, each character in str
var arcs: [CGFloat] = [] // This will be the arcs subtended by each character
var totalArc: CGFloat = 0 // ... and the total arc subtended by the string
// Calculate the arc subtended by each letter and their total
for i in 0 ..< l {
// arcs = [chordToArc(characters[i].widthOfString(usingFont: self.font), radius: radius)]
arcs += [chordToArc(characters[i].size(withAttributes: attributes).width, radius: radius)]
totalArc += arcs[i]
}
// Are we writing clockwise (right way up at 12 o'clock, upside down at 6 o'clock)
// or anti-clockwise (right way up at 6 o'clock)?
let direction: CGFloat = clockwise ? -1 : 1
let slantCorrection = clockwise ? -CGFloat(Double.pi/2) : CGFloat(Double.pi/2)
// The centre of the first character will then be at
// thetaI = theta - totalArc / 2 + arcs[0] / 2
// But we add the last term inside the loop
var thetaI = angle - direction * totalArc / 2
for i in 0 ..< l {
thetaI += direction * arcs[i] / 2
// Call centre with each character in turn.
// Remember to add +/-90ยบ to the slantAngle otherwise
// the characters will "stack" round the arc rather than "text flow"
centre(text: characters[i], context: context, radius: radius, angle: thetaI, slantAngle: thetaI + slantCorrection)
// The centre of the next character will then be at
// thetaI = thetaI + arcs[i] / 2 + arcs[i + 1] / 2
// but again we leave the last term to the start of the next loop...
thetaI += direction * arcs[i] / 2
}
}
func chordToArc(_ chord: CGFloat, radius: CGFloat) -> CGFloat {
// *******************************************************
// Simple geometry
// *******************************************************
return 2 * asin(chord / (2 * radius))
}
/**
This draws the String str centred at the position
specified by the polar coordinates (r, theta)
i.e. the x= r * cos(theta) y= r * sin(theta)
and rotated by the angle slantAngle
*/
func centre(text str: String, context: CGContext, radius r:CGFloat, angle theta: CGFloat, slantAngle: CGFloat) {
// Set the text attributes
let attributes = [NSAttributedString.Key.font: self.font!] as [NSAttributedString.Key : Any]
// Save the context
context.saveGState()
// Move the origin to the centre of the text (negating the y-axis manually)
context.translateBy(x: r * cos(theta), y: -(r * sin(theta)))
// Rotate the coordinate system
context.rotate(by: -slantAngle)
// Calculate the width of the text
let offset = str.size(withAttributes: attributes)
// Move the origin by half the size of the text
context.translateBy(x: -offset.width / 2, y: -offset.height / 2) // Move the origin to the centre of the text (negating the y-axis manually)
// Draw the text
str.draw(at: CGPoint(x: 0, y: 0), withAttributes: attributes)
// Restore the context
context.restoreGState()
}
func getRadiusForLabel() -> CGFloat {
// Imagine the bounds of this label will have a circle inside it.
// The circle will be as big as the smallest width or height of this label.
// But we need to fit the size of the font on the circle so make the circle a little
// smaller so the text does not get drawn outside the bounds of the circle.
let smallestWidthOrHeight = min(self.bounds.size.height, self.bounds.size.width)
let heightOfFont = self.text?.size(withAttributes: [NSAttributedString.Key.font: self.font]).height ?? 0
// Dividing the smallestWidthOrHeight by 2 gives us the radius for the circle.
return (smallestWidthOrHeight/2) - heightOfFont + 5
}
}
I am using following class to create curved text to be added to a CALayer
class CurvedTextLayer: CALayer {
override init() {
super.init()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
override init(layer: Any) {
super.init(layer: layer)
}
init(with bounds: CGRect) {
super.init()
self.frame = bounds
self.setNeedsDisplay()
}
func update(bounds: CGRect) {
self.frame = bounds
self.setNeedsDisplay()
}
override func draw(in ctx: CGContext) {
super.draw(in: ctx)
UIGraphicsPushContext(ctx)
ctx.translateBy(x: bounds.size.width / 2, y: bounds.size.height / 2)
ctx.scaleBy(x: 1, y: -1)
centreArcPerpendicular(text: "Hello round world", context: ctx, radius: 100, angle: 0, colour: UIColor.red, font: UIFont.systemFont(ofSize: 16), clockwise: true)
centreArcPerpendicular(text: "Anticlockwise", context: ctx, radius: 100, angle: CGFloat(-Double.pi/2), colour: UIColor.red, font: UIFont.systemFont(ofSize: 16), clockwise: false)
centre(text: "Hello flat world", context: ctx, radius: 0, angle: 0 , colour: UIColor.yellow, font: UIFont.systemFont(ofSize: 16), slantAngle: CGFloat(Double.pi/4))
UIGraphicsPopContext()
}
func centreArcPerpendicular(text str: String, context: CGContext, radius r: CGFloat, angle theta: CGFloat, colour c: UIColor, font: UIFont, clockwise: Bool){
let characters: [String] = str.map { String($0) }
let l = characters.count
let attributes = [NSAttributedString.Key.font: font]
var arcs: [CGFloat] = []
var totalArc: CGFloat = 0
for i in 0 ..< l {
arcs += [chordToArc(characters[i].size(withAttributes: attributes).width, radius: r)]
totalArc += arcs[i]
}
let direction: CGFloat = clockwise ? -1 : 1
let slantCorrection: CGFloat = clockwise ? -.pi / 2 : .pi / 2
var thetaI = theta - direction * totalArc / 2
for i in 0 ..< l {
thetaI += direction * arcs[i] / 2
centre(text: characters[i], context: context, radius: r, angle: thetaI, colour: c, font: font, slantAngle: thetaI + slantCorrection)
thetaI += direction * arcs[i] / 2
}
}
func chordToArc(_ chord: CGFloat, radius: CGFloat) -> CGFloat {
return 2 * asin(chord / (2 * radius))
}
func centre(text str: String, context: CGContext, radius r: CGFloat, angle theta: CGFloat, colour c: UIColor, font: UIFont, slantAngle: CGFloat) {
let attributes = [NSAttributedString.Key.foregroundColor: c, NSAttributedString.Key.font: font]
context.saveGState()
context.scaleBy(x: 1, y: -1)
context.translateBy(x: r * cos(theta), y: -(r * sin(theta)))
context.rotate(by: -slantAngle)
let offset = str.size(withAttributes: attributes)
context.translateBy (x: -offset.width / 2, y: -offset.height / 2)
str.draw(at: CGPoint(x: 0, y: 0), withAttributes: attributes)
context.restoreGState()
}
}
In ViewController I add the layer as follows
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let sublayer = CurvedTextLayer(with: myView.bounds)
myView.layer.insertSublayer(sublayer, at: 0)
animate()
}
After this I add this animation
func animate() {
let rotationAnimation = CABasicAnimation(keyPath: "transform.scale")
rotationAnimation.fromValue = 1
rotationAnimation.toValue = 2
rotationAnimation.duration = 3
rotationAnimation.fillMode = .forwards
rotationAnimation.isRemovedOnCompletion = false
myView.layer.add(rotationAnimation, forKey: "wateva")
}
After scaling I get this pixelated text.
How can I make it so that it doesn't look pixelated?
I got a center CGPoint and radius Float, I need to get N number of points surrounding the circle, for example in below image how to get the 12 points corresponding red dots.
This is my incomplete function:
func getCirclePoints(centerPoint point: CGPoint, and radius: CGFloat, n: Int) [CGPoint] {
let result: [CGPoint] = stride(from: 0.0, to: 360.0, by: CGFloat(360 / n)).map {
let bearing = $0 * .pi / 180
// NO IDEA WHERE TO MOVE FURTHER
}
return result
}
getCirclePoints(centerPoint: CGPoint(x: 160, y: 240), radius: 120.0, n: 12)
You were almost there!
func getCirclePoints(centerPoint point: CGPoint, radius: CGFloat, n: Int)->[CGPoint] {
let result: [CGPoint] = stride(from: 0.0, to: 360.0, by: Double(360 / n)).map {
let bearing = CGFloat($0) * .pi / 180
let x = point.x + radius * cos(bearing)
let y = point.y + radius * sin(bearing)
return CGPoint(x: x, y: y)
}
return result
}
let points = getCirclePoints(centerPoint: CGPoint(x: 160, y: 240), radius: 120.0, n: 12)
I didn't think and was very clear as an argument name so I've removed this.
Use radians instead of degrees. They are needed inside trigonometric functions
func getCirclePoints(centerPoint point: CGPoint, and radius: CGFloat, n: Int) -> [CGPoint] {
return Array(repeating: 0, count: n).enumerated().map { offset, element in
let cgFloatIndex = CGFloat(offset)
let radiansStep = CGFloat.pi * CGFloat(2.0) / CGFloat(n)
let radians = radiansStep * cgFloatIndex
let x = cos(radians) * radius + point.x
let y = sin(radians) * radius + point.y
return CGPoint(x: x, y: y)
}
}
func getCirclePoints1(centerPoint point: CGPoint, and radius: CGFloat, n: Int) -> [CGPoint] {
var resultPoints: [CGPoint] = []
let radianStep = CGFloat.pi * CGFloat(2.0) / CGFloat(n)
for radians in stride(from: CGFloat(0.0), to: CGFloat.pi * CGFloat(2.0), by: radianStep) {
let x = cos(radians) * radius + point.x
let y = sin(radians) * radius + point.y
resultPoints.append(CGPoint(x: x, y: y))
}
return resultPoints
}
func getCirclePoints2(centerPoint point: CGPoint, and radius: CGFloat, n: Int) -> [CGPoint] {
let radianStep = CGFloat.pi * CGFloat(2.0) / CGFloat(n)
return stride(from: CGFloat(0.0), to: CGFloat.pi * CGFloat(2.0), by: radianStep).map { element in
let cgFloatIndex = CGFloat(element)
let radiansStep = CGFloat.pi * CGFloat(2.0) / CGFloat(n)
let radians = radiansStep * cgFloatIndex
let x = cos(radians) * radius + point.x
let y = sin(radians) * radius + point.y
return CGPoint(x: x, y: y)
}
}
getCirclePoints(centerPoint: CGPoint(x: 160, y: 240), and: 120.0, n: 12)
For having a draw reference
import UIKit
let numOfItems = 10
class customView : UIView {
// Only override draw() if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
override func draw(_ rect: CGRect) {
for i in 0...numOfItems
{
let angle = 360/CGFloat(numOfItems) * CGFloat(i) * .pi / 180
let rad = self.bounds.size.width/2 - 10
let x = bounds.midX + cos(angle) * rad
let y = bounds.midY + sin(angle) * rad
let circlePath = UIBezierPath(
arcCenter: CGPoint(x:x,y:y),
radius:10,
startAngle:0,
endAngle:360,
clockwise: true)
let shapeLayer = CAShapeLayer()
shapeLayer.fillColor = UIColor.red.cgColor
shapeLayer.strokeColor = UIColor.blue.cgColor
shapeLayer.lineWidth = 3
shapeLayer.path = circlePath.cgPath
layer.addSublayer(shapeLayer)
}
}
}
I've been trying to figure this out for too long. With the help of this blog I managed to draw the diagram itself, but it can't show me any data, because it seems like my idea of creating a context array is not possible and I can have only one context per view, is that right? So how can I change the color of each marker individually? I've seen the solution using SpriteKit, but I don't know anything at all about SpriteKit.
func degree2Radian(a:CGFloat)->CGFloat {
let b = CGFloat(M_PI) * a/180
return b
}
override func draw(_ rect: CGRect) {
color.set()
pathForCircleCenteredAtPoint(midPoint: circleCenter, withRadius: circleRadius).stroke()
color = UIColor.white
color.set()
pathForCircleCenteredAtPoint(midPoint: CGPoint(x: bounds.midX, y: bounds.midY), withRadius: circleRadius).fill()
color = UIColor(red: 0.93, green: 0.93, blue: 0.94, alpha: 1)
color.set()
let ctx = UIGraphicsGetCurrentContext()
for i in 0...100 {
secondMarkers(ctx: ctx!, x: circleCenter.x, y: circleCenter.y, radius: circleRadius - 4, sides: 100, color: color)
}
diagramArray[0].strokePath()
}
func degree2radian(a:CGFloat)->CGFloat {
let b = CGFloat(M_PI) * a/180
return b
}
func circleCircumferencePoints(sides:Int,x:CGFloat,y:CGFloat,radius:CGFloat,adjustment:CGFloat=0)->[CGPoint] {
let angle = degree2radian(a: 360/CGFloat(sides))
let cx = x // x origin
let cy = y // y origin
let r = radius // radius of circle
var i = sides
var points = [CGPoint]()
while points.count <= sides {
let xpo = cx - r * cos(angle * CGFloat(i)+degree2radian(a: adjustment))
let ypo = cy - r * sin(angle * CGFloat(i)+degree2radian(a: adjustment))
points.append(CGPoint(x: xpo, y: ypo))
i -= 1;
}
return points
}
func secondMarkers(ctx:CGContext, x:CGFloat, y:CGFloat, radius:CGFloat, sides:Int, color:UIColor) {
// retrieve points
let points = circleCircumferencePoints(sides: sides,x: x,y: y,radius: radius)
// create path
// determine length of marker as a fraction of the total radius
var divider:CGFloat = 1/16
//for p in points {
let path = CGMutablePath()
divider = 1/10
let xn = points[counter].x + divider * (x-points[counter].x)
let yn = points[counter].y + divider * (y-points[counter].y)
// build path
path.move(to: CGPoint(x: points[counter].x, y: points[counter].y))
//path, nil, p.x, p.y)
path.addLine(to: CGPoint(x: xn, y: yn))
//CGPathAddLineToPoint(path, nil, xn, yn)
path.closeSubpath()
// add path to context
ctx.addPath(path)
ctx.setStrokeColor(color.cgColor)
ctx.setLineWidth(2.0)
//ctx.strokePath()
diagramArray.append(ctx)
counter += 1
//}
// set path color
}
So basically I'm trying to append context for each marker to an array, but when I draw one element of this array, it draws the whole diagram. This is what I need to achieve.
You shouldn't need to create more than one CGContext - you should just be reusing the same one to draw all graphics. Also, your method to calculate the secondMarkers seems unnecessarily complex. I believe this does what you want:
private func drawTicks(context: CGContext, tickCount: Int, center: CGPoint, startRadius: CGFloat, endRadius: CGFloat, ticksToColor: Int) {
for i in 0 ... tickCount {
let color: UIColor = i < ticksToColor ? .blue : .lightGray
context.setStrokeColor(color.cgColor)
let angle = .pi - degree2Radian(a: (CGFloat(360.0) / CGFloat(tickCount)) * CGFloat(i))
let path = CGMutablePath()
path.move(to: circleCircumferencePoint(center: center, angle: angle, radius: startRadius))
path.addLine(to: circleCircumferencePoint(center: center, angle: angle, radius: endRadius))
context.addPath(path)
context.strokePath()
}
}
private func circleCircumferencePoint(center: CGPoint, angle: CGFloat, radius: CGFloat) -> CGPoint {
return CGPoint(x: radius * sin(angle) + center.x, y: radius * cos(angle) + center.y)
}
So I have the following code that rotates the CGContext to position where my text should be:
var nums: Int = 0
let oNums: [Int] = [3,4,5,6,7,8,9,10,11,12,1,2]
for i in 0..<60 {
CGContextSaveGState(ctx)
CGContextTranslateCTM(ctx, rect.width / 2, rect.height / 2)
CGContextRotateCTM(ctx, CGFloat(6.0 * Double(i) * M_PI / 180))
CGContextSetStrokeColorWithColor(ctx, UIColor.grayColor().CGColor)
CGContextMoveToPoint(ctx, 72, 0)
CGContextSetLineWidth(ctx, 3.0)
CGContextAddLineToPoint(ctx, 42, 0)
drawText(ctx!, text: getRoman(oNums[nums]), attributes: [NSForegroundColorAttributeName : UIColor.blackColor().CGColor, NSFontAttributeName : UIFont.systemFontOfSize(12)], x: 42, y: 0, align: CGFloat(6.0 * Double(i) * M_PI / 180))
nums++
}
Where drawText(_:) is:
func drawText(context: CGContextRef, text: NSString, attributes: [String: AnyObject], x: CGFloat, y: CGFloat, align: CGFloat) -> CGSize {
CGContextTranslateCTM(context, 0, 0)
CGContextScaleCTM(context, 1, -1)
let font = attributes[NSFontAttributeName] as! UIFont
let attributedString = NSAttributedString(string: text as String, attributes: attributes)
let textSize = text.sizeWithAttributes(attributes)
let textPath = CGPathCreateWithRect(CGRect(x: x, y: y + font.descender, width: ceil(textSize.width), height: ceil(textSize.height)), nil)
let frameSetter = CTFramesetterCreateWithAttributedString(attributedString)
let frame = CTFramesetterCreateFrame(frameSetter, CFRange(location: 0, length: attributedString.length), textPath, nil)
CTFrameDraw(frame, context)
return textSize
}
And getRoman(_:) is:
func getRoman(numeral: Int) -> String {switch numeral {case 1:return "I"case 2:return "II"case 3:return "III"case 4:return "IV"case 5:return "V"case 6:return "VI"case 7:return "VII"case 8:return "VIII"case 9:return "IX"case 10:return "X"case 11:return "XI"case 12:return "XII"default:return ""}}
The issue, is that this prints text rotated to an angle (the desired result would be text all angled to the same degree (standard text orientation))
Is there a way to rotate Core Text?
Regards, Brandon