AtcoderDevotionGraph

Overlay your devoiting graph on your rating graph

2020/11/23のページです。最新版はこちら

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