convert.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. const jab2hex = (jab) => d3.jab(...jab).formatHex();
  2. const rgb2hex = (rgb) => d3.rgb(...rgb).formatHex();
  3. const jab2hue = (jab) => d3.jch(d3.jab(...jab)).h || 0;
  4. const rgb2hue = (rgb) => d3.hsl(d3.rgb(...rgb)).h || 0;
  5. const jab2lit = ([j]) => j / 100;
  6. const rgb2lit = (rgb) => d3.hsl(d3.rgb(...rgb)).l || 0;
  7. const jab2chroma = (jab) => d3.jch(d3.jab(...jab)).C / 100;
  8. const rgb2chroma = (rgb) => d3.jch(d3.rgb(...rgb)).C / 100;
  9. const buildVectorData = (vector, toHue, toLightness, toChroma, toHex) => {
  10. const sqMag = vectorDot(vector, vector);
  11. const mag = Math.sqrt(sqMag);
  12. const unit = vector.map((c) => c / mag);
  13. const hue = toHue(vector);
  14. const lightness = toLightness(vector);
  15. const chroma = toChroma(vector);
  16. const hex = toHex(vector);
  17. return { vector, sqMag, mag, unit, hue, lightness, chroma, hex };
  18. };
  19. const calcImportance = (chroma, lightness, proportion) =>
  20. chroma +
  21. Math.tanh(100 * (chroma - 0.25)) + // penalty for being <25%
  22. Math.tanh(100 * (chroma - 0.4)) + // penalty for being <40%
  23. lightness +
  24. Math.tanh(100 * (lightness - 0.5)) + // penalty for being <50%
  25. proportion +
  26. Math.tanh(100 * (proportion - 0.05)) + // penalty for being <5%
  27. Math.tanh(100 * (proportion - 0.1)) + // penalty for being <15%
  28. Math.tanh(100 * (proportion - 0.15)) + // penalty for being <15%
  29. Math.tanh(100 * (proportion - 0.25)) + // penalty for being <25%
  30. Math.tanh(100 * (proportion - 0.8)); // penalty for being <50%
  31. const buildClusterData = (
  32. size,
  33. inertia,
  34. mu1,
  35. mu2,
  36. mu3,
  37. nu1,
  38. nu2,
  39. nu3,
  40. totalSize,
  41. toHue,
  42. toLightness,
  43. toChroma,
  44. toHex
  45. ) => {
  46. const mu = buildVectorData(
  47. [mu1, mu2, mu3],
  48. toHue,
  49. toLightness,
  50. toChroma,
  51. toHex
  52. );
  53. const nu = [nu1, nu2, nu3];
  54. const muNuAngle = rad2deg * Math.acos(vectorDot(mu.unit, nu) / vectorMag(nu));
  55. const proportion = size / totalSize;
  56. const importance = calcImportance(mu.chroma, mu.lightness, proportion);
  57. return {
  58. size,
  59. inertia,
  60. mu,
  61. nu,
  62. muNuAngle,
  63. proportion,
  64. importance,
  65. };
  66. };
  67. const buildPokemonData = ([name, size, ...values]) => ({
  68. name,
  69. jab: {
  70. total: buildClusterData(
  71. size,
  72. ...values.slice(0, 7),
  73. size,
  74. jab2hue,
  75. jab2lit,
  76. jab2chroma,
  77. jab2hex
  78. ),
  79. clusters: [
  80. buildClusterData(
  81. ...values.slice(7, 15),
  82. size,
  83. jab2hue,
  84. jab2lit,
  85. jab2chroma,
  86. jab2hex
  87. ),
  88. buildClusterData(
  89. ...values.slice(15, 23),
  90. size,
  91. jab2hue,
  92. jab2lit,
  93. jab2chroma,
  94. jab2hex
  95. ),
  96. buildClusterData(
  97. ...values.slice(23, 31),
  98. size,
  99. jab2hue,
  100. jab2lit,
  101. jab2chroma,
  102. jab2hex
  103. ),
  104. buildClusterData(
  105. ...values.slice(31, 39),
  106. size,
  107. jab2hue,
  108. jab2lit,
  109. jab2chroma,
  110. jab2hex
  111. ),
  112. ].filter((c) => c.size !== 0),
  113. },
  114. rgb: {
  115. total: buildClusterData(
  116. size,
  117. ...values.slice(39, 46),
  118. size,
  119. rgb2hue,
  120. rgb2lit,
  121. rgb2chroma,
  122. rgb2hex
  123. ),
  124. clusters: [
  125. buildClusterData(
  126. ...values.slice(46, 54),
  127. size,
  128. rgb2hue,
  129. rgb2lit,
  130. rgb2chroma,
  131. rgb2hex
  132. ),
  133. buildClusterData(
  134. ...values.slice(54, 62),
  135. size,
  136. rgb2hue,
  137. rgb2lit,
  138. rgb2chroma,
  139. rgb2hex
  140. ),
  141. buildClusterData(
  142. ...values.slice(62, 70),
  143. size,
  144. rgb2hue,
  145. rgb2lit,
  146. rgb2chroma,
  147. rgb2hex
  148. ),
  149. buildClusterData(
  150. ...values.slice(70, 78),
  151. size,
  152. rgb2hue,
  153. rgb2lit,
  154. rgb2chroma,
  155. rgb2hex
  156. ),
  157. ].filter((c) => c.size !== 0),
  158. },
  159. });
  160. const pokemonData = databaseV3.map((row) => buildPokemonData(row));