Skip to content

Instantly share code, notes, and snippets.

@nitobuendia
Last active February 26, 2022 10:43
Show Gist options
  • Save nitobuendia/19bcb05fda3d61ecf64237958c730254 to your computer and use it in GitHub Desktop.
Save nitobuendia/19bcb05fda3d61ecf64237958c730254 to your computer and use it in GitHub Desktop.
A gradient calculator in pure vanilla JavaScript
/**
* @typdef {{
* r: number,
* g: number,
* b: number
* }}
*/
let Color;
/**
* Converts a color in hex form and returns its RGB form.
* @param {string} hexColor Color in hex form (e.g. #000000).
* @return {!Color} Color in RGB form.
*/
function hexToRgb(hexColor) {
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hexColor);
return result ? {
r: parseInt(result[1], 16),
g: parseInt(result[2], 16),
b: parseInt(result[3], 16)
} : null;
}
/**
* Converts a number into hex form (2 characters).
* @param {number} Number to convert to hex.
* @return {string} Number in hex form, 2 characters.
*/
function componentToHex(c) {
const hex = c.toString(16);
return hex.length == 1 ? '0' + hex : hex;
}
/**
* Converts a color in RGB form and returns its hex form.
* @param {!Color} rgbColor Color in RGB form.
* @return {string} Color in hex form (e.g. #000000).
*/
function rgbToHex(rgbColor) {
return '#' +
componentToHex(rgbColor['r']) +
componentToHex(rgbColor['g']) +
componentToHex(rgbColor['b']);
}
/**
* Calculate the slope between two numbers given a number of steps.
* @param {number} startInt Initial number.
* @param {number} endInt End number.
* @param {number} steps Number of steps to take in between start and end.
* @return {number} Slope to get from start to end int in given steps.
*/
function getSlope(startInt, endInt, steps) {
return (endInt - startInt) / steps;
}
/**
* Calculates gradient of colors between two colors.
* @param {string} startHexColor Starting color in Hex form.
* @param {string} endHexColor Ending color in Hex form.
* @param {number=} gradientSteps Number of colors to return in between.
* @return {!Array<string>} List of colors in Hex form in between.
*/
function calculateGradient(startHexColor, endHexColor, gradientSteps = 1) {
const startRgbColor = hexToRgb(startHexColor);
const endRgbColor = hexToRgb(endHexColor);
const rSlope = (endRgbColor['r'] - startRgbColor['r']) / (gradientSteps + 1);
const gSlope = (endRgbColor['g'] - startRgbColor['g']) / (gradientSteps + 1);
const bSlope = (endRgbColor['b'] - startRgbColor['b']) / (gradientSteps + 1);
const colors = [];
for (let c = 1; c <= gradientSteps; c++) {
colors.push(rgbToHex({
'r': Math.round(startRgbColor['r'] + rSlope * c),
'g': Math.round(startRgbColor['g'] + gSlope * c),
'b': Math.round(startRgbColor['b'] + bSlope * c),
}));
}
return colors;
}
/**
* Calculates gradient between start and end color in the input values.
* Takes into consideration the number of steps input.
* Adds the colors generated to the screen.
*/
function calculateColors() {
const startHexColor = document.getElementById('startHexColor').value;
const endHexColor = document.getElementById('endHexColor').value;
const gradientSteps = parseInt(document.getElementById('gradientSteps').value, 0);
const gradientColors =
calculateGradient(startHexColor, endHexColor, gradientSteps);
const fullGradient = [startHexColor, ...gradientColors, endHexColor];
addColorsToScreen(fullGradient);
}
/**
* Changes the background and title of a color box/layer.
* @param {!Element} colorBox Layer to which to change background color.
* @param {string} color Color to which to change background.
*/
function changeColorBoxColor(colorBox, color) {
colorBox.className = 'colorBox';
colorBox.setAttribute('alt', color);
colorBox.setAttribute('title', color);
colorBox.style.backgroundColor = color;
}
/**
* Generates a color box for each color in the array into gradients layer.
* @param {!Array<string>} colors List of colors in hex to add to screen.
*/
function addColorsToScreen(colors) {
const colorLayer = document.getElementById('gradients');
colorLayer.innerHTML = '';
for (const color of colors) {
const colorBox = document.createElement('div');
changeColorBoxColor(colorBox, color);
colorLayer.appendChild(colorBox);
}
}
<html>
<head>
<title>Calculate gradient colors</title>
<script src="hex.js"></script>
<script src="html.js"></script>
<link rel="stylesheet" href="main.css" />
</head>
<body>
<div id="gradients">
<div class="colorBox" alt="#ffffff" title="#ffffff" style="background-color: #ffffff;"></div>
<div class="colorBox" alt="#000000" title="#000000" style="background-color: #000000;"></div>
</div>
<input type="text" name="startHexColor" id="startHexColor" value="#ffffff" />
<input type="text" name="endHexColor" id="endHexColor" value="#000000" />
<input type="number" name="gradientSteps" id="gradientSteps" maxlength="3" value="0" />
<button id="calculateColors">Calculate Gradient</button>
<script>
/** Add colors to screen. */
const button = document.getElementById('calculateColors');
button.addEventListener('click', calculateColors);
const startHexColorLayer = document.getElementById('startHexColor');
startHexColorLayer.addEventListener('input', calculateColors);
const endHexColorLayer = document.getElementById('endHexColor');
endHexColorLayer.addEventListener('input', calculateColors);
</script>
</body>
</html>
html,
body {
margin: 0;
padding: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
font-size: 24pt;
}
body {
text-align: center;
}
.colorBox {
display: inline-block;
height: 3em;
width: 3em;
padding: 0.5em;
margin: 1em;
border: 1px solid black;
}
button {
font-size: 1em;
padding: 0.5em;
}
input {
font-size: 1em;
text-align: center;
padding: 0.5em;
}
#startHexColor,
#endHexColor {
width: 7em;
}
#gradientSteps {
width: 3em;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment