Browse Source

First part of new form, WIP

Kirk Trombley 2 years ago
parent
commit
c4c5483936
3 changed files with 381 additions and 89 deletions
  1. 22 3
      form.js
  2. 215 76
      index.html
  3. 144 10
      styles.css

+ 22 - 3
form.js

@@ -5,6 +5,9 @@ const selectors = {
   get clusterControl() {
     return document.forms.clusterControl.elements;
   },
+  get colorSelect(){
+    return document.forms.colorSelect.elements;
+  },
   get resultsToDisplay() {
     return selectors.sortControl.resultsToDisplay.value;
   },
@@ -41,6 +44,9 @@ const selectors = {
   get scaleFormTemplate() {
     return document.getElementById("scale-form-template").content;
   },
+  get sizeFactorFormTemplate() {
+    return document.getElementById("size-factor-template").content;
+  },
   get pokemonTemplate() {
     return document.getElementById("pkmn-template").content;
   },
@@ -56,6 +62,12 @@ const selectors = {
   set highlight(hex) {
     document.querySelector(":root").style.setProperty("--highlight", hex);
   },
+  set colorText(hex) {
+    selectors.colorSelect.colorText.value = hex;
+  },
+  set colorPicker(hex) {
+    selectors.colorSelect.colorPicker.value = hex;
+  },
 };
 
 const onMetricChange = (elements, skipUpdates = false) => {
@@ -86,8 +98,8 @@ const onColorChange = (inputValue, skipUpdates = false) => {
   }
 
   const hex = rgb.formatHex();
-  selectors.sortControl.colorText.value = hex;
-  selectors.sortControl.colorPicker.value = hex;
+  selectors.colorText = hex;
+  selectors.colorPicker = hex;
 
   const contrast = getContrastingTextColor(hex);
 
@@ -128,6 +140,13 @@ const scaleOptions = {
   ],
 };
 
+const cardinalityTerms = {
+  clusterSize: (scores, index) => scores.clusters[index].size,
+  invClusterSize: (scores, index) => scores.clusters[index].inverseSize,
+  totalSize: (scores) => scores.total.size,
+  invTotalSize: (scores) => scores.total.inverseSize,
+};
+
 const currentScores = {};
 const currentBestClusterIndices = {};
 const currentSortValues = {};
@@ -315,7 +334,7 @@ const showResults = () => {
 window.addEventListener("load", () => {
   const metricTemplate = selectors.metricFormTemplate;
 
-  selectors.sortControl.metric.appendChild(metricTemplate.cloneNode(true));
+  selectors.sortControl.metric.prepend(metricTemplate.cloneNode(true));
   selectors.sortControl.metricKind.value = "whole";
   selectors.sortControl.whole.value = "alpha";
   onMetricChange(selectors.sortControl, true);

+ 215 - 76
index.html

@@ -22,47 +22,79 @@
           (click to toggle)
         </label>
       </div>
-      <div>
-        <label>
-          <input type="radio" name="metricKind" value="whole" />
-          Set Comparison
-        </label>
-      </div>
-      <div>
-        <label>
-          <input type="radio" name="metricKind" value="mean" />
-          Mean Comparison
-        </label>
-      </div>
-      <div>
-        <label>
-          <input type="radio" name="metricKind" value="statistic" />
-          Set Statistics
-        </label>
-      </div>
-      <select name="whole" disabled>
-        <option value="sigma">RMS Deviation (σ)</option>
-        <option value="bigTheta">Cosine Difference (Θ)</option>
-        <option value="alpha">Geometric Difference (α)</option>
-      </select>
-      <select name="mean" disabled>
-        <option value="theta">Angular Difference (θ)</option>
-        <option value="phi">Hue Azimuth (ϕ)</option>
-        <option value="delta">Euclidean (δ)</option>
-        <option value="manhattan">Manhattan (M)</option>
-        <option value="ch">Chebyshev (Ч)</option>
-        <option value="lightnessDiff">Lightness (ℓ)</option>
-      </select>
-      <select name="statistic" disabled>
-        <option value="inertia">Inertia (I)</option>
-        <option value="variance">Variance (V)</option>
-        <option value="muNuAngle">Mu-Nu Angle (Φ)</option>
-        <option value="size">Size (N)</option>
-        <option value="lightness">Mean Lightness (L)</option>
-        <option value="chroma">Mean Chroma (C)</option>
-        <option value="importance">Visual Importance (β)</option>
-      </select>
-      <output name="sortMetric" hidden aria-hidden="true"></output>
+
+      <fieldset>
+        <legend>Evaluation Function</legend>
+        <div>
+          <label>
+            <input type="radio" name="metricKind" value="whole" />
+            Set Comparison
+          </label>
+        </div>
+        <div>
+          <label>
+            <input type="radio" name="metricKind" value="mean" />
+            Mean Comparison
+          </label>
+        </div>
+        <div>
+          <label>
+            <input type="radio" name="metricKind" value="statistic" />
+            Set Statistics
+          </label>
+        </div>
+        <select name="whole" disabled>
+          <option value="sigma">RMS Deviation (σ)</option>
+          <option value="bigTheta">Cosine Difference (Θ)</option>
+          <option value="alpha">Geometric Difference (α)</option>
+        </select>
+        <select name="mean" disabled>
+          <option value="theta">Angular Difference (θ)</option>
+          <option value="phi">Hue Azimuth (ϕ)</option>
+          <option value="delta">Euclidean (δ)</option>
+          <option value="manhattan">Manhattan (M)</option>
+          <option value="ch">Chebyshev (Ч)</option>
+          <option value="lightnessDiff">Lightness (ℓ)</option>
+        </select>
+        <select name="statistic" disabled>
+          <option value="inertia">Inertia (I)</option>
+          <option value="variance">Variance (V)</option>
+          <option value="muNuAngle">Mu-Nu Angle (Φ)</option>
+          <option value="size">Size (N)</option>
+          <option value="lightness">Mean Lightness (L)</option>
+          <option value="chroma">Mean Chroma (C)</option>
+          <option value="importance">Visual Importance (β)</option>
+        </select>
+        <output name="sortMetric" hidden aria-hidden="true"></output>
+      </fieldset>
+
+      <fieldset>
+        <legend>Cardinality Terms</legend>
+        <div>
+          <label>
+            <input type="checkbox" name="clusterSize" />
+            Cluster Size
+          </label>
+        </div>
+        <div>
+          <label>
+            <input type="checkbox" name="invClusterSize" />
+            Inverse Cluster Size
+          </label>
+        </div>
+        <div>
+          <label>
+            <input type="checkbox" name="totalSize" />
+            Image Size
+          </label>
+        </div>
+        <div>
+          <label>
+            <input type="checkbox" name="invTotalSize" />
+            Inverse Image Size
+          </label>
+        </div>
+      </fieldset>
     </template>
 
     <template id="scale-form-template">
@@ -111,24 +143,115 @@
       </div>
     </template>
 
-    <form action="javascript:void(0);" id="sortControl" autocomplete="off">
-      <div>
-        <label>
-          <div>Target Color</div>
-          <input
-            name="colorText"
-            type="text"
-            maxlength="7"
-            oninput="onColorChange(event.target.value)"
-          />
+    <form action="javascript:void(0);" id="sortFunction" autocomplete="off">
+      <div class="fn-group fn-group-outer">
+        <label class="fn-minmax">
+          <input type="checkbox" name="sortOrder" role="button" hidden />
+          <div class="fn-minmax-toggle">
+            <span>min</span>
+            <span>max</span>
+          </div>
         </label>
-        <input
-          name="colorPicker"
-          type="color"
-          onchange="onColorChange(event.target.value)"
-        />
-        <button type="button" onclick="onColorChange(randomColor())">Random Color</button>
+        <span class="fn-bracket">[</span>
+        <div
+          class="fn-group"
+          onchange="event.target.parentNode.classList.toggle('fn-part--disabled')"
+        >
+          <label class="fn-part">
+            <input type="checkbox" name="useBestCluster" checked />
+            <output name="metricSymbolP">α</output>(P)
+          </label>
+          ⋅
+          <label class="fn-part">
+            <input type="checkbox" name="useWholeImage" checked />
+            <output name="metricSymbolB">α</output>(B)
+          </label>
+          ⋅
+          <label class="fn-part fn-part--disabled">
+            <input type="checkbox" name="clusterSize" />
+            |B|
+          </label>
+          ⋅
+          <label class="fn-part">
+            <input type="checkbox" name="invClusterSize" checked />
+            |B|<sup>-1</sup>
+          </label>
+          ⋅
+          <label class="fn-part">
+            <input type="checkbox" name="totalSize" checked />
+            |P|
+          </label>
+          ⋅
+          <label class="fn-part fn-part--disabled">
+            <input type="checkbox" name="invTotalSize" />
+            |P|<sup>-1</sup>
+          </label>
+        </div>
+        <span class="fn-bracket">]</span>
       </div>
+    </form>
+
+    <form action="javascript:void(0);" id="clusterFunction" autocomplete="off">
+      <div class="fn-group">
+        <span>where B =&nbsp;</span>
+        <label class="fn-minmax fn-minmax--wide">
+          <input type="checkbox" name="sortOrder" role="button" checked hidden />
+          <div class="fn-minmax-toggle">
+            <span>argmin</span>
+            <span>argmax</span>
+          </div>
+        </label>
+        <span class="fn-bracket">[</span>
+        <div
+          class="fn-group"
+          onchange="event.target.parentNode.classList.toggle('fn-part--disabled')"
+        >
+          <span class="fn-part fn-part--fixed">
+            <output name="metricSymbol">β</output>(K)
+          </span>
+          ⋅
+          <label class="fn-part fn-part--disabled">
+            <input type="checkbox" name="clusterSize" />
+            |K|
+          </label>
+          ⋅
+          <label class="fn-part fn-part--disabled">
+            <input type="checkbox" name="invClusterSize" />
+            |K|<sup>-1</sup>
+          </label>
+          ⋅
+          <label class="fn-part fn-part--disabled">
+            <input type="checkbox" name="totalSize" />
+            |P|
+          </label>
+          ⋅
+          <label class="fn-part fn-part--disabled">
+            <input type="checkbox" name="invTotalSize" />
+            |P|<sup>-1</sup>
+          </label>
+        </div>
+        <span class="fn-bracket">]</span>
+      </div>
+    </form>
+
+    <form action="javascript:void(0);" id="colorSelect" autocomplete="off">
+      <label for="color-input-text">Target Color</label>
+      <input
+        id="color-input-text"
+        name="colorText"
+        type="text"
+        maxlength="7"
+        oninput="onColorChange(event.target.value)"
+      />
+      <button type="button" onclick="onColorChange(randomColor())">Random Color</button>
+      <input
+        name="colorPicker"
+        type="color"
+        onchange="onColorChange(event.target.value)"
+      />
+    </form>
+
+    <form action="javascript:void(0);" id="sortControl" autocomplete="off">
       <div>
         <label>
           <div>Results:&nbsp;<output name="resultsToDisplayOutput">10</output></div>
@@ -145,29 +268,41 @@
           />
         </label>
       </div>
-      <fieldset onchange="updateSort()">
-        <legend>Color Space</legend>
+      <div>
+        <label>
+          <input
+            type="radio"
+            onchange="updateSort()"
+            name="colorSpace"
+            value="jab"
+            checked
+          />
+          CIECAM
+        </label>
+      </div>
+      <div>
+        <label>
+          <input type="radio" onchange="updateSort()" name="colorSpace" value="rgb" />
+          sRGB
+        </label>
+      </div>
+      <div>Best Match</div>
+      <fieldset name="metric" onchange="onMetricChange(event.target.form.elements)">
+        <!-- template mount point -->
+        <legend>Sort By</legend>
         <div>
           <label>
-            <input type="radio" name="colorSpace" value="jab" checked />
-            CIECAM
+            <input type="checkbox" name="useBestCluster" />
+            Best Cluster
           </label>
         </div>
         <div>
           <label>
-            <input type="radio" name="colorSpace" value="rgb" />
-            sRGB
+            <input type="checkbox" name="useWholeImage" />
+            Whole Image
           </label>
         </div>
       </fieldset>
-      <fieldset name="metric" onchange="onMetricChange(event.target.form.elements)">
-        <legend>Distance Metric</legend>
-        <!-- template mount point -->
-      </fieldset>
-      <fieldset name="rescaleSection" onchange="updateSort()">
-        <legend>Scaled By</legend>
-        <!-- template mount point -->
-      </fieldset>
       <fieldset
         onchange="
           const elements = event.target.form.elements;
@@ -176,30 +311,34 @@
           onMetricChange(elements);
         "
       >
-        <legend>Compare With</legend>
+        <legend>Comparison Value</legend>
         <div>
           <label>
             <input type="radio" name="useClusters" value="off" />
-            Whole Image
+            Distance of Whole Image
           </label>
         </div>
         <div>
           <label>
             <input type="radio" name="useClusters" value="on" />
-            Best Cluster
+            Distance of Best Cluster
           </label>
         </div>
         <div>
           <label>
             <input type="radio" name="useClusters" value="mult" checked />
-            Best Cluster Times Whole
+            Product of Distance Values
           </label>
         </div>
       </fieldset>
+      <fieldset name="rescaleSection" onchange="updateSort()">
+        <legend>Scaled By</legend>
+        <!-- template mount point -->
+      </fieldset>
     </form>
 
     <form action="javascript:void(0);" id="clusterControl" autocomplete="off">
-      <div>Cluster Ranking</div>
+      <div>Best Cluster</div>
       <fieldset name="metric" onchange="onMetricChange(event.target.form.elements)">
         <legend>Distance Metric</legend>
         <!-- template mount point -->

+ 144 - 10
styles.css

@@ -1,7 +1,7 @@
 :root {
   --highlight: #ddd;
   --background: #222;
-  --tile-width: 484px;
+  --highlight-border: 1px solid var(--highlight);
 }
 
 body {
@@ -29,7 +29,7 @@ select:disabled {
     "... total cls2"
     "... total cls1";
   align-items: center;
-  border: 1px solid var(--highlight);
+  border: var(--highlight-border);
 }
 
 .pkmn > img {
@@ -43,27 +43,27 @@ select:disabled {
 }
 
 .pkmn > .pkmn-total {
-  border: 1px solid var(--highlight);
+  border: var(--highlight-border);
   border-radius: 100vmax;
   grid-area: total;
   height: 100%;
   display: inline-flex;
   align-items: center;
-  padding-right: 1ch;
+  padding-inline-end: 1ch;
 }
 
 .pkmn > .pkmn-score {
   grid-area: score;
-  padding-left: 4ch;
+  padding-inline-start: 4ch;
 }
 
 .pkmn > .pkmn-cls {
-  border: 1px solid var(--highlight);
+  border: var(--highlight-border);
   border-radius: 100vmax;
   font-weight: 600;
   font-size: 0.75rem;
   padding: 0.125rem;
-  padding-right: 0.5rem;
+  padding-inline-end: 0.5ch;
   display: flex;
   justify-content: space-between;
 }
@@ -72,9 +72,8 @@ select:disabled {
   display: inline-block;
   content: "";
   width: 1ch;
-  margin-left: 0.25rem;
-  margin-right: 0.25rem;
-  margin-bottom: 0.125ch;
+  margin-inline: 0.25ch;
+  margin-block-end: 0.125rem;
 }
 
 .pkmn-total-selected > .pkmn-total::before,
@@ -106,3 +105,138 @@ select:disabled {
   min-width: fit-content;
   max-width: 50vw;
 }
+
+.fn-part {
+  display: inline-flex;
+  width: 3ch;
+  justify-content: center;
+  align-items: flex-end;
+
+  padding-block-end: 0.125rem;
+  padding-inline: 0.375ch;
+  margin-inline: 0.125ch;
+  border: var(--highlight-border);
+  border-radius: 100vmax;
+
+  color: var(--background);
+  background-color: var(--highlight);
+  transition: opacity 250ms, color 250ms, background-color 250ms;
+
+  cursor: pointer;
+  user-select: none;
+}
+
+.fn-part--fixed {
+  cursor: not-allowed;
+}
+
+/*
+pls hurry up mozilla 
+.fn-part:not(:has(input:checked)),
+*/
+.fn-part--disabled {
+  color: var(--highlight);
+  background-color: var(--background);
+  opacity: 50%;
+}
+
+.fn-part > input {
+  display: none;
+}
+
+.fn-part sup {
+  font-size: 0.75rem;
+  align-self: flex-start;
+}
+
+.fn-minmax {
+  min-width: 3.5ch;
+  text-align: center;
+  padding-inline-end: 0.25ch;
+
+  cursor: pointer;
+  user-select: none;
+}
+
+.fn-minmax--wide {
+  min-width: 6.5ch;
+}
+
+.fn-group {
+  display: flex;
+  align-items: center;
+}
+
+.fn-bracket {
+  font-weight: 300;
+  font-size: 2rem;
+  align-self: flex-start;
+  padding-block-end: 0.125rem;
+}
+
+.fn-minmax-toggle {
+  display: flex;
+  flex-direction: column;
+  padding-block-end: 0.25rem;
+  position: relative;
+}
+
+.fn-minmax-toggle::before {
+  content: "";
+  background-color: var(--highlight);
+  border-radius: 100vmax;
+
+  position: absolute;
+  top: 5%;
+  left: 0px;
+  right: 0px;
+  height: 45%;
+  transition: top 250ms;
+  z-index: -1;
+}
+
+input:checked + .fn-minmax-toggle::before {
+  top: 50%;
+}
+
+.fn-minmax-toggle > span {
+  opacity: 50%;
+  transition: opacity 250ms, color 250ms;
+}
+
+input:not(:checked) + .fn-minmax-toggle > span:first-child {
+  opacity: 100%;
+  color: var(--background);
+}
+
+input:checked + .fn-minmax-toggle > span:last-child {
+  opacity: 100%;
+  color: var(--background);
+}
+
+#colorSelect {
+  display: grid;
+  grid-template-columns: repeat(2, minmax(min-content, 12ch));
+  grid-auto-rows: 1fr;
+  gap: 0.25rem;
+  justify-items: stretch;
+  align-items: stretch;
+
+  border: var(--highlight-border);
+  padding: 0.125rem;
+  width: fit-content;
+}
+
+#colorSelect label {
+  display: inline-flex;
+  justify-content: center;
+  align-items: center;
+}
+
+#colorSelect input {
+  box-sizing: border-box;
+  width: 100%;
+  padding: 0;
+  margin: 0;
+  text-align: center;
+}