浏览代码

Score calculation and sorting

Kirk Trombley 2 年之前
父节点
当前提交
7bf473947e
共有 1 个文件被更改,包括 137 次插入38 次删除
  1. 137 38
      script.js

+ 137 - 38
script.js

@@ -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();