<!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 -&gt; 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 -&gt; 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>