Greasy Fork is available in English.

AtcoderDevotionGraph

Overlay your devoiting graph on your rating graph

Pada tanggal 02 Desember 2020. Lihat %(latest_version_link).

  1. // ==UserScript==
  2. // @name AtcoderDevotionGraph
  3. // @namespace http://atcoder.jp/
  4. // @version 1.0.0
  5. // @description Overlay your devoiting graph on your rating graph
  6. // @author kemkemG0
  7. // @include *://atcoder.jp/users*
  8. // @exclude *://atcoder.jp/users/*?graph=rank
  9. // @exclude *://atcoder.jp/users/*/history*
  10. // @grant none
  11. // @require https://code.jquery.com/jquery-1.8.0.min.js
  12. //@run-at document-end
  13.  
  14. // ==/UserScript==
  15.  
  16. "use strict";
  17.  
  18. //上書きされるから消す必要ないやん
  19.  
  20. // let scriptsArray = $('script');
  21. // scriptsArray[14].remove(); // 対象のタグを消す記述 x[14]がグラフを読み込むjs
  22. // //なんでこれ必要?? -->>一度読み込んだscriptタグはDOMから消しても効果は残るからそれを消すため
  23. // let copyPage = $("html").clone().html();
  24. // $("html").remove();
  25. // document.write(copyPage);
  26.  
  27. //##//##//##//##//##//##//##//##//##//##//##//##//##//##//##//##//##//##//##//##//##//##//##//##//##//##//##//##//##//##
  28.  
  29.  
  30. {
  31. const element = document.getElementsByClassName('btn-text-group')[document.getElementsByClassName('btn-text-group').length - 1];
  32. const insertButton = Object.assign(document.createElement('button'), {
  33. className: '',
  34. id: 'shoujinButtonID',
  35. style: '\
  36. margin-left:100px;\
  37. appearance: none;\
  38. border: 0;\
  39. border-radius: 5px;\
  40. background: #20b2aa;\
  41. color: #fff;\
  42. padding: 5px 10px;\
  43. font-size: 16px;\
  44. '
  45. }
  46. );
  47. insertButton.textContent = "精進"
  48. element.appendChild(insertButton)
  49. }
  50.  
  51. // const
  52. const MARGIN_VAL_X = 86400 * 30;
  53. const MARGIN_VAL_Y_LOW = 100;//
  54. const MARGIN_VAL_Y_HIGH = 300;//自分の最高レート+表示する領域
  55. const OFFSET_X = 50;//グラフの位置?
  56. const OFFSET_Y = 5;
  57. const DEFAULT_WIDTH = 640;
  58. let canvas_status = document.getElementById("ratingStatus");
  59. // <canvas id="ratingStatus" width="1280" height="160"
  60. // style="max-width: 640px; max-height: 80px; height: 100%; width: 100%;"></canvas>
  61. const STATUS_WIDTH = canvas_status.width - OFFSET_X - 10;
  62. const STATUS_HEIGHT = canvas_status.height - OFFSET_Y - 5;
  63. let canvas_graph = document.getElementById("ratingGraph");
  64. /* <canvas id="ratingGraph"
  65. width="1280" height="720"
  66. style="max-width: 640px; max-height: 360px; height: 100%; width: 100%;"></canvas>*/
  67. const PANEL_WIDTH = canvas_graph.width - OFFSET_X - 10;
  68. const PANEL_HEIGHT = canvas_graph.height - OFFSET_Y - 30;
  69. //HIGHEST:932 とかの吹き出しのサイズ
  70. const HIGHEST_WIDTH = 80;
  71. const HIGHEST_HEIGHT = 20;
  72. const LABEL_FONT = "12px Lato";
  73. const START_YEAR = 2010;
  74. const MONTH_NAMES = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
  75. const YEAR_SEC = 86400 * 365;
  76. const STEP_SIZE = 400;//グラフのy軸のステップ数
  77. const COLORS = [
  78. [0, "#808080", 0.15],
  79. [400, "#804000", 0.15],
  80. [800, "#008000", 0.15],
  81. [1200, "#00C0C0", 0.2],
  82. [1600, "#0000FF", 0.1],
  83. [2000, "#C0C000", 0.25],
  84. [2400, "#FF8000", 0.2],
  85. [2800, "#FF0000", 0.1]
  86. ];
  87.  
  88. //??????????????????
  89. const STAR_MIN = 3200;
  90. const PARTICLE_MIN = 3;
  91. const PARTICLE_MAX = 20;
  92. const LIFE_MAX = 30;
  93. const EPS = 1e-9;
  94.  
  95. let cj = createjs;
  96. let stage_graph, stage_status;
  97. // graph
  98. let panel_shape, border_shape;
  99. let chart_container, line_shape, vertex_shapes, highest_shape;
  100. let n, x_min, x_max, y_min, y_max;
  101.  
  102. //devoting graph
  103. let devoting_panel_shape, devoting_border_shape;
  104. let devoting_chart_container, devoting_line_shape, devoting_vertex_shapes, devoting_highest_shape;
  105. let devoting_n, devoting_x_min, devoting_x_max, devoting_y_min, devoting_y_max;
  106. let devoting_rating_history = []
  107.  
  108. // status
  109. let border_status_shape;
  110. let rating_text, place_text, diff_text, date_text, contest_name_text;
  111. let particles;
  112. let standings_url;
  113. const username = document.getElementsByClassName("username")[0].textContent;
  114. //クリエイトjsとやらをつかっている
  115. //いい感じにキャンバスの大きさを設定してマウスオーバーもONにする
  116. function initStage(stage, canvas) {
  117. let width = canvas.getAttribute('width');// <canvas width="">を取得
  118. let height = canvas.getAttribute('height');
  119.  
  120. //最悪、なくても画質悪くなったが動いた よくわからん
  121. if (window.devicePixelRatio) {//ピクセル比 によって解像度を変える 本来は2のときに1にしたらぼやけた
  122. //縦横の設定
  123. canvas.setAttribute('width', Math.round(width * window.devicePixelRatio));//Math.round()は四捨五入
  124. canvas.setAttribute('height', Math.round(height * window.devicePixelRatio));
  125. stage.scaleX = stage.scaleY = window.devicePixelRatio;
  126. }
  127. //最大のキャンパスサイズ=もとのキャンバスサイズにする
  128. canvas.style.maxWidth = width + "px";
  129. canvas.style.maxHeight = height + "px";
  130. canvas.style.width = canvas.style.height = "100%";
  131. stage.enableMouseOver();
  132. }
  133. //parent===stageに図形を追加し、その図形をreturnで参照渡し
  134. function newShape(parent) {
  135. let s = new cj.Shape();
  136. parent.addChild(s);
  137. return s;
  138. }
  139. //上のテキストバージョン
  140. function newText(parent, x, y, font) {
  141. let t = new cj.Text("", font, "#000");
  142. t.x = x;
  143. t.y = y;
  144. t.textAlign = "center";
  145. t.textBaseline = "middle";
  146. parent.addChild(t);
  147. return t;
  148. }
  149. //多分一番の大元
  150. function init() {
  151. //rating_history はHTML内で取得してある
  152. //rating_history=[{"EndTime":時間(単位不明),"NewRating":11,"OldRating":0,"Place":5200,"ContestName":"コンテスト名","StandingsUrl":"/contests/m-solutions2020/standings?watching=kemkemG0"}];
  153. n = rating_history.length;
  154. devoting_n = devoting_rating_history.length;
  155. if (n == 0 ) return;
  156.  
  157. //土台のステージ これに図形とかを追加していくイメージ
  158. stage_graph = new cj.Stage("ratingGraph");// Stage("canvasのID");
  159. stage_status = new cj.Stage("ratingStatus");
  160. initStage(stage_graph, canvas_graph);
  161. initStage(stage_status, canvas_status);
  162.  
  163. //グラフのサイズ決定
  164. x_min = 100000000000;
  165. x_max = 0;
  166. y_min = 10000;
  167. y_max = 0;
  168. for (let i = 0; i < n; i++) {
  169. x_min = Math.min(x_min, rating_history[i].EndTime);
  170. x_max = Math.max(x_max, rating_history[i].EndTime);
  171. y_min = Math.min(y_min, rating_history[i].NewRating);
  172. y_max = Math.max(y_max, rating_history[i].NewRating);
  173. }
  174. x_min -= MARGIN_VAL_X;//最初にコンテストに参加した日ー1ヶ月
  175. x_max += MARGIN_VAL_X;//最後にコンテストに参加した日+1ヶ月
  176. y_min = Math.min(1500, Math.max(0, y_min - MARGIN_VAL_Y_LOW));//いい感じに高さも設定
  177. y_max += MARGIN_VAL_Y_HIGH;
  178.  
  179. //精進グラフのサイズ決定
  180. devoting_x_min = 100000000000;
  181. devoting_x_max = 0;
  182. devoting_y_min = 10000;
  183. devoting_y_max = 0;
  184. for (let i = 0; i < devoting_rating_history.length; i++) {
  185. devoting_x_min = Math.min(devoting_x_min, devoting_rating_history[i].epoch_second);
  186. devoting_x_max = Math.max(devoting_x_max, devoting_rating_history[i].epoch_second);
  187. devoting_y_min = Math.min(devoting_y_min, devoting_rating_history[i].point);
  188. devoting_y_max = Math.max(devoting_y_max, devoting_rating_history[i].point);
  189. }
  190. devoting_x_min -= MARGIN_VAL_X;//最初にコンテストに参加した日ー1ヶ月
  191. devoting_x_max += MARGIN_VAL_X;//最後にコンテストに参加した日+1ヶ月
  192. devoting_y_min = Math.min(1500, Math.max(0, devoting_y_min - MARGIN_VAL_Y_LOW));//いい感じに高さも設定
  193. devoting_y_max += MARGIN_VAL_Y_HIGH;
  194.  
  195. //形を決める
  196. y_min = Math.min(y_min, devoting_y_min);
  197. y_max = Math.max(y_max, devoting_y_max);
  198. x_min = Math.min(x_min, devoting_x_min);
  199. x_max = Math.max(x_max, devoting_x_max);
  200.  
  201. initBackground();//背景の描画
  202. initChart();//プロットと直線の描画
  203. initDevotingChart()
  204. stage_graph.update();
  205.  
  206. initStatus();//グラフの上のコンテスト情報とかの描画
  207. stage_status.update();
  208. //マウスオーバー時のほわほわの管理
  209. cj.Ticker.setFPS(60);
  210. cj.Ticker.addEventListener("tick", handleTick);
  211. function handleTick(event) {
  212. updateParticles();
  213. stage_status.update();
  214. }
  215. }
  216.  
  217. function getPer(x, l, r) {
  218. return (x - l) / (r - l);
  219. }
  220. function getColor(x) {
  221. for (let i = COLORS.length - 1; i >= 0; i--) {
  222. if (x >= COLORS[i][0]) return COLORS[i];
  223. }
  224. return [-1, "#000000", 0.1];
  225. }
  226. function initBackground() {
  227.  
  228. panel_shape = newShape(stage_graph);//stage_graphに図形を追加、また panel_shapeはstage_graphの内部とつながってる(オブジェクトは参照渡し)
  229. panel_shape.x = OFFSET_X;
  230. panel_shape.y = OFFSET_Y;
  231. panel_shape.alpha = 0.3;
  232.  
  233. border_shape = newShape(stage_graph);
  234. border_shape.x = OFFSET_X;
  235. border_shape.y = OFFSET_Y;
  236.  
  237. //左の軸のレートの設定
  238. function newLabelY(s, y) {
  239. let t = new cj.Text(s, LABEL_FONT, "#000");
  240. t.x = OFFSET_X - 10;//理解
  241. t.y = OFFSET_Y + y;
  242. t.textAlign = "right";
  243. t.textBaseline = "middle";
  244. stage_graph.addChild(t);
  245. }
  246. //上と同様にX軸のラベルの設定
  247. function newLabelX(s, x, y) {
  248. let t = new cj.Text(s, LABEL_FONT, "#000");
  249. t.x = OFFSET_X + x;
  250. t.y = OFFSET_Y + PANEL_HEIGHT + 2 + y;
  251. t.textAlign = "center";
  252. t.textBaseline = "top";
  253. stage_graph.addChild(t);
  254. }
  255.  
  256. //https://createjs.com/docs/easeljs/classes/Graphics.html Graphics Classのドキュメント
  257. let y1 = 0;
  258. // グラフの中の正方形のパネルを色を設定
  259. for (let i = COLORS.length - 1; i >= 0; i--) {
  260. let y2 = PANEL_HEIGHT - PANEL_HEIGHT * getPer(COLORS[i][0], y_min, y_max);
  261. if (y2 > 0 && y1 < PANEL_HEIGHT) {
  262. y1 = Math.max(y1, 0); //rect ( x, y, w , h )
  263. panel_shape.graphics.beginFill(COLORS[i][1]).rect(0, y1, PANEL_WIDTH, Math.min(y2, PANEL_HEIGHT) - y1);
  264. }
  265. y1 = y2;
  266. }
  267. //Y軸ラベルの設定
  268. for (let i = 0; i <= y_max; i += STEP_SIZE) {
  269. if (i >= y_min) {
  270. let y = PANEL_HEIGHT - PANEL_HEIGHT * getPer(i, y_min, y_max);
  271. newLabelY(String(i), y);
  272. border_shape.graphics.beginStroke("#FFF").setStrokeStyle(0.5);
  273. if (i == 2000) border_shape.graphics.beginStroke("#000");
  274. border_shape.graphics.moveTo(0, y).lineTo(PANEL_WIDTH, y);
  275. }
  276. }
  277. border_shape.graphics.beginStroke("#FFF").setStrokeStyle(0.5);
  278.  
  279. let month_step = 6;
  280. for (let i = 3; i >= 1; i--) {
  281. if (x_max - x_min <= YEAR_SEC * i + MARGIN_VAL_X * 2) month_step = i;//初めてすぐの人は短めに
  282. }
  283.  
  284. //X軸ラベルの設定
  285. let first_flag = true;
  286. for (let i = START_YEAR; i < 3000; i++) {
  287. let break_flag = false;
  288. for (let j = 0; j < 12; j += month_step) {
  289. let month = ('00' + (j + 1)).slice(-2);
  290. let unix = Date.parse(String(i) + "-" + month + "-01T00:00:00") / 1000;
  291. if (x_min < unix && unix < x_max) {
  292. let x = PANEL_WIDTH * getPer(unix, x_min, x_max);
  293. if (j == 0 || first_flag) {
  294. newLabelX(MONTH_NAMES[j], x, 0);
  295. newLabelX(String(i), x, 13);
  296. first_flag = false;
  297. } else {
  298. newLabelX(MONTH_NAMES[j], x, 0);
  299. }
  300. border_shape.graphics.mt(x, 0).lt(x, PANEL_HEIGHT)
  301. }
  302. if (unix > x_max) { break_flag = true; break; }
  303. }
  304. if (break_flag) break;
  305. }
  306. border_shape.graphics.s("#888").ss(1.5).rr(0, 0, PANEL_WIDTH, PANEL_HEIGHT, 2);
  307. }
  308.  
  309. function initChart() {
  310. chart_container = new cj.Container();//コンテナでまとめると、同時に動かせたりして良い
  311. stage_graph.addChild(chart_container);
  312. chart_container.shadow = new cj.Shadow("rgba(0,0,0,0.3)", 1, 2, 3);//チャートの下に影
  313.  
  314. line_shape = newShape(chart_container);
  315. highest_shape = newShape(chart_container);
  316. vertex_shapes = new Array();
  317.  
  318. //マウスおいたら丸が大きくなるやつ
  319. function mouseoverVertex(e) {
  320. vertex_shapes[e.target.i].scaleX = vertex_shapes[e.target.i].scaleY = 1.2;
  321. stage_graph.update();
  322. setStatus(rating_history[e.target.i], true);
  323. };
  324. function mouseoutVertex(e) {
  325. vertex_shapes[e.target.i].scaleX = vertex_shapes[e.target.i].scaleY = 1;
  326. stage_graph.update();
  327. };
  328.  
  329. let highest_i = 0;
  330. for (let i = 0; i < n; i++) {
  331. if (rating_history[highest_i].NewRating < rating_history[i].NewRating) {
  332. highest_i = i;
  333. }
  334. }
  335. //historyの数だけ配列にpushしてイベントリスナーも設定
  336. for (let i = 0; i < n; i++) {
  337. vertex_shapes.push(newShape(chart_container));
  338. vertex_shapes[i].graphics.beginStroke("#FFF");
  339. if (i == highest_i) vertex_shapes[i].graphics.s("#000");//Highestなら外枠を黒に
  340. vertex_shapes[i].graphics.setStrokeStyle(0.5).beginFill(getColor(rating_history[i].NewRating)[1]).dc(0, 0, 3.5);
  341.  
  342. vertex_shapes[i].x = OFFSET_X + PANEL_WIDTH * getPer(rating_history[i].EndTime, x_min, x_max);
  343. vertex_shapes[i].y = OFFSET_Y + (PANEL_HEIGHT - PANEL_HEIGHT * getPer(rating_history[i].NewRating, y_min, y_max));
  344.  
  345. vertex_shapes[i].i = i;//なにこれ??
  346.  
  347. let hitArea = new cj.Shape();
  348. hitArea.graphics.f("#000").dc(1.5, 1.5, 6);
  349. vertex_shapes[i].hitArea = hitArea;
  350. vertex_shapes[i].addEventListener("mouseover", mouseoverVertex);
  351. vertex_shapes[i].addEventListener("mouseout", mouseoutVertex);
  352. }
  353.  
  354. {//highest 関連
  355. let dx = 80;
  356. if ((x_min + x_max) / 2 < rating_history[highest_i].EndTime) dx = -80;
  357. let x = vertex_shapes[highest_i].x + dx;
  358. let y = vertex_shapes[highest_i].y - 16;
  359. highest_shape.graphics.s("#FFF").mt(vertex_shapes[highest_i].x, vertex_shapes[highest_i].y).lt(x, y);
  360. highest_shape.graphics.s("#888").f("#FFF").rr(x - HIGHEST_WIDTH / 2, y - HIGHEST_HEIGHT / 2, HIGHEST_WIDTH, HIGHEST_HEIGHT, 2);
  361. highest_shape.i = highest_i;
  362. let highest_text = newText(stage_graph, x, y, "12px Lato");
  363. highest_text.text = "Highest: " + rating_history[highest_i].NewRating;
  364. highest_shape.addEventListener("mouseover", mouseoverVertex);
  365. highest_shape.addEventListener("mouseout", mouseoutVertex);
  366. }
  367.  
  368.  
  369. for (let j = 0; j < 2; j++) {
  370. if (j == 0) line_shape.graphics.s("#AAA").ss(2);
  371. else line_shape.graphics.s("#FFF").ss(0.5);//線の種類を変えてる? よくわからん
  372.  
  373. line_shape.graphics.mt(vertex_shapes[0].x, vertex_shapes[0].y);
  374. for (let i = 0; i < n; i++) {
  375. line_shape.graphics.lt(vertex_shapes[i].x, vertex_shapes[i].y);
  376. }
  377. }
  378. }
  379. function initDevotingChart() {
  380. devoting_chart_container = new cj.Container();//コンテナでまとめると、同時に動かせたりして良い
  381. stage_graph.addChild(devoting_chart_container);//これは devoting_じゃない
  382. devoting_chart_container.shadow = new cj.Shadow("rgba(0,0,0,0.3)", 1, 2, 3);//チャートの下に影
  383.  
  384. devoting_line_shape = newShape(devoting_chart_container);
  385. devoting_highest_shape = newShape(devoting_chart_container);
  386. devoting_vertex_shapes = new Array();
  387.  
  388. //historyの数だけ配列にpushしてイベントリスナーも設定
  389. for (let i = 0; i < devoting_n; i++) {
  390. devoting_vertex_shapes.push(newShape(devoting_chart_container));
  391. devoting_vertex_shapes[i].graphics.beginStroke("#FFF");
  392. if (i == devoting_n - 1) {
  393. devoting_vertex_shapes[i].graphics.s("#000");
  394. devoting_vertex_shapes[i].graphics.setStrokeStyle(1).beginFill(getColor(devoting_rating_history[i].point)[1]).dc(0, 0, 2.5);
  395. }
  396. else {
  397. devoting_vertex_shapes[i].graphics.setStrokeStyle(0.5).beginFill(getColor(devoting_rating_history[i].point)[1]).dc(0, 0, 2);
  398. }
  399. devoting_vertex_shapes[i].x = OFFSET_X + PANEL_WIDTH * getPer(devoting_rating_history[i].epoch_second, x_min, x_max);//devotingじゃないほうに合わせる?
  400. devoting_vertex_shapes[i].y = OFFSET_Y + (PANEL_HEIGHT - PANEL_HEIGHT * getPer(devoting_rating_history[i].point, y_min, y_max));
  401. devoting_vertex_shapes[i].i = i;
  402. let hitArea = new cj.Shape();
  403. hitArea.graphics.f("#000").dc(1.5, 1.5, 6);
  404. devoting_vertex_shapes[i].hitArea = hitArea;
  405. }
  406. //チャートの線関連
  407. for (let index = 0; index < 2; index++) {
  408. if (index == 0) devoting_line_shape.graphics.s("#AAA").ss(2);
  409. else devoting_line_shape.graphics.s("#FFF").ss(0.5);
  410. devoting_line_shape.graphics.mt(devoting_vertex_shapes[0].x, devoting_vertex_shapes[0].y);
  411. for (let i = 0; i < devoting_rating_history.length; i++) {
  412. devoting_line_shape.graphics.lt(devoting_vertex_shapes[i].x, devoting_vertex_shapes[i].y);
  413. }
  414. }
  415. }
  416. function initStatus() {
  417. border_status_shape = newShape(stage_status);
  418. rating_text = newText(stage_status, OFFSET_X + 75, OFFSET_Y + STATUS_HEIGHT / 2, "48px 'Squada One'");
  419. place_text = newText(stage_status, OFFSET_X + 160, OFFSET_Y + STATUS_HEIGHT / 2.7, "16px Lato");
  420. diff_text = newText(stage_status, OFFSET_X + 160, OFFSET_Y + STATUS_HEIGHT / 1.5, "11px Lato");
  421. diff_text.color = '#888';
  422. date_text = newText(stage_status, OFFSET_X + 200, OFFSET_Y + STATUS_HEIGHT / 4, "14px Lato");
  423. contest_name_text = newText(stage_status, OFFSET_X + 200, OFFSET_Y + STATUS_HEIGHT / 1.6, "20px Lato");
  424. date_text.textAlign = contest_name_text.textAlign = "left";
  425. contest_name_text.maxWidth = STATUS_WIDTH - 200 - 10;
  426. {
  427. let hitArea = new cj.Shape(); hitArea.graphics.f("#000").r(0, -12, contest_name_text.maxWidth, 24);
  428. contest_name_text.hitArea = hitArea;
  429. contest_name_text.cursor = "pointer";
  430. contest_name_text.addEventListener("click", function () {
  431. location.href = standings_url;
  432. });
  433. }
  434. particles = new Array();
  435. for (let i = 0; i < PARTICLE_MAX; i++) {
  436. particles.push(newText(stage_status, 0, 0, "64px Lato"));
  437. particles[i].visible = false;
  438. }
  439. setStatus(rating_history[rating_history.length - 1], false);
  440. }
  441.  
  442. function getRatingPer(x) {
  443. let pre = COLORS[COLORS.length - 1][0] + STEP_SIZE;
  444. for (let i = COLORS.length - 1; i >= 0; i--) {
  445. if (x >= COLORS[i][0]) return (x - COLORS[i][0]) / (pre - COLORS[i][0]);
  446. pre = COLORS[i][0];
  447. }
  448. return 0;
  449. }
  450. //@#//@#//@#//@#//@#//@#//@#// 関係ない //@#//@#//@#//@#//@#//@#//@#//@#//@#//@#
  451. function getOrdinal(x) {
  452. let s = ["th", "st", "nd", "rd"], v = x % 100;
  453. return x + (s[(v - 20) % 10] || s[v] || s[0]);
  454. }
  455. function getDiff(x) {
  456. let sign = x == 0 ? 'ツア' : (x < 0 ? '-' : '+');
  457. return sign + Math.abs(x);
  458. }
  459. function setStatus(data, particle_flag) {
  460. let date = new Date(data.EndTime * 1000);
  461. let rating = data.NewRating, old_rating = data.OldRating;
  462. let place = data.Place;
  463. let contest_name = data.ContestName;
  464. let tmp = getColor(rating); let color = tmp[1], alpha = tmp[2];
  465. border_status_shape.graphics.c().s(color).ss(1).rr(OFFSET_X, OFFSET_Y, STATUS_WIDTH, STATUS_HEIGHT, 2);
  466. rating_text.text = rating;
  467. rating_text.color = color;
  468. place_text.text = getOrdinal(place);
  469. diff_text.text = getDiff(rating - old_rating);
  470. date_text.text = date.toLocaleDateString();
  471. contest_name_text.text = contest_name;
  472. if (particle_flag) {
  473. let particle_num = parseInt(Math.pow(getRatingPer(rating), 2) * (PARTICLE_MAX - PARTICLE_MIN) + PARTICLE_MIN);
  474. setParticles(particle_num, color, alpha, rating);
  475. }
  476. standings_url = data.StandingsUrl;
  477. }
  478. //Particle は マウスオーバー時のくるくるのやつw
  479. function setParticle(particle, x, y, color, alpha, star_flag) {
  480. particle.x = x;
  481. particle.y = y;
  482. let ang = Math.random() * Math.PI * 2;
  483. let speed = Math.random() * 4 + 4;
  484. particle.vx = Math.cos(ang) * speed;
  485. particle.vy = Math.sin(ang) * speed;
  486. particle.rot_speed = Math.random() * 20 + 10;
  487. particle.life = LIFE_MAX;
  488. particle.visible = true;
  489. particle.color = color;
  490.  
  491. if (star_flag) {
  492. particle.text = "★";
  493. } else {
  494. particle.text = "@";
  495. }
  496. particle.alpha = alpha;
  497. }
  498. function setParticles(num, color, alpha, rating) {
  499. for (let i = 0; i < PARTICLE_MAX; i++) {
  500. if (i < num) {
  501. setParticle(particles[i], rating_text.x, rating_text.y, color, alpha, rating >= STAR_MIN);
  502. } else {
  503. particles[i].life = 0;
  504. particles[i].visible = false;
  505. }
  506. }
  507. }
  508. function updateParticle(particle) {
  509. if (particle.life <= 0) {
  510. particle.visible = false;
  511. return;
  512. }
  513. particle.x += particle.vx;
  514. particle.vx *= 0.9;
  515. particle.y += particle.vy;
  516. particle.vy *= 0.9;
  517. particle.life--;
  518. particle.scaleX = particle.scaleY = particle.life / LIFE_MAX;
  519. particle.rotation += particle.rot_speed;
  520. }
  521. function updateParticles() {
  522. for (let i = 0; i < PARTICLE_MAX; i++) {
  523. if (particles[i].life > 0) {
  524. updateParticle(particles[i]);
  525. }
  526. }
  527. }
  528. //@#//@#//@#//@#//@#//@#//@#// 関係ない //@#//@#//@#//@#//@#//@#//@#//@#//@#//@#
  529.  
  530. //##//##//##//##//##//##//##//##//##//##//##//##//##//##//##//##//##//##//##//##//##//##//##//##//##//##//##//##//##//##
  531.  
  532. async function main() {
  533. //get json
  534. let allJson;
  535. try {
  536. const res = await fetch("https://kenkoooo.com/atcoder/atcoder-api/results?user=" + username);
  537. allJson = await res.json()
  538. console.log(allJson.length)
  539. } catch (reaseon) { console.log('try失敗') }
  540. {
  541. let isExist = {};
  542. for (let i = 0; i < allJson.length; i++) {//なぜか負のポイントがあったから追加
  543. if (allJson[i].result === 'AC' && 0 <= allJson[i].point && allJson[i].point <= 3000 && isExist[allJson[i].problem_id] === undefined) {
  544. devoting_rating_history.push({ ...allJson[i] });
  545. isExist[allJson[i].problem_id] = 0;
  546. }
  547. }
  548. }
  549. function compare(a, b) { return a.epoch_second - b.epoch_second; }//比較関数
  550. devoting_rating_history.sort(compare);//時間順にソート
  551.  
  552. for (let i = 0; i < devoting_rating_history.length - 1; i++) {//合計の累積和的な
  553. devoting_rating_history[i + 1].point += devoting_rating_history[i].point;
  554. devoting_rating_history[i].point /= 100;
  555. }
  556. devoting_rating_history[devoting_rating_history.length - 1].point /= 100;
  557. //今までの累積和/100 が高さ
  558.  
  559. let shoujinButtonID = document.getElementById('shoujinButtonID');
  560. shoujinButtonID.addEventListener('click', function () {
  561. devoting_chart_container.visible = !devoting_chart_container.visible;
  562. stage_graph.update();
  563. });
  564.  
  565. init();
  566.  
  567. }
  568.  
  569. main();