@@ -25,15 +25,98 @@ public protocol ColorMapProtocol {
25
25
// Linear Gradients.
26
26
27
27
struct LinearGradient : ColorMapProtocol {
28
- var start : Color
29
- var end : Color
28
+ struct Stop {
29
+ var color : Color
30
+ var position : Double
31
+
32
+ init ( _ color: Color , at pos: Double ) {
33
+ self . color = color; self . position = pos
34
+ }
35
+ }
36
+
37
+ var stops : [ Stop ]
38
+
39
+ init ( stops: [ Stop ] ) {
40
+ self . stops = stops. sorted { $0. position < $1. position }
41
+ }
42
+
43
+ init ( start: Color , end: Color ) {
44
+ self . init ( stops: [ Stop ( start, at: 0 ) , Stop ( end, at: 1 ) ] )
45
+ }
46
+
30
47
func colorForOffset( _ offset: Float ) -> Color {
31
- return lerp ( startColor: start, endColor: end, offset)
48
+ return colorForOffset ( Double ( offset) )
49
+ }
50
+
51
+ func colorForOffset( _ offset: Double ) -> Color {
52
+ guard ( 0 ... 1 ) . contains ( offset) ,
53
+ let rightStopIdx = stops. firstIndex ( where: { $0. position > offset } ) else {
54
+ return stops. last? . color ?? . black
55
+ }
56
+ let rightStop = stops [ rightStopIdx]
57
+ guard rightStopIdx > stops. startIndex else { return rightStop. color }
58
+ let leftStop = stops [ stops. index ( before: rightStopIdx) ]
59
+ assert ( leftStop. position <= offset)
60
+
61
+ let distance = rightStop. position - leftStop. position
62
+ guard distance > 0 else { return rightStop. color }
63
+
64
+ let offset = Float ( ( offset - leftStop. position) / distance)
65
+ return leftStop. color. linearBlend ( with: rightStop. color, offset: offset)
32
66
}
33
67
}
34
68
35
69
extension ColorMap {
70
+
36
71
public static func linear( _ start: Color , _ end: Color ) -> ColorMap {
37
72
return ColorMap ( LinearGradient ( start: start, end: end) )
38
73
}
74
+
75
+ public static let fiveColorHeatMap = ColorMap ( LinearGradient ( stops: [
76
+ LinearGradient . Stop ( Color ( 0 , 0 , 1 , 1 ) , at: 0 ) ,
77
+ LinearGradient . Stop ( Color ( 0 , 1 , 1 , 1 ) , at: 0.25 ) ,
78
+ LinearGradient . Stop ( Color ( 0 , 1 , 0 , 1 ) , at: 0.5 ) ,
79
+ LinearGradient . Stop ( Color ( 1 , 1 , 0 , 1 ) , at: 0.75 ) ,
80
+ LinearGradient . Stop ( Color ( 1 , 0 , 0 , 1 ) , at: 1 ) ,
81
+ ] ) )
82
+
83
+ public static let sevenColorHeatMap = ColorMap ( LinearGradient ( stops: [
84
+ LinearGradient . Stop ( Color ( 0 , 0 , 0 , 1 ) , at: 0 ) ,
85
+ LinearGradient . Stop ( Color ( 0 , 0 , 1 , 1 ) , at: 0.1666666667 ) ,
86
+ LinearGradient . Stop ( Color ( 0 , 1 , 1 , 1 ) , at: 0.3333333333 ) ,
87
+ LinearGradient . Stop ( Color ( 0 , 1 , 0 , 1 ) , at: 0.5 ) ,
88
+ LinearGradient . Stop ( Color ( 1 , 1 , 0 , 1 ) , at: 0.6666666667 ) ,
89
+ LinearGradient . Stop ( Color ( 1 , 0 , 0 , 1 ) , at: 0.8333333333 ) ,
90
+ LinearGradient . Stop ( Color ( 1 , 1 , 1 , 1 ) , at: 1 )
91
+ ] ) )
92
+ }
93
+
94
+ // Transforming.
95
+
96
+ struct ColorTransformer < T> : ColorMapProtocol where T: ColorMapProtocol {
97
+ var base : T
98
+ var transform : ( inout Color ) -> Void
99
+ init ( _ base: T , transform: @escaping ( inout Color ) -> Void ) {
100
+ self . base = base; self . transform = transform
101
+ }
102
+ func colorForOffset( _ offset: Float ) -> Color {
103
+ var color = base. colorForOffset ( offset)
104
+ transform ( & color)
105
+ return color
106
+ }
107
+ }
108
+
109
+ extension ColorMap {
110
+
111
+ public func withAlpha( _ alpha: Float ) -> ColorMap {
112
+ return ColorMap ( ColorTransformer ( self ) { $0. a = alpha } )
113
+ }
114
+
115
+ public func lightened( by: Float ) -> ColorMap {
116
+ return ColorMap ( ColorTransformer ( self ) { $0 = $0. linearBlend ( with: . white, offset: by) } )
117
+ }
118
+
119
+ public func darkened( by: Float ) -> ColorMap {
120
+ return ColorMap ( ColorTransformer ( self ) { $0 = $0. linearBlend ( with: . black, offset: by) } )
121
+ }
39
122
}
0 commit comments