in Source/Charts/Renderers/LineChartRenderer.swift [806:861]
func drawGradientLine(context: CGContext, dataSet: LineChartDataSetProtocol, spline: CGPath, matrix: CGAffineTransform)
{
guard let gradientPositions = dataSet.gradientPositions else
{
assertionFailure("Must set `gradientPositions if `dataSet.isDrawLineWithGradientEnabled` is true")
return
}
// `insetBy` is applied since bounding box
// doesn't take into account line width
// so that peaks are trimmed since
// gradient start and gradient end calculated wrong
let boundingBox = spline.boundingBox
.insetBy(dx: -dataSet.lineWidth / 2, dy: -dataSet.lineWidth / 2)
guard !boundingBox.isNull, !boundingBox.isInfinite, !boundingBox.isEmpty else {
return
}
let gradientStart = CGPoint(x: 0, y: boundingBox.minY)
let gradientEnd = CGPoint(x: 0, y: boundingBox.maxY)
let gradientColorComponents: [CGFloat] = dataSet.colors
.reversed()
.reduce(into: []) { (components, color) in
guard let (r, g, b, a) = color.nsuirgba else {
return
}
components += [r, g, b, a]
}
let gradientLocations: [CGFloat] = gradientPositions.reversed()
.map { (position) in
let location = CGPoint(x: boundingBox.minX, y: position)
.applying(matrix)
let normalizedLocation = (location.y - boundingBox.minY)
/ (boundingBox.maxY - boundingBox.minY)
return normalizedLocation.clamped(to: 0...1)
}
let baseColorSpace = CGColorSpaceCreateDeviceRGB()
guard let gradient = CGGradient(
colorSpace: baseColorSpace,
colorComponents: gradientColorComponents,
locations: gradientLocations,
count: gradientLocations.count) else {
return
}
context.saveGState()
defer { context.restoreGState() }
context.beginPath()
context.addPath(spline)
context.replacePathWithStrokedPath()
context.clip()
context.drawLinearGradient(gradient, start: gradientStart, end: gradientEnd, options: [])
}