mastodon-app-ufficiale-ipho.../MastodonSDK/Sources/MastodonUI/View/Control/LineChartView.swift

112 lines
3.3 KiB
Swift
Raw Normal View History

2021-10-18 11:41:43 +02:00
//
// LineChartView.swift
// Mastodon
//
// Created by Cirno MainasuK on 2021-10-18.
//
import UIKit
import Accelerate
import MastodonAsset
2021-10-18 11:41:43 +02:00
public final class LineChartView: UIView {
2021-10-18 11:41:43 +02:00
public var data: [CGFloat] = [] {
2021-10-18 11:41:43 +02:00
didSet {
setNeedsLayout()
}
}
let lineShapeLayer = CAShapeLayer()
let gradientLayer = CAGradientLayer()
public override init(frame: CGRect) {
2021-10-18 11:41:43 +02:00
super.init(frame: frame)
_init()
}
public required init?(coder: NSCoder) {
2021-10-18 11:41:43 +02:00
super.init(coder: coder)
_init()
}
}
extension LineChartView {
private func _init() {
lineShapeLayer.frame = bounds
gradientLayer.frame = bounds
layer.addSublayer(lineShapeLayer)
layer.addSublayer(gradientLayer)
gradientLayer.colors = [
Asset.Colors.brandBlue.color.withAlphaComponent(0.5).cgColor, // set the same alpha to fill
Asset.Colors.brandBlue.color.withAlphaComponent(0.5).cgColor,
2021-10-18 11:41:43 +02:00
]
gradientLayer.startPoint = CGPoint(x: 0.5, y: 0)
gradientLayer.endPoint = CGPoint(x: 0.5, y: 1)
}
public override func layoutSubviews() {
2021-10-18 11:41:43 +02:00
super.layoutSubviews()
lineShapeLayer.frame = bounds
gradientLayer.frame = bounds
guard data.count > 1 else {
lineShapeLayer.path = nil
gradientLayer.isHidden = true
return
}
gradientLayer.isHidden = false
// Draw smooth chart
guard let maxDataPoint = data.max() else {
return
}
2021-10-18 12:35:19 +02:00
func calculateY(for point: CGFloat, in frame: CGRect) -> CGFloat {
2021-10-18 11:41:43 +02:00
guard maxDataPoint > 0 else { return .zero }
2021-10-18 12:35:19 +02:00
return (1 - point / maxDataPoint) * frame.height
2021-10-18 11:41:43 +02:00
}
2021-10-18 12:35:19 +02:00
let segmentCount = data.count - 1
2021-10-18 11:41:43 +02:00
let segmentWidth = bounds.width / CGFloat(segmentCount)
2021-10-18 12:35:19 +02:00
let points: [CGPoint] = {
var points: [CGPoint] = []
var x: CGFloat = 0
for value in data {
let point = CGPoint(x: x, y: calculateY(for: value, in: bounds))
points.append(point)
x += segmentWidth
}
return points
}()
2021-10-18 11:41:43 +02:00
2021-10-18 12:35:19 +02:00
guard let linePath = CurveAlgorithm.shared.createCurvedPath(points) else { return }
let dotPath = UIBezierPath()
2021-10-18 11:41:43 +02:00
if let last = points.last {
2021-10-18 12:35:19 +02:00
dotPath.addArc(withCenter: last, radius: 3, startAngle: 0, endAngle: 2 * .pi, clockwise: true)
2021-10-18 11:41:43 +02:00
}
2021-10-18 13:00:55 +02:00
lineShapeLayer.lineWidth = 1
lineShapeLayer.strokeColor = Asset.Colors.brandBlue.color.cgColor
2021-10-18 11:41:43 +02:00
lineShapeLayer.fillColor = UIColor.clear.cgColor
2021-10-18 13:00:55 +02:00
lineShapeLayer.lineJoin = .round
2021-10-18 11:41:43 +02:00
lineShapeLayer.lineCap = .round
lineShapeLayer.path = linePath.cgPath
let maskPath = UIBezierPath(cgPath: linePath.cgPath)
maskPath.addLine(to: CGPoint(x: bounds.maxX, y: bounds.maxY))
maskPath.addLine(to: CGPoint(x: bounds.minX, y: bounds.maxY))
maskPath.close()
let maskLayer = CAShapeLayer()
maskLayer.path = maskPath.cgPath
maskLayer.fillColor = Asset.Colors.brandBlue.color.cgColor
2021-10-18 11:41:43 +02:00
maskLayer.strokeColor = UIColor.clear.cgColor
maskLayer.lineWidth = 0.0
gradientLayer.mask = maskLayer
}
}