render.js 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. const getSprite = (() => {
  2. const stripForm = ["flabebe", "floette", "florges", "vivillon", "basculin", "furfrou", "magearna", "alcremie",];
  3. return pokemon => {
  4. pokemon = pokemon
  5. .replace("-alola", "-alolan")
  6. .replace("-galar", "-galarian")
  7. .replace("-phony", "") // sinistea and polteageist
  8. .replace("darmanitan-galarian", "darmanitan-galarian-standard");
  9. if (stripForm.find(s => pokemon.includes(s))) {
  10. pokemon = pokemon.replace(/-.*$/, "");
  11. }
  12. return `https://img.pokemondb.net/sprites/sword-shield/icon/${pokemon}.png`;
  13. }
  14. })();
  15. const renderStatPair = (lbl, val, valueClass = "value") => `
  16. <span class="pkmn-tile_label">${lbl}</span>
  17. <span class="pkmn-tile_${valueClass}">${val}</span>
  18. `;
  19. const renderStatRow = lines => `
  20. <div class="pkmn-tile_row">
  21. ${lines.join("\n")}
  22. </div>
  23. `;
  24. const renderPokemonTileCluster = (area, { mu, nu, proportion }, scores) => {
  25. const textColor = getContrastingTextColor(mu.hex);
  26. return `
  27. <div
  28. class="pkmn-tile_stats"
  29. style="grid-area: ${area}; color: ${textColor}; background-color: ${mu.hex};"
  30. >
  31. <div class="pkmn-tile_row" style="justify-content: center;">
  32. ${(100 * proportion).toFixed(2)}% ${mu.hex}
  33. </div>
  34. <div class="toggle-on">
  35. ${
  36. [ ["α =", scores.alpha.toFixed(3)],
  37. ["σ =", scores.sigma.toFixed(3)],
  38. ["Θ =", scores.bigTheta.toFixed(3)],
  39. ["θ =", scores.theta.toFixed(3) + "°"],
  40. ["ϕ =", scores.phi.toFixed(3) + "°"],
  41. ["δ =", scores.delta.toFixed(3)],
  42. ["M =", scores.manhattan.toFixed(3)],
  43. ["Ч =", scores.ch.toFixed(3)],
  44. ["ℓ =", scores.lightnessDiff.toFixed(3)],
  45. ]
  46. .map(([lbl, val]) => renderStatPair(lbl, val))
  47. .map(ls => renderStatRow([ls]))
  48. .join("\n")
  49. }
  50. <hr style="width: 80%; color: ${textColor}"/>
  51. ${
  52. [ ["μ =", `(${mu.vector[0].toFixed(2)},`],
  53. ["", mu.vector[1].toFixed(2) + ","],
  54. ["", mu.vector[2].toFixed(2) + ")"],
  55. ["ν =", `(${nu[0].toFixed(2)},`],
  56. ["", nu[1].toFixed(2) + ","],
  57. ["", nu[2].toFixed(2) + ")"],
  58. ["I =", scores.inertia.toFixed(2)],
  59. ["V =", scores.variance.toFixed(2)],
  60. ["Φ =", scores.muNuAngle.toFixed(2) + "°"],
  61. ["N =", scores.size],
  62. ["L =", scores.lightness.toFixed(2)],
  63. ["C =", scores.chroma.toFixed(2)],
  64. ["β = ", scores.importance.toFixed(2)],
  65. ]
  66. .map(([lbl, val]) => renderStatPair(lbl, val))
  67. .map(ls => renderStatRow([ls]))
  68. .join("\n")
  69. }
  70. </div>
  71. </div>
  72. `;
  73. };
  74. const clusterToggles = {};
  75. const renderPokemonTile = (kind, name, { total: { mu, nu, size }, clusters }, scores, bestClusterIndex) => {
  76. const clusterToggleId = `${name}-${kind}-pkmn-expand-toggle`;
  77. const textColor = getContrastingTextColor(mu.hex);
  78. return `
  79. <div class="pkmn-tile toggle-box">
  80. <input
  81. autocomplete="off"
  82. type="checkbox"
  83. ${clusterToggles?.[clusterToggleId] ? "checked" : ""}
  84. id="${clusterToggleId}"
  85. onchange="clusterToggles['${clusterToggleId}'] = event.target.checked"
  86. class="toggle-button"
  87. role="button"
  88. >
  89. <label for="${clusterToggleId}" style="grid-area: togg; text-align: center; align-self: start;">
  90. <div class="toggle-off">►</div>
  91. <div class="toggle-on">▼</div>
  92. </label>
  93. <img style="grid-area: icon" src="${getSprite(name)}" />
  94. <span style="grid-area: name">
  95. ${name.split("-").map(part => part.charAt(0).toUpperCase() + part.substr(1)).join(" ")}
  96. </span>
  97. <div
  98. class="pkmn-tile_stats"
  99. style="grid-area: totl; color: ${textColor}; background-color: ${mu.hex};"
  100. >
  101. <div class="pkmn-tile_row" style="justify-content: center;">
  102. ${mu.hex}
  103. </div>
  104. <div class="toggle-on">
  105. ${ renderStatRow(
  106. [ ["α =", scores.total.alpha.toFixed(3)],
  107. ["σ =", scores.total.sigma.toFixed(3)],
  108. ["Θ =", scores.total.bigTheta.toFixed(3)],
  109. ["θ =", scores.total.theta.toFixed(3) + "°"],
  110. ["ϕ =", scores.total.phi.toFixed(3) + "°"],
  111. ].map(([lbl, val]) => renderStatPair(lbl, val))
  112. )}
  113. ${ renderStatRow(
  114. [ ["δ =", scores.total.delta.toFixed(3)],
  115. ["M =", scores.total.manhattan.toFixed(3)],
  116. ["Ч =", scores.total.ch.toFixed(3)],
  117. ["ℓ =", scores.total.lightnessDiff.toFixed(3)],
  118. ].map(([lbl, val]) => renderStatPair(lbl, val))
  119. )}
  120. <hr style="width: 80%; color: ${textColor}"/>
  121. ${ renderStatRow(
  122. [ ["μ =", `(${mu.vector.map(c => c.toFixed(2)).join(", ")})`, "vector"],
  123. ["ν =", `(${nu.map(c => c.toFixed(2)).join(", ")})`, "vector"],
  124. ].map(([lbl, val, cls]) => renderStatPair(lbl, val, cls))
  125. )}
  126. ${ renderStatRow(
  127. [ ["I =", scores.total.inertia.toFixed(2)],
  128. ["V =", scores.total.variance.toFixed(2)],
  129. ["Φ =", scores.total.muNuAngle.toFixed(2) + "°"],
  130. ["N =", size],
  131. ["L =", scores.total.lightness.toFixed(2)],
  132. ["C =", scores.total.chroma.toFixed(2)],
  133. ].map(([lbl, val, cls]) => renderStatPair(lbl, val, cls))
  134. )}
  135. ${ bestClusterIndex < 0 ? "" : `<hr style="width: 80%; color: ${textColor}"/>` }
  136. ${ renderStatRow([
  137. `<span class="pkmn-tile_indicator">${bestClusterIndex === 0 ? "▼" : ""}</span>`,
  138. `<span class="pkmn-tile_indicator">${bestClusterIndex === 1 ? "▼" : ""}</span>`,
  139. `<span class="pkmn-tile_indicator">${bestClusterIndex === 2 ? "▼" : ""}</span>`,
  140. `<span class="pkmn-tile_indicator">${bestClusterIndex === 3 ? "▼" : ""}</span>`,
  141. ])}
  142. </div>
  143. </div>
  144. ${clusters.map((c, i) => renderPokemonTileCluster(`cls${i+1}`, c, scores.clusters[i])).join("\n")}
  145. </div>
  146. `
  147. };