### Src/Index # chroma.js **chroma.js** is a [small-ish](https://bundlephobia.com/result?p=chroma-js) zero-dependency JavaScript library ([13.5kB](https://bundlephobia.com/result?p=chroma-js)) for all kinds of color conversions and color scales. [](https://travis-ci.com/gka/chroma.js) ## Quick-start Here are a couple of things chroma.js can do for you: * read colors from a wide range of formats * analyze and manipulate colors * convert colors into wide range of formats * linear and bezier interpolation in different color spaces Here's an example for a simple read / manipulate / output chain: ```js chroma('pink').darken().saturate(2).hex() ``` Aside from that, chroma.js can also help you **generate nice colors** using various methods, for instance to be [used](https://www.vis4.net/blog/posts/avoid-equidistant-hsv-colors/) in color palette for maps or data visualization. ```js chroma.scale(['#fafa6e', '#2A4858']) .mode('lch').colors(6) ``` chroma.js has a lot more to offer, but that's the gist of it. ## Installation For Node.js: Install the `chroma-js` npm module using your favorite package manager: ```shell npm install chroma-js # pnpm add chroma-js # yarn add chroma-js ``` Then import the module into your JavaScript: ```js import chroma from 'chroma-js'; ``` If you just want to use parts of chroma.js and not bundle the entire package, you can import directly from `chroma-js/src/*` to benefit from treeshaking. For instance, the following import would only result in a [1.24kB bundle increase](https://bundlejs.com/?q=chroma-js%2Fsrc%2Futils%2Fdelta-e.js&treeshake=%5B*+as+default%5D&config=%7B%22analysis%22%3A%22treemap%22%7D): ```js import deltaE from 'chroma-js/src/utils/deltaE.js ``` And for browsers, download [`chroma.min.js`](https://unpkg.com/chroma-js/dist/chroma.min.cjs) or use the [hosted version on unpkg.com](https://unpkg.com/chroma-js/dist/chroma.min.cjs). You can also just import chroma.js as ES module, as demonstrated in this [StackBlitz](https://stackblitz.com/edit/stackblitz-starters-axiqsz?description=HTML/CSS/JS%20Starter&file=script.js,styles.css&terminalHeight=10&title=Static%20Starter). To use chroma.js in [Observable notebooks](https://observablehq.com/), you can import it like this: ```js import { chroma } from "@gka/chroma-js" ``` The [interactive documentation](http://gka.github.io/chroma.js/) continues below (and there's a [static version](https://github.com/gka/chroma.js/blob/master/docs/src/index.md), too) for usage examples. Or use it from SASS using [chromatic-sass](https://github.com/bugsnag/chromatic-sass)! ## API ### chroma #### (*color*) The first step is to get your color into chroma.js. That's what the generic constructor ``chroma()`` does. This function attempts to guess the format of the input color for you. For instance, it will recognize any named color from the W3CX11 specification: ```js chroma('hotpink') ``` If there's no matching named color, chroma.js checks for a **hexadecimal string**. It ignores case, the `#` sign is optional, and it can recognize the shorter three letter format as well. So, any of these are valid hexadecimal representations: `#ff3399`, `FF3399`, `#f39`, etc. ```js chroma('#ff3399'); chroma('F39'); ``` In addition to hex strings, **hexadecimal numbers** (in fact, just any number between `0` and `16777215`) will be recognized, too. ```js chroma(0xff3399) ``` You also can pass RGB values individually. Each parameter must be within `0..255`. You can pass the numbers as individual arguments or as an array. ```js chroma(0xff, 0x33, 0x99); chroma(255, 51, 153); chroma([255, 51, 153]); ``` You can construct colors from different color spaces by passing the name of color space as the last argument. Here we define the same color in HSL by passing the h*ue angle (0-360) and percentages for *s*aturation and *l*ightness: ```js chroma(330, 1, 0.6, 'hsl') ``` **New (since 2.0):** you can also construct colors by passing an plain JS object with attributes corresponding to a color space supported by chroma.js: ```js chroma({ h:120, s:1, l:0.75}); chroma({ l:80, c:25, h:200 }); chroma({ c:1, m:0.5, y:0, k:0.2}); ``` ### chroma.valid Also new: you can use `chroma.valid` to try if a color argument can be correctly parsed as color by chroma.js: ```js chroma.valid('red'); chroma.valid('bread'); chroma.valid('#F0000D'); chroma.valid('#FOOOOD'); ``` ### chroma.hsl #### (hue, saturation, lightness) Alternatively, every color space has its own constructor function under the `chroma` namespace. For a list of all supported color spaces, check the [appendix](#supported-color-spaces-and-output-formats). ```js chroma.hsl(330, 1, 0.6) ``` ### chroma.hsv #### (hue, saturation, value) ### chroma.lab #### (Lightness, a, b) CIE Lab color space. To calculate the lightness value of a color, the CIE Lab color space uses a reference white point. This reference white point defines what is considered to be "white" in the color space. By default chroma.js is using the D65 reference point. ```js chroma.lab(40, -20, 50); chroma.lab(50, -20, 50); chroma.lab(80, -20, 50); ``` ### chroma.setLabWhitePoint #### (whitePoint) Sets the current CIE Lab white reference point. Possible values: | | | |-------------|-------------------------------------------------------------------------------------------------------| | `D50` | Represents the color temperature of daylight at 5000K. | | `D55` | Represents mid-morning or mid-afternoon daylight at 5500K. | | `D65` | Represents average daylight at 6500K. | | `A` | Represents the color temperature of a typical incandescent light bulb at approximately 2856K. | | `B` | Represents noon daylight with a color temperature of approximately 4874K. | | `C` | Represents average or north sky daylight; it's a theoretical construct, not often used in practical applications. | | `F2` | Represents cool white fluorescent light. | | `F7` | This is a broad-band fluorescent light source with a color temperature of approximately 6500K. | | `F11` | This is a narrow tri-band fluorescent light source with a color temperature of approximately 4000K. | | `E` | Represents an equal energy white point, where all wavelengths in the visible spectrum are equally represented. | ```js chroma('hotpink').lab(); chroma.setLabWhitePoint('F2'); chroma('hotpink').lab(); ``` ### chroma.getLabWhitePoint Returns the name of the currently set CIE Lab white reference point. ```js chroma.getLabWhitePoint(); ``` ### chroma.lch #### (Lightness, chroma, hue) The range for `lightness` and `chroma` depend on the hue, but go roughly from 0..100-150. The range for `hue` is 0..360. ```js chroma.lch(80, 40, 130); chroma(80, 40, 130, 'lch'); ``` ### chroma.hcl #### (hue, chroma, lightness) You can use **hcl** instead of Lch. Lightness and hue channels are switched to be more consistent with HSL. ```js chroma.hcl(130, 40, 80); chroma(130, 40, 80, 'hcl'); ``` ### chroma.oklab #### (Lightness, a, b) [Oklab color space](https://bottosson.github.io/posts/oklab/) ```js chroma.oklab(0.4,-0.2,0.5); chroma.oklab(0.5,-0.2,0.5); chroma.oklab(0.8,-0.2,0.5); ``` ### chroma.oklch #### (Lightness, chromacity, hue) ```js chroma.oklch(0.5, 0.2, 240); chroma(0.8, 0.12, 60, 'oklch'); ``` ### chroma.cmyk #### (cyan, magenta, yellow, black) Each between 0 and 1. ```js chroma.cmyk(0.2, 0.8, 0, 0); chroma(0.2, 0.8, 0, 0, 'cmyk'); ``` ### chroma.gl #### (red, green, blue, [alpha]) **GL** is a variant of RGB(A), with the only difference that the components are normalized to the range of `0..1`. ```js chroma.gl(0.6, 0, 0.8); chroma.gl(0.6, 0, 0.8, 0.5); chroma(0.6, 0, 0.8, 'gl'); ``` ### chroma.temperature #### (K) Returns a color from the [color temperature](http://www.zombieprototypes.com/?p=210) scale. Based on [Neil Bartlett's implementation](https://github.com/neilbartlett/color-temperature). ```js chroma.temperature(2000); // candle light chroma.temperature(3500); // sunset chroma.temperature(6500); // daylight ``` The effective temperature range goes from `0` to about `30000` Kelvin, ```js f = function(i) { return chroma.temperature(i * 30000) } ``` ### chroma.mix #### (color1, color2, ratio=0.5, mode='lrgb') Mixes two colors. The mix *ratio* is a value between 0 and 1. ```js chroma.mix('red', 'blue'); chroma.mix('red', 'blue', 0.25); chroma.mix('red', 'blue', 0.75); ``` The color mixing produces different results based the color space used for interpolation. ```js chroma.mix('red', 'blue', 0.5, 'rgb'); chroma.mix('red', 'blue', 0.5, 'hsl'); chroma.mix('red', 'blue', 0.5, 'lab'); chroma.mix('red', 'blue', 0.5, 'lch'); chroma.mix('red', 'blue', 0.5, 'lrgb'); ``` ### chroma.average #### (colors, mode='lrgb', weights=[]) Similar to `chroma.mix`, but accepts more than two colors. Simple averaging of R,G,B components and the alpha channel. ```js colors = ['#ddd', 'yellow', 'red', 'teal']; chroma.average(colors); // lrgb chroma.average(colors, 'rgb'); chroma.average(colors, 'lab'); chroma.average(colors, 'lch'); ``` Also works with alpha channels. ```js chroma.average(['red', 'rgba(0,0,0,0.5)']).css(); ``` As of version 2.1 you can also provide an array of `weights` to compute a **weighted average** of colors. ```js colors = ['#ddd', 'yellow', 'red', 'teal']; chroma.average(colors, 'lch'); // unweighted chroma.average(colors, 'lch', [1,1,2,1]); chroma.average(colors, 'lch', [1.5,0.5,1,2.3]); ``` ### chroma.blend #### (color1, color2, mode) Blends two colors using RGB channel-wise blend functions. Valid blend modes are `multiply`, `darken`, `lighten`, `screen`, `overlay`, `burn`, and `dodge`. ```js chroma.blend('4CBBFC', 'EEEE22', 'multiply'); chroma.blend('4CBBFC', 'EEEE22', 'darken'); chroma.blend('4CBBFC', 'EEEE22', 'lighten'); ``` ### chroma.random #### (rng = Math.random) Creates a random color by generating a [random hexadecimal string](https://github.com/gka/chroma.js/blob/main/src/generator/random.js#L7-L11). You can also pass a custom random number generator function as first argument. ```js chroma.random(); chroma.random(); chroma.random(); ``` ### chroma.contrast #### (color1, color2) Computes the WCAG contrast ratio between two colors. A minimum contrast of 4.5:1 [is recommended](http://www.w3.org/TR/WCAG20-TECHS/G18.html) to ensure that text is still readable against a background color. ```js // contrast smaller than 4.5 = too low chroma.contrast('pink', 'hotpink'); // contrast greater than 4.5 = high enough chroma.contrast('pink', 'purple'); ``` ### chroma.contrastAPCA #### (text, background) **New (3.1):** Computes the [APCA contrast](https://www.myndex.com/APCA/) ratio of a text color against its background color. The basic idea is that you check the contrast between the text and background color and then use [this lookup table](https://raw.githubusercontent.com/Myndex/apca-w3/master/images/APCAlookupByContrast.jpeg) to find the minimum font size you're allowed to use (given the font weight and purpose of the text). ```js chroma.contrastAPCA('hotpink', 'pink'); chroma.contrastAPCA('purple', 'pink'); ``` Read more about how to interpret and use this metric at [APCA Readability Criterion](https://readtech.org/ARC). Please note that the APCA algorithm is still in beta and may change be subject to changes in the future. ### chroma.distance #### (color1, color2, mode='lab') Computes the [Euclidean distance](https://en.wikipedia.org/wiki/Euclidean_distance#Three_dimensions) between two colors in a given color space (default is `Lab`). ```js chroma.distance('#fff', '#ff0', 'rgb'); chroma.distance('#fff', '#f0f', 'rgb'); chroma.distance('#fff', '#ff0'); chroma.distance('#fff', '#f0f'); ``` ### chroma.deltaE #### (color1, color2, Kl=1, Kc=1, Kh=1) Computes [color difference](https://en.wikipedia.org/wiki/Color_difference#CIEDE2000) as developed by the International Commission on Illumination (CIE) in 2000. The implementation is based on the formula from [Bruce Lindbloom](http://www.brucelindbloom.com/index.html?Eqn_DeltaE_CIE2000.html). Resulting values range from 0 (no difference) to 100 (maximum difference), and are a metric for how the human eye percieves color difference. The optional parameters Kl, Kc, and Kh may be used to adjust weightings of lightness, chroma, and hue. ```js chroma.deltaE('#ededee', '#ededee'); chroma.deltaE('#ededee', '#edeeed'); chroma.deltaE('#ececee', '#eceeec'); chroma.deltaE('#e9e9ee', '#e9eee9'); chroma.deltaE('#e4e4ee', '#e4eee4'); chroma.deltaE('#e0e0ee', '#e0eee0'); chroma.deltaE('#000000', '#ffffff'); ``` ### chroma.brewer chroma.brewer is an map of [ColorBrewer palettes](http://colorbrewer2.org/) that are included in chroma.js for convenience. chroma.scale uses the colors to construct. ```js chroma.brewer.OrRd ``` Note that chroma.js only includes the 9-step versions of the palettes (11 steps for the diverging palettes). So, for instance, if you use chroma.js to construct a 5-color palette, they will be different from the "official" 5-color palettes in ColorBrewer (which have lower contrast). ```js chroma.scale('RdBu').colors(5); // offical 5-color RdBu: ['#ca0020', '#f4a582', '#f7f7f7', '#92c5de', '#0571b0'] ``` One way to compensate for this would be to "slice off" the extreme colors: ```js chroma .scale(chroma.brewer.RdBu.slice(1,-1)) .colors(5); ``` Of course you can also just construct the scale from the official 5-step colors that you can copy and paste from [colorbrewer2.org](https://colorbrewer2.org/#type=diverging&scheme=RdBu&n=5): ```js chroma.scale(['#ca0020', '#f4a582', '#f7f7f7', '#92c5de', '#0571b0']) ``` You can access a list of all available palettes via `Object.keys(chroma.brewer)`: ```js Object.keys(chroma.brewer) // ['OrRd', 'PuBu', 'BuPu', 'Oranges', 'BuGn', 'YlOrBr', 'YlGn', 'Reds', 'RdPu', 'Greens', 'YlGnBu', 'Purples', 'GnBu', 'Greys', 'YlOrRd', 'PuRd', 'Blues', 'PuBuGn', 'Viridis', 'Spectral', 'RdYlGn', 'RdBu', 'PiYG', 'PRGn', 'RdYlBu', 'BrBG', 'RdGy', 'PuOr', 'Set2', 'Accent', 'Set1', 'Set3', 'Dark2', 'Paired', 'Pastel2', 'Pastel1'] ``` ### chroma.limits #### (data, mode, n) A helper function that computes class breaks for you, based on data. It supports the modes _equidistant_ (e), _quantile_ (q), _logarithmic_ (l), and _k-means_ (k). Let's take a few numbers as sample data. ```js var data = [2.0,3.5,3.6,3.8,3.8,4.1,4.3,4.4, 4.6,4.9,5.2,5.3,5.4,5.7,5.8,5.9, 6.2,6.5,6.8,7.2,8]; ``` **equidistant** breaks are computed by dividing the total range of the data into _n_ groups of equal size. ```js chroma.limits(data, 'e', 4); ``` In the **quantile** mode, the input domain is divided by quantile ranges. ```js chroma.limits(data, 'q', 4); ``` **logarithmic** breaks are equidistant breaks but on a logarithmic scale. ```js chroma.limits(data, 'l', 4); ``` **k-means** break is using the 1-dimensional [k-means clustering](https://en.wikipedia.org/wiki/K-means_clustering) algorithm to find (roughly) _n_ groups of "similar" values. Note that this k-means implementation does not guarantee to find exactly _n_ groups. ```js chroma.limits(data, 'k', 4); ``` ## color ### color.alpha #### (a) Get and set the color opacity using ``color.alpha``. ```js chroma('red').alpha(0.5); chroma('rgba(255,0,0,0.35)').alpha(); ``` ### color.darken #### (value=1) Once loaded, chroma.js can change colors. One way we already saw above, you can change the lightness. ```js chroma('hotpink').darken(); chroma('hotpink').darken(2); chroma('hotpink').darken(2.6); ``` ### color.brighten #### (value=1) Similar to `darken`, but the opposite direction ```js chroma('hotpink').brighten(); chroma('hotpink').brighten(2); chroma('hotpink').brighten(3); ``` ### color.saturate #### (value=1) Changes the saturation of a color by manipulating the Lch chromaticity. ```js chroma('slategray').saturate(); chroma('slategray').saturate(2); chroma('slategray').saturate(3); ``` ### color.desaturate #### (value=1) Similar to `saturate`, but the opposite direction. ```js chroma('hotpink').desaturate(); chroma('hotpink').desaturate(2); chroma('hotpink').desaturate(3); ``` ### color.mix #### (targetcolor, ratio=0.5, mode='lrgb') Mix this color with a target color. The mix *ratio* is a value between 0 and 1. This is the same as `chroma.mix` but with the first parameter already set. As such, the color space used can be adjusted. ```js chroma('hotpink').mix('blue'); chroma('hotpink').mix('blue', 0.25); chroma('hotpink').mix('blue', 0.75, 'lab'); ``` ### color.shade #### (ratio=0.5, mode='lrgb') Produce a shade of the color. This is syntactic sugar for `color.mix` with a target color of black. ```js chroma('hotpink').shade(0.25); chroma('hotpink').shade(0.5); chroma('hotpink').shade(0.75); ``` ### color.tint #### (ratio=0.5, mode='lrgb') Produce a tint of the color. This is syntactic sugar for `color.mix` with a target color of white. ```js chroma('hotpink').tint(0.25); chroma('hotpink').tint(0.5); chroma('hotpink').tint(0.75); ``` ### color.set #### (channel, value) Changes a single channel and returns the result a new `chroma` object. ```js // change hue to 0 deg (=red) chroma('skyblue').set('hsl.h', 0); // set chromaticity to 30 chroma('hotpink').set('lch.c', 30); ``` Relative changes work, too: ```js // half Lab lightness chroma('orangered').set('lab.l', '*0.5'); // double Lch saturation chroma('darkseagreen').set('lch.c', '*2'); ``` ### color.get #### (channel) Returns a single channel value. ```js chroma('orangered').get('lab.l'); chroma('orangered').get('hsl.l'); chroma('orangered').get('rgb.g'); ``` ### color.luminance #### ([lum, mode='rgb']) If called without arguments color.luminance returns the relative brightness, according to the [WCAG definition](http://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef). Normalized to `0` for darkest black and `1` for lightest white. ```js chroma('white').luminance(); chroma('aquamarine').luminance(); chroma('hotpink').luminance(); chroma('darkslateblue').luminance(); chroma('black').luminance(); ``` chroma.js also allows you to **adjust the luminance** of a color. The source color will be interpolated with black or white until the correct luminance is found. ```js // set lumincance to 50% for all colors chroma('white').luminance(0.5); chroma('aquamarine').luminance(0.5); chroma('hotpink').luminance(0.5); chroma('darkslateblue').luminance(0.5); ``` By default, this interpolation is done in RGB, but you can interpolate in different color spaces by passing them as second argument: ```js chroma('aquamarine').luminance(0.5); // rgb chroma('aquamarine').luminance(0.5, 'lab'); chroma('aquamarine').luminance(0.5, 'hsl'); ``` ### color.hex #### (mode='auto|rgb|rgba|argb') Finally, chroma.js allows you to output colors in various color spaces and formats. Most often you will want to output the color as hexadecimal string. ```js chroma('orange').hex() ``` **Note** that as of version 1.4.0 the default mode is "auto" which means that the hex string will include the alpha channel if it's less than 1. If you don't want the alpha channel to be included you must explicitly set the mode to "rgb" now: ```js chroma('orange').hex(); chroma('orange').alpha(0.5).hex(); chroma('orange').alpha(0.5).hex('rgb'); ``` You can use `.hex('argb')` in [case](https://developer.android.com/reference/android/graphics/Color) you need to encode the color with the alpha channel as first byte rather than the last: ```js chroma('orange').hex('argb');; // '#ffffa500' ``` ### color.name Returns the named color. Falls back to hexadecimal RGB string, if the color isn't present. ```js chroma('#ffa500').name(); chroma('#ffa505').name(); ``` ### color.css Returns a CSS string representation that can be used as CSS-color definition. ```js chroma('teal').css(); chroma('teal').alpha(0.5).css(); ``` By default chroma is using the rgb() color space, but you can pass a color space name as first argument. Accepted color spaces are `rgb`, `hsl`, `lab`, `lch`, `oklab`, and `oklch`. ```js chroma('teal').css('hsl'); chroma('teal').css('lab'); chroma('teal').css('oklch'); ``` ### color.rgb #### (round=true) Returns an array with the `red`, `green`, and `blue` component, each as number within the range `0..255`. Chroma internally stores RGB channels as floats but rounds the numbers before returning them. You can pass `false` to prevent the rounding. ```js chroma('orange').rgb(); chroma('orange').darken().rgb(); chroma('orange').darken().rgb(false); ``` ### color.rgba #### (round=true) Just like `color.rgb` but adds the alpha channel to the returned array. ```js chroma('orange').rgba(); chroma('hsla(20, 100%, 40%, 0.5)').rgba(); ``` ### color.hsl Returns an array with the `hue`, `saturation`, and `lightness` component. Hue is the color angle in degree (`0..360`), saturation and lightness are within `0..1`. Note that for hue-less colors (black, white, and grays), the hue component will be NaN. ```js chroma('orange').hsl(); chroma('white').hsl(); ``` ### color.hsv Returns an array with the `hue`, `saturation`, and `value` components. Hue is the color angle in degree (`0..360`), saturation and value are within `0..1`. Note that for hue-less colors (black, white, and grays), the hue component will be NaN. ```js chroma('orange').hsv(); chroma('white').hsv(); ``` ### color.hsi Returns an array with the `hue`, `saturation`, and `intensity` components, each as number between 0 and 255. Note that for hue-less colors (black, white, and grays), the hue component will be NaN. ```js chroma('orange').hsi(); chroma('white').hsi(); ``` ### color.lab Returns an array with the **L**, **a**, and **b** components. ```js chroma('orange').lab() ``` ### color.lch Returns an array with the **Lightness**, **chroma**, and **hue** components. ```js chroma('skyblue').lch() ``` ### color.hcl Alias of [lch](#color-lch), but with the components in reverse order. ```js chroma('skyblue').hcl() ``` ### color.oklab Returns an array with the **L**, **a**, and **b** components in the [OKLab](https://bottosson.github.io/posts/oklab/) color space. ```js chroma('orange').oklab() ``` ### color.oklch Returns an array with the **Lightness**, **chroma**, and **hue** components in the [OKLch](https://bottosson.github.io/posts/oklab/) color space. ```js chroma('skyblue').oklch() ``` ### color.num Returns the numeric representation of the hexadecimal RGB color. ```js chroma('#000000').num(); chroma('#0000ff').num(); chroma('#00ff00').num(); chroma('#ff0000').num(); ``` ### color.temperature Estimate the temperature in Kelvin of any given color, though this makes the only sense for colors from the [temperature gradient](#chroma-temperature) above. ```js chroma('#ff3300').temperature(); chroma('#ff8a13').temperature(); chroma('#ffe3cd').temperature(); chroma('#cbdbff').temperature(); chroma('#b3ccff').temperature(); ``` ### color.gl Like RGB, but in the channel range of `[0..1]` instead of `[0..255]` ```js chroma('33cc00').gl(); ``` ### color.clipped When converting colors from CIELab color spaces to RGB the color channels get clipped to the range of `[0..255]`. Colors outside that range may exist in nature but are not displayable on RGB monitors (such as ultraviolet). you can use color.clipped to test if a color has been clipped or not. ```js [c = chroma.hcl(50, 40, 20), c.clipped()]; [c = chroma.hcl(50, 40, 40), c.clipped()]; [c = chroma.hcl(50, 40, 60), c.clipped()]; [c = chroma.hcl(50, 40, 80), c.clipped()]; [c = chroma.hcl(50, 40, 100), c.clipped()]; ``` As a bonus feature you can access the unclipped RGB components using `color._rgb._unclipped`. ```js chroma.hcl(50, 40, 100).rgb(); chroma.hcl(50, 40, 100)._rgb._unclipped; ``` ## color scales ### chroma.scale #### (colors=['white', 'black']) A color scale, created with `chroma.scale`, is a function that maps numeric values to a color palette. The default scale has the domain `0..1` and goes from white to black. ```js f = chroma.scale(); f(0.25); f(0.5); f(0.75); ``` You can pass an array of colors to `chroma.scale`. Any color that can be read by `chroma()` will work here, too. If you pass more than two colors, they will be evenly distributed along the gradient. ```js chroma.scale(['yellow', '008ae5']); chroma.scale(['yellow', 'red', 'black']); ``` ### scale.domain #### (domain) You can change the input domain to match your specific use case. If called with no arguments, `scale.domain` returns the original array of positions along the scale where the color ramp was sampled. ```js // default domain is [0,1] chroma.scale(['yellow', '008ae5']); // set domain to [0,100] chroma.scale(['yellow', '008ae5']).domain([0,100]); ``` You can use the domain to set the exact positions of each color. ```js // default domain is [0,1] chroma.scale(['yellow', 'lightgreen', '008ae5']) .domain([0,0.25,1]); ``` ### scale.mode #### (mode) As with `chroma.mix`, the result of the color interpolation will depend on the color mode in which the channels are interpolated. The default mode is `RGB`: ```js chroma.scale(['yellow', '008ae5']); ``` This is often fine, but sometimes, two-color `RGB` gradients goes through kind of grayish colors, and `Lab` interpolation produces better results: ```js chroma.scale(['yellow', 'navy']); chroma.scale(['yellow', 'navy']).mode('lab'); ``` Also note how the RGB interpolation can get very dark around the center. You can achieve better results using [linear RGB interpolation](https://www.youtube.com/watch?v=LKnqECcg6Gw): ```js chroma.scale(['#f00', '#0f0']); chroma.scale(['#f00', '#0f0']).mode('lrgb'); ``` Other useful interpolation modes could be `HSL` or `Lch`, though both tend to produce too saturated / glowing gradients. ```js chroma.scale(['yellow', 'navy']).mode('lab'); chroma.scale(['yellow', 'navy']).mode('hsl'); chroma.scale(['yellow', 'navy']).mode('lch'); ``` ### scale.gamma Gamma-correction can be used to "shift" a scale's center more the the beginning (gamma < 1) or end (gamma > 1), typically used to "even" the lightness gradient. Default is 1. ```js chroma.scale('YlGn').gamma(0.5); chroma.scale('YlGn').gamma(1); chroma.scale('YlGn').gamma(2); ``` ### scale.correctLightness This makes sure the lightness range is spread evenly across a color scale. Especially useful when working with [multi-hue color scales](https://www.vis4.net/blog/2013/09/mastering-multi-hued-color-scales/), where simple gamma correction can't help you very much. ```js chroma.scale(['black', 'red', 'yellow', 'white']); chroma.scale(['black', 'red', 'yellow', 'white']) .correctLightness(); ``` ### scale.cache #### (true|false) By default `chroma.scale` instances will cache each computed value => color pair. You can turn off the cache by setting ```js chroma.scale(['yellow', '008ae5']).cache(false); ``` ### scale.padding #### (pad) Reduces the color range by cutting of a fraction of the gradient on both sides. If you pass a single number, the same padding will be applied to both ends. ```js chroma.scale('RdYlBu'); chroma.scale('RdYlBu').padding(0.15); chroma.scale('RdYlBu').padding(0.3); chroma.scale('RdYlBu').padding(-0.15); ``` Alternatively you can specify the padding for each sides individually by passing an array of two numbers. ```js chroma.scale('OrRd'); chroma.scale('OrRd').padding([0.2, 0]); ``` ### scale.colors #### (num, format='hex') You can call `scale.colors(n)` to quickly grab `n` equi-distant colors from a color scale. If called with no arguments, `scale.colors` returns the original array of colors used to create the scale. ```js chroma.scale('OrRd').colors(5); chroma.scale(['white', 'black']).colors(12); ``` If you want to return `chroma` instances just pass *null* as `format`. ### scale.classes #### (numOrArray) If you want the scale function to return a distinct set of colors instead of a continuous gradient, you can use `scale.classes`. If you pass a number the scale will broken into equi-distant classes: ```js // continuous chroma.scale('OrRd'); // class breaks chroma.scale('OrRd').classes(5); chroma.scale('OrRd').classes(8); ``` You can also define custom class breaks by passing them as array: ```js chroma.scale('OrRd').classes([0,0.3,0.55,0.85,1]); ``` ### scale.nodata #### (color) When you pass a non-numeric value like `null` or `undefined` to a chroma.scale, "#cccccc" is returned as fallback or "no data" color. You can change the no-data color: ```js chroma.scale('OrRd')(null); chroma.scale('OrRd')(undefined); chroma.scale('OrRd').nodata('#eee')(null); ``` ### chroma.brewer chroma.js includes the definitions from [ColorBrewer2.org](http://colorbrewer2.org/). Read more about these colors [in the corresponding paper](http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.361.6082&rep=rep1&type=pdf) by Mark Harrower and Cynthia A. Brewer. ```js chroma.scale('YlGnBu'); chroma.scale('Spectral'); ``` To reverse the colors you could simply reverse the domain: ```js chroma.scale('Spectral').domain([1,0]); ``` You can access the colors directly using `chroma.brewer`. ```js chroma.brewer.OrRd ``` ### chroma.bezier #### (colors) `chroma.bezier` returns a function that [bezier-interpolates between colors](https://www.vis4.net/blog/mastering-multi-hued-color-scales/) in `Lab` space. The input range of the function is `[0..1]`. ```js // linear interpolation chroma.scale(['yellow', 'red', 'black']); // bezier interpolation chroma.bezier(['yellow', 'red', 'black']); ``` You can convert an bezier interpolator into a chroma.scale instance ```js chroma.bezier(['yellow', 'red', 'black']) .scale() .colors(5); ``` ## cubehelix ### chroma.cubehelix #### (start=300, rotations=-1.5, hue=1, gamma=1, lightness=[0,1]) Dave Green's [cubehelix color scheme](http://www.mrao.cam.ac.uk/~dag/CUBEHELIX/)!! ```js // use the default helix... chroma.cubehelix(); // or customize it chroma.cubehelix() .start(200) .rotations(-0.5) .gamma(0.8) .lightness([0.3, 0.8]); ``` ### cubehelix.start #### (hue) **start** color for [hue rotation](http://en.wikipedia.org/wiki/Hue#/media/File:HueScale.svg), default=`300` ```js chroma.cubehelix().start(300); chroma.cubehelix().start(200); ``` ### cubehelix.rotations #### (num) number (and direction) of hue rotations (e.g. 1=`360°`, 1.5=`540°``), default=-1.5 ```js chroma.cubehelix().rotations(-1.5); chroma.cubehelix().rotations(0.5); chroma.cubehelix().rotations(3); ``` ### cubehelix.hue #### (numOrRange) hue controls how saturated the colour of all hues are. either single value or range, default=1 ```js chroma.cubehelix(); chroma.cubehelix().hue(0.5); chroma.cubehelix().hue([1,0]); ``` ### cubehelix.gamma #### (factor) gamma factor can be used to emphasise low or high intensity values, default=1 ```js chroma.cubehelix().gamma(1); chroma.cubehelix().gamma(0.5); ``` ### cubehelix.lightness #### (range) lightness range: default: [0,1] (black -> white) ```js chroma.cubehelix().lightness([0,1]); chroma.cubehelix().lightness([1,0]); chroma.cubehelix().lightness([0.3,0.7]); ``` ### cubehelix.scale You can call `cubehelix.scale()` to use the cube-helix through the `chroma.scale` interface. ```js chroma.cubehelix() .start(200) .rotations(-0.35) .gamma(0.7) .lightness([0.3, 0.8]) .scale() // convert to chroma.scale .correctLightness() .colors(5); ``` --- ### CHANGELOG ## Changelog ### 3.2.0 - scale.domain now returns the original domain array when called with no arguments ### 3.1.3 - updated dependencies ### 3.1.2 - fixed a bug in Lch interpolation of hue-less colors ### 3.1.1 - fix: allow deep-imports in vite projects ### 3.1.0 - feat: parse `'transparent'` as black with 0% opacity - resolves [#280](https://github.com/gka/chroma.js/issues/280) - make it easier to access colorbrewer palette names - resolves [#314](https://github.com/gka/chroma.js/issues/314) - docs: explain differences to official colorbrewer scales - resolves [#316](https://github.com/gka/chroma.js/issues/316) - fix: correct parsing of modern css colors with percentage alpha - resolves [#297](https://github.com/gka/chroma.js/issues/297) - fix: css output for hue-less colors in lch() and oklch() - resolves [#357](https://github.com/gka/chroma.js/issues/357) ### 3.0.0 - 🎉 NEW: Add support for modern CSS color spaces. This means you can now export and parse CSS colors in `lab()`, `lch()`, `oklab()`, `oklch()` space. - 🎉 NEW: you can now control the standard white reference point for the CIE Lab and CIE Lch color spaces via `setLabWhitePoint`. - Breaking: `color.css()` will no longer return [legacy CSS colors](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/rgb#legacy_syntax_comma-separated_values) like `rgb(255, 255, 0)` but use modern CSS colors like `rgb(255 255 0)` instead. - fix: you can now use chroma.js both via the default export as well as named exports in ES6. - fix: switch to W3C implementation of OKLab color space ### 2.6.0 - 🎉 NEW: add [`color.shade()`](#color-shade), [`color.tint()`](#color-shade). - fix: remove false w3c color cornflower ### 2.5.0 - refactored code base to ES6 modules ### 2.4.0 - add support for Oklab and Oklch color spaces ### 2.3.0 - use binom of degree n in chroma.bezier ### 2.2.0 - use Delta e2000 for chroma.deltaE #269 ### 2.0.3 - hsl2rgb will, like other x2rgb conversions now set the default alpha to 1 ### 2.0.2 - use a more mangle-safe check for Color class constructor to fix issues with uglifyjs and terser ### 2.0.1 - added `chroma.valid()` for checking if a color can be parsed by chroma.js ### 2.0.0 - chroma.js has been ported from CoffeeScript to ES6! This means you can now import parts of chroma in your projects! - changed HCG input space from [0..360,0..100,0..100] to [0..360,0..1,0..1] (to be in line with HSL) - added new object unpacking (e.g. `hsl2rgb({h,s,l})`) - changed default interpolation to `lrgb` in mix/interpolate and average. - if colors can't be parsed correctly, chroma will now throw Errors instead of silently failing with console.errors ### 1.4.1 - chroma.scale() now interprets `null` as NaN and returns the fallback color. Before it had interpreted `null` as `0` - added `scale.nodata()` to allow customizing the previously hard-coded fallback (aka "no data") color #cccccc ### 1.4.0 - color.hex() now automatically sets the mode to 'rgba' if the colors alpha channel is < 1. so `chroma('rgba(255,0,0,.5)').hex()` will now return `"#ff000080"` instead of `"#ff0000"`. if this is not what you want, you must explicitly set the mode to `rgb` using `.hex("rgb")`. - bugfix in chroma.average in LRGB mode ([#187](https://github.com/gka/chroma.js/issues/187)) - chroma.scale now also works with just one color ([#180](https://github.com/gka/chroma.js/issues/180)) ### 1.3.5 - added LRGB interpolation ### 1.3.4 - passing _null_ as mode in scale.colors will return chroma objects ### 1.3.3 - added [color.clipped](https://gka.github.io/chroma.js/#color-clipped) - added [chroma.distance](https://gka.github.io/chroma.js/#chroma-distance) - added [chroma.deltaE](https://gka.github.io/chroma.js/#chroma-deltae) - [color.set](https://gka.github.io/chroma.js/#color-set) now returns a new chroma instance - chroma.scale now allows [disabling of internal cache](https://gka.github.io/chroma.js/#scale-cache) - [chroma.average](https://gka.github.io/chroma.js/#chroma-average) now works with any color mode - added unit tests for color conversions - use hex colors as default string representation - RGB channels are now stored as floats internally for higher precision - bugfix with cubehelix and constant lightness - bugfix in chroma.limits quantiles - bugfix when running scale.colors(1) - bugfix in hsi2rgb color conversion ### 1.2.2 - scale.colors() now returns the original colors instead of just min/max range ### 1.2.0 - added chroma.average for averaging colors ### 1.1.0 - refactored chroma.scale - changed behaviour of scale.domain - added scale.classes - added scale.padding ### 1.0.2 - standardized alpha channel construction - chroma.bezier automatically returns chroma.scale ### 1.0.1 - added simple color output to chroma.scale().colors() ### 1.0.0 - numeric interpolation does what it should - refactored and modularized code base - changed argument order of Color::interpolate --- ### Readme # Chroma.js [Chroma.js](https://vis4.net/chromajs/) is a ~~tiny~~ [small-ish](https://bundlejs.com/?q=chroma-js) zero-dependency JavaScript library for all kinds of color conversions and color scales. [](https://travis-ci.com/gka/chroma.js) [](https://bundlejs.com/?q=chroma-js) ### Usage Install from npm ``` npm install chroma-js ``` Import package into project ```javascript import chroma from "chroma-js"; ``` Initiate and manipulate colors: ```javascript chroma('#D4F880').darken().hex(); // #a1c550 ``` Working with color scales is easy, too: ```javascript scale = chroma.scale(['white', 'red']); scale(0.5).hex(); // #FF7F7F ``` Lab/Lch interpolation looks better than RGB ```javascript chroma.scale(['white', 'red']).mode('lab'); ``` Custom domains! Quantiles! Color Brewer!! ```javascript chroma.scale('RdYlBu').domain(myValues, 7, 'quantiles'); ``` And why not use logarithmic color scales once in your life? ```javascript chroma.scale(['lightyellow', 'navy']).domain([1, 100000], 7, 'log'); ``` ### Like it? Why not dive into the [interactive documentation](http://gka.github.io/chroma.js/) (there's a [static version](https://github.com/gka/chroma.js/blob/master/docs/src/index.md), too). You can download [chroma.min.js](https://raw.github.com/gka/chroma.js/master/chroma.min.js) or use the [hosted version on unpkg.com](https://app.unpkg.com/chroma-js@latest/files/dist). You can use it in node.js, too! npm install chroma-js Or you can use it in SASS using [chromatic-sass](https://github.com/bugsnag/chromatic-sass)! ### Want to contribute? Come over and say hi in our [Discord channel](https://discord.gg/7fgurEqTRe)! ### Build instructions First clone the repository and install the dev dependencies: git clone git@github.com:gka/chroma.js.git cd chroma.js npm install Then compile the coffee-script source files to the build files: npm run build Don't forget to tests your changes! You will probably also want to add new test to the `/test` folder in case you added a feature. npm test And to update the documentation just run npm run docs To preview the docs locally you can use npm run docs-preview ### Similar Libraries / Prior Art * [Chromatist](https://github.com/jrus/chromatist) * [GrapeFruit](https://github.com/xav/Grapefruit) (Python) * [colors.py](https://github.com/mattrobenolt/colors.py) (Python) * [d3.js](https://github.com/mbostock/d3) * [Color Art](https://github.com/JiatLn/color-art) (Rust) ### Author Chroma.js is written by [Gregor Aisch](http://driven-by-data.net). ### License Released under [BSD license](http://opensource.org/licenses/BSD-3-Clause). Versions prior to 0.4 were released under [GPL](http://www.gnu.org/licenses/gpl-3.0). ### Further reading * [How To Avoid Equidistant HSV Colors](https://www.vis4.net/blog/avoid-equidistant-hsv-colors/) * [Mastering Multi-hued Color Scales with Chroma.js](https://www.vis4.net/blog/mastering-multi-hued-color-scales/) ### FAQ **There have been no commits in X weeks. Is chroma.js dead?** No! It's just that the author of this library has other things to do than devoting every week of his life to making cosmetic changes to a piece of software that is working just fine as it is, just so that people like you don't feel like it's abandoned and left alone in this world to die. Bugs will be fixed. Some new things will come at some point. Patience. **I want to help maintaining chroma.js!** Yay, that's awesome! Please say hi at our [Discord chat](https://discord.gg/m2M7k5Nf) to get in touch ---