<!DOCTYPE html>
<html>
<head>
<style>
#header {
text-align: center;
}
#type {
display: inline;
text-align: left;
}
.vert {
display: block;
float: left;
width: 100%;
height: 30px;
}
.hori {
display: inline-block;
float: left;
width: 25%;
height: 1px;
}
#picker {
display: none;
text-align: center;
height: 300px;
border: 1px solid black;
}
.picker-display {
visibility: hidden;
display: inline-table;
text-align: left;
border: 1px solid #888;
height: 100%;
}
#colourpicker-title {
text-align: center;
}
#colourpicker-sample {
height: 20%;
border-style: solid;
border-color: white;
border-width: 10px 2px;
}
.colour-box {
border: 3px solid white;
width: 21%;
}
#palettepicker {
visibility: hidden;
display: inline-table;
}
#picker, #palette {
width: 50%;
}
#palette tbody {
display: block;
overflow-y: auto;
overflow-x: hidden;
width: 100%;
height: 100px;
background-color: #07f;
}
#palette tr {
display: block;
width: 100%;
}
#palette td {
display: inline-block;
border: 1px solid black;
height: calc(100% - 4px);
}
</style>
<script>
function handleEscKey(event) {
var x = event.which || event.keyCode;
if (x == 27) {
selectCell();
}
}
/*
function attemptEsc(event) {
var elem = document.elementFromPoint(event.clientX, event.clientY);
if (elem == null || elem.nodeName === "BODY" || elem.nodeName === "DIV")
selectCell();
}
*/
// Thanks StackOverflow!
// https://stackoverflow.com/a/3955238
function clearInnerNodes(elem) {
var node = elem;
while (node.firstChild)
node.removeChild(node.firstChild);
}
function hexCodeFromRgb(rgb) {
var code = new Array(7);
code[0] = "#";
for (var i = 0; i < 3; i++) {
var h = Math.floor(rgb[i] / 16);
if (h < 10) h += 0x30;
else h += 0x57;
var l = rgb[i] & 15;
if (l < 10) l += 0x30;
else l += 0x57;
code[i*2 + 1] = String.fromCharCode(h);
code[i*2 + 2] = String.fromCharCode(l);
}
return code.join("");
}
function rgbFromHexCode(code) {
return [
parseInt(code.substring(1, 3), 16),
parseInt(code.substring(3, 5), 16),
parseInt(code.substring(5, 7), 16)
];
}
function randomColour() {
var nybs = new Array(7);
nybs[0] = "#";
for (var i = 0; i < 6; i++) {
var n = Math.floor(Math.random() * 16);
if (n < 10) n += 0x30;
else n += 0x57;
nybs[i+1] = String.fromCharCode(n);
}
return nybs.join("");
}
function fitColours(table, num) {
clearInnerNodes(table);
var nCols = num < 8 ? num : 8;
var nRows = Math.ceil(num / nCols);
var rowH = nRows == 1 ? "100px" : "50px";
var cellW = "calc(" + (100 / nCols) + "% - 4px)";
var idx = 0;
for (var i = 0; i < nRows; i++) {
var row = table.insertRow(i);
row.style.height = rowH;
for (var j = 0; j < nCols; j++) {
var cell = row.insertCell(j);
cell.id = "cell" + idx;
cell.setAttribute("onclick", "selectCell(cell" + idx + ");");
cell.style.width = cellW;
cell.innerHTML = idx;
idx++;
if (idx >= num)
return;
}
}
}
var ncolours = 0;
function generate() {
var num = parseInt(document.getElementById("ncolours").value);
if (isNaN(num))
return;
var table = document.getElementById("palette");
if (num != ncolours) {
table.style.border = "1px solid black";
fitColours(table, num);
ncolours = num;
}
for (var i = 0; i < table.rows.length; i++) {
var row = table.rows[i];
for (var j = 0; j < row.cells.length; j++) {
var clr = randomColour();
var cell = row.cells[j];
cell.style.backgroundColor = clr;
cell.setAttribute("code", clr);
}
}
refreshPicker();
}
var currentCell;
function selectCell(id) {
if (currentCell)
currentCell.style.opacity = "1.0";
currentCell = id;
if (!id) {
colourPicker.style.visibility = "hidden";
palettePicker.style.visibility = "hidden";
return;
}
else {
colourPicker.style.visibility = "visible";
palettePicker.style.visibility = "visible";
}
currentCell.style.opacity = "0.6";
var display = document.getElementById("picker").firstChild;
if (display.id === colourPicker.id) {
updateColourPicker();
}
else if (display.id === palettePicker.id) {
updatePalettePicker();
}
}
function updateSlider(row, idx, rgb) {
var lowRgb = rgb.slice();
lowRgb[idx] = 0;
var highRgb = rgb.slice();
highRgb[idx] = 255;
row.cells[1].style.backgroundColor = hexCodeFromRgb(lowRgb);
row.cells[2].firstChild.value = rgb[idx];
row.cells[3].style.backgroundColor = hexCodeFromRgb(highRgb);
}
var wink = false;
function winkyface() {
wink = !wink;
var a = !wink ? "#000" : "#fff";
var b = wink ? "#000" : "#fff";
document.body.childNodes.forEach(
function(value, idx, list) {
if (value instanceof HTMLElement)
value.style.color = this;
},
a
);
document.body.style.backgroundColor = b;
}
function setSlider(elem) {
var sample = document.getElementById("colourpicker-sample");
var rgb = rgbFromHexCode(sample.innerHTML);
var idx = parseInt(elem.id.substr(-1, 1));
rgb[idx] = elem.value;
var rows = colourPicker.rows;
updateSlider(rows[1], 0, rgb);
updateSlider(rows[2], 1, rgb);
updateSlider(rows[3], 2, rgb);
var code = hexCodeFromRgb(rgb);
sample.style.backgroundColor = code;
sample.innerHTML = code;
currentCell.style.backgroundColor = code;
currentCell.setAttribute("code", code);
}
function updateColourPicker() {
if (!currentCell)
return;
var title = document.getElementById("colourpicker-title");
title.innerHTML = "<b>Colour " + currentCell.id.substr("cell".length) + "</b>";
var clrCode = currentCell.getAttribute("code");
var rgb = rgbFromHexCode(clrCode);
var sample = document.getElementById("colourpicker-sample");
sample.style.backgroundColor = clrCode;
sample.innerHTML = clrCode;
var rows = colourPicker.rows;
updateSlider(rows[1], 0, rgb);
updateSlider(rows[2], 1, rgb);
updateSlider(rows[3], 2, rgb);
}
function updatePalettePicker() {
}
function createSlider(row, idx, name) {
var desc = row.insertCell(0);
desc.innerHTML = name;
var lowBox = row.insertCell(1);
lowBox.style.backgroundColor = "red";
lowBox.className = "colour-box";
var slider = document.createElement("input");
slider.id = "slider" + idx;
slider.setAttribute("type", "range");
slider.setAttribute("min", "0");
slider.setAttribute("max", "255");
slider.setAttribute("value", "0");
slider.setAttribute("oninput", "setSlider(slider" + idx + ");");
var sliderCell = row.insertCell(2);
sliderCell.appendChild(slider);
var highBox = row.insertCell(3);
highBox.style.backgroundColor = "yellow";
highBox.className = "colour-box";
var height = getComputedStyle(row).getPropertyValue("height");
}
var colourPicker;
var palettePicker;
function swapDisplays(table, oldPanel, newPanel) {
var found = document.getElementById(oldPanel.id);
if (found != null)
table.removeChild(found);
table.appendChild(newPanel);
}
function refreshPicker() {
var picker = document.getElementById("picker");
picker.style.display = "table";
// https://stackoverflow.com/a/30917988
var type = document.querySelector('input[name="pickertype"]:checked').value;
if (type === "toreal") {
swapDisplays(picker, palettePicker, colourPicker);
updateColourPicker();
}
else if (type === "topal") {
swapDisplays(picker, colourPicker, palettePicker);
updatePalettePicker();
}
}
function createColourRow(picker, name) {
var row = picker.insertRow(-1);
var elem = row.insertCell(0);
elem.id = "colourpicker-" + name;
elem.setAttribute("colspan", "4");
}
function initColourPicker() {
colourPicker = document.createElement("table");
colourPicker.id = "colourpicker";
colourPicker.className = "picker-display";
createColourRow(colourPicker, "title");
var row = colourPicker.insertRow(1);
createSlider(row, 0, "Red");
row = colourPicker.insertRow(2);
createSlider(row, 1, "Green");
row = colourPicker.insertRow(3);
createSlider(row, 2, "Blue");
createColourRow(colourPicker, "sample");
}
function initPalettePicker() {
palettePicker = document.createElement("table");
palettePicker.id = "palettepicker";
palettePicker.className = "picker-display";
var row = palettePicker.insertRow(0);
var cell = row.insertCell(0);
cell.innerHTML = "palette picker";
}
function init() {
initColourPicker();
initPalettePicker();
}
</script>
</head>
<body onload="init();" onkeydown="handleEscKey(event);"> <!--onclick="attemptEsc(event);"-->
<div id="header">
<h1 onclick="winkyface();">Palette Tab Mockup</h1>
<label>Number of colours: <input type="text" id="ncolours" /></label>
<button onclick="generate();">Generate</button>
<p />
<table id="type">
<tr>
<td><input type="radio" onchange="refreshPicker();" name="pickertype" value="topal" id="topal"/></td>
<td><label for="topal">Index -> Palette</label></td>
</tr>
<tr>
<td><input type="radio" onchange="refreshPicker();" name="pickertype" value="toreal" id="toreal" checked="checked"/></td>
<td><label for="toreal">Index -> Real</label></td>
</tr>
</table>
</div>
<div class="vert"></div>
<div class="hori"></div>
<table id="picker"></table>
<div class="vert"></div>
<div class="hori"></div>
<table id="palette">
</table>
</body>
</html>