I have a line chart that made with UIBezier path. Here is a code of my draw graph function
override func draw(_ rect: CGRect) {
let width = rect.width
let height = rect.height
let path = UIBezierPath(
roundedRect: rect,
byRoundingCorners: .allCorners,
cornerRadii: Constants.cornerRadiusSize
)
path.addClip()
guard let context = UIGraphicsGetCurrentContext() else {
return
}
let colors = [startColor.cgColor, endColor.cgColor]
let colorSpace = CGColorSpaceCreateDeviceRGB()
let colorLocations: [CGFloat] = [0.0, 1.0]
guard let gradient = CGGradient(
colorsSpace: colorSpace,
colors: colors as CFArray,
locations: colorLocations
) else {
return
}
let startPoint = CGPoint.zero
let endPoint = CGPoint(x: 0, y: bounds.height)
context.drawLinearGradient(
gradient,
start: startPoint,
end: endPoint,
options: []
)
let margin = Constants.margin
let graphWidth = width - margin * 2 - 4
let columnXPoint = { (column: Int) -> CGFloat in
// Calculate the gap between points
let spacing = graphWidth / CGFloat(self.graphPoints.count - 1)
return CGFloat(column) * spacing + margin + 2
}
let topBorder = Constants.topBorder
let bottomBorder = Constants.bottomBorder
let graphHeight = height - topBorder - bottomBorder
guard let maxValue = graphPoints.max() else {
return
}
let columnYPoint = { (graphPoint: Int) -> CGFloat in
let yPoint = CGFloat(graphPoint) / CGFloat(maxValue) * graphHeight
return graphHeight + topBorder - yPoint // Переворот графика
}
UIColor.white.setFill()
UIColor.white.setStroke()
let graphPath = UIBezierPath()
graphPath.move(to: CGPoint(x: columnXPoint(0), y: columnYPoint(graphPoints[0])))
for i in 1 ..< graphPoints.count {
let nextPoint = CGPoint(x: columnXPoint(i), y: columnYPoint(graphPoints[i]))
print(nextPoint)
graphPath.addLine(to: nextPoint)
}
self.drawAnimatedGraph(path: graphPath, rect)
context.saveGState()
guard let clippingPath = graphPath.copy() as? UIBezierPath else {
return
}
clippingPath.addLine(to: CGPoint(
x: columnXPoint(graphPoints.count - 1),
y: height))
clippingPath.addLine(to: CGPoint(x: columnXPoint(0), y: height))
clippingPath.close()
clippingPath.addClip()
let highestYPoint = columnYPoint(maxValue)
let graphStartPoint = CGPoint(x: margin, y: highestYPoint)
let graphEndPoint = CGPoint(x: margin, y: bounds.height)
context.drawLinearGradient(
gradient,
start: graphStartPoint,
end: graphEndPoint,
options: [])
context.restoreGState()
graphPath.lineWidth = 2.0
graphPath.stroke()
for i in 0 ..< graphPoints.count {
var point = CGPoint(x: columnXPoint(i), y: columnYPoint(graphPoints[i]))
point.x -= Constants.circleDiameter / 2
point.y -= Constants.circleDiameter / 2
let circle = UIBezierPath(
ovalIn: CGRect(
origin: point,
size: CGSize(
width: Constants.circleDiameter,
height: Constants.circleDiameter)
)
)
circle.fill()
}
let linePath = UIBezierPath()
linePath.move(to: CGPoint(x: margin, y: topBorder))
linePath.addLine(to: CGPoint(x: width - margin, y: topBorder))
linePath.move(to: CGPoint(x: margin, y: graphHeight / 2 + topBorder))
linePath.addLine(to: CGPoint(x: width - margin, y: graphHeight / 2 + topBorder))
linePath.move(to: CGPoint(x: margin, y: height - bottomBorder))
linePath.addLine(to: CGPoint(x: width - margin, y: height - bottomBorder))
let color = UIColor(white: 1.0, alpha: Constants.colorAlpha)
color.setStroke()
linePath.lineWidth = 1.0
linePath.stroke()
}
But my problem is that I want to draw my chart with animation and I've found code for it
func drawAnimatedGraph(path: UIBezierPath, _ rect: CGRect) {
//Create a CAShape Layer
let pathLayer: CAShapeLayer = CAShapeLayer()
pathLayer.frame = self.bounds
pathLayer.path = path.cgPath
pathLayer.strokeColor = UIColor.red.cgColor
pathLayer.fillColor = nil
pathLayer.lineWidth = 2.0
pathLayer.lineJoin = CAShapeLayerLineJoin.bevel
//Add the layer to your view's layer
self.layer.addSublayer(pathLayer)
//This is basic animation, quite a few other methods exist to handle animation see the reference site answers
let pathAnimation: CABasicAnimation = CABasicAnimation(keyPath: "strokeEnd")
pathAnimation.duration = 2.0
pathAnimation.fromValue = 0
pathAnimation.toValue = 1
//Animation will happen right away
pathLayer.add(pathAnimation, forKey: "strokeEnd")
}
The problem is that I have a timer which removes first element of array of Integers and append random integer. So when im changing data in array and redraw my chart it draws new chart above main chart. So my question is am I able to draw animated line chart using these technologies or I should look on another way of solving that problem?