|
@@ -1,52 +1,27 @@
|
|
|
const selectors = {
|
|
|
- get sortControl() {
|
|
|
- return document.forms.sortControl.elements;
|
|
|
- },
|
|
|
- get clusterControl() {
|
|
|
- return document.forms.clusterControl.elements;
|
|
|
- },
|
|
|
- get colorSelect(){
|
|
|
+ get colorSelect() {
|
|
|
return document.forms.colorSelect.elements;
|
|
|
},
|
|
|
- get resultsToDisplay() {
|
|
|
- return selectors.sortControl.resultsToDisplay.value;
|
|
|
- },
|
|
|
- get colorSpace() {
|
|
|
- return selectors.sortControl.colorSpace.value;
|
|
|
- },
|
|
|
- get sortMetric() {
|
|
|
- return selectors.sortControl.sortMetric.value;
|
|
|
- },
|
|
|
- get sortOrder() {
|
|
|
- return selectors.sortControl.sortOrder.checked ? "max" : "min";
|
|
|
- },
|
|
|
- get scaleFactor() {
|
|
|
- return selectors.sortControl.rescaleFactor.value;
|
|
|
+ set colorText(hex) {
|
|
|
+ selectors.colorSelect.colorText.value = hex;
|
|
|
},
|
|
|
- get useClusters() {
|
|
|
- return selectors.sortControl.useClusters.value;
|
|
|
+ set colorPicker(hex) {
|
|
|
+ selectors.colorSelect.colorPicker.value = hex;
|
|
|
},
|
|
|
- get clusterSortMetric() {
|
|
|
- return selectors.clusterControl.sortMetric.value;
|
|
|
+
|
|
|
+ get sortControl() {
|
|
|
+ return document.forms.sortControl;
|
|
|
},
|
|
|
- get clusterSortOrder() {
|
|
|
- return selectors.clusterControl.sortOrder.checked ? "max" : "min";
|
|
|
+ get resultsToDisplay() {
|
|
|
+ return selectors.sortControl.elements.resultsToDisplay.value;
|
|
|
},
|
|
|
- get clusterScaleFactor() {
|
|
|
- return selectors.clusterControl.rescaleFactor.value;
|
|
|
+ get colorSpace() {
|
|
|
+ return selectors.sortControl.elements.colorSpace.value;
|
|
|
},
|
|
|
+
|
|
|
get prevColors() {
|
|
|
return document.getElementById("prev-colors");
|
|
|
},
|
|
|
- get metricFormTemplate() {
|
|
|
- return document.getElementById("metric-form-template").content;
|
|
|
- },
|
|
|
- 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,24 +31,77 @@ const selectors = {
|
|
|
get nameSearchResults() {
|
|
|
return document.getElementById("name-results");
|
|
|
},
|
|
|
+
|
|
|
set background(hex) {
|
|
|
document.querySelector(":root").style.setProperty("--background", hex);
|
|
|
},
|
|
|
set highlight(hex) {
|
|
|
document.querySelector(":root").style.setProperty("--highlight", hex);
|
|
|
},
|
|
|
- set colorText(hex) {
|
|
|
- selectors.colorSelect.colorText.value = hex;
|
|
|
+
|
|
|
+ get metricSelectTemplate() {
|
|
|
+ return document.getElementById("metric-select-template").content;
|
|
|
},
|
|
|
- set colorPicker(hex) {
|
|
|
- selectors.colorSelect.colorPicker.value = hex;
|
|
|
+
|
|
|
+ get sortFunction() {
|
|
|
+ return document.forms.sortFunction;
|
|
|
+ },
|
|
|
+ get sortMetric() {
|
|
|
+ return selectors.sortFunction.elements.sortMetric.value;
|
|
|
+ },
|
|
|
+ get sortOrder() {
|
|
|
+ return selectors.sortFunction.elements.sortOrder.checked ? "max" : "min";
|
|
|
+ },
|
|
|
+ get sortUseBestCluster() {
|
|
|
+ return selectors.sortFunction.elements.useBestCluster.checked;
|
|
|
+ },
|
|
|
+ get sortUseWholeImage() {
|
|
|
+ return selectors.sortFunction.elements.useWholeImage.checked;
|
|
|
+ },
|
|
|
+ get sortClusterSize() {
|
|
|
+ return selectors.sortFunction.elements.clusterSize.checked;
|
|
|
+ },
|
|
|
+ get sortInverseClusterSize() {
|
|
|
+ return selectors.sortFunction.elements.invClusterSize.checked;
|
|
|
+ },
|
|
|
+ get sortTotalSize() {
|
|
|
+ return selectors.sortFunction.elements.totalSize.checked;
|
|
|
+ },
|
|
|
+ get sortInverseTotalSize() {
|
|
|
+ return selectors.sortFunction.elements.invTotalSize.checked;
|
|
|
+ },
|
|
|
+ set sortMetricSymbol(sym) {
|
|
|
+ selectors.sortFunction.elements.metricSymbolP.value = sym;
|
|
|
+ selectors.sortFunction.elements.metricSymbolB.value = sym;
|
|
|
+ },
|
|
|
+
|
|
|
+ get clusterFunction() {
|
|
|
+ return document.forms.clusterFunction;
|
|
|
+ },
|
|
|
+ get clusterSortMetric() {
|
|
|
+ return selectors.clusterFunction.elements.sortMetric.value;
|
|
|
+ },
|
|
|
+ get clusterSortOrder() {
|
|
|
+ return selectors.clusterFunction.elements.sortOrder.checked ? "max" : "min";
|
|
|
+ },
|
|
|
+ get clusterSortClusterSize() {
|
|
|
+ return selectors.clusterFunction.elements.clusterSize.checked;
|
|
|
+ },
|
|
|
+ get clusterSortInverseClusterSize() {
|
|
|
+ return selectors.clusterFunction.elements.invClusterSize.checked;
|
|
|
+ },
|
|
|
+ get clusterSortTotalSize() {
|
|
|
+ return selectors.clusterFunction.elements.totalSize.checked;
|
|
|
+ },
|
|
|
+ get clusterSortInverseTotalSize() {
|
|
|
+ return selectors.clusterFunction.elements.invTotalSize.checked;
|
|
|
+ },
|
|
|
+ set clusterMetricSymbol(sym) {
|
|
|
+ selectors.clusterFunction.elements.metricSymbol.value = sym;
|
|
|
},
|
|
|
};
|
|
|
|
|
|
const onMetricChange = (elements, skipUpdates = false) => {
|
|
|
- elements.sortOrderLabel.value = elements.sortOrder.checked
|
|
|
- ? "Maximizing"
|
|
|
- : "Minimizing";
|
|
|
const kind = elements.metricKind.value;
|
|
|
elements.whole.disabled = kind !== "whole";
|
|
|
elements.mean.disabled = kind !== "mean";
|
|
@@ -81,6 +109,14 @@ const onMetricChange = (elements, skipUpdates = false) => {
|
|
|
elements.sortMetric.value = elements[kind].value;
|
|
|
|
|
|
if (!skipUpdates) {
|
|
|
+ // terrible hack
|
|
|
+ selectors.sortMetricSymbol = document
|
|
|
+ .querySelector(`option[value=${selectors.sortMetric}]`)
|
|
|
+ .textContent.at(-2);
|
|
|
+ selectors.clusterMetricSymbol = document
|
|
|
+ .querySelector(`option[value=${selectors.clusterSortMetric}]`)
|
|
|
+ .textContent.at(-2);
|
|
|
+
|
|
|
updateSort();
|
|
|
}
|
|
|
};
|
|
@@ -128,23 +164,32 @@ const sortOrders = {
|
|
|
min: (a, b) => a - b,
|
|
|
};
|
|
|
|
|
|
-const scaleOptions = {
|
|
|
- none: () => [1, 1, 1],
|
|
|
- direct: (scores) => scores.clusters.map((c) => c.proportion),
|
|
|
- inverse: (scores) => scores.clusters.map((c) => c.inverseProportion),
|
|
|
- size: (scores) => [scores.total.size, scores.total.size, scores.total.size],
|
|
|
- inverseSize: (scores) => [
|
|
|
- scores.total.inverseSize,
|
|
|
- scores.total.inverseSize,
|
|
|
- scores.total.inverseSize,
|
|
|
- ],
|
|
|
-};
|
|
|
-
|
|
|
-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 getCardinalityFactorExtractor = (
|
|
|
+ clusterSize,
|
|
|
+ invClusterSize,
|
|
|
+ totalSize,
|
|
|
+ invTotalSize
|
|
|
+) => {
|
|
|
+ const extractors = [];
|
|
|
+ if (clusterSize) {
|
|
|
+ extractors.push((scores) => scores.clusters.map(({ size }) => size));
|
|
|
+ }
|
|
|
+ if (invClusterSize) {
|
|
|
+ extractors.push((scores) => scores.clusters.map(({ inverseSize }) => inverseSize));
|
|
|
+ }
|
|
|
+ if (totalSize) {
|
|
|
+ extractors.push((scores) => scores.clusters.map(() => scores.total.size));
|
|
|
+ }
|
|
|
+ if (invTotalSize) {
|
|
|
+ extractors.push((scores) => scores.clusters.map(() => scores.total.inverseSize));
|
|
|
+ }
|
|
|
+ return (scores) =>
|
|
|
+ extractors
|
|
|
+ .map((ext) => ext(scores))
|
|
|
+ .reduce(
|
|
|
+ (acc, xs) => acc.map((a, i) => a * xs[i]),
|
|
|
+ scores.clusters.map(() => 1)
|
|
|
+ );
|
|
|
};
|
|
|
|
|
|
const currentScores = {};
|
|
@@ -179,22 +224,55 @@ const updateScores = (rgb) => {
|
|
|
const updateSort = () => {
|
|
|
// update cluster rankings
|
|
|
const clusterSortOrder = sortOrders[selectors.clusterSortOrder];
|
|
|
- const clusterScaleOption = scaleOptions[selectors.clusterScaleFactor];
|
|
|
+ const getClusterCardinalityFactors = getCardinalityFactorExtractor(
|
|
|
+ selectors.clusterSortClusterSize,
|
|
|
+ selectors.clusterSortInverseClusterSize,
|
|
|
+ selectors.clusterSortTotalSize,
|
|
|
+ selectors.clusterSortInverseTotalSize
|
|
|
+ );
|
|
|
pokemonData.forEach(({ name }) => {
|
|
|
const { jab, rgb } = currentScores[name];
|
|
|
- // multiply scale with the intended metric, and find the index of the best value
|
|
|
- const forSpace = (clusters, scales) =>
|
|
|
+ // multiply scales with the intended metric, and find the index of the best value
|
|
|
+ const forSpace = (clusters, factors) =>
|
|
|
clusters
|
|
|
- .map((c, i) => [c[selectors.clusterSortMetric] * scales[i], i])
|
|
|
+ .map((c, i) => [c[selectors.clusterSortMetric] * factors[i], i])
|
|
|
.reduce((a, b) => (clusterSortOrder(a[0], b[0]) > 0 ? b : a))[1];
|
|
|
currentBestClusterIndices[name] = {
|
|
|
- jab: forSpace(jab.clusters, clusterScaleOption(jab)),
|
|
|
- rgb: forSpace(rgb.clusters, clusterScaleOption(rgb)),
|
|
|
+ jab: forSpace(jab.clusters, getClusterCardinalityFactors(jab)),
|
|
|
+ rgb: forSpace(rgb.clusters, getClusterCardinalityFactors(rgb)),
|
|
|
};
|
|
|
});
|
|
|
|
|
|
// set up for actual sort
|
|
|
- const scaleOption = scaleOptions[selectors.scaleFactor];
|
|
|
+ const getCardinalityFactors = getCardinalityFactorExtractor(
|
|
|
+ selectors.sortClusterSize,
|
|
|
+ selectors.sortInverseClusterSize,
|
|
|
+ selectors.sortTotalSize,
|
|
|
+ selectors.sortInverseTotalSize
|
|
|
+ );
|
|
|
+ const factors = [
|
|
|
+ (name) =>
|
|
|
+ getCardinalityFactors(currentScores[name][selectors.colorSpace])[
|
|
|
+ currentBestClusterIndices[name][selectors.colorSpace]
|
|
|
+ ],
|
|
|
+ ];
|
|
|
+ if (selectors.sortUseWholeImage) {
|
|
|
+ factors.push(
|
|
|
+ (name) => currentScores[name][selectors.colorSpace].total[selectors.sortMetric]
|
|
|
+ );
|
|
|
+ }
|
|
|
+ if (selectors.sortUseBestCluster) {
|
|
|
+ factors.push(
|
|
|
+ (name) =>
|
|
|
+ currentScores[name][selectors.colorSpace].clusters[
|
|
|
+ currentBestClusterIndices[name][selectors.colorSpace]
|
|
|
+ ][selectors.sortMetric]
|
|
|
+ );
|
|
|
+ }
|
|
|
+ pokemonData.forEach(({ name }) => {
|
|
|
+ currentSortValues[name] = factors.map((fn) => fn(name)).reduce((x, y) => x * y);
|
|
|
+ });
|
|
|
+ /*
|
|
|
switch (selectors.useClusters) {
|
|
|
case "off":
|
|
|
pokemonData.forEach(({ name }) => {
|
|
@@ -220,6 +298,7 @@ const updateSort = () => {
|
|
|
});
|
|
|
break;
|
|
|
}
|
|
|
+ */
|
|
|
|
|
|
// update actual sorted data
|
|
|
const sortOrder = sortOrders[selectors.sortOrder];
|
|
@@ -288,9 +367,14 @@ const makePokemonTile = (name) => {
|
|
|
`;
|
|
|
});
|
|
|
|
|
|
- if (selectors.useClusters === "off") {
|
|
|
+ if (selectors.sortUseWholeImage) {
|
|
|
clone.querySelector(".pkmn").classList.add("pkmn-total-selected");
|
|
|
- } else {
|
|
|
+ }
|
|
|
+ if (
|
|
|
+ selectors.sortUseBestCluster ||
|
|
|
+ selectors.sortClusterSize ||
|
|
|
+ selectors.sortInverseClusterSize
|
|
|
+ ) {
|
|
|
clone
|
|
|
.querySelector(".pkmn")
|
|
|
.classList.add(
|
|
@@ -332,25 +416,18 @@ const showResults = () => {
|
|
|
};
|
|
|
|
|
|
window.addEventListener("load", () => {
|
|
|
- const metricTemplate = selectors.metricFormTemplate;
|
|
|
-
|
|
|
- selectors.sortControl.metric.prepend(metricTemplate.cloneNode(true));
|
|
|
- selectors.sortControl.metricKind.value = "whole";
|
|
|
- selectors.sortControl.whole.value = "alpha";
|
|
|
- onMetricChange(selectors.sortControl, true);
|
|
|
-
|
|
|
- selectors.clusterControl.metric.appendChild(metricTemplate.cloneNode(true));
|
|
|
- selectors.clusterControl.sortOrder.checked = true;
|
|
|
- selectors.clusterControl.metricKind.value = "statistic";
|
|
|
- selectors.clusterControl.statistic.value = "importance";
|
|
|
- onMetricChange(selectors.clusterControl, true);
|
|
|
-
|
|
|
- const scaleTemplate = selectors.scaleFormTemplate;
|
|
|
- selectors.sortControl.rescaleSection.appendChild(scaleTemplate.cloneNode(true));
|
|
|
- selectors.sortControl.rescaleFactor.value = "inverse";
|
|
|
-
|
|
|
- selectors.clusterControl.rescaleSection.appendChild(scaleTemplate.cloneNode(true));
|
|
|
- selectors.clusterControl.rescaleFactor.value = "none";
|
|
|
+ const metricSelect = selectors.metricSelectTemplate;
|
|
|
+
|
|
|
+ selectors.sortFunction.appendChild(metricSelect.cloneNode(true));
|
|
|
+ selectors.sortFunction.elements.metricKind.value = "whole";
|
|
|
+ selectors.sortFunction.elements.whole.value = "alpha";
|
|
|
+ onMetricChange(selectors.sortFunction.elements, true);
|
|
|
+
|
|
|
+ selectors.clusterFunction.appendChild(metricSelect.cloneNode(true));
|
|
|
+ selectors.clusterFunction.elements.sortOrder.checked = true;
|
|
|
+ selectors.clusterFunction.elements.metricKind.value = "statistic";
|
|
|
+ selectors.clusterFunction.elements.statistic.value = "importance";
|
|
|
+ onMetricChange(selectors.clusterFunction.elements, true);
|
|
|
|
|
|
document.body.addEventListener("click", ({ target: { innerText }, detail }) => {
|
|
|
if (detail === 2 && innerText?.includes("#")) {
|