on master help sign in
Revamp Color library
23a01b3Evan Czaplicki
libraries/Color.elm+176−88
@@ -2,18 +2,18 @@ module Color where
2
2
3{-| Library for working with colors. Includes
3{-| Library for working with colors. Includes
4[RGB](https://en.wikipedia.org/wiki/RGB_color_model) and
4[RGB](https://en.wikipedia.org/wiki/RGB_color_model) and
5−[HSV](http://en.wikipedia.org/wiki/HSL_and_HSV) creation, gradients, and
5+[HSL](http://en.wikipedia.org/wiki/HSL_and_HSV) creation, gradients, and
6built-in names.
6built-in names.
7
7
8# Creation
8# Creation
9−@docs rgb, rgba, hsv, hsva, greyscale, grayscale
9+@docs rgb, rgba, hsl, hsla, greyscale, grayscale, complement
10−
11−# From Other Colors
12−@docs complement
13
10
14# Gradients
11# Gradients
15@docs linear, radial
12@docs linear, radial
16
13
14+# Extracting Colors
15+@docs toRgb, toHsl
16+
17# Built-in Colors
17# Built-in Colors
18These colors come from the [Tango
18These colors come from the [Tango
19palette](http://tango.freedesktop.org/Tango_Icon_Theme_Guidelines)
19palette](http://tango.freedesktop.org/Tango_Icon_Theme_Guidelines)
@@ -24,12 +24,10 @@ comes with a light and dark version.
24@docs red, orange, yellow, green, blue, purple, brown
24@docs red, orange, yellow, green, blue, purple, brown
25
25
26### Light
26### Light
27−@docs lightRed, lightOrange, lightYellow, lightGreen, lightBlue, lightPurple,
27+@docs lightRed, lightOrange, lightYellow, lightGreen, lightBlue, lightPurple, lightBrown
28− lightBrown
29
28
30### Dark
29### Dark
31−@docs darkRed, darkOrange, darkYellow, darkGreen, darkBlue, darkPurple,
30+@docs darkRed, darkOrange, darkYellow, darkGreen, darkBlue, darkPurple, darkBrown
32− darkBrown
33
31
34### Eight Shades of Grey
32### Eight Shades of Grey
35These colors are a compatible series of shades of grey, fitting nicely
33These colors are a compatible series of shades of grey, fitting nicely
@@ -42,133 +40,223 @@ that has never helped me remember which one I should be writing.
42
40
43-}
41-}
44
42
45−import Native.Color
46−import Basics ((-))
43+import Basics (..)
47
44
45+data Color
48−data Color = Color Int Int Int Float
46+ = RGBA Int Int Int Float
47+ | HSLA Float Float Float Float
49
48
50{-| Create RGB colors with an alpha component for transparency.
49{-| Create RGB colors with an alpha component for transparency.
51The alpha component is specified with numbers between 0 and 1. -}
50The alpha component is specified with numbers between 0 and 1. -}
52rgba : Int -> Int -> Int -> Float -> Color
51rgba : Int -> Int -> Int -> Float -> Color
53−rgba = Color
52+rgba = RGBA
54
53
55{-| Create RGB colors from numbers between 0 and 255 inclusive. -}
54{-| Create RGB colors from numbers between 0 and 255 inclusive. -}
56rgb : Int -> Int -> Int -> Color
55rgb : Int -> Int -> Int -> Color
57−rgb r g b = Color r g b 1
56+rgb r g b = RGBA r g b 1
57+
58+{-| Produce a gray based on the input. 0 is white, 1 is black. -}
59+grayscale : Float -> Color
60+grayscale p = HSLA 0 0 (1-p) 1
61+
62+greyscale : Float -> Color
63+greyscale p = HSLA 0 0 (1-p) 1
64+
65+{-| Produce a “complementary color”. The two colors will
66+accent each other. This is the same as rotating the hue by 180°.
67+-}
68+complement : Color -> Color
69+complement color =
70+ case color of
71+ HSLA h s l a -> hsla (h + degrees 180) s l a
72+ RGBA r g b a -> let (h,s,l) = rgbToHsl r g b
73+ in hsla (h + degrees 180) s l a
74+
75+{-| Create [HSL colors](http://en.wikipedia.org/wiki/HSL_and_HSV)
76+with an alpha component for transparency.
77+-}
78+hsla : Float -> Float -> Float -> Float -> Color
79+hsla hue saturation lightness alpha =
80+ HSLA (hue - toFloat (floor (hue / (2*pi)))) saturation lightness alpha
81+
82+{-| Create [HSL colors](http://en.wikipedia.org/wiki/HSL_and_HSV). This is very
83+convenient for creating colors that cycle and shift. Hue is an angle and should
84+be given in standard Elm angles (radians).
85+-}
86+hsl : Float -> Float -> Float -> Color
87+hsl hue saturation lightness =
88+ hsla hue saturation lightness 1
89+
90+{-| Extract the the components of a color in the HSL format.
91+-}
92+toHsl : Color -> { hue:Float, saturation:Float, lightness:Float, alpha:Float }
93+toHsl color =
94+ case color of
95+ HSLA h s l a -> { hue=h, saturation=s, lightness=l, alpha=a }
96+ RGBA r g b a ->
97+ let (h,s,l) = rgbToHsl r g b
98+ in { hue=h, saturation=s, lightness=l, alpha=a }
99+
100+{-| Extract the the components of a color in the RGB format.
101+-}
102+toRgb : Color -> { red:Int, green:Int, blue:Int, alpha:Float }
103+toRgb color =
104+ case color of
105+ RGBA r g b a -> { red=r, green=g, blue=b, alpha=a }
106+ HSLA h s l a ->
107+ let (r,g,b) = hslToRgb h s l
108+ in { red = round (255 * r)
109+ , green = round (255 * g)
110+ , blue = round (255 * b)
111+ , alpha = a
112+ }
113+
114+fmod : Float -> Int -> Float
115+fmod f n =
116+ let integer = floor f
117+ in toFloat (integer `mod` n) + f - toFloat integer
118+
119+rgbToHsl : Int -> Int -> Int -> (Float,Float,Float)
120+rgbToHsl red green blue =
121+ let r = toFloat red / 255
122+ g = toFloat green / 255
123+ b = toFloat blue / 255
124+
125+ cMax = max (max r g) b
126+ cMin = min (min r g) b
127+
128+ c = cMax - cMin
129+
130+ hue = degrees 60 * if | cMax == r -> ((g - b) / c) `fmod` 6
131+ | cMax == g -> ((b - r) / c) + 2
132+ | cMax == b -> ((r - g) / c) + 4
133+
134+ lightness = (cMax + cMin) / 2
135+
136+ saturation =
137+ if lightness == 0
138+ then 0
139+ else c / (1 - abs (2 * lightness - 1))
140+ in
141+ (hue, saturation, lightness)
142+
143+hslToRgb : Float -> Float -> Float -> (Float,Float,Float)
144+hslToRgb hue saturation lightness =
145+ let chroma = (1 - abs (2 * lightness - 1)) * saturation
146+ hue' = hue / degrees 60
147+
148+ x = chroma * (1 - abs (fmod hue' 2 - 1))
149+
150+ (r,g,b) = if | hue' < 0 -> (0, 0, 0)
151+ | hue' < 1 -> (chroma, x, 0)
152+ | hue' < 2 -> (x, chroma, 0)
153+ | hue' < 3 -> (0, chroma, x)
154+ | hue' < 4 -> (0, x, chroma)
155+ | hue' < 5 -> (x, 0, chroma)
156+ | hue' < 6 -> (chroma, 0, x)
157+ | otherwise -> (0, 0, 0)
158+
159+ m = lightness - chroma / 2
160+ in
161+ (r + m, g + m, b + m)
162+
163+--toV3 : Color -> V3
164+
165+--toV4 : Color -> V4
166+
167+data Gradient
168+ = Linear (Float,Float) (Float,Float) [(Float,Color)]
169+ | Radial (Float,Float) Float (Float,Float) Float [(Float,Color)]
170+
171+{-| Create a linear gradient. Takes a start and end point and then a series of
172+&ldquo;color stops&rdquo; that indicate how to interpolate between the start and
173+end points. See [this example](/edit/examples/Elements/LinearGradient.elm) for a
174+more visual explanation. -}
175+linear : (number, number) -> (number, number) -> [(Float,Color)] -> Gradient
176+linear = Linear
177+
178+{-| Create a radial gradient. First takes a start point and inner radius. Then
179+takes an end point and outer radius. It then takes a series of &ldquo;color
180+stops&rdquo; that indicate how to interpolate between the inner and outer
181+circles. See [this example](/edit/examples/Elements/RadialGradient.elm) for a
182+more visual explanation. -}
183+radial : (number,number) -> number -> (number,number) -> number -> [(Float,Color)] -> Gradient
184+radial = Radial
185+
186+
187+-- BUILT-IN COLORS
58
188
59lightRed : Color
189lightRed : Color
60−lightRed = Color 239 41 41 1
190+lightRed = RGBA 239 41 41 1
61red : Color
191red : Color
62−red = Color 204 0 0 1
192+red = RGBA 204 0 0 1
63darkRed : Color
193darkRed : Color
64−darkRed = Color 164 0 0 1
194+darkRed = RGBA 164 0 0 1
65
195
66lightOrange : Color
196lightOrange : Color
67−lightOrange = Color 252 175 62 1
197+lightOrange = RGBA 252 175 62 1
68orange : Color
198orange : Color
69−orange = Color 245 121 0 1
199+orange = RGBA 245 121 0 1
70darkOrange : Color
200darkOrange : Color
71−darkOrange = Color 206 92 0 1
201+darkOrange = RGBA 206 92 0 1
72
202
73lightYellow : Color
203lightYellow : Color
74−lightYellow = Color 255 233 79 1
204+lightYellow = RGBA 255 233 79 1
75yellow : Color
205yellow : Color
76−yellow = Color 237 212 0 1
206+yellow = RGBA 237 212 0 1
77darkYellow : Color
207darkYellow : Color
78−darkYellow = Color 196 160 0 1
208+darkYellow = RGBA 196 160 0 1
79
209
80lightGreen : Color
210lightGreen : Color
81−lightGreen = Color 138 226 52 1
211+lightGreen = RGBA 138 226 52 1
82green : Color
212green : Color
83−green = Color 115 210 22 1
213+green = RGBA 115 210 22 1
84darkGreen : Color
214darkGreen : Color
85−darkGreen = Color 78 154 6 1
215+darkGreen = RGBA 78 154 6 1
86
216
87lightBlue : Color
217lightBlue : Color
88−lightBlue = Color 114 159 207 1
218+lightBlue = RGBA 114 159 207 1
89blue : Color
219blue : Color
90−blue = Color 52 101 164 1
220+blue = RGBA 52 101 164 1
91darkBlue : Color
221darkBlue : Color
92−darkBlue = Color 32 74 135 1
222+darkBlue = RGBA 32 74 135 1
93
223
94lightPurple : Color
224lightPurple : Color
95−lightPurple = Color 173 127 168 1
225+lightPurple = RGBA 173 127 168 1
96purple : Color
226purple : Color
97−purple = Color 117 80 123 1
227+purple = RGBA 117 80 123 1
98darkPurple : Color
228darkPurple : Color
99−darkPurple = Color 92 53 102 1
229+darkPurple = RGBA 92 53 102 1
100
230
101lightBrown : Color
231lightBrown : Color
102−lightBrown = Color 233 185 110 1
232+lightBrown = RGBA 233 185 110 1
103brown : Color
233brown : Color
104−brown = Color 193 125 17 1
234+brown = RGBA 193 125 17 1
105darkBrown : Color
235darkBrown : Color
106−darkBrown = Color 143 89 2 1
236+darkBrown = RGBA 143 89 2 1
107
237
108black : Color
238black : Color
109−black = Color 0 0 0 1
239+black = RGBA 0 0 0 1
110white : Color
240white : Color
111−white = Color 255 255 255 1
241+white = RGBA 255 255 255 1
112
242
113lightGrey : Color
243lightGrey : Color
114−lightGrey = Color 238 238 236 1
244+lightGrey = RGBA 238 238 236 1
115grey : Color
245grey : Color
116−grey = Color 211 215 207 1
246+grey = RGBA 211 215 207 1
117darkGrey : Color
247darkGrey : Color
118−darkGrey = Color 186 189 182 1
248+darkGrey = RGBA 186 189 182 1
119
249
120lightGray : Color
250lightGray : Color
121−lightGray = Color 238 238 236 1
251+lightGray = RGBA 238 238 236 1
122gray : Color
252gray : Color
123−gray = Color 211 215 207 1
253+gray = RGBA 211 215 207 1
124darkGray : Color
254darkGray : Color
125−darkGray = Color 186 189 182 1
255+darkGray = RGBA 186 189 182 1
126
256
127lightCharcoal : Color
257lightCharcoal : Color
128−lightCharcoal = Color 136 138 133 1
258+lightCharcoal = RGBA 136 138 133 1
129charcoal : Color
259charcoal : Color
130−charcoal = Color 85 87 83 1
260+charcoal = RGBA 85 87 83 1
131darkCharcoal : Color
261darkCharcoal : Color
132−darkCharcoal = Color 46 52 54 1
262+darkCharcoal = RGBA 46 52 54 1
133−
134−{-| Produce a gray based on the input. 0 is white, 1 is black. -}
135−grayscale : Float -> Color
136−grayscale p = hsv 0 0 (1-p)
137−
138−greyscale : Float -> Color
139−greyscale p = hsv 0 0 (1-p)
140−
141−{-| Produce a &ldquo;complementary color&rdquo;.
142−The two colors will accent each other. -}
143−complement : Color -> Color
144−complement = Native.Color.complement
145−
146−{-| Create [HSV colors](http://en.wikipedia.org/wiki/HSL_and_HSV)
147−with an alpha component for transparency. -}
148−hsva : Float -> Float -> Float -> Float -> Color
149−hsva = Native.Color.hsva
150−
151−{-| Create [HSV colors](http://en.wikipedia.org/wiki/HSL_and_HSV). This is very
152−convenient for creating colors that cycle and shift. Hue is an angle and should
153−be given in standard Elm angles (radians). -}
154−hsv : Float -> Float -> Float -> Color
155−hsv = Native.Color.hsv
156−
157−data Gradient
158− = Linear (Float,Float) (Float,Float) [(Float,Color)]
159− | Radial (Float,Float) Float (Float,Float) Float [(Float,Color)]
160−
161−{-| Create a linear gradient. Takes a start and end point and then a series of
162−&ldquo;color stops&rdquo; that indicate how to interpolate between the start and
163−end points. See [this example](/edit/examples/Elements/LinearGradient.elm) for a
164−more visual explanation. -}
165−linear : (number, number) -> (number, number) -> [(Float,Color)] -> Gradient
166−linear = Linear
167−
168−{-| Create a radial gradient. First takes a start point and inner radius. Then
169−takes an end point and outer radius. It then takes a series of &ldquo;color
170−stops&rdquo; that indicate how to interpolate between the inner and outer
171−circles. See [this example](/edit/examples/Elements/RadialGradient.elm) for a
172−more visual explanation. -}
173−radial : (number,number) -> number -> (number,number) -> number -> [(Float,Color)] -> Gradient
174−radial = Radial
libraries/Native/Color.js+16−60
@@ -7,69 +7,25 @@ Elm.Native.Color.make = function(elm) {
7 var Utils = Elm.Native.Utils.make(elm);
7 var Utils = Elm.Native.Utils.make(elm);
8
8
9 function toCss(c) {
9 function toCss(c) {
10− return (c._3 === 1)
10+ var format = '';
11− ? ('rgb(' + c._0 + ', ' + c._1 + ', ' + c._2 + ')')
11+ var colors = '';
12− : ('rgba(' + c._0 + ', ' + c._1 + ', ' + c._2 + ', ' + c._3 + ')');
12+ if (c.ctor === 'RGBA') {
13− }
13+ format = 'rgb';
14−
14+ colors = c._0 + ', ' + c._1 + ', ' + c._2;
15− function complement(rgb) {
15+ } else {
16− var hsv = toHSV(rgb);
16+ format = 'hsl';
17− hsv.hue = (hsv.hue + 180) % 360;
17+ colors = (c._0 * 180 / Math.PI) + ', ' +
18− return toRGB(hsv);
18+ (c._1 * 100) + '%, ' +
19− }
19+ (c._2 * 100) + '%';
20−
20+ }
21− function hsva(h,s,v,a) {
21+ if (c._3 === 1) {
22− var degree = A2(Utils.mod, h * 180 / Math.PI, 360);
22+ return format + '(' + colors + ')';
23− var clr = toRGB({hue:degree, saturation:s, value:v});
23+ } else {
24− clr._3 = a;
24+ return format + 'a(' + colors + ', ' + c._3 + ')';
25− return clr;
25+ }
26− }
27−
28− function hsv(h,s,v) {
29− var degree = A2(Utils.mod, h * 180 / Math.PI, 360);
30− return toRGB({hue:degree, saturation:s, value:v});
31− }
32−
33− function toHSV(rgb) {
34− var hsv = {};
35− var r = rgb._0 / 255.0, g = rgb._1 / 255.0, b = rgb._2 / 255.0;
36− var M = Math.max(r,g,b);
37− var m = Math.min(r,g,b);
38− var c = M - m;
39−
40− var h = 0;
41− if (c === 0) { h = 0; }
42− else if (M === r) { h = ((g - b) / c) % 6; }
43− else if (M === g) { h = ((b - r) / c) + 2; }
44− else if (M === b) { h = ((r - g) / c) + 4; }
45− h *= 60;
46−
47− return { value : M, hue : h, saturation : (M === 0 ? 0 : c / M) };
48− }
49−
50− function between(lo,hi,x) { return lo <= x && x < hi; }
51− function norm(n) { return Math.round(n*255); }
52−
53− function toRGB(hsv) {
54− var c = hsv.value * hsv.saturation;
55− var hue = hsv.hue / 60;
56− var x = c * (1 - Math.abs((hue % 2) - 1));
57− var r = 0, g = 0, b = 0;
58− if (between(0,1,hue)) { r = c; g = x; b = 0; }
59− else if (between(1,2,hue)) { r = x; g = c; b = 0; }
60− else if (between(2,3,hue)) { r = 0; g = c; b = x; }
61− else if (between(3,4,hue)) { r = 0; g = x; b = c; }
62− else if (between(4,5,hue)) { r = x; g = 0; b = c; }
63− else if (between(5,6,hue)) { r = c; g = 0; b = x; }
64−
65− var m = hsv.value - c;
66− return { ctor:"Color", _0:norm(r+m), _1:norm(g+m), _2:norm(b+m), _3:1 };
67 }
26 }
68
27
69 return elm.Native.Color.values = {
28 return elm.Native.Color.values = {
70− hsva:F4(hsva),
71− hsv:F3(hsv),
72− complement:complement,
73 toCss:toCss
29 toCss:toCss
74 };
30 };
75
31
runtime/Render/Element.js+3−3
@@ -3,7 +3,7 @@ ElmRuntime.Render.Element = function() {
3'use strict';
3'use strict';
4
4
5var Utils = ElmRuntime.use(ElmRuntime.Render.Utils);
5var Utils = ElmRuntime.use(ElmRuntime.Render.Utils);
6−var newElement = Utils.newElement, extract = Utils.extract,
6+var newElement = Utils.newElement, colorToCss = Utils.colorToCss,
7 addTransform = Utils.addTransform, removeTransform = Utils.removeTransform,
7 addTransform = Utils.addTransform, removeTransform = Utils.removeTransform,
8 fromList = Utils.fromList, eq = Utils.eq;
8 fromList = Utils.fromList, eq = Utils.eq;
9
9
@@ -18,7 +18,7 @@ function setProps(elem, e) {
18 e.style.opacity = props.opacity;
18 e.style.opacity = props.opacity;
19 }
19 }
20 if (props.color.ctor === 'Just') {
20 if (props.color.ctor === 'Just') {
21− e.style.backgroundColor = extract(props.color._0);
21+ e.style.backgroundColor = colorToCss(props.color._0);
22 }
22 }
23 if (props.tag !== '') { e.id = props.tag; }
23 if (props.tag !== '') { e.id = props.tag; }
24 if (props.href !== '') {
24 if (props.href !== '') {
@@ -370,7 +370,7 @@ function updateProps(node, curr, next) {
370 e.style.opacity = props.opacity;
370 e.style.opacity = props.opacity;
371 }
371 }
372 var nextColor = (props.color.ctor === 'Just' ?
372 var nextColor = (props.color.ctor === 'Just' ?
373− extract(props.color._0) : '');
373+ colorToCss(props.color._0) : '');
374 if (e.style.backgroundColor !== nextColor) {
374 if (e.style.backgroundColor !== nextColor) {
375 e.style.backgroundColor = (nextColor === '' ? 'transparent' : nextColor);
375 e.style.backgroundColor = (nextColor === '' ? 'transparent' : nextColor);
376 }
376 }
runtime/Render/Utils.js+2−7
@@ -10,11 +10,6 @@ ElmRuntime.Render.Utils = function() {
10 container.appendChild(elem);
10 container.appendChild(elem);
11 }
11 }
12
12
13− function extract(c) {
14− if (c._3 === 1) { return 'rgb(' + c._0 + ', ' + c._1 + ', ' + c._2 + ')'; }
15− return 'rgba(' + c._0 + ', ' + c._1 + ', ' + c._2 + ', ' + c._3 + ')';
16− }
17−
18 function addTransform(style, trans) {
13 function addTransform(style, trans) {
19 style.transform = trans;
14 style.transform = trans;
20 style.msTransform = trans;
15 style.msTransform = trans;
@@ -34,8 +29,8 @@ ElmRuntime.Render.Utils = function() {
34 var List = Elm.Native.List.make({});
29 var List = Elm.Native.List.make({});
35
30
36 return {addTo:addTo,
31 return {addTo:addTo,
37− newElement:newElement,
32+ newElement: newElement,
38− extract : extract,
33+ colorToCss: Elm.Native.Color.make({}).toCss,
39 fromList: List.toArray,
34 fromList: List.toArray,
40 fromString: function(s) { return s; },
35 fromString: function(s) { return s; },
41 toString: function(s) { return s; },
36 toString: function(s) { return s; },