|
@@ -1,423 +0,0 @@
|
|
|
-<!DOCTYPE html>
|
|
|
-<html lang="en">
|
|
|
- <head>
|
|
|
- <meta charset="utf-8" />
|
|
|
- <title>Pokemon By Color</title>
|
|
|
- <link rel="stylesheet" href="web/nearest.css" />
|
|
|
- <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.min.js"></script>
|
|
|
- <script src="https://unpkg.com/texzilla@1.0.2/TeXZilla.js"></script>
|
|
|
- <script src="database-v3.js"></script>
|
|
|
- <script src="web/math.js"></script>
|
|
|
- <script src="web/metrics.js"></script>
|
|
|
- <script src="web/convert.js"></script>
|
|
|
- <script src="web/score.js"></script>
|
|
|
- <script src="web/render.js"></script>
|
|
|
- <script src="web/listeners.js"></script>
|
|
|
- <script lang="javascript">
|
|
|
- const state = {
|
|
|
- target: null,
|
|
|
- number: 10,
|
|
|
- useCluster: true,
|
|
|
- clusterSettings: {
|
|
|
- sortMetric: "importance",
|
|
|
- scaleOption: "none",
|
|
|
- sortOrder: "max",
|
|
|
- multWithTotal: true,
|
|
|
- },
|
|
|
- space: "jab",
|
|
|
- sortMetric: "alpha",
|
|
|
- scaleOption: "inverse",
|
|
|
- sortOrder: "min",
|
|
|
- };
|
|
|
- window.onload = () => {
|
|
|
- document.getElementById("mu-def").innerHTML = TeXZilla.toMathMLString(String.raw`
|
|
|
- \vec{\mu}\left(P\right) = \frac{1}{\left|P\right|}\sum_{p\in P}{\vec{p}}
|
|
|
- `);
|
|
|
- document.getElementById("nu-def").innerHTML = TeXZilla.toMathMLString(String.raw`
|
|
|
- \vec{\nu}\left(P\right) = \frac{1}{\left|P\right|}\sum_{p\in P}{\hat{p}}
|
|
|
- `);
|
|
|
- document.body.addEventListener("click", event => {
|
|
|
- if (event.detail === 2 && event.target.innerText.includes("#")) {
|
|
|
- const clickedHex = event.target.innerText?.match(/.*(#[0-9a-fA-F]{6}).*/)?.[1] ?? "";
|
|
|
- if (clickedHex) {
|
|
|
- document.getElementById("color-input").value = clickedHex;
|
|
|
- onColorChanged(state, clickedHex);
|
|
|
- }
|
|
|
- }
|
|
|
- });
|
|
|
-
|
|
|
- const metricSelect = document.getElementById("sort-metric");
|
|
|
- const clusterMetricSelect = document.getElementById("cluster-sort-metric");
|
|
|
- const addOption = (name, value) => {
|
|
|
- const opt = document.createElement("option");
|
|
|
- if (value) {
|
|
|
- opt.setAttribute("value", value);
|
|
|
- } else {
|
|
|
- opt.disabled = true;
|
|
|
- }
|
|
|
- metricSelect.appendChild(opt);
|
|
|
- opt.innerHTML = name;
|
|
|
- const clone = opt.cloneNode();
|
|
|
- clusterMetricSelect.appendChild(clone);
|
|
|
- clone.innerHTML = name;
|
|
|
- }
|
|
|
- addOption("--- Compare to whole ---");
|
|
|
- Object.entries(metrics).forEach(([value, metric]) => {
|
|
|
- if (value === "theta") {
|
|
|
- addOption("--- Angle to mean ---");
|
|
|
- } else if (value === "delta") {
|
|
|
- addOption("--- Distance to mean ---");
|
|
|
- } else if (value === "inertia") {
|
|
|
- addOption("--- Statistics ---");
|
|
|
- }
|
|
|
- addOption(metric.option, value);
|
|
|
- });
|
|
|
-
|
|
|
- document.getElementById("sort-metric").firstChild.nextSibling.nextSibling.selected = true;
|
|
|
- document.getElementById("cluster-sort-metric").lastChild.selected = true;
|
|
|
-
|
|
|
- onRandomColor(state);
|
|
|
- }
|
|
|
- </script>
|
|
|
- </head>
|
|
|
-
|
|
|
- <body>
|
|
|
- <noscript>Requires javascript</noscript>
|
|
|
- <div
|
|
|
- style="
|
|
|
- display: flex;
|
|
|
- flex-flow: row nowrap;
|
|
|
- justify-content: flex-start;
|
|
|
- align-items: stretch;
|
|
|
- "
|
|
|
- >
|
|
|
- <div style="display: inline-block" class="toggle-box">
|
|
|
- <input
|
|
|
- autocomplete="off"
|
|
|
- type="checkbox"
|
|
|
- id="all-control-toggle"
|
|
|
- class="toggle-button"
|
|
|
- role="button"
|
|
|
- />
|
|
|
- <label
|
|
|
- for="all-control-toggle"
|
|
|
- style="min-width: 1.1em; display: inline-block"
|
|
|
- >
|
|
|
- <div class="toggle-off" style="writing-mode: vertical-rl">
|
|
|
- ► Controls
|
|
|
- </div>
|
|
|
- <hr
|
|
|
- class="toggle-off"
|
|
|
- style="color: var(--highlight); margin-top: 1em"
|
|
|
- />
|
|
|
- <div
|
|
|
- class="toggle-off"
|
|
|
- style="margin-top: 16px; text-align: center"
|
|
|
- id="collapsed-sort"
|
|
|
- ></div>
|
|
|
- <div
|
|
|
- class="toggle-off"
|
|
|
- style="margin-top: 16px; text-align: center"
|
|
|
- id="collapsed-fn-name"
|
|
|
- ></div>
|
|
|
- <hr
|
|
|
- class="toggle-off"
|
|
|
- style="color: var(--highlight); margin-top: 1em"
|
|
|
- />
|
|
|
- <div
|
|
|
- class="toggle-off"
|
|
|
- style="margin-top: 16px; text-align: center"
|
|
|
- id="collapsed-cluster-sort"
|
|
|
- ></div>
|
|
|
- <div
|
|
|
- class="toggle-off"
|
|
|
- style="margin-top: 16px; text-align: center"
|
|
|
- id="collapsed-cluster"
|
|
|
- ></div>
|
|
|
- <div
|
|
|
- class="toggle-off"
|
|
|
- style="margin-top: 16px; text-align: center"
|
|
|
- id="collapsed-cluster-scale"
|
|
|
- ></div>
|
|
|
- <div
|
|
|
- class="toggle-off"
|
|
|
- style="margin-top: 16px; text-align: center"
|
|
|
- id="collapsed-cluster-mult-total"
|
|
|
- ></div>
|
|
|
- <hr
|
|
|
- class="toggle-off"
|
|
|
- style="color: var(--highlight); margin-top: 1em"
|
|
|
- />
|
|
|
- <div
|
|
|
- class="toggle-off"
|
|
|
- style="margin-top: 16px; text-align: center"
|
|
|
- id="collapsed-scale"
|
|
|
- ></div>
|
|
|
- <div class="toggle-on">▼ Controls</div>
|
|
|
- </label>
|
|
|
- <div class="toggle-on">
|
|
|
- <div class="control-grid">
|
|
|
- <img
|
|
|
- style="grid-area: bulb; justify-self: center"
|
|
|
- src="https://img.pokemondb.net/sprites/sword-shield/icon/bulbasaur.png"
|
|
|
- />
|
|
|
- <div style="grid-area: qvec" id="qvec"></div>
|
|
|
- <div class="toggle-box" style="grid-area: cspc">
|
|
|
- <input
|
|
|
- autocomplete="off"
|
|
|
- type="checkbox"
|
|
|
- class="toggle-button"
|
|
|
- id="space-toggle"
|
|
|
- role="button"
|
|
|
- onchange="state.space = event.target.checked ? 'rgb' : 'jab'; onControlsChanged(state); rerenderSearch(state)"
|
|
|
- />
|
|
|
- <label
|
|
|
- for="space-toggle"
|
|
|
- style="
|
|
|
- display: flex;
|
|
|
- flex-flow: row nowrap;
|
|
|
- justify-content: flex-start;
|
|
|
- align-items: flex-start;
|
|
|
- padding-bottom: 0.5em;
|
|
|
- "
|
|
|
- >
|
|
|
- Color space:
|
|
|
- <span class="toggle-off">CIECAM02-UCS (Jab)</span>
|
|
|
- <span class="toggle-on">sRGB</span>
|
|
|
- </label>
|
|
|
- </div>
|
|
|
- <label for="num-poke" style="grid-area: liml">
|
|
|
- Results: <span id="num-poke-display">10</span>
|
|
|
- </label>
|
|
|
- <input
|
|
|
- id="num-poke"
|
|
|
- style="grid-area: limt"
|
|
|
- autocomplete="off"
|
|
|
- type="range"
|
|
|
- min="1"
|
|
|
- max="100"
|
|
|
- value="10"
|
|
|
- oninput="document.getElementById('num-poke-display').textContent = event.target.value"
|
|
|
- onchange="state.number = event.target.value; onControlsChanged(state)"
|
|
|
- />
|
|
|
- <div class="toggle-box" style="grid-area: sort">
|
|
|
- <input
|
|
|
- autocomplete="off"
|
|
|
- type="checkbox"
|
|
|
- class="toggle-button"
|
|
|
- id="sort-order"
|
|
|
- role="button"
|
|
|
- onchange="state.sortOrder = event.target.checked ? 'max' : 'min'; onControlsChanged(state)"
|
|
|
- />
|
|
|
- <label for="sort-order">
|
|
|
- <span class="toggle-off">Minimize</span>
|
|
|
- <span class="toggle-on">Maximize</span>
|
|
|
- </label>
|
|
|
- </div>
|
|
|
- <select
|
|
|
- style="grid-area: metr"
|
|
|
- autocomplete="off"
|
|
|
- id="sort-metric"
|
|
|
- onchange="state.sortMetric = event.target.value; onControlsChanged(state)"
|
|
|
- ></select>
|
|
|
- <div
|
|
|
- style="
|
|
|
- grid-area: disp;
|
|
|
- padding-bottom: 0.5em;
|
|
|
- justify-self: center;
|
|
|
- "
|
|
|
- id="metric-display"
|
|
|
- ></div>
|
|
|
- <div
|
|
|
- style="
|
|
|
- grid-area: munu;
|
|
|
- padding-top: 0.5em;
|
|
|
- justify-self: center;
|
|
|
- display: flex;
|
|
|
- flex-flow: row nowrap;
|
|
|
- justify-content: space-between;
|
|
|
- width: 90%;
|
|
|
- "
|
|
|
- >
|
|
|
- <div id="mu-def"></div>
|
|
|
- <div id="nu-def"></div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div class="toggle-box cluster-grid">
|
|
|
- <input
|
|
|
- autocomplete="off"
|
|
|
- type="checkbox"
|
|
|
- class="toggle-button"
|
|
|
- id="cluster-toggle"
|
|
|
- role="button"
|
|
|
- checked
|
|
|
- onchange="state.useCluster = event.target.checked; onControlsChanged(state)"
|
|
|
- />
|
|
|
- <label
|
|
|
- for="cluster-toggle"
|
|
|
- style="
|
|
|
- grid-area: albl;
|
|
|
- display: flex;
|
|
|
- flex-flow: row nowrap;
|
|
|
- justify-content: flex-start;
|
|
|
- align-items: flex-start;
|
|
|
- padding-bottom: 0.5em;
|
|
|
- "
|
|
|
- >
|
|
|
- Across
|
|
|
- <span class="toggle-off">whole image</span>
|
|
|
- <span class="toggle-on">best cluster by...</span>
|
|
|
- </label>
|
|
|
- <div
|
|
|
- style="grid-area: sort; justify-self: end"
|
|
|
- class="toggle-on toggle-box"
|
|
|
- >
|
|
|
- <input
|
|
|
- autocomplete="off"
|
|
|
- checked
|
|
|
- type="checkbox"
|
|
|
- class="toggle-button"
|
|
|
- id="cluster-sort-order"
|
|
|
- role="button"
|
|
|
- onchange="state.clusterSettings.sortOrder = event.target.checked ? 'max' : 'min'; onControlsChanged(state)"
|
|
|
- />
|
|
|
- <label for="cluster-sort-order">
|
|
|
- <span class="toggle-off">Minimizing</span>
|
|
|
- <span class="toggle-on">Maximizing</span>
|
|
|
- </label>
|
|
|
- </div>
|
|
|
- <select
|
|
|
- style="grid-area: metr"
|
|
|
- autocomplete="off"
|
|
|
- id="cluster-sort-metric"
|
|
|
- class="toggle-on"
|
|
|
- onchange="state.clusterSettings.sortMetric = event.target.value; onControlsChanged(state)"
|
|
|
- ></select>
|
|
|
- <span style="grid-area: blbl; justify-self: end" class="toggle-on"
|
|
|
- >Rescaled by</span
|
|
|
- >
|
|
|
- <select
|
|
|
- style="grid-area: clus"
|
|
|
- autocomplete="off"
|
|
|
- id="cluster-scale-option"
|
|
|
- class="toggle-on"
|
|
|
- onchange="state.clusterSettings.scaleOption = event.target.value; onControlsChanged(state)"
|
|
|
- >
|
|
|
- <option value="none" selected>None</option>
|
|
|
- <option value="direct">Cluster size</option>
|
|
|
- <option value="inverse">Inverse cluster size</option>
|
|
|
- <option value="size">Image size</option>
|
|
|
- <option value="inverseSize">Inverse image size</option>
|
|
|
- </select>
|
|
|
- <span style="grid-area: slbl" class="toggle-on"
|
|
|
- >And scale result by</span
|
|
|
- >
|
|
|
- <select
|
|
|
- style="grid-area: scal"
|
|
|
- autocomplete="off"
|
|
|
- id="scale-option"
|
|
|
- class="toggle-on"
|
|
|
- onchange="state.scaleOption = event.target.value; onControlsChanged(state)"
|
|
|
- >
|
|
|
- <option value="none">None</option>
|
|
|
- <option value="direct">Cluster size</option>
|
|
|
- <option value="inverse" selected>Inverse cluster size</option>
|
|
|
- <option value="size">Image size</option>
|
|
|
- <option value="inverseSize">Inverse image size</option>
|
|
|
- </select>
|
|
|
- <div class="toggle-on toggle-box" style="grid-area: mult">
|
|
|
- <input
|
|
|
- autocomplete="off"
|
|
|
- type="checkbox"
|
|
|
- class="toggle-button"
|
|
|
- id="multiply-toggle"
|
|
|
- role="button"
|
|
|
- checked
|
|
|
- onchange="state.clusterSettings.multWithTotal = event.target.checked; onControlsChanged(state)"
|
|
|
- />
|
|
|
- <label
|
|
|
- for="multiply-toggle"
|
|
|
- style="
|
|
|
- display: flex;
|
|
|
- flex-flow: row nowrap;
|
|
|
- justify-content: flex-start;
|
|
|
- align-items: flex-start;
|
|
|
- padding-bottom: 0.5em;
|
|
|
- "
|
|
|
- >
|
|
|
- And
|
|
|
- <span class="toggle-off"> do not </span>
|
|
|
- multiply by whole image score
|
|
|
- </label>
|
|
|
- </div>
|
|
|
- <div
|
|
|
- style="
|
|
|
- grid-area: disp;
|
|
|
- padding-top: 0.5em;
|
|
|
- padding-bottom: 0.5em;
|
|
|
- padding-top: 0.5em;
|
|
|
- padding-bottom: 0.5em;
|
|
|
- justify-self: center;
|
|
|
- overflow: hidden;
|
|
|
- "
|
|
|
- id="cluster-metric-display"
|
|
|
- class="toggle-on"
|
|
|
- ></div>
|
|
|
- </div>
|
|
|
- <div
|
|
|
- style="
|
|
|
- width: 100%;
|
|
|
- display: flex;
|
|
|
- flex-flow: column nowrap;
|
|
|
- justify-content: flex-start;
|
|
|
- align-items: center;
|
|
|
- "
|
|
|
- >
|
|
|
- <span style="align-self: flex-start">Final metric:</span>
|
|
|
- <div
|
|
|
- id="final-metric-display"
|
|
|
- style="padding-top: 0.5em; padding-bottom: 0.5em"
|
|
|
- ></div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div class="divider"></div>
|
|
|
- <div class="list-container">
|
|
|
- <div class="search-container">
|
|
|
- <button type="button" onclick="onRandomColor(state)">
|
|
|
- Random Color
|
|
|
- </button>
|
|
|
- <input
|
|
|
- autocomplete="off"
|
|
|
- maxlength="7"
|
|
|
- id="color-input"
|
|
|
- value="#222222"
|
|
|
- oninput="onColorChanged(state, event.target.value)"
|
|
|
- />
|
|
|
- </div>
|
|
|
- <ul id="result-list" class="pkmn-list"></ul>
|
|
|
- </div>
|
|
|
- <div class="divider"></div>
|
|
|
- <div class="list-container">
|
|
|
- <div class="search-container">
|
|
|
- <button type="button" onclick="onRandomName(state)">
|
|
|
- Random Pokemon
|
|
|
- </button>
|
|
|
- <input
|
|
|
- autocomplete="off"
|
|
|
- size="15"
|
|
|
- oninput="onSearch(state, event.target.value)"
|
|
|
- />
|
|
|
- </div>
|
|
|
- <ul id="search-list" class="pkmn-list"></ul>
|
|
|
- </div>
|
|
|
- <div class="divider"></div>
|
|
|
- <div>
|
|
|
- Previous colors:
|
|
|
- <div id="prev-colors"></div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </body>
|
|
|
-</html>
|