|
@@ -20,11 +20,17 @@ const vectorMag = v => Math.sqrt(vectorDot(v, v));
|
|
|
const pokemonLookup = new Fuse(database, { keys: [ "name" ] });
|
|
|
|
|
|
// hex codes already include leading # in these functions
|
|
|
-// rgb values are [0, 1] in these functions
|
|
|
-const luv2hex = $.colorspaces.converter("CIELUV", "hex");
|
|
|
-const rgb2luv = $.colorspaces.converter("sRGB", "CIELUV");
|
|
|
-const rgb2hex = $.colorspaces.converter("sRGB", "hex");
|
|
|
-const hex2rgb = $.colorspaces.converter("hex", "sRGB");
|
|
|
+// rgb values are [0, 255] in these functions
|
|
|
+const jab2hex = jab => d3.jab(...jab).formatHex();
|
|
|
+const rgb2hex = rgb => d3.rgb(...rgb).formatHex();
|
|
|
+const rgb2jab = rgb => {
|
|
|
+ const { J, a, b } = d3.jab(d3.rgb(...rgb));
|
|
|
+ return [ J, a, b ];
|
|
|
+}
|
|
|
+const hex2rgb = hex => {
|
|
|
+ const { r, g, b } = d3.rgb(hex);
|
|
|
+ return [ r, g, b ];
|
|
|
+};
|
|
|
|
|
|
// scoring functions
|
|
|
const getNormedScorer = (c, q) => {
|
|
@@ -42,7 +48,7 @@ const createTile = hexColor => {
|
|
|
return tile;
|
|
|
}
|
|
|
|
|
|
-const createPokemon = ({ name, score, yRGB, yLUV }) => {
|
|
|
+const createPokemon = ({ name, score, yRGB, yJAB }) => {
|
|
|
const img = document.createElement("img");
|
|
|
img.setAttribute("src", getSprite(name));
|
|
|
|
|
@@ -56,8 +62,8 @@ const createPokemon = ({ name, score, yRGB, yLUV }) => {
|
|
|
textSpan.textContent = text;
|
|
|
textSpan.setAttribute("class", "pokemon_text");
|
|
|
pkmn.appendChild(textSpan);
|
|
|
- pkmn.appendChild(createTile(rgb2hex(yRGB.map(x => x / 255))));
|
|
|
- pkmn.appendChild(createTile(luv2hex(yLUV)));
|
|
|
+ pkmn.appendChild(createTile(rgb2hex(yRGB)));
|
|
|
+ pkmn.appendChild(createTile(jab2hex(yJAB)));
|
|
|
return pkmn;
|
|
|
}
|
|
|
|
|
@@ -83,7 +89,7 @@ const onUpdate = (event) => {
|
|
|
const numPoke = document.getElementById("num-poke")?.value ?? 20;
|
|
|
const pokemonName = document.getElementById("pokemon-name")?.value?.toLowerCase() ?? "";
|
|
|
const targetColor = "#" + (document.getElementById("color-input")?.value?.replace("#", "") ?? "FFFFFF");
|
|
|
- const targetRGB = hex2rgb(targetColor).map(x => x * 255);
|
|
|
+ const targetRGB = hex2rgb(targetColor);
|
|
|
|
|
|
// Update display values
|
|
|
document.getElementById("x-term").textContent = includeX ? "X(P)" : "";
|
|
@@ -94,9 +100,9 @@ const onUpdate = (event) => {
|
|
|
document.getElementById("num-poke-display").textContent = numPoke;
|
|
|
|
|
|
// determine metrics from configuration
|
|
|
- const targetInSpace = useRGB ? targetRGB : rgb2luv(targetRGB.map(x => x / 255));
|
|
|
- const xSelector = includeX ? (useRGB ? ({ xRGB }) => xRGB : ({ xLUV }) => xLUV) : () => 0;
|
|
|
- const ySelector = useRGB ? ({ yRGB }) => yRGB : ({ yLUV }) => yLUV;
|
|
|
+ const targetInSpace = useRGB ? targetRGB : rgb2jab(targetRGB);
|
|
|
+ const xSelector = includeX ? (useRGB ? ({ xRGB }) => xRGB : ({ xJAB }) => xJAB) : () => 0;
|
|
|
+ const ySelector = useRGB ? ({ yRGB }) => yRGB : ({ yJAB }) => yJAB;
|
|
|
const yScorer = (normQY ? getNormedScorer : getUnnormedScorer)(closeCoeff, targetInSpace);
|
|
|
const totalScorer = info => xSelector(info) - yScorer(ySelector(info));
|
|
|
|
|
@@ -139,14 +145,14 @@ const onUpdate = (event) => {
|
|
|
};
|
|
|
|
|
|
const onRandomColor = () => {
|
|
|
- document.getElementById("color-input").value = rgb2hex([Math.random(), Math.random(), Math.random()]);
|
|
|
+ document.getElementById("color-input").value = rgb2hex([Math.random(), Math.random(), Math.random()].map(c => c * 255));
|
|
|
onUpdate();
|
|
|
};
|
|
|
|
|
|
const onToggleSpace = () => {
|
|
|
const element = document.getElementById("color-space");
|
|
|
const current = element?.textContent;
|
|
|
- element.textContent = current === "RGB" ? "CIELUV" : "RGB";
|
|
|
+ element.textContent = current === "RGB" ? "CAM02-UCS" : "RGB";
|
|
|
document.getElementById("space-toggle").textContent = `Swap to ${current}`
|
|
|
onUpdate();
|
|
|
};
|