colorjs.io
Version:
Color space agnostic color manipulation library
156 lines (143 loc) • 7.27 kB
HTML
<html>
<head>
<title>Interpolation • Color.js</title>
<meta name="viewport" content="width=device-width" />
<link rel="shortcut icon" href="../logo.svg">
<link rel="stylesheet" href="../assets/css/style.css">
<script src="../color.js" type="module"></script>
<link rel="stylesheet" href="../assets/css/docs.css" />
</head>
<body class="language-js">
<header>
<nav>
<a href=".." class="logo"><h1 class="logo"><img src="../logo.svg" alt="Color.js"></h1></a>
<a href="../get/">Get<span class="wide"> Color.js</span></a>
<a href="../docs/">Docs</a>
<a href="../api/">API</a>
<a href="../notebook/">Play!</a>
<a href="../apps/">Demos</a>
<a href="../tests/" class="footer">Tests</a>
<a href="https://github.com/LeaVerou/color.js">GitHub</a>
<a href="https://github.com/LeaVerou/color.js/issues/new" class="footer">File bug</a>
</nav>
<h1>Interpolation</h1>
</header>
<main>
<aside id="toc">
<ul>
<li><a href="the-color-object.html">The Color object</a></li>
<li><a href="spaces.html">Supported color spaces</a></li>
<li><a href="color-difference.html">Color difference</a></li>
<li><a href="manipulation.html">Color manipulation</a></li>
<li><a href="gamut-mapping.html">Gamut Mapping</a></li>
<li><a href="interpolation.html">Interpolation</a></li>
<li><a href="adaptation.html">Chromatic Adaptation</a></li>
<li><a href="output.html">Output</a></li>
</ul>
</aside>
<h2 id="ranges">Ranges</h2>
<p><a href="../api/#Color#range"><code>color.range()</code></a> and <a href="../api/#Color.range"><code>Color.range()</code></a> are at the core of Color.js’ interpolation engine.
They give you a function that accepts a number and returns a color.
For numbers in the range 0 to 1, the function <em>interpolates</em>; for numbers outside that range, the function <em>extrapolates</em> (and thus, may not return the results you expect):</p>
<pre><code class="js language-js"> let color = new Color("p3", [0, 1, 0]);
let redgreen = color.range("red", {
space: "lch", // interpolation space
outputSpace: "srgb"
});
redgreen(.5); // midpoint</code></pre>
<p>Percentages (0 to 100%) should be converted to numbers (0 to 1).</p>
<p>The <code>space</code> parameter controls the <a href="spaces.html">color space</a>
interpolation occurs in, and defaults to Lab.
Colors do not need to be in that space, they will be converted for interpolation.
The interpolation space can make a big difference in the result:</p>
<pre><code class="js language-js">let c1 = new Color("rebeccapurple");
let c2 = new Color("lch", [85, 100, 85]);
c1.range(c2); // lab
c1.range(c2, {space: "lch"});
c1.range(c2, {space: "srgb"}); // gamma corrected sRGB
c1.range(c2, {space: "xyz"}); // XYZ, same result as linear RGB
c1.range(c2, {space: "hsl"});
c1.range(c2, {space: "hwb"});</code></pre>
<p>Note that for color spaces with a hue angle there are multiple ways to interpolate, which can produce drastically different results.
The <code>hue</code> argument is inspired by <a href="https://drafts.csswg.org/css-color-5/#hue-adjuster">the hue-adjuster in CSS Color 5</a>.</p>
<pre><code class="js language-js">let c1 = new Color("rebeccapurple");
c1.lch;
let c2 = new Color("lch", [85, 85, 85 + 720]);
c1.range(c2, {space: "lch", hue: "longer"});
c1.range(c2, {space: "lch", hue: "shorter"});
c1.range(c2, {space: "lch", hue: "increasing"});
c1.range(c2, {space: "lch", hue: "decreasing"});
c1.range(c2, {space: "lch", hue: "raw"});
c1.range(c2, {space: "lch"}); // default is "shorter"</code></pre>
<p>Range interpolates between colors as they were at the time of its creation.
If you change the colors afterwards, the range will not be affected:</p>
<pre><code class="js language-js"> let color = new Color("red");
let color2 = new Color("black");
let gradient = color.range(color2);
color.coords[1] = 1;
color2.coords[2] = 1;
gradient(.5);
gradient = color.range(color2);
gradient(.5);</code></pre>
<p>Interpolating between a coordinate and <code>NaN</code> keeps that coordinate constant.
This is useful for achromatic transitions:</p>
<pre><code class="js language-js">let lime = new Color("p3", [0, 1, 0]);
let white = new Color("lch", [100, 0, 0]);
let white2 = new Color("lch", [100, 0, NaN]);
let limewhite = lime.range(white, {space: "lch"});
let limewhite2 = lime.range(white2, {space: "lch"});
// Two kinds of fade out to transparent
lime.range(new Color("transparent"));
lime.range(new Color(lime.space, [NaN, NaN, NaN], 0), {space: lime.space});</code></pre>
<p>You can use the <code>progression</code> parameter to customize the progression and make it non-linear:</p>
<pre><code class="js language-js"> let r = new Color("lch(50 50 0)").range("lch(90 50 20)");
Color.range(r, {progression: p => p ** 3});</code></pre>
<p>Note that you can use <code>Color.range(rangeFunction)</code> to modify a range after it has been created, as you can see in the example above.
This produces a new range, and leaves the old one unaffected.</p>
<h2 id="interpolation-by-discrete-steps">Interpolation by discrete steps</h2>
<p><a href="../api/#Color#steps"><code>color.steps()</code></a> and <a href="../api/#Color.steps"><code>Color.steps()</code></a> give you an array of discrete steps.</p>
<pre><code class="js language-js"> let color = new Color("p3", [0, 1, 0]);
color.steps("red", {
space: "lch",
outputSpace: "srgb",
maxDeltaE: 3, // max deltaE between consecutive steps (optional)
steps: 10 // min number of steps
});</code></pre>
<p>By default, the deltaE76 function is used.</p>
<h2 id="mixing-colors">Mixing colors</h2>
<p>Interpolation can be used to create color mixtures,
in any desired proportion,
between two colors.</p>
<p>Shortcut for specific points in the range:</p>
<pre><code class="js language-js"> let color = new Color("p3", [0, 1, 0]);
let redgreen = color.mix("red", .5, {space: "lch", outputSpace: "srgb"});
let reddishGreen = color.mix("red", .25, {space: "lch", outputSpace: "srgb"});</code></pre>
<p>Static syntax, for one-off mixing:</p>
<pre><code class="js language-js"> Color.mix("color(display-p3 0 1 0)", "red", .5);</code></pre>
<footer>
<a href="../notebook/index.html?storage=https://github.com/leaverou/color.js/docs/interpolation.md" class="edit-page" target="_blank">
Edit this page on Color Notebook
</a>
</footer>
</main>
<footer>
From <a href="http://lea.verou.me">Lea Verou</a> (co-editor of CSS Color 5)
and <a href="https://svgees.us">Chris Lilley</a> (co-editor of CSS Color 3, 4, and 5; W3C representative to ICC)
<nav>
<a href="../get/">Get<span class="wide"> Color.js</span></a>
<a href="../docs/">Docs</a>
<a href="../api/">API</a>
<a href="../notebook/">Play!</a>
<a href="../apps/">Demos</a>
<a href="../tests/" class="footer">Tests</a>
<a href="https://github.com/LeaVerou/color.js">GitHub</a>
<a href="https://github.com/LeaVerou/color.js/issues/new" class="footer">File bug</a>
</nav>
</footer>
<script src="../assets/js/prism.js"></script>
<script src="https://blissfuljs.com/bliss.shy.js"></script>
<script src="https://live.prismjs.com/src/prism-live.js?load=javascript" async></script>
<script src="../assets/js/index.js" type="module"></script>
</body>
</html>