Kirk Trombley 2 years ago
parent
commit
92a4a978b2
1 changed files with 39 additions and 51 deletions
  1. 39 51
      main.js

+ 39 - 51
main.js

@@ -7,7 +7,6 @@ const vectorMag = v => Math.sqrt(vectorDot(v, v));
 const rad2deg = 180 / Math.PI;
 
 // Misc
-const clamp = (mn, v, mx) => Math.min(Math.max(v, mn), mx);
 const productLift =
   (...factors) =>
   (...args) =>
@@ -16,40 +15,8 @@ const productLift =
       .map(fn => fn(...args))
       .reduce((x, y) => x * y, 1);
 
-// Contrast + Shadow + Hover Colors
-const getContrastingTextColor = hex => {
-  const { r, g, b } = d3.color(hex);
-  return vectorDot([r, g, b], [0.3, 0.6, 0.1]) >= 128
-    ? "var(--color-dark)"
-    : "var(--color-light)";
-};
-
-// "Visual Importance"
-const calcImportance = (chroma, lightness, proportion) =>
-  chroma +
-  Math.tanh(100 * (chroma - 0.25)) + // penalty for being <25%
-  Math.tanh(100 * (chroma - 0.4)) + // penalty for being <40%
-  lightness +
-  Math.tanh(100 * (lightness - 0.5)) + // penalty for being <50%
-  proportion +
-  Math.tanh(100 * (proportion - 0.05)) + // penalty for being <5%
-  Math.tanh(100 * (proportion - 0.1)) + // penalty for being <15%
-  Math.tanh(100 * (proportion - 0.15)) + // penalty for being <15%
-  Math.tanh(100 * (proportion - 0.25)) + // penalty for being <25%
-  Math.tanh(100 * (proportion - 0.8)); // penalty for being <50%
-
-// Conversions
-const jab2hex = jab => d3.jab(...jab).formatHex();
-const rgb2hex = rgb => d3.rgb(...rgb).formatHex();
-const jab2hue = jab => d3.jch(d3.jab(...jab)).h || 0;
-const rgb2hue = rgb => d3.hsl(d3.rgb(...rgb)).h || 0;
-const jab2lit = ([j]) => j / 100;
-const rgb2lit = rgb => d3.hsl(d3.rgb(...rgb)).l || 0;
-const jab2chroma = jab => d3.jch(d3.jab(...jab)).C / 100;
-const rgb2chroma = rgb => d3.jch(d3.rgb(...rgb)).C / 100;
-
 // Pre-computation
