如何在饼图上为标签找到合适的位置?
How do I find an appropriate position for my labels on a pie chart?
我没有使用任何库,所以这不是 this 的副本。
我自己画饼图是这样的:
var sections: [PieChartSection] = [] {
didSet {
setNeedsDisplay()
}
}
override func draw(_ rect: CGRect) {
let sumOfSections = sections.map { [=10=].value }.reduce(0, +)
var pathStart = CGFloat.pi
let smallerDimension = min(height, width)
for section in sections {
// draw section
let percentage = section.value / sumOfSections
let pathEnd = pathStart + CGFloat.pi * percentage.f * 2
let path = UIBezierPath(arcCenter: CGPoint(x: bounds.midX, y: bounds.midY),
radius: smallerDimension / 4, startAngle: pathStart, endAngle: pathEnd, clockwise: true)
//draw labels
// this is my attempt at calculating the position of the labels
let midAngle = (pathStart + pathEnd) / 2
let textX = bounds.midX + smallerDimension * 3 / 8 * cos(midAngle)
let textY = bounds.midY + smallerDimension * 3 / 8 * sin(midAngle)
// creating the text to be shown, don't this is relevant
let attributedString = NSMutableAttributedString(string: section.name, attributes: [
.foregroundColor: UIColor.black.withAlphaComponent(0.15),
.font: UIFont.systemFont(ofSize: 9)
])
let formatter = NumberFormatter()
formatter.maximumFractionDigits = 0
let percentageString = "\n" + formatter.string(from: (percentage * 100) as NSNumber)! + "%"
attributedString.append(NSAttributedString(string: percentageString, attributes: [
.foregroundColor: UIColor.black.withAlphaComponent(0.5),
.font: UIFont.systemFont(ofSize: 12)
]))
attributedString.draw(at: CGPoint(x: textX, y: textY))
// stroke path
path.lineWidth = 6
section.color.setStroke()
path.stroke()
pathStart = pathEnd
}
}
PieChartSection
是一个简单的结构:
struct PieChartSection {
let value: Double
let color: UIColor
let name: String
}
饼看起来不错,但标签有时离饼很远有时离饼很近:
我认为问题是 NSAttriutedString.draw
总是从左上角绘制文本,这意味着文本的 左上角 都是等距离的到饼图,而我需要绘制文本,以便它们 离饼图最近的点 都与饼图等距。
如何绘制这样的文字?
我没有使用 cocoa pod,因为我发现使用高级 API 很难按照我想要的方式制作图表。涉及的复杂性太多了。我希望对饼图的绘制方式进行较低级别的控制。
I think the problem is that NSAttriutedString.draw
always draws the text from the top left corner
当然,draw
方法会将字符串的原点放在您经过的点上。在这种情况下,解决方案很简单 - 找到字符串的 size
并做出正确的来源。
let size = attributedString.size()
let origin = CGPoint(x: textX - size.width / 2, y: textY - size.height / 2)
attributedString.draw(at: origin)
结果:
我没有使用任何库,所以这不是 this 的副本。
我自己画饼图是这样的:
var sections: [PieChartSection] = [] {
didSet {
setNeedsDisplay()
}
}
override func draw(_ rect: CGRect) {
let sumOfSections = sections.map { [=10=].value }.reduce(0, +)
var pathStart = CGFloat.pi
let smallerDimension = min(height, width)
for section in sections {
// draw section
let percentage = section.value / sumOfSections
let pathEnd = pathStart + CGFloat.pi * percentage.f * 2
let path = UIBezierPath(arcCenter: CGPoint(x: bounds.midX, y: bounds.midY),
radius: smallerDimension / 4, startAngle: pathStart, endAngle: pathEnd, clockwise: true)
//draw labels
// this is my attempt at calculating the position of the labels
let midAngle = (pathStart + pathEnd) / 2
let textX = bounds.midX + smallerDimension * 3 / 8 * cos(midAngle)
let textY = bounds.midY + smallerDimension * 3 / 8 * sin(midAngle)
// creating the text to be shown, don't this is relevant
let attributedString = NSMutableAttributedString(string: section.name, attributes: [
.foregroundColor: UIColor.black.withAlphaComponent(0.15),
.font: UIFont.systemFont(ofSize: 9)
])
let formatter = NumberFormatter()
formatter.maximumFractionDigits = 0
let percentageString = "\n" + formatter.string(from: (percentage * 100) as NSNumber)! + "%"
attributedString.append(NSAttributedString(string: percentageString, attributes: [
.foregroundColor: UIColor.black.withAlphaComponent(0.5),
.font: UIFont.systemFont(ofSize: 12)
]))
attributedString.draw(at: CGPoint(x: textX, y: textY))
// stroke path
path.lineWidth = 6
section.color.setStroke()
path.stroke()
pathStart = pathEnd
}
}
PieChartSection
是一个简单的结构:
struct PieChartSection {
let value: Double
let color: UIColor
let name: String
}
饼看起来不错,但标签有时离饼很远有时离饼很近:
我认为问题是 NSAttriutedString.draw
总是从左上角绘制文本,这意味着文本的 左上角 都是等距离的到饼图,而我需要绘制文本,以便它们 离饼图最近的点 都与饼图等距。
如何绘制这样的文字?
我没有使用 cocoa pod,因为我发现使用高级 API 很难按照我想要的方式制作图表。涉及的复杂性太多了。我希望对饼图的绘制方式进行较低级别的控制。
I think the problem is that
NSAttriutedString.draw
always draws the text from the top left corner
当然,draw
方法会将字符串的原点放在您经过的点上。在这种情况下,解决方案很简单 - 找到字符串的 size
并做出正确的来源。
let size = attributedString.size()
let origin = CGPoint(x: textX - size.width / 2, y: textY - size.height / 2)
attributedString.draw(at: origin)
结果: