web-color-wheel/colors.html

368 lines
11 KiB
HTML

<!DOCTYPE html>
<head>
<title>Named Colors Wheel</title>
<style>
body {
font-family: sans-serif;
text-align: center;
}
.swatch {
display: inline-block;
min-width: 5em;
}
#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 25%;
position: fixed;
top: 10em;
}
#about:target {
display: block;
}
#about .close {
color: black;
float: right;
margin: 1ex;
text-decoration: none;
}
svg {
clip-path: circle(300px at center);
}
#css1 h1 {
display: inline-block;
margin: 1ex 1em;
width: 5em;
}
</style>
</head>
<body>
<svg
baseProfile="full"
height="600"
version="1.1"
viewbox="0 0 1024 1024"
width="600"
xmlns="http://www.w3.org/2000/svg"
>
<style>
polygon { stroke-width: 5px; }
</style>
</svg>
<!-- https://github.com/gorhill/Javascript-Voronoi -->
<script src="rhill-voronoi-core.min.js"></script>
<script>
// Based on https://developer.mozilla.org/en-US/docs/Web/CSS/named-color .
const colors = {
'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],
};
// 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);
let h= c && ((v==r) ? (g-b)/c : ((v==g) ? 2+(b-r)/c : 4+(r-g)/c));
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');
const svgStyle = svg.querySelector('style').sheet;
// 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);
// Based on https://stackoverflow.com/a/54522007/91238 .
let colorRadius = s * radius;
let colorAngle = h/360 * 2 * Math.PI;
let x = Math.cos(colorAngle) * colorRadius + 512;
let y = Math.sin(colorAngle) * colorRadius + 512;
sites.push({x: x, y: y});
colorsBySite[[x, y]] = name;
});
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];
let c = document.createElementNS('http://www.w3.org/2000/svg', 'polygon');
c.setAttribute('data-color', colorName);
c.setAttribute('mask', 'url(#circle-mask)');
let points = '';
cell.halfedges.forEach(edge => {
let s = edge.getStartpoint();
let e = edge.getEndpoint();
points += `${s.x} ${s.y}, `;
});
c.setAttribute('points', points);
svg.appendChild(c);
let rgb = `rgb(${r}, ${g}, ${b})`;
svgStyle.insertRule(`[data-color='${colorName}'] { fill: ${rgb}; stroke: ${rgb}; }`);
});
}
renderWheel();
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';
}
// 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}
<span class="swatch" style="background-color: ${color};">&nbsp;</span>
${rgbToHex(r, g, b).toUpperCase()}
`;
}
svg.addEventListener('mouseover', e => {
let el = e.target;
if (el.tagName != 'polygon') return;
if (!el.nextElementSibling) return;
if (!previewLocked) {
activateColor(el);
}
});
svg.addEventListener('mouseout', e => {
let el = e.target;
if (el.tagName != 'polygon') return;
if (!previewLocked) {
renderPreview(null);
// Reset forced stroke from mouseover.
el.removeAttribute('style');
}
});
document.body.addEventListener('click', e => {
let el = e.target;
// Remove possible forced stroke from previously-locked color.
document.querySelectorAll('polygon[style]').forEach(el => {
el.removeAttribute('style');
});
if (el.tagName != 'polygon') {
previewLocked = false;
renderPreview(null);
return;
}
previewLocked = true;
activateColor(el);
});
</script>
<h1 id="preview"></h1>
<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;'>&nbsp;</span></h1>
<h1>silver <span class='swatch' style='background-color: silver;'>&nbsp;</span></h1>
<h1>gray <span class='swatch' style='background-color: gray;'>&nbsp;</span></h1>
<h1>white <span class='swatch' style='background-color: white;'>&nbsp;</span></h1>
<h1>maroon <span class='swatch' style='background-color: maroon;'>&nbsp;</span></h1>
<h1>red <span class='swatch' style='background-color: red;'>&nbsp;</span></h1>
<h1>purple <span class='swatch' style='background-color: purple;'>&nbsp;</span></h1>
<h1>fuchsia <span class='swatch' style='background-color: fuchsia;'>&nbsp;</span></h1>
<h1>green <span class='swatch' style='background-color: green;'>&nbsp;</span></h1>
<h1>lime <span class='swatch' style='background-color: lime;'>&nbsp;</span></h1>
<h1>olive <span class='swatch' style='background-color: olive;'>&nbsp;</span></h1>
<h1>yellow <span class='swatch' style='background-color: yellow;'>&nbsp;</span></h1>
<h1>navy <span class='swatch' style='background-color: navy;'>&nbsp;</span></h1>
<h1>blue <span class='swatch' style='background-color: blue;'>&nbsp;</span></h1>
<h1>teal <span class='swatch' style='background-color: teal;'>&nbsp;</span></h1>
<h1>aqua <span class='swatch' style='background-color: aqua;'>&nbsp;</span></h1>
</div>
<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. (Rather thank picking from all possible colors.)</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 to fill the wheel with a Voronoi diagram. The arrangement of polygons, and their sizes, is intriguing.</p>
<p>Hover colors to see their name (and preview swatch and hex code). Click one to "lock" it.</p>
</div>