使用 Core Graphics 制作饼图
Making a pie chart using Core Graphics
到目前为止,我有一个实心圆圈,仅此而已。我正在尝试制作一个饼图来表示满意和不满意的客户数量并展示它。我对 CG 非常陌生,想知道有人可以编写出足够的代码来给我一个想法或指导我。
我是否应该让底部的圆圈代表满意的客户数量,然后在其顶部添加另一个圆圈以显示不满意的客户数量?我是否以正确的方式接近它?
到目前为止,这是我的代码。
override func drawRect(rect: CGRect) {
// Get current context
let context = UIGraphicsGetCurrentContext()
// Set color
CGContextSetStrokeColorWithColor(context,UIColor(red: 0.2, green: 0.4, blue: 1, alpha: 1.0).CGColor)
let rectangle = CGRectMake((frame.size.width / 3) - 50, frame.size.height / 2 + 40,220,220)
CGContextAddEllipseInRect(context,rectangle)
CGContextSetFillColorWithColor(context, UIColor(red: 0.2, green: 0.4, blue: 1, alpha: 1.0).CGColor)
CGContextFillPath(context)
CGContextStrokePath(context)
}
编辑
此外,现在我开始发现我可能需要根据不满意的客户总数用弧线覆盖我的圆圈。如何根据人数增加或减少覆盖弧的大小?
如有任何帮助,我们将不胜感激!
您需要使用 CGContextAddArc()
函数(Swift 3 中的 CGContext.addArc()
)。这将允许您通过为饼图的每个部分绘制一条弧来为饼图创建多个部分。
像这样应该可以解决问题:
import UIKit
struct Segment {
// the color of a given segment
var color: UIColor
// the value of a given segment – will be used to automatically calculate a ratio
var value: CGFloat
}
class PieChartView: UIView {
/// An array of structs representing the segments of the pie chart
var segments = [Segment]() {
didSet {
setNeedsDisplay() // re-draw view when the values get set
}
}
override init(frame: CGRect) {
super.init(frame: frame)
isOpaque = false // when overriding drawRect, you must specify this to maintain transparency.
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func draw(_ rect: CGRect) {
// get current context
let ctx = UIGraphicsGetCurrentContext()
// radius is the half the frame's width or height (whichever is smallest)
let radius = min(frame.size.width, frame.size.height) * 0.5
// center of the view
let viewCenter = CGPoint(x: bounds.size.width * 0.5, y: bounds.size.height * 0.5)
// enumerate the total value of the segments by using reduce to sum them
let valueCount = segments.reduce(0, {[=10=] + .value})
// the starting angle is -90 degrees (top of the circle, as the context is flipped). By default, 0 is the right hand side of the circle, with the positive angle being in an anti-clockwise direction (same as a unit circle in maths).
var startAngle = -CGFloat.pi * 0.5
for segment in segments { // loop through the values array
// set fill color to the segment color
ctx?.setFillColor(segment.color.cgColor)
// update the end angle of the segment
let endAngle = startAngle + 2 * .pi * (segment.value / valueCount)
// move to the center of the pie chart
ctx?.move(to: viewCenter)
// add arc from the center for each segment (anticlockwise is specified for the arc, but as the view flips the context, it will produce a clockwise arc)
ctx?.addArc(center: viewCenter, radius: radius, startAngle: startAngle, endAngle: endAngle, clockwise: false)
// fill segment
ctx?.fillPath()
// update starting angle of the next segment to the ending angle of this segment
startAngle = endAngle
}
}
}
您可以将饼图数据作为 Segment
结构数组输入,其中每个 Segment
代表该段的颜色和值。
该值可以是任何浮点数,并且会自动缩小到饼图中使用的比例。因此,例如,如果您希望您的饼图表示不满意的客户数量与满意的客户数量,您可以直接将值传入。
用法示例:
let pieChartView = PieChartView()
pieChartView.frame = CGRect(x: 0, y: 0, width: view.frame.size.width, height: 400)
pieChartView.segments = [
Segment(color: .red, value: 57),
Segment(color: .blue, value: 30),
Segment(color: .green, value: 25),
Segment(color: .yellow, value: 40)
]
view.addSubview(pieChartView)
输出:
完整项目(具有一些额外功能):https://github.com/hamishknight/Pie-Chart-View
到目前为止,我有一个实心圆圈,仅此而已。我正在尝试制作一个饼图来表示满意和不满意的客户数量并展示它。我对 CG 非常陌生,想知道有人可以编写出足够的代码来给我一个想法或指导我。
我是否应该让底部的圆圈代表满意的客户数量,然后在其顶部添加另一个圆圈以显示不满意的客户数量?我是否以正确的方式接近它?
到目前为止,这是我的代码。
override func drawRect(rect: CGRect) {
// Get current context
let context = UIGraphicsGetCurrentContext()
// Set color
CGContextSetStrokeColorWithColor(context,UIColor(red: 0.2, green: 0.4, blue: 1, alpha: 1.0).CGColor)
let rectangle = CGRectMake((frame.size.width / 3) - 50, frame.size.height / 2 + 40,220,220)
CGContextAddEllipseInRect(context,rectangle)
CGContextSetFillColorWithColor(context, UIColor(red: 0.2, green: 0.4, blue: 1, alpha: 1.0).CGColor)
CGContextFillPath(context)
CGContextStrokePath(context)
}
编辑
此外,现在我开始发现我可能需要根据不满意的客户总数用弧线覆盖我的圆圈。如何根据人数增加或减少覆盖弧的大小?
如有任何帮助,我们将不胜感激!
您需要使用 CGContextAddArc()
函数(Swift 3 中的 CGContext.addArc()
)。这将允许您通过为饼图的每个部分绘制一条弧来为饼图创建多个部分。
像这样应该可以解决问题:
import UIKit
struct Segment {
// the color of a given segment
var color: UIColor
// the value of a given segment – will be used to automatically calculate a ratio
var value: CGFloat
}
class PieChartView: UIView {
/// An array of structs representing the segments of the pie chart
var segments = [Segment]() {
didSet {
setNeedsDisplay() // re-draw view when the values get set
}
}
override init(frame: CGRect) {
super.init(frame: frame)
isOpaque = false // when overriding drawRect, you must specify this to maintain transparency.
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func draw(_ rect: CGRect) {
// get current context
let ctx = UIGraphicsGetCurrentContext()
// radius is the half the frame's width or height (whichever is smallest)
let radius = min(frame.size.width, frame.size.height) * 0.5
// center of the view
let viewCenter = CGPoint(x: bounds.size.width * 0.5, y: bounds.size.height * 0.5)
// enumerate the total value of the segments by using reduce to sum them
let valueCount = segments.reduce(0, {[=10=] + .value})
// the starting angle is -90 degrees (top of the circle, as the context is flipped). By default, 0 is the right hand side of the circle, with the positive angle being in an anti-clockwise direction (same as a unit circle in maths).
var startAngle = -CGFloat.pi * 0.5
for segment in segments { // loop through the values array
// set fill color to the segment color
ctx?.setFillColor(segment.color.cgColor)
// update the end angle of the segment
let endAngle = startAngle + 2 * .pi * (segment.value / valueCount)
// move to the center of the pie chart
ctx?.move(to: viewCenter)
// add arc from the center for each segment (anticlockwise is specified for the arc, but as the view flips the context, it will produce a clockwise arc)
ctx?.addArc(center: viewCenter, radius: radius, startAngle: startAngle, endAngle: endAngle, clockwise: false)
// fill segment
ctx?.fillPath()
// update starting angle of the next segment to the ending angle of this segment
startAngle = endAngle
}
}
}
您可以将饼图数据作为 Segment
结构数组输入,其中每个 Segment
代表该段的颜色和值。
该值可以是任何浮点数,并且会自动缩小到饼图中使用的比例。因此,例如,如果您希望您的饼图表示不满意的客户数量与满意的客户数量,您可以直接将值传入。
用法示例:
let pieChartView = PieChartView()
pieChartView.frame = CGRect(x: 0, y: 0, width: view.frame.size.width, height: 400)
pieChartView.segments = [
Segment(color: .red, value: 57),
Segment(color: .blue, value: 30),
Segment(color: .green, value: 25),
Segment(color: .yellow, value: 40)
]
view.addSubview(pieChartView)
输出:
完整项目(具有一些额外功能):https://github.com/hamishknight/Pie-Chart-View