-const buildVectorData = (vector, toHue, toLightness, toChroma, toHex) => {
+const getVectorDataBuilder = (toHue, toLightness, toChroma, toHex) => vector => {
   const sqMag = vectorDot(vector, vector);
   const mag = Math.sqrt(sqMag);
   const unit = vector.map(c => c / mag);
@@ -59,10 +26,18 @@ const buildVectorData = (vector, toHue, toLightness, toChroma, toHex) => {
   const hex = toHex(vector);
   return { vector, sqMag, mag, unit, hue, lightness, chroma, hex };
 };
-const buildVectorDataJab = vector =>
-  buildVectorData(vector, jab2hue, jab2lit, jab2chroma, jab2hex);
-const buildVectorDataRgb = vector =>
-  buildVectorData(vector, rgb2hue, rgb2lit, rgb2chroma, rgb2hex);
+const buildVectorDataJab = getVectorDataBuilder(
+  jab => d3.jch(d3.jab(...jab)).h || 0, // Jab -> hue
+  ([j]) => j / 100, // Jab -> lightness
+  jab => d3.jch(d3.jab(...jab)).C / 100, // Jab -> chroma
+  jab => d3.jab(...jab).formatHex() // Jab -> hex
+);
+const buildVectorDataRgb = getVectorDataBuilder(
+  rgb => d3.hsl(d3.rgb(...rgb)).h || 0, // RGB -> hue
+  rgb => d3.hsl(d3.rgb(...rgb)).l || 0, // RGB -> lightness
+  rgb => d3.jch(d3.rgb(...rgb)).C / 100, // RGB -> chroma
+  rgb => d3.rgb(...rgb).formatHex() // RGB -> hex
+);
 
 const buildClusterData = (
   size,
@@ -80,7 +55,18 @@ const buildClusterData = (
   const nu = [nu1, nu2, nu3];
   const muNuAngle = rad2deg * Math.acos(vectorDot(mu.unit, nu) / vectorMag(nu));
   const proportion = size / totalSize;
-  const importance = calcImportance(mu.chroma, mu.lightness, proportion);
+  const importance = // "Visual Importance"
+    mu.chroma +
+    Math.tanh(100 * (mu.chroma - 0.25)) + // penalty for being <25%
+    Math.tanh(100 * (mu.chroma - 0.4)) + // penalty for being <40%
+    mu.lightness +
+    Math.tanh(100 * (mu.lightness - 0.5)) + // penalty for being <50%
+    proportion +
+    Math.tanh(100 * (proportion - 0.05)) + // penalty for being <5%
+    Math.tanh(100 * (proportion - 0.1)) + // penalty for being <15%
+    Math.tanh(100 * (proportion - 0.15)) + // penalty for being <15%
+    Math.tanh(100 * (proportion - 0.25)) + // penalty for being <25%
+    Math.tanh(100 * (proportion - 0.8)); // penalty for being <50%
   return {
     size,
     inverseSize: 1 / size,
@@ -94,7 +80,7 @@ const buildClusterData = (
   };
 };
 
-const buildPokemonData = ([name, size, ...values]) => ({
+const pokemonData = databaseV3.map(([name, size, ...values]) => ({
   name,
   jab: {
     total: buildClusterData(size, ...values.slice(0, 7), size, buildVectorDataJab),
@@ -114,9 +100,7 @@ const buildPokemonData = ([name, size, ...values]) => ({
       buildClusterData(...values.slice(70, 78), size, buildVectorDataRgb),
     ].filter(c => c.size !== 0),
   },
-});
-
-const pokemonData = databaseV3.map(row => buildPokemonData(row));
+}));
 
 const calcScores = (data, target) => {
   const sigma = Math.sqrt(
@@ -164,7 +148,11 @@ const sortOrders = {
 const rootStyle = document.querySelector(":root").style;
 
 const setColorStyles = (style, hex) => {
-  const highlight = getContrastingTextColor(hex);
+  const { r, g, b } = d3.color(hex);
+  const highlight =
+    vectorDot([r, g, b], [0.3, 0.6, 0.1]) >= 128
+      ? "var(--color-dark)"
+      : "var(--color-light)";
   style.setProperty("--highlight", highlight);
   style.setProperty("--background", hex);
   style.setProperty("--shadow-component", highlight.includes("light") ? "255" : "0");
@@ -224,12 +212,6 @@ const getSpriteName = (() => {
   };
 })();
 
-const formatName = name =>
-  name
-    .split("-")
-    .map(part => part.charAt(0).toUpperCase() + part.substr(1))
-    .join(" ");
-
 const renderPokemon = (list, target) => {
   target.innerText = "";
 
@@ -265,7 +247,13 @@ const renderPokemon = (list, target) => {
     image.addEventListener("error", imageErrHandler);
     image.src = `https://img.pokemondb.net/sprites/sword-shield/icon/${spriteName}.png`;
 
-    name.innerText = name.title = image.alt = formatName(pkmnName);
+    name.innerText =
+      name.title =
+      image.alt =
+        pkmnName
+          .split("-")
+          .map(part => part.charAt(0).toUpperCase() + part.substr(1))
+          .join(" ");
 
     const colorSpace = document.forms.colorSortForm.elements.colorSpace.value;