Greasy Fork is available in English.

AtcoderDevotionGraph

Overlay your devoiting graph on your rating graph

Tính đến 22-11-2020. Xem phiên bản mới nhất.

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