nearest.js 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. const getSprite = pokemon => `https://img.pokemondb.net/sprites/sword-shield/icon/${pokemon}.png`
  2. const vectorMag = v => Math.sqrt(v.map(x => x * x).reduce((x, y) => x + y));
  3. const onColorChange = () => {
  4. const numPoke = document.getElementById("num-poke")?.value;
  5. document.getElementById("num-poke-display").innerHTML = numPoke;
  6. const closeCoeff = document.getElementById("close-coeff")?.value;
  7. document.getElementById("close-coeff-display").innerHTML = closeCoeff;
  8. const includeX = document.getElementById("include-x")?.checked ?? false;
  9. const normQY = document.getElementById("norm-q-y")?.checked ?? false;
  10. const bestList = document.getElementById("best-list");
  11. bestList.innerHTML = ''; // do the lazy thing
  12. const color = document.getElementById("color-input")?.value;
  13. if (color.length !== 6) {
  14. return;
  15. }
  16. document.querySelector("body").setAttribute("style", `background: #${color}`);
  17. const colorValues = [
  18. Number.parseInt(color.substring(0, 2), 16),
  19. Number.parseInt(color.substring(2, 4), 16),
  20. Number.parseInt(color.substring(4, 6), 16),
  21. ];
  22. const colorMag = vectorMag(colorValues);
  23. database.map(([name, x, ...y]) => {
  24. const xComp = includeX ? x : 0;
  25. const norm = normQY ? vectorMag(y) * colorMag : 1;
  26. return {
  27. name,
  28. score: xComp - closeCoeff * y.map((yc, i) => yc * colorValues[i] / norm).reduce((x, y) => x + y),
  29. avgColor: y,
  30. };
  31. }).sort((a, b) => a.score - b.score)
  32. .slice(0, numPoke)
  33. .forEach(({ name, avgColor}) => {
  34. const li = document.createElement("li");
  35. const img = document.createElement("img");
  36. const tile = document.createElement("div");
  37. const hexColor = avgColor.map(c => Math.round(c).toString(16).padStart(2, "0")).reduce((x, y) => x + y);
  38. tile.setAttribute("style", `width: 25px; height: 25px; background-color: #${hexColor}`)
  39. img.setAttribute("src", getSprite(name));
  40. li.appendChild(img)
  41. li.appendChild(document.createTextNode(name));
  42. li.appendChild(tile)
  43. li.setAttribute("style", "display: flex; flex-flow: row nowrap; justify-content: space-between; width: 320px")
  44. bestList.appendChild(li);
  45. });
  46. };
  47. const onRandomColor = () => {
  48. const colorInput = document.getElementById("color-input");
  49. colorInput.value = hsvToRGB(Math.random(), 0.9, 0.9);
  50. onColorChange();
  51. };
  52. // mostly stolen from https://stackoverflow.com/a/17243070
  53. // adapted slightly
  54. const hsvToRGB = (h, s, v) => {
  55. var r, g, b, i, f, p, q, t;
  56. i = Math.floor(h * 6);
  57. f = h * 6 - i;
  58. p = v * (1 - s);
  59. q = v * (1 - f * s);
  60. t = v * (1 - (1 - f) * s);
  61. switch (i % 6) {
  62. case 0: r = v, g = t, b = p; break;
  63. case 1: r = q, g = v, b = p; break;
  64. case 2: r = p, g = v, b = t; break;
  65. case 3: r = p, g = q, b = v; break;
  66. case 4: r = t, g = p, b = v; break;
  67. case 5: r = v, g = p, b = q; break;
  68. }
  69. return [r, g, b].map(c => Math.round(c * 255).toString(16).padStart(2, "0")).reduce((x, y) => x + y);
  70. }