Browse Source

port over some scoring logic

Kirk Trombley 2 years ago
parent
commit
330ac1493a
2 changed files with 101 additions and 28 deletions
  1. 71 6
      form.js
  2. 30 22
      index.html

+ 71 - 6
form.js

@@ -5,6 +5,9 @@ const selectors = {
   get clusterControl() {
     return document.forms.clusterControl.elements;
   },
+  get colorSpace() {
+    return selectors.colorSpace.value;
+  },
 };
 
 const onMetricChange = (elements) => {
@@ -17,7 +20,7 @@ const onMetricChange = (elements) => {
   elements.statistic.disabled = kind !== "statistic";
   elements.sortMetric.value = elements[kind].value;
 
-  sortImages();
+  updateSort();
   showResults(selectors.sortControl.resultsToDisplay.value);
 };
 
@@ -38,16 +41,78 @@ const onColorChange = (inputValue) => {
   selectors.sortControl.colorText.value = refomatted;
   selectors.sortControl.colorPicker.value = refomatted;
 
-  scoreImages();
-  sortImages();
+  // TODO last color saver
+  // TODO bg + text color change
+
+  updateScores(rgb);
+  updateSort();
   showResults(selectors.sortControl.resultsToDisplay.value);
 };
 
-const scoreImages = () => {
-  // TODO
+const calcScores = (data, target) => {
+  const sigma = Math.sqrt(
+    data.inertia - 2 * vectorDot(data.mu.vector, target.vector) + target.sqMag
+  );
+  const theta = rad2deg * Math.acos(vectorDot(data.mu.unit, target.unit));
+  const rawPhi = Math.abs(data.mu.hue - target.hue);
+  return {
+    sigma,
+    bigTheta: 1 - vectorDot(data.nu, target.unit),
+    alpha: sigma * Math.pow(bigTheta, target.chroma + target.lightness),
+
+    theta,
+    phi: Math.min(rawPhi, 360 - rawPhi),
+    delta: vectorMag(data.mu.vector.map((x, i) => x - target.vector[i])),
+    manhattan: data.mu.vector
+      .map((x, i) => Math.abs(x - target.vector[i]))
+      .reduce((x, y) => x + y),
+    ch: Math.max(...data.mu.vector.map((x, i) => Math.abs(x - target.vector[i]))),
+    lightnessDiff: Math.abs(data.mu.lightness - target.lightness),
+
+    inertia: data.inertia,
+    variance: data.inertia - data.mu.sqMag,
+    muNuAngle: data.muNuAngle,
+    size: data.size,
+    lightness: data.mu.lightness,
+    chroma: data.mu.chroma,
+    importance: data.importance,
+  };
+};
+
+const currentScores = {};
+const currentBestClusterIndices = {};
+let sortedData = pokemonData;
+
+const updateScores = (rgb) => {
+  const { J, a, b } = d3.jab(rgb);
+  const targetJab = buildVectorData([J, a, b], jab2hue, jab2lit, jab2chroma, jab2hex);
+  const targetRgb = buildVectorData(
+    [rgb.r, rgb.g, rgb.b],
+    rgb2hue,
+    rgb2lit,
+    rgb2chroma,
+    rgb2hex
+  );
+  pokemonData.forEach(({ name, jab, rgb }) => {
+    currentScores[name] = {
+      jab: {
+        total: calcScores(jab.total, targetJab),
+        clusters: jab.clusters.map((c) => calcScores(c, targetJab)),
+      },
+      rgb: {
+        total: calcScores(rgb.total, targetRgb),
+        clusters: rgb.clusters.map((c) => calcScores(c, targetRgb)),
+      },
+    };
+    currentBestClusterIndices[name] = {
+      // TODO
+      jab: 0,
+      rgb: 0,
+    };
+  });
 };
 
-const sortImages = () => {
+const updateSort = () => {
   // TODO
 };
 

+ 30 - 22
index.html

@@ -7,6 +7,9 @@
     <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="database-v3.js"></script>
+    <!-- TODO move these files -->
+    <script src="web/math.js"></script>
+    <script src="web/convert.js"></script>
     <script src="form.js"></script>
   </head>
   <body>
@@ -64,14 +67,16 @@
     </template>
 
     <form action="javascript:void(0);" id="sortControl" autocomplete="off">
-      <div>Target Color</div>
       <div>
-        <input
-          name="colorText"
-          type="text"
-          maxlength="7"
-          oninput="onColorChange(event.target.value)"
-        />
+        <label>
+          <div>Target Color</div>
+          <input
+            name="colorText"
+            type="text"
+            maxlength="7"
+            oninput="onColorChange(event.target.value)"
+          />
+        </label>
         <input
           name="colorPicker"
           type="color"
@@ -80,6 +85,7 @@
       </div>
       <div>
         <label>
+          <div>Results:&nbsp;<output name="resultsToDisplayOutput">10</output></div>
           <input
             name="resultsToDisplay"
             type="range"
@@ -91,22 +97,23 @@
             "
             onchange="showResults(event.target.value)"
           />
-          Results:&nbsp;<output name="resultsToDisplayOutput">10</output>
-        </label>
-      </div>
-      <div>Color Space</div>
-      <div>
-        <label>
-          <input type="radio" name="color-space" value="jab" checked />
-          CIECAM
-        </label>
-      </div>
-      <div>
-        <label>
-          <input type="radio" name="color-space" value="rgb" />
-          sRGB
         </label>
       </div>
+      <fieldset onchange="updateSort()">
+        <legend>Color Space</legend>
+        <div>
+          <label>
+            <input type="radio" name="colorSpace" value="jab" checked />
+            CIECAM
+          </label>
+        </div>
+        <div>
+          <label>
+            <input type="radio" name="colorSpace" value="rgb" />
+            sRGB
+          </label>
+        </div>
+      </fieldset>
       <fieldset name="metric" onchange="onMetricChange(event.target.form.elements)">
         <legend>Distance Metric</legend>
         <!-- template mount point -->
@@ -118,6 +125,7 @@
         onchange="
           const elements = event.target.form.elements;
           elements.metric.hidden = elements.useClusters.value === 'off';
+          onMetricChange(elements);
         "
       >
         <legend>Compare With</legend>
@@ -133,7 +141,7 @@
             Best Cluster
           </label>
         </div>
-        <fieldset name="metric" onchange="onMetricChange(event.target.form.elements)">
+        <fieldset name="metric">
           <legend>Cluster Ranking</legend>
           <!-- template mount point -->
         </fieldset>