HSL to RGB
by Lamik
HTML
<div>
<button class="btn" onclick="setColIndexChart(0)">Chart R</button>
<button class="btn" onclick="setColIndexChart(1)">Chart G</button>
<button class="btn" onclick="setColIndexChart(2)">Chart B</button>
</div>
<div>Luminance <input type="range" min="0" max="100" value="50" oninput="setLum(event)"></div>
<div>Saturation <input type="range" min="0" max="100" value="100" oninput="setSat(event)"></div>
<div>Wiki-Opt max <span id="error"></span> </div>
<div id="labelOpt">Optimized</div>
<svg viewBox="0 0 360 60" class="chart">
<text x="0" y="59" class="axis">0</text>
<text x="0" y="10" class="axis">1</text>
<text x="320" y="59" class="axis">360 hue</text>
<polyline id="chartA" fill="none" stroke="#0074d9" stroke-width="1" points=""/>
</svg>
<div id="labelWiki">Wiki</div>
<svg viewBox="0 0 360 60" class="chart">
<text x="0" y="59" class="axis">0</text>
<text x="0" y="10" class="axis">1</text>
<text x="320" y="59" class="axis">360 hue</text>
<polyline id="chartB" fill="none" stroke="#0074d9" stroke-width="1" points=""/>
</svg>
<div class="test">
<div id="colA" class="col"></div>
<div id="colB" class="col"></div>
</div>
CSS
.col { margin: 5px; width: 50px; height: 50px; }
#btn { display: block; margin: 10px; }
.test { display: flex; height: 400px}
.color { width: 50px; height: 1px; }
.chart { border: 1px solid black; }
.axis { font: 10px sans-serif;}
#labelOpt { margin-top: 20px }
JavaScript
function hsl2rgb(h,s,l)
{
let a=s*Math.min(l,1-l);
let f= (n,k=(n+h/30)%12) => l - a*Math.max(Math.min(k-3,9-k,1),-1);
return [f(0),f(8),f(4)];
}
function hsl2rgb_wiki(h,s,l) {
let c = (1-Math.abs(2*l-1))*s;
let k = h/60;
let x = c*(1 - Math.abs(k%2-1));
let r1 = g1 = b1 = 0;
if(k>=0 && k<=1) { r1=c; g1=x }
if(k>1 && k<=2) { r1=x; g1=c }
if(k>2 && k<=3) { g1=c; b1=x }
if(k>3 && k<=4) { g1=x; b1=c }
if(k>4 && k<=5) { r1=x; b1=c }
if(k>5 && k<=6) { r1=c; b1=x }
let m = l - c/2;
return [r1+m,g1+m,b1+m]
}
// ----------------------------
// TEST code
// ----------------------------
$ = x=>document.querySelector(x);
function calcMaxError() {
s = colorSat;
l = colorLum;
err = [];
for(let h=0; h<361; h++) {
o = hsl2rgb(h,s,l);
w = hsl2rgb_wiki(h,s,l);
e = Math.max( Math.abs(o[0]-w[0]), Math.abs(o[1]-w[1]), Math.abs(o[2]-w[2]));
err.push({ h, e });
}
err.sort((a,b)=> b.e-a.e);
$('#error').innerHTML = `err=${err[0].e} for hue=${err[0].h}°`
}
function setColors(h,s,l) {
opt = hsl2rgb(h,s,l);
wiki = hsl2rgb_wiki(h,s,l);
chartAA( h, opt[colorIdx]);
chartBB( h, wiki[colorIdx]);
$('#colA').insertAdjacentHTML('beforeend', `<div class="color" style="background: ${rgbToStyle(opt)}"</div>`);
$('#colB').insertAdjacentHTML('beforeend',`<div class="color" style="background: ${rgbToStyle(wiki)}"</div>`);
}
function refresh() {
s = colorSat;
l = colorLum;
$('#colA').innerHTML = "opt";
$('#colB').innerHTML = "wiki";
chartAA(0,0,1); chartBB(0,0,1); // clean charts
let info = ['R','G','B'][colorIdx]
+ ` (lum: ${colorLum}, sat: ${colorSat})`;
$('#labelWiki').innerHTML = "Wiki " + info;
$('#labelOpt').innerHTML = "Optimized " + info;
calcMaxError();
for(let h=0; h<361; h++) setColors(h,s,l);
}
function rgbToStyle(c) {
return...