2022-11-20 22:54:54 +01:00
<!DOCTYPE html>
< head >
< title > Named Colors Wheel< / title >
< style >
2022-11-21 01:50:27 +01:00
body {
2022-11-21 01:51:45 +01:00
font-family: sans-serif;
2022-11-21 01:50:27 +01:00
text-align: center;
}
2022-11-21 03:21:50 +01:00
.swatch {
2022-11-21 01:51:45 +01:00
display: inline-block;
min-width: 5em;
}
2022-11-21 02:16:00 +01:00
#about-link {
margin: 1ex;
position: absolute;
right: 0;
text-decoration: none;
top: 0;
}
#about {
background: white;
border: 2px solid black;
display: none;
color: black;
left: 0;
margin: 0 10em;
position: fixed;
top: 10em;
}
#about:target {
display: block;
}
#about .close {
color: black;
float: right;
margin: 1ex;
text-decoration: none;
}
2022-11-21 02:18:38 +01:00
svg {
clip-path: circle(300px at center);
}
2022-11-21 03:21:50 +01:00
#css1 h1 {
display: inline-block;
margin: 1ex 1em;
width: 5em;
}
2022-11-20 22:54:54 +01:00
< / style >
< / head >
< body >
< svg
baseProfile="full"
height="600"
version="1.1"
viewbox="0 0 1024 1024"
2022-11-21 02:18:38 +01:00
width="600"
2022-11-20 22:54:54 +01:00
xmlns="http://www.w3.org/2000/svg"
2022-11-20 23:34:51 +01:00
>
< style >
2022-11-21 01:50:27 +01:00
polygon { stroke-width: 5px; }
2022-11-20 23:34:51 +01:00
< / style >
2022-11-20 22:54:54 +01:00
< / svg >
2022-11-20 23:28:42 +01:00
<!-- https://github.com/gorhill/Javascript - Voronoi -->
< script src = "rhill-voronoi-core.min.js" > < / script >
2022-11-20 22:54:54 +01:00
< script >
2022-11-21 03:21:50 +01:00
// Based on https://developer.mozilla.org/en-US/docs/Web/CSS/named-color .
2022-11-20 22:54:54 +01:00
const colors = {
2022-11-21 03:21:50 +01:00
'orange': [255, 165, 0],
'aliceblue': [240, 248, 255],
'antiquewhite': [250, 235, 215],
'aquamarine': [127, 255, 212],
'azure': [240, 255, 255],
'beige': [245, 245, 220],
'bisque': [255, 228, 196],
'blanchedalmond': [255, 235, 205],
'blueviolet': [138, 43, 226],
'brown': [165, 42, 42],
'burlywood': [222, 184, 135],
'cadetblue': [95, 158, 160],
'chartreuse': [127, 255, 0],
'chocolate': [210, 105, 30],
'coral': [255, 127, 80],
'cornflowerblue': [100, 149, 237],
'cornsilk': [255, 248, 220],
'crimson': [220, 20, 60],
'cyan (synonym of aqua)': [0, 255, 255],
'darkblue': [0, 0, 139],
'darkcyan': [0, 139, 139],
'darkgoldenrod': [184, 134, 11],
'darkgray': [169, 169, 169],
'darkgreen': [0, 100, 0],
'darkgrey': [169, 169, 169],
'darkkhaki': [189, 183, 107],
'darkmagenta': [139, 0, 139],
'darkolivegreen': [85, 107, 47],
'darkorange': [255, 140, 0],
'darkorchid': [153, 50, 204],
'darkred': [139, 0, 0],
'darksalmon': [233, 150, 122],
'darkseagreen': [143, 188, 143],
'darkslateblue': [72, 61, 139],
'darkslategray': [47, 79, 79],
'darkslategrey': [47, 79, 79],
'darkturquoise': [0, 206, 209],
'darkviolet': [148, 0, 211],
'deeppink': [255, 20, 147],
'deepskyblue': [0, 191, 255],
'dimgray': [105, 105, 105],
'dimgrey': [105, 105, 105],
'dodgerblue': [30, 144, 255],
'firebrick': [178, 34, 34],
'floralwhite': [255, 250, 240],
'forestgreen': [34, 139, 34],
'gainsboro': [220, 220, 220],
'ghostwhite': [248, 248, 255],
'gold': [255, 215, 0],
'goldenrod': [218, 165, 32],
'greenyellow': [173, 255, 47],
'grey': [128, 128, 128],
'honeydew': [240, 255, 240],
'hotpink': [255, 105, 180],
'indianred': [205, 92, 92],
'indigo': [75, 0, 130],
'ivory': [255, 255, 240],
'khaki': [240, 230, 140],
'lavender': [230, 230, 250],
'lavenderblush': [255, 240, 245],
'lawngreen': [124, 252, 0],
'lemonchiffon': [255, 250, 205],
'lightblue': [173, 216, 230],
'lightcoral': [240, 128, 128],
'lightcyan': [224, 255, 255],
'lightgoldenrodyellow': [250, 250, 210],
'lightgray': [211, 211, 211],
'lightgreen': [144, 238, 144],
'lightgrey': [211, 211, 211],
'lightpink': [255, 182, 193],
'lightsalmon': [255, 160, 122],
'lightseagreen': [32, 178, 170],
'lightskyblue': [135, 206, 250],
'lightslategray': [119, 136, 153],
'lightslategrey': [119, 136, 153],
'lightsteelblue': [176, 196, 222],
'lightyellow': [255, 255, 224],
'limegreen': [50, 205, 50],
'linen': [250, 240, 230],
'magenta (synonym of fuchsia)': [255, 0, 255],
'mediumaquamarine': [102, 205, 170],
'mediumblue': [0, 0, 205],
'mediumorchid': [186, 85, 211],
'mediumpurple': [147, 112, 219],
'mediumseagreen': [60, 179, 113],
'mediumslateblue': [123, 104, 238],
'mediumspringgreen': [0, 250, 154],
'mediumturquoise': [72, 209, 204],
'mediumvioletred': [199, 21, 133],
'midnightblue': [25, 25, 112],
'mintcream': [245, 255, 250],
'mistyrose': [255, 228, 225],
'moccasin': [255, 228, 181],
'navajowhite': [255, 222, 173],
'oldlace': [253, 245, 230],
'olivedrab': [107, 142, 35],
'orangered': [255, 69, 0],
'orchid': [218, 112, 214],
'palegoldenrod': [238, 232, 170],
'palegreen': [152, 251, 152],
'paleturquoise': [175, 238, 238],
'palevioletred': [219, 112, 147],
'papayawhip': [255, 239, 213],
'peachpuff': [255, 218, 185],
'peru': [205, 133, 63],
'pink': [255, 192, 203],
'plum': [221, 160, 221],
'powderblue': [176, 224, 230],
'rosybrown': [188, 143, 143],
'royalblue': [65, 105, 225],
'saddlebrown': [139, 69, 19],
'salmon': [250, 128, 114],
'sandybrown': [244, 164, 96],
'seagreen': [46, 139, 87],
'seashell': [255, 245, 238],
'sienna': [160, 82, 45],
'skyblue': [135, 206, 235],
'slateblue': [106, 90, 205],
'slategray': [112, 128, 144],
'slategrey': [112, 128, 144],
'snow': [255, 250, 250],
'springgreen': [0, 255, 127],
'steelblue': [70, 130, 180],
'tan': [210, 180, 140],
'thistle': [216, 191, 216],
'tomato': [255, 99, 71],
'turquoise': [64, 224, 208],
'violet': [238, 130, 238],
'wheat': [245, 222, 179],
'whitesmoke': [245, 245, 245],
'yellowgreen': [154, 205, 50],
'rebeccapurple': [102, 51, 153],
2022-11-20 22:54:54 +01:00
};
// Based on https://stackoverflow.com/a/54070620/91238 .
// input: r,g,b in [0,1], out: h in [0,360) and s,v in [0,1]
function rgb2hsv(r,g,b) {
let v=Math.max(r,g,b), c=v-Math.min(r,g,b);
2022-11-20 23:28:42 +01:00
let h= c & & ((v==r) ? (g-b)/c : ((v==g) ? 2+(b-r)/c : 4+(r-g)/c));
2022-11-20 22:54:54 +01:00
return [60*(h< 0 ? h + 6:h ) , v & & c / v , v ] ;
}
// For the whole color wheel, radius and center x/y.
const radius = 512;
const cx = radius;
const cy = radius;
const svg = document.querySelector('svg');
2022-11-21 01:50:27 +01:00
const svgStyle = svg.querySelector('style').sheet;
2022-11-20 22:54:54 +01:00
2022-11-21 02:02:35 +01:00
// TODO: Select-able color categories, re-render wheel.
function renderWheel() {
let colorsBySite = {};
let sites = [];
Object.entries(colors).forEach(([name, color], _) => {
let [r, g, b] = color;
let [h, s, v] = rgb2hsv(r/255, g/255, b/255);
2022-11-20 22:54:54 +01:00
2022-11-21 02:02:35 +01:00
// Based on https://stackoverflow.com/a/54522007/91238 .
let colorRadius = s * radius;
let colorAngle = h/360 * 2 * Math.PI;
2022-11-20 22:54:54 +01:00
2022-11-21 02:02:35 +01:00
let x = Math.cos(colorAngle) * colorRadius + 512;
let y = Math.sin(colorAngle) * colorRadius + 512;
sites.push({x: x, y: y});
colorsBySite[[x, y]] = name;
});
2022-11-20 22:54:54 +01:00
2022-11-21 02:02:35 +01:00
let voronoi = new Voronoi().compute(sites, {xl: 0, xr: 1024, yt: 0, yb: 1024});
voronoi.cells.forEach(cell => {
if (cell.closeMe) {
console.warn('cell', cell, 'needs closing');
return;
}
let colorName = colorsBySite[[cell.site.x, cell.site.y]];
let [r, g, b] = colors[colorName];
2022-11-20 23:28:42 +01:00
2022-11-21 02:02:35 +01:00
let c = document.createElementNS('http://www.w3.org/2000/svg', 'polygon');
c.setAttribute('data-color', colorName);
c.setAttribute('mask', 'url(#circle-mask)');
2022-11-20 23:28:42 +01:00
2022-11-21 02:02:35 +01:00
let points = '';
cell.halfedges.forEach(edge => {
let s = edge.getStartpoint();
let e = edge.getEndpoint();
points += `${s.x} ${s.y}, `;
});
c.setAttribute('points', points);
2022-11-20 23:28:42 +01:00
2022-11-21 02:02:35 +01:00
svg.appendChild(c);
let rgb = `rgb(${r}, ${g}, ${b})`;
2022-11-21 03:21:50 +01:00
svgStyle.insertRule(`[data-color='${colorName}'] { fill: ${rgb}; stroke: ${rgb}; }`);
2022-11-21 02:02:35 +01:00
});
}
renderWheel();
2022-11-21 01:50:27 +01:00
2022-11-21 01:51:45 +01:00
function activateColor(el) {
renderPreview(el.getAttribute('data-color'));
// Move the SVG node to the end, so it(s stroke) will draw above all others.
el.parentNode.appendChild(el);
// Force its stroke to be black. (Doing this with CSS doesn't work; the
// hover state is broken by mutating the DOM.)
el.style.stroke = 'black';
}
2022-11-21 02:02:35 +01:00
// https://stackoverflow.com/a/5624139/91238
function componentToHex(c) {
var hex = c.toString(16);
return hex.length == 1 ? "0" + hex : hex;
}
function rgbToHex(r, g, b) {
return "#" + componentToHex(r) + componentToHex(g) + componentToHex(b);
}
let previewLocked = false;
function renderPreview(color) {
if (!color) {
document.getElementById('preview').innerHTML = '';
return;
}
let [r, g, b] = colors[color];
document.getElementById('preview').innerHTML = `
${color}
2022-11-21 03:21:50 +01:00
< span class = "swatch" style = "background-color: ${color};" > < / span >
2022-11-21 02:02:35 +01:00
${rgbToHex(r, g, b).toUpperCase()}
`;
}
2022-11-21 01:50:27 +01:00
svg.addEventListener('mouseover', e => {
let el = e.target;
if (el.tagName != 'polygon') return;
if (!el.nextElementSibling) return;
2022-11-21 01:51:45 +01:00
if (!previewLocked) {
activateColor(el);
}
2022-11-21 01:50:27 +01:00
});
svg.addEventListener('mouseout', e => {
let el = e.target;
if (el.tagName != 'polygon') return;
2022-11-21 01:51:45 +01:00
if (!previewLocked) {
renderPreview(null);
// Reset forced stroke from mouseover.
el.removeAttribute('style');
}
});
2022-11-21 02:02:35 +01:00
document.body.addEventListener('click', e => {
2022-11-21 01:51:45 +01:00
let el = e.target;
// Remove possible forced stroke from previously-locked color.
document.querySelectorAll('polygon[style]').forEach(el => {
el.removeAttribute('style');
});
2022-11-21 02:02:35 +01:00
if (el.tagName != 'polygon') {
previewLocked = false;
renderPreview(null);
2022-11-21 01:51:45 +01:00
return;
}
2022-11-21 02:02:35 +01:00
previewLocked = true;
activateColor(el);
});
2022-11-20 22:54:54 +01:00
< / script >
2022-11-21 02:02:35 +01:00
< h1 id = "preview" > < / h1 >
2022-11-21 03:21:50 +01:00
< div id = "css1" >
< p > Plus the sixteen CSS1 colors don't fit well on a color wheel (due to a low/overlapping set of saturation values):< / p >
< h1 > black < span class = 'swatch' style = 'background-color: black;' > < / span > < / h1 >
< h1 > silver < span class = 'swatch' style = 'background-color: silver;' > < / span > < / h1 >
< h1 > gray < span class = 'swatch' style = 'background-color: gray;' > < / span > < / h1 >
< h1 > white < span class = 'swatch' style = 'background-color: white;' > < / span > < / h1 >
< h1 > maroon < span class = 'swatch' style = 'background-color: maroon;' > < / span > < / h1 >
< h1 > red < span class = 'swatch' style = 'background-color: red;' > < / span > < / h1 >
< h1 > purple < span class = 'swatch' style = 'background-color: purple;' > < / span > < / h1 >
< h1 > fuchsia < span class = 'swatch' style = 'background-color: fuchsia;' > < / span > < / h1 >
< h1 > green < span class = 'swatch' style = 'background-color: green;' > < / span > < / h1 >
< h1 > lime < span class = 'swatch' style = 'background-color: lime;' > < / span > < / h1 >
< h1 > olive < span class = 'swatch' style = 'background-color: olive;' > < / span > < / h1 >
< h1 > yellow < span class = 'swatch' style = 'background-color: yellow;' > < / span > < / h1 >
< h1 > navy < span class = 'swatch' style = 'background-color: navy;' > < / span > < / h1 >
< h1 > blue < span class = 'swatch' style = 'background-color: blue;' > < / span > < / h1 >
< h1 > teal < span class = 'swatch' style = 'background-color: teal;' > < / span > < / h1 >
< h1 > aqua < span class = 'swatch' style = 'background-color: aqua;' > < / span > < / h1 >
< / div >
2022-11-21 02:16:00 +01:00
< a id = 'about-link' href = '#about' >
❔
< / a >
< div id = 'about' >
< a class = 'close' href = '#' > ⌧< / a >
< p > I'm far from a designer, but I make web pages. For quite some time I've thought about the palette of "web colors". I'd like to be able to pick from those colors, when making simple web pages.< / p >
< p > I've thought about this "color wheel" arrangement, i.e. when using image editors. It's a compact way to represent a whole range of colors. I was reminded of the combination of these things by < a href = "https://news.ycombinator.com/item?id=33647207" > a recent Hacker News comment thread< / a > .< / p >
< p > So here it is: a color wheel, with only "web colors" on it. Each color is placed on the wheel, then grown to a polygon with a Voronoi diagram.< / p >
< p > Hover colors to see their name (and preview swatch and hex code). Click one to "lock" it.< / p >
< / div >