浏览代码

Convert web impl to CAM02

Kirk Trombley 3 年之前
父节点
当前提交
f1d6189458
共有 2 个文件被更改,包括 23 次插入17 次删除
  1. 3 3
      nearest.html
  2. 20 14
      nearest.js

+ 3 - 3
nearest.html

@@ -3,8 +3,8 @@
     <head>
         <meta charset="utf-8" />
         <title>Pokemon By Color</title>
-        <script src="https://unpkg.com/jquery@3.6.0/dist/jquery.min.js"></script>
-        <script src="https://unpkg.com/colorspaces@0.1.5/colorspaces.js"></script>
+        <script src="https://unpkg.com/d3-color@3.0.1/dist/d3-color.min.js"></script>
+        <script src="https://unpkg.com/d3-cam02@0.1.5/build/d3-cam02.min.js"></script>
         <script src="https://unpkg.com/fuse.js@6.5.3/dist/fuse.js"></script>
         <script src="database.js"></script>
         <script src="nearest.js"></script>
@@ -137,7 +137,7 @@
                     </div>
 
                     <div class="container control">
-                        <div>Color Space: <span id="color-space">CIELUV</span></div>
+                        <div>Color Space: <span id="color-space">CAM02-UCS</span></div>
                         <button id="space-toggle" type="button" onclick="onToggleSpace()">Swap to RGB</button>
                     </div>
                 </form>

+ 20 - 14
nearest.js

@@ -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();
 };