|
@@ -31,40 +31,15 @@ const clusterMetric = addMetricForm(
|
|
|
"cls-metric-mount"
|
|
|
);
|
|
|
|
|
|
-// ---- Score Calculation ----
|
|
|
-const currentScores = U.obs(() => {
|
|
|
- const rgb = d3.rgb(targetColor.value);
|
|
|
- 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
|
|
|
+const sortIgnoresCluster = U.obs(() =>
|
|
|
+ [
|
|
|
+ // ensure dep on all three
|
|
|
+ sortUseBestCluster.value,
|
|
|
+ sortUseClusterSize.value,
|
|
|
+ sortUseInverseClusterSize.value,
|
|
|
+ ].every((v) => !v)
|
|
|
);
|
|
|
|
|
|
- const scores = {};
|
|
|
- pokemonData.forEach(({ name, jab, rgb }) => {
|
|
|
- scores[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)),
|
|
|
- },
|
|
|
- };
|
|
|
- });
|
|
|
- return scores;
|
|
|
-});
|
|
|
-
|
|
|
-const extractScore = (name) => {
|
|
|
- // TODO
|
|
|
-};
|
|
|
-
|
|
|
// ---- Color Controls ----
|
|
|
const randomizeTargetColor = () => {
|
|
|
targetColor.value = d3
|
|
@@ -248,12 +223,136 @@ U.template(
|
|
|
);
|
|
|
|
|
|
U.reactive(() => {
|
|
|
- document.forms.clsMetric.dataset.faded = document.forms.clsFunction.dataset.faded = [
|
|
|
- // ensure dep on all three
|
|
|
- sortUseBestCluster.value,
|
|
|
- sortUseClusterSize.value,
|
|
|
- sortUseInverseClusterSize.value,
|
|
|
- ].every((v) => !v);
|
|
|
+ document.forms.clsMetric.dataset.faded = document.forms.clsFunction.dataset.faded =
|
|
|
+ sortIgnoresCluster.value;
|
|
|
+});
|
|
|
+
|
|
|
+// ---- Score Calculation ----
|
|
|
+const currentScores = U.obs(() => {
|
|
|
+ const rgb = d3.rgb(targetColor.value);
|
|
|
+ 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
|
|
|
+ );
|
|
|
+
|
|
|
+ const scores = {};
|
|
|
+ pokemonData.forEach(({ name, jab, rgb }) => {
|
|
|
+ scores[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)),
|
|
|
+ },
|
|
|
+ };
|
|
|
+ });
|
|
|
+ return scores;
|
|
|
});
|
|
|
|
|
|
+const sortOrders = {
|
|
|
+ max: (a, b) => b - a,
|
|
|
+ min: (a, b) => a - b,
|
|
|
+};
|
|
|
+
|
|
|
+const getClusterRankingValue = U.obs(() => {
|
|
|
+ const metric = clusterMetric.value;
|
|
|
+ const factors = [(cluster) => cluster[metric]];
|
|
|
+ if (clusterUseClusterSize.value) {
|
|
|
+ factors.push((cluster) => cluster.size);
|
|
|
+ }
|
|
|
+ if (clusterUseInverseClusterSize.value) {
|
|
|
+ factors.push((cluster) => cluster.inverseSize);
|
|
|
+ }
|
|
|
+ if (clusterUseTotalSize.value) {
|
|
|
+ factors.push((_, total) => total.size);
|
|
|
+ }
|
|
|
+ if (clusterUseInverseTotalSize.value) {
|
|
|
+ factors.push((_, total) => total.inverseSize);
|
|
|
+ }
|
|
|
+ return (cluster, total) =>
|
|
|
+ factors.map((fn) => fn(cluster, total)).reduce((x, y) => x * y);
|
|
|
+});
|
|
|
+
|
|
|
+const getBestClusterIndex = U.obs(() => {
|
|
|
+ const rank = getClusterRankingValue.value;
|
|
|
+ const clsSort = sortOrders[clusterOrder.value];
|
|
|
+
|
|
|
+ return (scores) => {
|
|
|
+ return scores.clusters
|
|
|
+ .map((c, i) => [rank(c, scores.total), i])
|
|
|
+ .reduce((a, b) => (clsSort(a[0], b[0]) > 0 ? b : a))[1];
|
|
|
+ };
|
|
|
+});
|
|
|
+
|
|
|
+const getRankingValue = U.obs(() => {
|
|
|
+ const metric = sortMetric.value;
|
|
|
+ const factors = [];
|
|
|
+ if (sortUseWholeImage.value) {
|
|
|
+ factors.push((scores) => scores.total[metric]);
|
|
|
+ }
|
|
|
+ if (sortUseBestCluster.value) {
|
|
|
+ factors.push((scores, index) => scores.clusters[index][metric]);
|
|
|
+ }
|
|
|
+ if (sortUseClusterSize.value) {
|
|
|
+ factors.push((scores, index) => scores.clusters[index].size);
|
|
|
+ }
|
|
|
+ if (sortUseInverseClusterSize.value) {
|
|
|
+ factors.push((scores, index) => scores.clusters[index].inverseSize);
|
|
|
+ }
|
|
|
+ if (sortUseTotalSize.value) {
|
|
|
+ factors.push((scores) => scores.total.size);
|
|
|
+ }
|
|
|
+ if (sortUseInverseTotalSize.value) {
|
|
|
+ factors.push((scores) => scores.total.inverseSize);
|
|
|
+ }
|
|
|
+ return (scores, bestClusterIndex) =>
|
|
|
+ factors.map((fn) => fn(scores, bestClusterIndex)).reduce((x, y) => x * y, 1);
|
|
|
+});
|
|
|
+
|
|
|
+const currentResults = U.obs(() => {
|
|
|
+ console.log("Recalculating");
|
|
|
+
|
|
|
+ const bestClusterIndices = {};
|
|
|
+ const rankingValues = {};
|
|
|
+
|
|
|
+ pokemonData.forEach(({ name }) => {
|
|
|
+ const { jab, rgb } = currentScores.value[name];
|
|
|
+ const bestJab = getBestClusterIndex.value(jab);
|
|
|
+ const bestRgb = getBestClusterIndex.value(rgb);
|
|
|
+ bestClusterIndices[name] = { jab: bestJab, rgb: bestRgb };
|
|
|
+ rankingValues[name] = {
|
|
|
+ jab: getRankingValue.value(jab, bestJab),
|
|
|
+ rgb: getRankingValue.value(rgb, bestRgb),
|
|
|
+ };
|
|
|
+ });
|
|
|
+
|
|
|
+ return { bestClusterIndices, rankingValues };
|
|
|
+});
|
|
|
+
|
|
|
+const sortedResults = U.obs(() => {
|
|
|
+ console.log("Resorting");
|
|
|
+
|
|
|
+ const { rankingValues } = currentResults.value;
|
|
|
+ const sort = sortOrders[sortOrder.value];
|
|
|
+ const space = colorSpace.value;
|
|
|
+ return pokemonData
|
|
|
+ .map(({ name }) => name)
|
|
|
+ .sort(
|
|
|
+ (a, b) =>
|
|
|
+ sort(rankingValues[a][space], rankingValues[b][space]) || a.localeCompare(b)
|
|
|
+ );
|
|
|
+});
|
|
|
+
|
|
|
+const colorSearchResults = U.obs(() =>
|
|
|
+ sortedResults.value.slice(0, resultsToDisplay.value)
|
|
|
+);
|
|
|
+
|
|
|
randomizeTargetColor();
|