<h1>Lightness functions</h1>
<div class="container">
<div class="innercont inputcont">
<label for="color">Enter color:</label>
<input type="color" name="color" id="color">
</div>
<div class="innercont buttoncont">
<button id="increase-sat">Increase lightness
</button>
<button id="decrease-sat">Decrease lightness</button>
</div>
<div class="innercont outputcont">
<label for="output" id="output-label"> Resulting color: </label>
<span id="hash-output">#000000</span>
<span id="rgb-output">rgb(0,0,0)</span>
<span id="hsl-output">hsl(0°,0%,0%)</span>
</div>
</div>
* {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica,
Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
margin: 0px;
padding: 0px;
box-sizing: border-box;
}
body {
display: flex;
flex-direction: column;
align-items: center;
}
.container {
margin: 3em;
display: flex;
align-items: flex-start;
max-width: 800px;
}
@media only screen and (max-width: 800px) {
.container {
display: flex;
flex-direction: column;
height: 400px;
justify-content: space-around;
}
}
label {
font-weight: bold;
}
button {
padding: 1vw;
margin: 1vw 0vw;
border-radius: 1.5vw;
font-weight: bold;
width: 15vw;
min-width: 100px;
}
.inputcont {
order: 2;
display: flex;
flex-direction: column;
align-items: center;
}
.buttoncont {
order: 1;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.outputcont {
order: 3;
display: flex;
flex-direction: column;
align-items: center;
}
.innercont {
height: 20vw;
max-height: 250px;
width: 50vw;
margin: 0vw 1vw;
}
#color {
display: block;
background-color: inherit;
appearance: none;
-webkit-appearance: none;
width: 100%;
flex-grow: 1;
box-sizing: inherit;
border-radius: 1.5vw;
}
#color::-webkit-color-swatch {
border-radius: 1.5vw;
}
#color::-moz-color-swatch {
border-radius: 1.5vw;
}
//Grab dom nodes
const colorInput = document.getElementById("color");
const hashOutput = document.getElementById("hash-output");
const rgbOutput = document.getElementById("rgb-output");
const hslOutput = document.getElementById("hsl-output");
const increase = document.getElementById("increase-sat");
const decrease = document.getElementById("decrease-sat");
//Add event listeners
colorInput.addEventListener("input", onColorInput);
increase.addEventListener("click", onIncreaseClick);
decrease.addEventListener("click", onDecreaseClick);
//Set output to match input on change
function onColorInput(e) {
hashOutput.textContent = e.target.value;
rgbOutput.textContent = hexToRgb(e.target.value);
hslOutput.textContent = rgbToHsl(hexToRgb(e.target.value));
}
//functionality for saturation buttons
function onIncreaseClick(e) {
result = rgbToHex(lightenByTenth(hexToRgb(colorInput.value)));
hashOutput.textContent = result;
rgbOutput.textContent = hexToRgb(result);
hslOutput.textContent = rgbToHsl(hexToRgb(result));
colorInput.value = result;
}
function onDecreaseClick(e) {
result = rgbToHex(darkenByTenth(hexToRgb(colorInput.value)));
hashOutput.textContent = result;
rgbOutput.textContent = hexToRgb(result);
hslOutput.textContent = rgbToHsl(hexToRgb(result));
colorInput.value = result;
}
//manipulation functions
function hexToRgb(h) {
var r = parseInt(cutHex(h).substring(0, 2), 16),
g = parseInt(cutHex(h).substring(2, 4), 16),
b = parseInt(cutHex(h).substring(4, 6), 16);
return "rgb(" + r + "," + g + "," + b + ")";
}
function cutHex(h) {
return h.charAt(0) == "#" ? h.substring(1, 7) : h;
}
function rgbToHex(rgb) {
const [red, green, blue] = rgb
.replace(/ /g, "")
.slice(4, -1)
.split(",")
.map((e) => parseInt(e));
return "#" + toHex(red) + toHex(green) + toHex(blue);
}
function toHex(n) {
n = parseInt(n, 10);
if (isNaN(n)) return "00";
n = Math.max(0, Math.min(n, 255));
return (
"0123456789ABCDEF".charAt((n - (n % 16)) / 16) +
"0123456789ABCDEF".charAt(n % 16)
);
}
function lightenByTenth(rgb) {
// Our rgb to int array function again
const rgbIntArray = rgb.replace(/ /g, '').slice(4, -1).split(',').map(e => parseInt(e));
const [lowest,middle,highest]=getLowestMiddleHighest(rgbIntArray);
if(lowest.val===255){
return rgb;
}
const returnArray = [];
returnArray[lowest.index]= Math.round(lowest.val+(Math.min(255-lowest.val,25.5)));
const increaseFraction = (returnArray[lowest.index]-lowest.val)/ (255-lowest.val);
returnArray[middle.index]= middle.val +(255-middle.val)*increaseFraction ;
returnArray[highest.index]= highest.val +(255-highest.val)*increaseFraction ;
// Convert the array back into an rgb string
return (`rgb(${returnArray.join()})`);
}
function darkenByTenth(rgb) {
// Our rgb to int array function again
const rgbIntArray = rgb.replace(/ /g, '').slice(4, -1).split(',').map(e => parseInt(e));
const [lowest,middle,highest]=getLowestMiddleHighest(rgbIntArray);
if(highest.val===0){
return rgb;
}
const returnArray = [];
returnArray[highest.index] = highest.val-(Math.min(highest.val,25.5));
const decreaseFraction =(highest.val-returnArray[highest.index])/ (highest.val);
returnArray[middle.index]= middle.val -middle.val*decreaseFraction;
returnArray[lowest.index]= lowest.val -lowest.val*decreaseFraction;
// Convert the array back into an rgb string
return (`rgb(${returnArray.join()}) `);
}
function getLowestMiddleHighest(rgbIntArray) {
let highest = {val:-1,index:-1};
let lowest = {val:Infinity,index:-1};
rgbIntArray.map((val,index)=>{
if(val>highest.val){
highest = {val:val,index:index};
}
if(val<lowest.val){
lowest = {val:val,index:index};
}
});
if(lowest.index===highest.index){
lowest.index=highest.index+1;
}
let middle = {index: (3 - highest.index - lowest.index)};
middle.val = rgbIntArray[middle.index];
console.log([lowest,middle,highest]);
return [lowest,middle,highest];
}
function getLightnessOfRGB(rgbString) {
// First convert to an array of integers by removing the whitespace, taking the 3rd char to the 2nd last then splitting by ','
const rgbIntArray = rgbString.replace(/ /g, '').slice(4, -1).split(',').map(e => parseInt(e));
// Get the highest and lowest out of red green and blue
const highest = Math.max(...rgbIntArray);
const lowest = Math.min(...rgbIntArray);
// Return the average divided by 255
return (highest + lowest) / 2 / 255;
}
function rgbToHsl(rgb){
let [r,g,b]= rgb.replace(/ /g, '').slice(4, -1).split(',').map(e => parseInt(e));
r /= 255;
g /= 255;
b /= 255;
// Find greatest and smallest channel values
let cmin = Math.min(r,g,b),
cmax = Math.max(r,g,b),
delta = cmax - cmin,
h = 0,
s = 0,
l = 0;
if (delta == 0)
h = 0;
// Red is max
else if (cmax == r)
h = ((g - b) / delta) % 6;
// Green is max
else if (cmax == g)
h = (b - r) / delta + 2;
// Blue is max
else
h = (r - g) / delta + 4;
h = Math.round(h * 60);
// Make negative hues positive behind 360°
if (h < 0)
h += 360;
l = (cmax + cmin) / 2;
// Calculate saturation
s = delta == 0 ? 0 : delta / (1 - Math.abs(2 * l - 1));
// Multiply l and s by 100
s = +(s * 100).toFixed(1);
l = +(l * 100).toFixed(1);
return "hsl(" + h + "," + Math.round(s) + "%," + Math.round(l) + "%)";
}
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.