render.js 6.4 KB

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