flaggy

generates avatars with deterministic pseudorandomness

  1. // ==UserScript==
  2. // @name flaggy
  3. // @description generates avatars with deterministic pseudorandomness
  4. // @match https://www.metaculus.com/*
  5. // @grant GM_addStyle
  6. // @version 1.0
  7. // @author casens
  8. // @namespace https://gf.qytechs.cn/users/673939
  9. // ==/UserScript==
  10.  
  11. const svgNameSpace = 'http://www.w3.org/2000/svg';
  12.  
  13. function bigChungus(input) {
  14. //
  15. // DO NOT ROLL YOUR OWN CRYPTO
  16. //
  17. // DO NOT USE THIS FOR ANYTHING IMPORTANT
  18. //
  19. // the sum of the 4 components is less than 9 * 10 ** 15, aka BigInt.
  20. // you can't do precise modulus on BigInts!
  21. // the sum is always greater than 10**12, so 9_999_999_967 is a prime less
  22. // than that.
  23. //
  24. // this function has slightly different output in chrome v firefox
  25. //
  26. const num = Math.floor(input);
  27. const val = Math.floor( ( ((5 ** (1 / 3)) ** (52 + (num % 13)))
  28. + ((2 ** (1 / 2)) ** (54 + (num % 47)))
  29. + ((3 ** (1 / 7)) ** (115 + (num % 109)))
  30. + ((7 ** (1 / 23)) ** (194 + (num % 223)))
  31. ) % 9999999967
  32. );
  33. return val;
  34. }
  35.  
  36. function createSvg() {
  37. const svg = document.createElementNS(svgNameSpace, 'svg');
  38. svg.setAttribute('version', '1.1');
  39. svg.setAttribute('baseProfile', 'full');
  40. return svg;
  41. }
  42.  
  43. function setBg(seed, color) {
  44. const svg = createSvg();
  45. const determiner = (seed % 101) / 101
  46. svg.isCircle = false;
  47. const dimensions = [];
  48. if (determiner < .3) {
  49. dimensions.push(50);
  50. dimensions.push(50);
  51. } else if (determiner < .43) {
  52. dimensions.push(59);
  53. dimensions.push(42);
  54. } else if (determiner < .56) {
  55. dimensions.push(42);
  56. dimensions.push(59);
  57. } else if (determiner < .69) {
  58. dimensions.push(67);
  59. dimensions.push(37);
  60. } else {
  61. dimensions.push(56);
  62. dimensions.push(56);
  63. svg.style.borderRadius = '28px';
  64. svg.isCircle = true;
  65. }
  66. svg.setAttribute('width', dimensions[0]);
  67. svg.setAttribute('height', dimensions[1]);
  68. const bgLayer = drawRect(dimensions[0], dimensions[1], color);
  69. bgLayer.setAttribute('transform', `translate(${dimensions[0]/2},${dimensions[1]/2})`);
  70. svg.appendChild(bgLayer);
  71. return svg;
  72. }
  73.  
  74. function drawCircle(radius, inputColor) {
  75. const circle = document.createElementNS(svgNameSpace, 'circle');
  76. const color = `hsl(${inputColor[0]}, ${inputColor[1]}%, ${inputColor[2]}%)`;
  77. circle.setAttribute('r', radius);
  78. circle.setAttribute('fill', color);
  79. return circle;
  80. }
  81.  
  82. function drawLine(start, finish, thickness, inputColor) {
  83. const line = document.createElementNS(svgNameSpace, 'line');
  84. const color = `hsl(${inputColor[0]}, ${inputColor[1]}%, ${inputColor[2]}%)`;
  85. line.setAttribute('x1', start[0]);
  86. line.setAttribute('y1', start[1]);
  87. line.setAttribute('x2', finish[0]);
  88. line.setAttribute('y2', finish[1]);
  89. line.setAttribute('stroke-width', thickness);
  90. line.setAttribute('stroke', color);
  91. return line;
  92. }
  93.  
  94. function drawRect(width, height, inputColor) {
  95. const rect = document.createElementNS(svgNameSpace, 'rect');
  96. const color = `hsl(${inputColor[0]}, ${inputColor[1]}%, ${inputColor[2]}%)`;
  97. rect.setAttribute('x', -width / 2);
  98. rect.setAttribute('y', -height / 2);
  99. rect.setAttribute('width', width);
  100. rect.setAttribute('height', height);
  101. rect.setAttribute('fill', color);
  102. return rect;
  103. }
  104.  
  105. function drawRhombus(axisX, axisY, inputColor) {
  106. const rhom = document.createElementNS(svgNameSpace, 'polygon');
  107. const color = `hsl(${inputColor[0]}, ${inputColor[1]}%, ${inputColor[2]}%)`;
  108. const points = [
  109. `0,${-axisY / 2}`,
  110. `${axisX / 2},0`,
  111. `0,${axisY / 2}`,
  112. `${-axisX / 2},0`
  113. ];
  114. rhom.setAttribute('points', points.join(' '));
  115. rhom.setAttribute('fill', color);
  116. return rhom;
  117. }
  118.  
  119. function drawTriangle(sideLength, inputColor) {
  120. const triangle = document.createElementNS(svgNameSpace, 'polygon');
  121. const color = `hsl(${inputColor[0]}, ${inputColor[1]}%, ${inputColor[2]}%)`;
  122. const pt1 = `0,${sideLength / (3 ** 0.5)}`;
  123. const pt2 = `${sideLength / 2},${-(sideLength / (2 * (3 ** 0.5)))}`;
  124. const pt3 = `${-(sideLength / 2)},${-(sideLength / (2 * (3 ** 0.5)))}`;
  125. triangle.setAttribute('points', pt1 + ' ' + pt2 + ' ' + pt3);
  126. triangle.setAttribute('fill', color);
  127. return triangle;
  128. }
  129.  
  130. function drawPent(sideLength, inputColor) {
  131. const pent = document.createElementNS(svgNameSpace, 'polygon');
  132. const color = `hsl(${inputColor[0]}, ${inputColor[1]}%, ${inputColor[2]}%)`;
  133. const points = [
  134. `0,${-sideLength * 0.85}`,
  135. `${sideLength * 0.81},${-sideLength * 0.26}`,
  136. `${sideLength / 2},${sideLength * 0.69}`,
  137. `${-sideLength / 2},${sideLength * 0.69}`,
  138. `${-sideLength * 0.81},${-sideLength * 0.26}`
  139. ];
  140. pent.setAttribute('points', points.join(' '));
  141. pent.setAttribute('fill', color);
  142. return pent;
  143. }
  144.  
  145. function drawStar(sideLength, inputColor) {
  146. const pent = document.createElementNS(svgNameSpace, 'polygon');
  147. const color = `hsl(${inputColor[0]}, ${inputColor[1]}%, ${inputColor[2]}%)`;
  148. // sideLength in this case refers to distance from star-end to neighboring
  149. // (non-connected) end. aka, the length of one point edge plus a central
  150. // pentagon edge. aka, one point edge * 1.618
  151. const points = [
  152. `0,${-sideLength * 0.85}`,
  153. `${sideLength / 2},${sideLength * 0.69}`,
  154. `${-sideLength * 0.81},${-sideLength * 0.26}`,
  155. `${sideLength * 0.81},${-sideLength * 0.26}`,
  156. `${-sideLength / 2},${sideLength * 0.69}`
  157. ];
  158. pent.setAttribute('points', points.join(' '));
  159. pent.setAttribute('fill', color);
  160. return pent;
  161. }
  162.  
  163. function drawHex(sideLength, inputColor) {
  164. const hex = document.createElementNS(svgNameSpace, 'polygon');
  165. const color = `hsl(${inputColor[0]}, ${inputColor[1]}%, ${inputColor[2]}%)`;
  166. const points = [
  167. `${-sideLength / 2},${-sideLength * (3 ** 0.5) / 2}`,
  168. `${sideLength / 2},${-sideLength * (3 ** 0.5) / 2}`,
  169. `${sideLength}, 0`,
  170. `${sideLength / 2},${sideLength * (3 ** 0.5) / 2}`,
  171. `${-sideLength / 2},${sideLength * (3 ** 0.5) / 2}`,
  172. `${-sideLength}, 0`
  173. ];
  174. hex.setAttribute('points', points.join(' '));
  175. hex.setAttribute('fill', color);
  176. return hex;
  177. }
  178.  
  179. function selectLightness(seed, numOfSelections) {
  180. const colors = ['color'];
  181. let colorCount = 1;
  182. // sometimes this loop will run with no effect. it's not count i up to num
  183. for (let i = 0; colors.length < numOfSelections; i++) {
  184. const determiner = (bigChungus(seed + 4312774567655 + i) % 241) / 241
  185. if ((determiner < .16) && (!colors.includes('black'))) {
  186. colors.push('black');
  187. } else if ((determiner < .30) && (!colors.includes('white'))) {
  188. colors.push('white');
  189. } else if ((determiner < .42) && (!colors.includes('gray'))) {
  190. colors.push('gray');
  191. } else if (determiner < (1 - (colorCount * .18))) {
  192. // colorCount decreases the chances of multiple colors being selected
  193. colorCount++;
  194. colors.push('color');
  195. }
  196. if (i > 49) { break; }
  197. }
  198. // * chef's kiss *
  199. const shuffleDeterminer = seed % 6;
  200. const shuffledColors = [];
  201. shuffledColors.push(colors.splice((shuffleDeterminer % 3), 1)[0]);
  202. shuffledColors.push(colors.splice((shuffleDeterminer % 2), 1)[0]);
  203. shuffledColors.push(colors[0]);
  204. return shuffledColors;
  205. }
  206.  
  207. function selectHues(inputColors, seed) {
  208. // only guanateed to pass when you have less than 4 hues to select.
  209. // (you could get more if you narrowed the hue contrast.
  210. // current min contrast val = 75)
  211. const colors = [];
  212. const hues = [];
  213. for (let index = 0; index < inputColors.length; index++) {
  214. if (inputColors[index] === 'white') {
  215. colors.push([0, 0, 100]);
  216. } else if (inputColors[index] === 'black') {
  217. colors.push([0, 0, 0]);
  218. } else if (inputColors[index] === 'gray') {
  219. colors.push([0, 0, 25 + (bigChungus(seed + (69 * index)) % 47)]);
  220. } else {
  221. // colors, presumably
  222. // if no hues exist yet
  223. if (hues[0] === undefined) {
  224. let val = (bigChungus(seed + index) % 360);
  225. hues.push(val);
  226. } else {
  227. // generate new hue with minimum hue contrast
  228. const huesNeeded = hues.length + 1;
  229. for (let salt = 0; hues.length < huesNeeded; salt++) {
  230. const hue = bigChungus(seed + (index * 10000) + salt) % 360;
  231. let hueAllowed = true;
  232. const minContrast = 75;
  233. hues.forEach((oldHue) => {
  234. if ( ( (hue > (oldHue - minContrast ) )
  235. &&(hue < (oldHue + minContrast ) ) )
  236. ||( (hue > (oldHue - minContrast + 360) )
  237. &&(hue < (oldHue + minContrast + 360) ) )
  238. ||( (hue > (oldHue - minContrast - 360) )
  239. &&(hue < (oldHue + minContrast - 360) ) )
  240. ) {
  241. hueAllowed = false;
  242. }
  243. });
  244. if (hueAllowed) {
  245. hues.push(hue);
  246. }
  247. if (salt > 99) {
  248. colors[index][0] = hue;
  249. hues.push(699);
  250. console.log('hue selection broke somehow');
  251. break;
  252. }
  253. }
  254. }
  255. const saturation = 100 - (bigChungus(seed + (500 * index)) % 53);
  256. const lightness = 25 + (bigChungus(seed + (8888 * index)) % 47);
  257. colors.push([ hues[hues.length - 1], saturation, lightness ]);
  258. }
  259. }
  260. let salt = 0;
  261. // lightness contrast
  262. for (let i = 0; i + 1 < colors.length; i++) {
  263. if (colors[i][2] == 0
  264. ||colors[i][2] == 100
  265. ||colors[i + 1][2] == 0
  266. ||colors[i + 1][2] == 100 ) {
  267. // do nothing
  268. } else if (Math.abs(colors[i][2] - colors[i + 1][2]) < 29) {
  269. colors[i + 1][2] = 19 + (bigChungus(seed + 3861533478814 + salt) % 63);
  270. i--;
  271. }
  272. salt++;
  273. }
  274. return colors;
  275. }
  276.  
  277. function selectColors(seed) {
  278. const lightVals = selectLightness(seed, 3);
  279. const colors = selectHues(lightVals, seed);
  280. return colors;
  281. }
  282.  
  283. function selectLayer(seed, dimensions, colors, colorCount, isCircle) {
  284. const sortedLengths = dimensions.slice().sort();
  285. if (isCircle) {sortedLengths[0] *= 0.8}
  286. const layerGroup = document.createElementNS(svgNameSpace, 'g');
  287. layerGroup.noEmblem = false;
  288. const rotGroup = document.createElementNS(svgNameSpace, 'g');
  289. const rotGroupTop = document.createElementNS(svgNameSpace, 'g');
  290. layerGroup.append(rotGroup);
  291. layerGroup.append(rotGroupTop);
  292. layerGroup.setAttribute('transform', `translate(${dimensions[0]/2},${dimensions[1]/2})`);
  293. const diagThickness = (dimensions[0] * dimensions[1]) / ((dimensions[0] ** 2) + (dimensions[1] ** 2)) ** 0.5;
  294. const bandThickness = (seed % 69877) / 69877;
  295. const rotDeterminer = (seed % 81353) / 81353;
  296. const posDeterminer = (seed % 28711) / 28711;
  297. const doubleBandsDet = (seed % 2137) / 2137;
  298. const determiner = (seed % 1009) / 1009;
  299. if (determiner < .15) {
  300. //console.log('half horizontal bands');
  301. const layer = drawRect(dimensions[0], dimensions[1] / 2, colors[1]);
  302. layer.setAttribute('transform', `translate(0, ${-dimensions[1] / 4})`);
  303. layerGroup.appendChild(layer);
  304. if (colorCount > 1) {
  305. //console.log('three horizontal bands');
  306. layer.setAttribute('transform', `translate(0, ${-dimensions[1] / 12})`);
  307. const layerTop = drawRect(dimensions[0], dimensions[1] / 3, colors[2]);
  308. layerTop.setAttribute('transform', `translate(0, ${-dimensions[1] / 3})`);
  309. layerGroup.appendChild(layerTop);
  310. }
  311. } else if (determiner < .30) {
  312. //console.log('half vertical band');
  313. const layer = drawRect(dimensions[0] / 2, dimensions[1], colors[1]);
  314. layer.setAttribute('transform', `translate(${-dimensions[0] / 4})`);
  315. layerGroup.appendChild(layer);
  316. if (colorCount > 1) {
  317. //console.log('three vertical bands');
  318. layer.setAttribute('transform', `translate(${-dimensions[0] / 12})`);
  319. const layerTop = drawRect(dimensions[0] / 3, dimensions[1], colors[2]);
  320. layerTop.setAttribute('transform', `translate(${-dimensions[0] / 3})`);
  321. layerGroup.appendChild(layerTop);
  322. }
  323. } else if (determiner < .45) {
  324. //console.log('half diagonal');
  325. layerGroup.setAttribute('transform', `translate(0)`);
  326. const layer = drawLine([-dimensions[0] / 2, dimensions[1]], [dimensions[0], -dimensions[1] / 2], diagThickness, colors[1]);
  327. layerGroup.appendChild(layer);
  328. if (colorCount > 1) {
  329. //console.log('three diag bands');
  330. const layerTop = drawLine([-dimensions[0] / 2, dimensions[1]], [dimensions[0], -dimensions[1] / 2], diagThickness, colors[2]);
  331. layer.setAttribute('transform', `translate(${dimensions[0] / 6}, ${dimensions[1] / 6})`);
  332. layerTop.setAttribute('transform', `translate(${-dimensions[0] / 6}, ${-dimensions[1] / 6})`);
  333. if (isCircle) {
  334. layer.setAttribute('transform', `translate(${dimensions[0] * 3 / 24}, ${dimensions[1] * 3 / 24})`);
  335. layerTop.setAttribute('transform', `translate(${-dimensions[0] * 3 / 24}, ${-dimensions[1] * 3 / 24})`);
  336. }
  337. layerGroup.appendChild(layerTop);
  338. }
  339. } else if (determiner < .60) {
  340. //console.log('half other diagonal');
  341. layerGroup.setAttribute('transform', `translate(0)`);
  342. const layer = drawLine([0, -dimensions[1] / 2], [dimensions[0] * 3 / 2, dimensions[1]], diagThickness, colors[1]);
  343. layerGroup.appendChild(layer);
  344. if (colorCount > 1) {
  345. //console.log('three diag bands');
  346. const layerTop = drawLine([0, -dimensions[1] / 2], [dimensions[0] * 3 / 2, dimensions[1]], diagThickness, colors[2]);
  347. layer.setAttribute('transform', `translate(${-dimensions[0] / 6}, ${dimensions[1] / 6})`);
  348. layerTop.setAttribute('transform', `translate(${dimensions[0] / 6}, ${-dimensions[1] / 6})`);
  349. layerGroup.appendChild(layerTop);
  350. if (isCircle) {
  351. layer.setAttribute('transform', `translate(${-dimensions[0] * 3 / 24}, ${dimensions[1] * 3 / 24})`);
  352. layerTop.setAttribute('transform', `translate(${dimensions[0] * 3 / 24}, ${-dimensions[1] * 3 / 24})`);
  353. }
  354. }
  355. } else if (determiner < .90) {
  356. //console.log('radial rays');
  357. if (posDeterminer < .66 && dimensions[0] !== dimensions[1]) {
  358. // offset for nordic style cross
  359. layerGroup.noEmblem = true;
  360. if (!isCircle) {
  361. layerGroup.setAttribute('transform', `translate(${sortedLengths[0]/2},${sortedLengths[0]/2})`);
  362. }
  363. }
  364. const baseRay = [[0, 0], [0, -sortedLengths[1]]];
  365. let rayCount = 2 + ((seed % 577) % 6)
  366. if (rayCount === 7) {rayCount++}
  367. const rayThickness = 4 + ((bandThickness * 26) * (sortedLengths[0] / sortedLengths[1]) / (rayCount ** 0.7))
  368. if (rayCount === 2) {
  369. const ray1 = drawLine(baseRay[0], baseRay[1], rayThickness, colors[1]);
  370. const ray2 = ray1.cloneNode()
  371. ray2.setAttribute('transform', `rotate(180)`);
  372. if (doubleBandsDet < .4) {
  373. const bgRay1 = drawLine(baseRay[0], baseRay[1], rayThickness * 1.23, colors[0]);
  374. const trimRay1 = drawLine(baseRay[0], baseRay[1], rayThickness * 1.42, colors[1]);
  375. const bgRay2 = bgRay1.cloneNode()
  376. const trimRay2 = trimRay1.cloneNode()
  377. bgRay2.setAttribute('transform', `rotate(180)`);
  378. trimRay2.setAttribute('transform', `rotate(180)`);
  379. rotGroup.appendChild(trimRay1);
  380. rotGroup.appendChild(trimRay2);
  381. rotGroup.appendChild(bgRay1);
  382. rotGroup.appendChild(bgRay2);
  383. }
  384. rotGroupTop.appendChild(ray1);
  385. rotGroupTop.appendChild(ray2);
  386. layerGroup.setAttribute('transform', `translate(${dimensions[0] / 2},${dimensions[1] / 2})`);
  387. } else if ((doubleBandsDet < .7) && (colorCount > 1)) {
  388. // overlapping colors
  389. for (let i = 0; i < rayCount; i++) {
  390. ray1 = drawLine(baseRay[0], baseRay[1], rayThickness, colors[1]);
  391. ray1.setAttribute('transform', `rotate(${i * 360 / rayCount})`);
  392. let thicknessRatio = .5
  393. if (doubleBandsDet < .35) {
  394. thicknessRatio = .354
  395. }
  396. ray2 = drawLine(baseRay[0], baseRay[1], rayThickness * thicknessRatio, colors[2]);
  397. ray2.setAttribute('transform', `rotate(${i * 360 / rayCount})`);
  398. rotGroup.appendChild(ray1);
  399. rotGroupTop.appendChild(ray2);
  400. }
  401. } else if (rayCount % 2 == 0) {
  402. // alternating color rays
  403. for (let i = 0; i < rayCount; i++) {
  404. let colorSwitch = 1
  405. if (colorCount > 1 && rayCount > 5) {
  406. colorSwitch = 1 + (i % 2)
  407. }
  408. ray = drawLine(baseRay[0], baseRay[1], rayThickness, colors[colorSwitch]);
  409. ray.setAttribute('transform', `rotate(${i * 360 / rayCount})`);
  410. if (i % 2 === 0) {
  411. rotGroup.appendChild(ray);
  412. } else {
  413. rotGroupTop.appendChild(ray);
  414. }
  415. }
  416. } else {
  417. // monocolor rays
  418. for (let i = 0; i < rayCount; i++) {
  419. ray = drawLine(baseRay[0], baseRay[1], rayThickness, colors[1]);
  420. ray.setAttribute('transform', `rotate(${i * 360 / rayCount})`);
  421. rotGroup.appendChild(ray);
  422. }
  423. }
  424. let degrees = 0
  425. if (rotDeterminer < .4) {
  426. degrees += 180 / rayCount
  427. }
  428. if ((rotDeterminer * 100) % 10 < 5) {
  429. degrees += 360 / rayCount
  430. }
  431. if ((rotDeterminer * 1000) % 10 < 4) {
  432. degrees += 90
  433. }
  434. if ((rayCount === 2) && ((rotDeterminer * 10000) % 10 < 5)) {
  435. degrees += 45
  436. }
  437. //console.log('deg', degrees);
  438. rotGroup.setAttribute('transform', `rotate(${degrees})`);
  439. rotGroupTop.setAttribute('transform', `rotate(${degrees})`);
  440. } else {
  441. // out of 1009
  442. //console.log('diagonal bands and crosses');
  443. layerGroup.setAttribute('transform', 'translate(0)');
  444. let thicknessRatio = .5
  445. if (doubleBandsDet < .5) {
  446. thicknessRatio = .354
  447. }
  448. const miniDeterminer = (seed % 643) / 643
  449. if (miniDeterminer < .30) {
  450. // diagonal nw to se
  451. const layer1 = drawLine([0, 0], [dimensions[0], dimensions[1]], 3 + bandThickness * 20, colors[1]);
  452. layerGroup.appendChild(layer1);
  453. if (colorCount > 1) {
  454. const layer2 = drawLine([0, 0], [dimensions[0], dimensions[1]], 3 + bandThickness * thicknessRatio * 20, colors[2]);
  455. layerGroup.appendChild(layer2);
  456. }
  457. } else if (miniDeterminer < .60) {
  458. //diagonal ne to sw
  459. const layer1 = drawLine([0, dimensions[1]], [dimensions[0], 0], 3 + bandThickness * 20, colors[1]);
  460. layerGroup.appendChild(layer1);
  461. if (colorCount > 1) {
  462. const layer2 = drawLine([0, dimensions[1]], [dimensions[0], 0], 3 + bandThickness * thicknessRatio * 20, colors[2]);
  463. layerGroup.appendChild(layer2);
  464. }
  465. } else {
  466. // cross
  467. const layer1 = drawLine([0, 0], [dimensions[0], dimensions[1]], (bandThickness * 16) + 3, colors[1]);
  468. const layer2 = drawLine([0, dimensions[1]], [dimensions[0], 0], (bandThickness * 16) + 3, colors[1]);
  469. layerGroup.appendChild(layer2);
  470. layerGroup.appendChild(layer1);
  471. if (colorCount > 1) {
  472. const layer3 = drawLine([0, 0], [dimensions[0], dimensions[1]], (bandThickness * thicknessRatio * 16) + 3, colors[2]);
  473. const layer4 = drawLine([0, dimensions[1]], [dimensions[0], 0], (bandThickness * thicknessRatio * 16) + 3, colors[2]);
  474. layerGroup.appendChild(layer3);
  475. layerGroup.appendChild(layer4);
  476. }
  477. }
  478. }
  479. if ((seed % 52391 ) / 52391 > .83) {layerGroup.noEmblem = true}
  480. return layerGroup;
  481. }
  482.  
  483. function selectEmblem(seed, dimensions, color, bgIsCircle) {
  484. let smallestSide = dimensions[0];
  485. if (dimensions[0] > dimensions[1]) { smallestSide = dimensions[1]; }
  486. emblemSide = smallestSide
  487. if (bgIsCircle) { emblemSide *= 0.82; }
  488. emblemSide *= 0.91;
  489. const sizeDeterminer = (seed % 30529) / 30529
  490. const sizeVariance = 3.2
  491. const sizeLimit = 2.1
  492. emblemSide *= 1 + ((((sizeDeterminer - .5) / sizeVariance) ** 3) / (sizeLimit * (sizeVariance ** 3)))
  493. const rotateDeterminer = (seed % 74897) / 74897
  494. const determiner = (seed % 997) / 997
  495. const layerGroup = document.createElementNS(svgNameSpace, 'g');
  496. let emblem;
  497. if (determiner < .16) {
  498. //console.log('circle');
  499. emblem = drawCircle((emblemSide * 0.28), color);
  500. } else if (determiner < .23) {
  501. //console.log('hex');
  502. emblem = drawHex((emblemSide * 0.3), color);
  503. let degrees = 0;
  504. if (rotateDeterminer > .5) {degrees = 30}
  505. emblem.setAttribute('transform', `rotate(${degrees})`);
  506. } else if (determiner < .31) {
  507. //console.log('pent');
  508. emblem = drawPent((emblemSide * 0.39), color);
  509. let degrees = 0;
  510. if (rotateDeterminer > .5) {degrees = 36}
  511. emblem.setAttribute('transform', `rotate(${degrees})`);
  512. } else if (determiner < .41) {
  513. //console.log('rhomb root 3');
  514. emblem = drawRhombus((emblemSide * 0.43), (emblemSide * 0.74), color);
  515. let degrees = 0;
  516. if (rotateDeterminer > .5) {degrees = 90}
  517. emblem.setAttribute('transform', `rotate(${degrees})`);
  518. } else if (determiner < .51) {
  519. //console.log('rhomb root 2');
  520. emblem = drawRhombus((emblemSide * 0.47), (emblemSide * 0.67), color);
  521. let degrees = 0;
  522. if (rotateDeterminer > .5) {degrees = 90}
  523. emblem.setAttribute('transform', `rotate(${degrees})`);
  524. } else if (determiner < .71) {
  525. //console.log('star');
  526. emblem = drawStar((emblemSide * 0.44), color);
  527. let degrees = 0;
  528. if (rotateDeterminer > .5) {degrees = 36}
  529. if (rotateDeterminer * 19 > 13) {degrees += 90}
  530. emblem.setAttribute('transform', `rotate(${degrees})`);
  531. } else if (determiner < .83) {
  532. //console.log('square');
  533. emblem = drawRect((emblemSide * 0.56), (emblemSide * 0.56), color);
  534. let degrees = 0;
  535. if (rotateDeterminer > .5) {degrees = 45}
  536. emblem.setAttribute('transform', `rotate(${degrees})`);
  537. } else {
  538. //console.log('triangle');
  539. emblem = drawTriangle((emblemSide * 0.65), color);
  540. let degrees = 0;
  541. if (rotateDeterminer > .5) {degrees = 60}
  542. if (rotateDeterminer * 19 > 12) {degrees += 90}
  543. emblem.setAttribute('transform', `rotate(${degrees})`);
  544. }
  545. const outlineDeterminer = (seed % 66883) / 66883
  546. if (outlineDeterminer < .35) {
  547. emblem.setAttribute('stroke', `hsl(${color[0]}, ${color[1]}%, ${color[2]}%)`);
  548. emblem.setAttribute('stroke-width', (smallestSide * 0.04));
  549. emblem.setAttribute('fill-opacity', 0);
  550. }
  551. layerGroup.setAttribute('transform', `translate(${dimensions[0]/2},${dimensions[1]/2})`);
  552. layerGroup.appendChild(emblem);
  553. return layerGroup;
  554. }
  555.  
  556. function selectFormat(seed, dimensions, colors, isCircle) {
  557. const determiner = (seed % 397) / 397
  558. const layerGroup = document.createElementNS(svgNameSpace, 'g');
  559. if (determiner < .35) {
  560. const layer = selectLayer(seed, dimensions, colors, 2, isCircle);
  561. layerGroup.appendChild(layer);
  562. } else if (determiner < .50) {
  563. // emblem with no bg layer
  564. const emblem = selectEmblem(seed, dimensions, colors[1], isCircle);
  565. layerGroup.appendChild(emblem);
  566. } else {
  567. // emblem plus mono layer
  568. const layer = selectLayer(seed, dimensions, colors, 1, isCircle);
  569. layerGroup.appendChild(layer);
  570. if (!layer.noEmblem) {
  571. const emblem = selectEmblem(seed, dimensions, colors[2], isCircle);
  572. layerGroup.appendChild(emblem);
  573. }
  574. }
  575. return layerGroup;
  576. }
  577.  
  578. function createAvatar(inputID) {
  579. const seed = bigChungus(inputID);
  580. const colors = selectColors(seed);
  581. //console.log('these are the colors', colors);
  582. const svg = setBg(seed, colors[0]);
  583. const width = svg.width.baseVal.value;
  584. const height = svg.height.baseVal.value;
  585. const dimensions = [width, height];
  586. svg.appendChild(selectFormat(seed, dimensions, colors, svg.isCircle));
  587. return svg;
  588. }
  589.  
  590. function createAvatarContainer() {
  591. const div = document.createElement('div');
  592. div.classList.add('avatar-container-div');
  593. div.style.width = 0;
  594. div.style.height = 0;
  595. return div;
  596. }
  597.  
  598. function styleRankingsTable(rankingsTable) {
  599. const rows = rankingsTable.children[0].rows;
  600. rows[0].insertCell(1).outerHTML = "<th>Avatar</th>";
  601. for (let i = 1; i < rows.length; i++) {
  602. if (i % 2 === 1) {
  603. rows[i].style.background = '#8883';
  604. }
  605. rows[i].style.height = '5em';
  606. let userID = rows[i].children[1].children[0].href.match(/\d+\/?/)[0];
  607. //console.log(rows[i].children[1].children[0].textContent); // username!!
  608. const avatar = createAvatar(userID);
  609. rows[i].insertCell(1).appendChild(avatar);
  610. //rows[i][1].classList.add('avatar-container');
  611. }
  612. }
  613.  
  614. function styleComments(commentNodeList) {
  615. commentNodeList.forEach(commentNode => {
  616. let userID = commentNode.href.match(/\d+\/$/)[0];
  617. userID = userID.slice(0, (userID.length - 1));
  618. const div = createAvatarContainer();
  619. avatars.push(div);
  620. //console.log(commentNode.innerText); // that's the user's username >:3
  621. const avatar = createAvatar(userID);
  622. avatar.style.position = 'relative';
  623. avatar.style.right = `${avatar.width.baseVal.value + 16}px`;
  624. div.appendChild(avatar);
  625. const commentContainer= commentNode.parentElement.parentElement.parentElement;
  626. if ( commentContainer.querySelector('.comment__prediction') !== null) {
  627. movePrediction(commentContainer, avatar.width.baseVal.value);
  628. }
  629. commentNode.prepend(div);
  630. });
  631. }
  632.  
  633. function movePrediction(commentContainer, distance) {
  634. const prediction = commentContainer.querySelector('.comment__prediction');
  635. prediction.style.left = `${-(distance - 16) / 16}em`;
  636. }
  637.  
  638. //function clearAvatars() {
  639. // console.log('clearing avatars');
  640. // avatars = document.querySelectorAll('.avatar-container');
  641. // avatars.forEach(div => div.remove());
  642. //}
  643.  
  644. //function addListeners() {
  645. // const loadMoreBtns = document.querySelectorAll('._load-more');
  646. // loadMoreBtns.forEach(btn => btn.addEventListener('click', () => {
  647. // document.addEventListener('readystatechange', event => {
  648. // if (event.target.readyState === "complete") {
  649. // main();
  650. // }
  651. // });
  652. // clearAvatars();
  653. // }));
  654. //}
  655.  
  656. function main() {
  657. const commentNodeList = document.querySelectorAll('.comment__author');
  658. if (commentNodeList.length > 0) {
  659. styleComments(commentNodeList);
  660. }
  661. // on contest page these get generated by an event, not pageload
  662. const rankingsTable = document.querySelector('.rankings-table');
  663. if (rankingsTable !== null) {
  664. styleRankingsTable(rankingsTable);
  665. }
  666. // author of question. not sure how to do this:
  667. //const authorUsername = document.querySelector('[auth-name]');
  668. }
  669.  
  670. const avatars = []
  671.  
  672. // necessary to wait for DOM to finish loading
  673. document.addEventListener('readystatechange', event => {
  674. if (event.target.readyState === "complete") {
  675. main();
  676. addListeners();
  677. }
  678. });
  679.  
  680.  
  681.  
  682.  
  683.  
  684.  
  685.  

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址