JSFiddle - React, Tailwind, and code Playground

Color ramp with color blend operation and opacity/saturation changes.

by Travis Almand

HTML

<label><input type="color" id="guidance_color" value="#3C8081" /> Guidance Color</label>
<label><input type="color" id="affordance_color" value="#F47929" /> Affordance Color</label>

<canvas id="canvas" width="10" height="10"></canvas>

<div id="titles">
  <span>steps</span>
  <span>guidance</span>
  <span>affordance</span>
  <span>grayscale ramp</span>
  <span>opacity ramp</span>
</div>

<div id="output">
  <div id="steps">
    <div>50</div>
    <div>100</div>
    <div>200</div>
    <div>300</div>
    <div>400</div>
    <div>500</div>
    <div>600</div>
    <div>700</div>
    <div>800</div>
    <div>900</div>
  </div>
  <div id="guidance">
    <div class="swatch guidance50"></div>
    <div class="swatch guidance100"></div>
    <div class="swatch guidance200"></div>
    <div class="swatch guidance300"></div>
    <div class="swatch guidance400"></div>
    <div class="swatch guidance500"></div>
    <div class="swatch guidance600"></div>
    <div class="swatch guidance700"></div>
    <div class="swatch guidance800"></div>
    <div class="swatch guidance900"></div>
  </div>
  <div id="affordance">
    <div class="swatch affordance50"></div>
    <div class="swatch affordance100"></div>
    <div class="swatch affordance200"></div>
    <div class="swatch affordance300"></div>
    <div class="swatch affordance400"></div>
    <div class="swatch affordance500"></div>
    <div class="swatch affordance600"></div>
    <div class="swatch affordance700"></div>
    <div class="swatch affordance800"></div>
    <div class="swatch affordance900"></div>
  </div>
  <div id="grayscaleRamp">
    <label><input type="color" value="" data-step="50" /> <span class="color"></span></label>
    <label><input type="color" value="" data-step="100" /> <span class="color"></span></label>
    <label><input type="color" value="" data-step="200" /> <span class="color"></span></label>
    <label><input type="color" value="" data-step="300" /> <span class="color"></span></label>
    <label><input...

SCSS

label {
  display: block;
  margin: 10px;
}

#titles {
  span {
    display: inline-block;
    text-indent: 5px;
  }
  span:nth-child(1) {
    width: 44px;
  }
  span:nth-child(2),
  span:nth-child(3){
    width: 120px;
  }
  span:nth-child(4) {
    width: 160px;
  }
  span:nth-child(5) {
    width: 218px;
  }
}

#steps div {
  align-items: center;
  display: flex;
  height: 25px;
  justify-content: center;
  margin: 10px;
}

#output {
  background-color: var(--outputColor);
  display: flex;
  
  .swatch {
    height: 25px;
    margin: 10px;
    width: 100px;
  }
  
  label {
    height: 25px;
    margin: 10px;
  }
  
  .guidance50 { background-color: var(--guidance50); transition: 0.25s 0s; };
  .guidance100 { background-color: var(--guidance100); transition: 0.25s 0.1s; };
  .guidance200 { background-color: var(--guidance200); transition: 0.25s 0.2s; };
  .guidance300 { background-color: var(--guidance300); transition: 0.25s 0.3s; };
  .guidance400 { background-color: var(--guidance400); transition: 0.25s 0.4s; };
  .guidance500 { background-color: var(--guidance500); transition: 0.25s 0.5s; };
  .guidance600 { background-color: var(--guidance600); transition: 0.25s 0.6s; };
  .guidance700 { background-color: var(--guidance700); transition: 0.25s 0.7s; };
  .guidance800 { background-color: var(--guidance800); transition: 0.25s 0.8s; };
  .guidance900 { background-color: var(--guidance900); transition: 0.25s 0.9s; };
  
  .affordance50 { background-color: var(--affordance50); transition: 0.25s 0s; };
  .affordance100 { background-color: var(--affordance100); transition: 0.25s 0.1s; };
  .affordance200 { background-color: var(--affordance200); transition: 0.25s 0.2s; };
  .affordance300 { background-color: var(--affordance300); transition: 0.25s 0.3s; };
  .affordance400 { background-color: var(--affordance400); transition: 0.25s 0.4s; };
  .affordance500 { background-color: var(--affordance500); transition: 0.25s 0.5s; };
  .affordance600 { background-color:...

JavaScript

console.clear();

// the two base colors
const guidanceColor = document.querySelector('#guidance_color');
const affordanceColor = document.querySelector('#affordance_color');

// background color of the whole panel for comparing against base colors
const outputColor = document.querySelector('#output_color');

// the grayscale ramp color inputs
const grayscaleButtons = document.querySelectorAll('#grayscaleRamp input');

// the opacity ramp percentage sliders
const opacitySliders = document.querySelectorAll('#opacityRamp input');

// canvas stuff
const canvas = document.createElement('canvas');
canvas.width = 10;
canvas.height = 10;
const ctx = canvas.getContext('2d');

// change these values to alter the default grayscale ramp
// these are the colors that are under the base color
const grayscaleRamp = {
	50: '#F2F2F2',
  100: '#E6E6E6',
  200: '#CCCCCC',
  300: '#B3B3B3',
  400: '#999999',
  500: '#808080',
  600: '#666666',
  700: '#4D4D4D',
  800: '#333333',
  900: '#1A1A1A'
};

// change these values to alter the default opacity ramp
// these values are applied to the black swatch that desaturates the base color
const opacityRamp = {
	50: 0.9,
  100: 0.8,
  200: 0.7,
  300: 0.35,
  400: 0,
  500: 0,
  600: 0,
  700: 0,
  800: 0,
  900: 0
};
let pickedColors = {};

// set grayscale button defaults from grayscaleRamp object
Object.entries(grayscaleRamp).forEach((entry, index) => {
  grayscaleButtons[index].value = entry[1];
  grayscaleButtons[index].nextElementSibling.innerText = entry[1];
});

// set opacity slider defaults from opacityRamp object
Object.entries(opacityRamp).forEach((entry, index) => {
	opacitySliders[index].value = entry[1];
  opacitySliders[index].nextElementSibling.innerText = entry[1];
});

// main function that creates/updates canvas and passes values to CSS variables
function setColors() {
	// builds rgba string from pixel data passed from canvas
	function getColor (imageData) {
    return `rgba(${imageData.data[0]}, ${imageData.data[1]},...