在 Core Graphics 中创建一个带有多色线段的圆
Create a circle with multi coloured segments in Core Graphics
我正在尝试绘制一个由大小相等的段组成的饼图,每个段具有不同的颜色。我的代码基于此
let circlePath = UIBezierPath(ovalInRect: CGRect(x: 200, y: 200, width: 150, height: 150))
var segments: [CAShapeLayer] = []
let segmentAngle: CGFloat = 1.0 / CGFloat(totalSegments)
for var i = 0; i < totalSegments; i++ {
let circleLayer = CAShapeLayer()
circleLayer.path = circlePath.CGPath
// start angle is number of segments * the segment angle
circleLayer.strokeStart = segmentAngle * CGFloat(i)
//create a gap to show segments
let gapSize: CGFloat = 0.008
circleLayer.strokeEnd = circleLayer.strokeStart + segmentAngle - gapSize
circleLayer.lineWidth = 10
circleLayer.strokeColor = UIColor(red:0, green:0.004, blue:0.549, alpha:1).CGColor
circleLayer.fillColor = UIColor.redColor().CGColor
// add the segment to the segments array and to the view
segments.insert(circleLayer, atIndex: i)
view.layer.addSublayer(segments[i])
}
但是我想使用它来制作它,以便我可以根据 for 循环中的索引值 i 为每个段着色。最初我只是用奇数或偶数测试,但发现填充部分会用上次使用的颜色填充整个圆。
我怀疑这是因为填充颜色填充了整个圆,即使笔划的起点和终点有限。我怎样才能创建相同的效果,但为每个段启用单独的填充颜色?
这是我在 playground 中创建的饼图绘制函数,玩得很开心。也许您可以根据您的要求使用它:
import Foundation
import UIKit
// Pie Chart Drawing function
// --------------------------
// - Takes an array of tuples with relative value and color for slices
// - draws at center coordinates with a givn radius
//
func drawPieChart(slices:[(value:CGFloat, color:UIColor)], at center:CGPoint, radius:CGFloat)
{
// the calue component of the tuples are summed up to get the denominator for surface ratios
let totalValues:CGFloat = slices.reduce(0, combine: {[=10=] + .value})
// starting at noon (-90deg)
var angle:CGFloat = -CGFloat(M_PI)/2
// draw each slice going counter clockwise
for (value,color) in slices
{
let path = UIBezierPath()
// slice's angle is proportional to circumference 2π
let sliceAngle = CGFloat(M_PI)*2*value/totalValues
// select fill color from tuple
color.setFill()
// draw pie slice using arc from center and closing path back to center
path.moveToPoint(center)
path.addArcWithCenter( center,
radius: radius,
startAngle: angle,
endAngle: angle - sliceAngle,
clockwise: false
)
path.moveToPoint(center)
path.closePath()
// draw slice in current context
path.fill()
// offset angle for next slice
angle -= sliceAngle
}
}
// Pie chart Data
let slices:[(value:CGFloat, color:UIColor)] =
[ (3, UIColor.greenColor()),
(5, UIColor.redColor()),
(8, UIColor.blueColor()),
(13,UIColor.yellowColor())
]
// UIView
let viewSize = CGSize(width: 300, height: 300)
let view:UIView = UIView(frame: CGRect(origin: CGPointZero, size: viewSize))
view.backgroundColor = UIColor.whiteColor()
// CoreGraphics drawing
UIGraphicsBeginImageContextWithOptions(viewSize, false, 0)
// draw pie chart in Image context
drawPieChart(slices, at:CGPointMake(150,150), radius:100 )
// set image to view layer (you could also use it elsewhere)
view.layer.contents = UIGraphicsGetImageFromCurrentImageContext().CGImage
UIGraphicsEndImageContext()
// Playground (quick look or Timeline)
let preview = view
注意:要获得相同大小的段,只需在元组数组的所有条目中提供相同的值即可。
更新
这是仅绘制饼图周长(边缘)的函数变体:
func drawPieRim(_ slices:[(value:CGFloat, color:UIColor)], at center:CGPoint,
radius:CGFloat, thickness:CGFloat=30)
{
let totalValues:CGFloat = slices.reduce(0){[=11=] + .value}
let gapAngle = CGFloat(Double.pi) * 0.01
var angle:CGFloat = -CGFloat(Double.pi)/2
for (value,color) in slices
{
let path = UIBezierPath()
let sliceAngle = CGFloat(Double.pi)*2*value/totalValues
path.lineWidth = thickness
color.setStroke()
path.addArc( withCenter:center,
radius: radius,
startAngle: angle + sliceAngle - gapAngle,
endAngle: angle,
clockwise: false)
path.stroke()
angle += sliceAngle
}
}
我正在尝试绘制一个由大小相等的段组成的饼图,每个段具有不同的颜色。我的代码基于此
let circlePath = UIBezierPath(ovalInRect: CGRect(x: 200, y: 200, width: 150, height: 150))
var segments: [CAShapeLayer] = []
let segmentAngle: CGFloat = 1.0 / CGFloat(totalSegments)
for var i = 0; i < totalSegments; i++ {
let circleLayer = CAShapeLayer()
circleLayer.path = circlePath.CGPath
// start angle is number of segments * the segment angle
circleLayer.strokeStart = segmentAngle * CGFloat(i)
//create a gap to show segments
let gapSize: CGFloat = 0.008
circleLayer.strokeEnd = circleLayer.strokeStart + segmentAngle - gapSize
circleLayer.lineWidth = 10
circleLayer.strokeColor = UIColor(red:0, green:0.004, blue:0.549, alpha:1).CGColor
circleLayer.fillColor = UIColor.redColor().CGColor
// add the segment to the segments array and to the view
segments.insert(circleLayer, atIndex: i)
view.layer.addSublayer(segments[i])
}
但是我想使用它来制作它,以便我可以根据 for 循环中的索引值 i 为每个段着色。最初我只是用奇数或偶数测试,但发现填充部分会用上次使用的颜色填充整个圆。
我怀疑这是因为填充颜色填充了整个圆,即使笔划的起点和终点有限。我怎样才能创建相同的效果,但为每个段启用单独的填充颜色?
这是我在 playground 中创建的饼图绘制函数,玩得很开心。也许您可以根据您的要求使用它:
import Foundation
import UIKit
// Pie Chart Drawing function
// --------------------------
// - Takes an array of tuples with relative value and color for slices
// - draws at center coordinates with a givn radius
//
func drawPieChart(slices:[(value:CGFloat, color:UIColor)], at center:CGPoint, radius:CGFloat)
{
// the calue component of the tuples are summed up to get the denominator for surface ratios
let totalValues:CGFloat = slices.reduce(0, combine: {[=10=] + .value})
// starting at noon (-90deg)
var angle:CGFloat = -CGFloat(M_PI)/2
// draw each slice going counter clockwise
for (value,color) in slices
{
let path = UIBezierPath()
// slice's angle is proportional to circumference 2π
let sliceAngle = CGFloat(M_PI)*2*value/totalValues
// select fill color from tuple
color.setFill()
// draw pie slice using arc from center and closing path back to center
path.moveToPoint(center)
path.addArcWithCenter( center,
radius: radius,
startAngle: angle,
endAngle: angle - sliceAngle,
clockwise: false
)
path.moveToPoint(center)
path.closePath()
// draw slice in current context
path.fill()
// offset angle for next slice
angle -= sliceAngle
}
}
// Pie chart Data
let slices:[(value:CGFloat, color:UIColor)] =
[ (3, UIColor.greenColor()),
(5, UIColor.redColor()),
(8, UIColor.blueColor()),
(13,UIColor.yellowColor())
]
// UIView
let viewSize = CGSize(width: 300, height: 300)
let view:UIView = UIView(frame: CGRect(origin: CGPointZero, size: viewSize))
view.backgroundColor = UIColor.whiteColor()
// CoreGraphics drawing
UIGraphicsBeginImageContextWithOptions(viewSize, false, 0)
// draw pie chart in Image context
drawPieChart(slices, at:CGPointMake(150,150), radius:100 )
// set image to view layer (you could also use it elsewhere)
view.layer.contents = UIGraphicsGetImageFromCurrentImageContext().CGImage
UIGraphicsEndImageContext()
// Playground (quick look or Timeline)
let preview = view
注意:要获得相同大小的段,只需在元组数组的所有条目中提供相同的值即可。
更新
这是仅绘制饼图周长(边缘)的函数变体:
func drawPieRim(_ slices:[(value:CGFloat, color:UIColor)], at center:CGPoint,
radius:CGFloat, thickness:CGFloat=30)
{
let totalValues:CGFloat = slices.reduce(0){[=11=] + .value}
let gapAngle = CGFloat(Double.pi) * 0.01
var angle:CGFloat = -CGFloat(Double.pi)/2
for (value,color) in slices
{
let path = UIBezierPath()
let sliceAngle = CGFloat(Double.pi)*2*value/totalValues
path.lineWidth = thickness
color.setStroke()
path.addArc( withCenter:center,
radius: radius,
startAngle: angle + sliceAngle - gapAngle,
endAngle: angle,
clockwise: false)
path.stroke()
angle += sliceAngle
}
}