Gradient.swift 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. /// A color gradient represented as an array of color stops, each having a normalized location value.
  2. public struct Gradient: Sendable, Hashable {
  3. /// The array of color stops, ordered by location.
  4. public var stops: [Gradient.Stop]
  5. /// Creates a gradient from an array of color stops ordered by location.
  6. ///
  7. /// - Parameters:
  8. /// - stops: The stops of the Gradient. If no stop is passed, the gradient will be fully transparent.
  9. init(stops: [Gradient.Stop]) {
  10. guard let first = stops.first else {
  11. let invisible = Color.black.opacity(0)
  12. self.stops = [
  13. Stop(color: invisible, location: 0),
  14. Stop(color: invisible, location: 1),
  15. ]
  16. return
  17. }
  18. #if DEBUG
  19. if stops != stops.sorted(by: { $0.location < $1.location }) {
  20. logger.warning("Gradient stop locations must be ordered")
  21. }
  22. #endif
  23. if stops.count == 1 {
  24. self.stops = [
  25. Stop(color: first.color, location: 0),
  26. Stop(color: first.color, location: 1),
  27. ]
  28. } else {
  29. self.stops = stops
  30. }
  31. }
  32. /// Creates a gradient from an array of colors.
  33. /// - Parameters:
  34. /// - colors: The colors of the gradient. The gradient synthesizes its location values to evenly
  35. /// space the colors along the gradient. If no color is passed, the gradient will be fully transparent.
  36. init(colors: [Color]) {
  37. guard let first = colors.first else {
  38. let invisible = Color.black.opacity(0)
  39. self.stops = [
  40. Stop(color: invisible, location: 0),
  41. Stop(color: invisible, location: 1),
  42. ]
  43. return
  44. }
  45. if colors.count == 1 {
  46. self.stops = [
  47. Stop(color: first, location: 0),
  48. Stop(color: first, location: 1),
  49. ]
  50. return
  51. }
  52. var stops = [Stop(color: first, location: 0)]
  53. for (i, color) in colors[1...].enumerated() {
  54. let location = Double(i + 1) / Double(colors.count - 1)
  55. stops.append(
  56. Stop(color: color, location: location)
  57. )
  58. }
  59. self.stops = stops
  60. }
  61. /// One color stop in a gradient.
  62. public struct Stop: Sendable, Equatable, Hashable {
  63. /// Creates a color stop with a color and location.
  64. /// - Parameters:
  65. /// - color: The color that should be placed at this stop.
  66. /// - location: The location of this stop. 0 corresponds to the start and 1 to the end.
  67. public init(color: Color, location: Double) {
  68. self.color = color
  69. self.location = location
  70. }
  71. /// The color for the stop.
  72. public var color: Color
  73. /// The parametric location of the stop.
  74. public var location: Double
  75. }
  76. }