module Color where {-| Library for working with colors. Includes [RGB](https://en.wikipedia.org/wiki/RGB_color_model) and [HSL](http://en.wikipedia.org/wiki/HSL_and_HSV) creation, gradients, and built-in names. # Creation @docs rgb, rgba, hsl, hsla, greyscale, grayscale, complement # Gradients @docs linear, radial # Extracting Colors @docs toRgb, toHsl # Built-in Colors These colors come from the [Tango palette](http://tango.freedesktop.org/Tango_Icon_Theme_Guidelines) which provides aesthetically reasonable defaults for colors. Each color also comes with a light and dark version. ### Standard @docs red, orange, yellow, green, blue, purple, brown ### Light @docs lightRed, lightOrange, lightYellow, lightGreen, lightBlue, lightPurple, lightBrown ### Dark @docs darkRed, darkOrange, darkYellow, darkGreen, darkBlue, darkPurple, darkBrown ### Eight Shades of Grey These colors are a compatible series of shades of grey, fitting nicely with the Tango palette. @docs white, lightGrey, grey, darkGrey, lightCharcoal, charcoal, darkCharcoal, black These are identical to the *grey* versions. It seems the spelling is regional, but that has never helped me remember which one I should be writing. @docs lightGray, gray, darkGray -} import Basics (..) import Native.Color type Color = RGBA Int Int Int Float | HSLA Float Float Float Float {-| Create RGB colors with an alpha component for transparency. The alpha component is specified with numbers between 0 and 1. -} rgba : Int -> Int -> Int -> Float -> Color rgba = RGBA {-| Create RGB colors from numbers between 0 and 255 inclusive. -} rgb : Int -> Int -> Int -> Color rgb r g b = RGBA r g b 1 {-| Create [HSL colors](http://en.wikipedia.org/wiki/HSL_and_HSV) with an alpha component for transparency. -} hsla : Float -> Float -> Float -> Float -> Color hsla hue saturation lightness alpha = HSLA (hue - turns (toFloat (floor (hue / (2*pi))))) saturation lightness alpha {-| Create [HSL colors](http://en.wikipedia.org/wiki/HSL_and_HSV). This gives you access to colors more like a color wheel, where all hues are aranged in a circle that you specify with standard Elm angles (radians). red = hsl (degrees 0) 1 0.5 green = hsl (degrees 120) 1 0.5 blue = hsl (degrees 240) 1 0.5 pastelRed = hsl (degrees 0) 0.7 0.7 To cycle through all colors, just cycle through degrees. The saturation level is how vibrant the color is, like a dial between grey and bright colors. The lightness level is a dial between white and black. -} hsl : Float -> Float -> Float -> Color hsl hue saturation lightness = hsla hue saturation lightness 1 {-| Produce a gray based on the input. 0 is white, 1 is black. -} grayscale : Float -> Color grayscale p = HSLA 0 0 (1-p) 1 greyscale : Float -> Color greyscale p = HSLA 0 0 (1-p) 1 {-| Produce a “complementary color”. The two colors will accent each other. This is the same as rotating the hue by 180°. -} complement : Color -> Color complement color = case color of HSLA h s l a -> hsla (h + degrees 180) s l a RGBA r g b a -> let (h,s,l) = rgbToHsl r g b in hsla (h + degrees 180) s l a {-| Extract the components of a color in the HSL format. -} toHsl : Color -> { hue:Float, saturation:Float, lightness:Float, alpha:Float } toHsl color = case color of HSLA h s l a -> { hue=h, saturation=s, lightness=l, alpha=a } RGBA r g b a -> let (h,s,l) = rgbToHsl r g b in { hue=h, saturation=s, lightness=l, alpha=a } {-| Extract the components of a color in the RGB format. -} toRgb : Color -> { red:Int, green:Int, blue:Int, alpha:Float } toRgb color = case color of RGBA r g b a -> { red=r, green=g, blue=b, alpha=a } HSLA h s l a -> let (r,g,b) = hslToRgb h s l in { red = round (255 * r) , green = round (255 * g) , blue = round (255 * b) , alpha = a } fmod : Float -> Int -> Float fmod f n = let integer = floor f in toFloat (integer % n) + f - toFloat integer rgbToHsl : Int -> Int -> Int -> (Float,Float,Float) rgbToHsl red green blue = let r = toFloat red / 255 g = toFloat green / 255 b = toFloat blue / 255 cMax = max (max r g) b cMin = min (min r g) b c = cMax - cMin hue = degrees 60 * if | cMax == r -> ((g - b) / c) `fmod` 6 | cMax == g -> ((b - r) / c) + 2 | cMax == b -> ((r - g) / c) + 4 lightness = (cMax + cMin) / 2 saturation = if lightness == 0 then 0 else c / (1 - abs (2 * lightness - 1)) in (hue, saturation, lightness) hslToRgb : Float -> Float -> Float -> (Float,Float,Float) hslToRgb hue saturation lightness = let chroma = (1 - abs (2 * lightness - 1)) * saturation hue' = hue / degrees 60 x = chroma * (1 - abs (fmod hue' 2 - 1)) (r,g,b) = if | hue' < 0 -> (0, 0, 0) | hue' < 1 -> (chroma, x, 0) | hue' < 2 -> (x, chroma, 0) | hue' < 3 -> (0, chroma, x) | hue' < 4 -> (0, x, chroma) | hue' < 5 -> (x, 0, chroma) | hue' < 6 -> (chroma, 0, x) | otherwise -> (0, 0, 0) m = lightness - chroma / 2 in (r + m, g + m, b + m) --toV3 : Color -> V3 --toV4 : Color -> V4 type Gradient = Linear (Float,Float) (Float,Float) (List (Float,Color)) | Radial (Float,Float) Float (Float,Float) Float (List (Float,Color)) {-| Create a linear gradient. Takes a start and end point and then a series of “color stops” that indicate how to interpolate between the start and end points. See [this example](http://elm-lang.org/edit/examples/Elements/LinearGradient.elm) for a more visual explanation. -} linear : (number, number) -> (number, number) -> List (Float,Color) -> Gradient linear = Linear {-| Create a radial gradient. First takes a start point and inner radius. Then takes an end point and outer radius. It then takes a series of “color stops” that indicate how to interpolate between the inner and outer circles. See [this example](http://elm-lang.org/edit/examples/Elements/RadialGradient.elm) for a more visual explanation. -} radial : (number,number) -> number -> (number,number) -> number -> List (Float,Color) -> Gradient radial = Radial -- BUILT-IN COLORS lightRed : Color lightRed = RGBA 239 41 41 1 red : Color red = RGBA 204 0 0 1 darkRed : Color darkRed = RGBA 164 0 0 1 lightOrange : Color lightOrange = RGBA 252 175 62 1 orange : Color orange = RGBA 245 121 0 1 darkOrange : Color darkOrange = RGBA 206 92 0 1 lightYellow : Color lightYellow = RGBA 255 233 79 1 yellow : Color yellow = RGBA 237 212 0 1 darkYellow : Color darkYellow = RGBA 196 160 0 1 lightGreen : Color lightGreen = RGBA 138 226 52 1 green : Color green = RGBA 115 210 22 1 darkGreen : Color darkGreen = RGBA 78 154 6 1 lightBlue : Color lightBlue = RGBA 114 159 207 1 blue : Color blue = RGBA 52 101 164 1 darkBlue : Color darkBlue = RGBA 32 74 135 1 lightPurple : Color lightPurple = RGBA 173 127 168 1 purple : Color purple = RGBA 117 80 123 1 darkPurple : Color darkPurple = RGBA 92 53 102 1 lightBrown : Color lightBrown = RGBA 233 185 110 1 brown : Color brown = RGBA 193 125 17 1 darkBrown : Color darkBrown = RGBA 143 89 2 1 black : Color black = RGBA 0 0 0 1 white : Color white = RGBA 255 255 255 1 lightGrey : Color lightGrey = RGBA 238 238 236 1 grey : Color grey = RGBA 211 215 207 1 darkGrey : Color darkGrey = RGBA 186 189 182 1 lightGray : Color lightGray = RGBA 238 238 236 1 gray : Color gray = RGBA 211 215 207 1 darkGray : Color darkGray = RGBA 186 189 182 1 lightCharcoal : Color lightCharcoal = RGBA 136 138 133 1 charcoal : Color charcoal = RGBA 85 87 83 1 darkCharcoal : Color darkCharcoal = RGBA 46 52 54 1