AtCoder_Rating_Graph_Color_Changer

change Atcoder Rating Graph's color.

  1. // ==UserScript==
  2. // @name AtCoder_Rating_Graph_Color_Changer
  3. // @version 0.1
  4. // @description change Atcoder Rating Graph's color.
  5. // @author NullNull
  6. // @match https://atcoder.jp/users/*
  7. // @require https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js
  8. // @namespace https://gf.qytechs.cn/users/319905
  9. // ==/UserScript==
  10.  
  11.  
  12. (function(){
  13. $(window).load(init);
  14.  
  15. // const
  16. const MARGIN_VAL_X = 86400 * 30;
  17. const MARGIN_VAL_Y_LOW = 100;
  18. const MARGIN_VAL_Y_HIGH = 300;
  19. const OFFSET_X = 50;
  20. const OFFSET_Y = 5;
  21. const DEFAULT_WIDTH = 640;
  22. var canvas_status = document.getElementById("ratingStatus");
  23. const STATUS_WIDTH = canvas_status.width - OFFSET_X - 10;
  24. const STATUS_HEIGHT = canvas_status.height - OFFSET_Y - 5;
  25. var canvas_graph = document.getElementById("ratingGraph");
  26. const PANEL_WIDTH = canvas_graph.width - OFFSET_X - 10;
  27. const PANEL_HEIGHT = canvas_graph.height - OFFSET_Y - 30;
  28. const HIGHEST_WIDTH = 80;
  29. const HIGHEST_HEIGHT = 20;
  30. const LABEL_FONT = "12px Lato";
  31. const START_YEAR = 2010;
  32. const MONTH_NAMES = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];
  33. const YEAR_SEC = 86400*365;
  34. const STEP_SIZE = 400;
  35. const COLORS = [
  36. [0, "#eeeeee", 0.15],
  37. [400, "#8b4513", 0.15],
  38. [800, "#7aff7a", 0.15],
  39. [1200, "#7affff", 0.2],
  40. [1600, "#7a7aff", 0.1],
  41. [2000, "#ffff7a", 0.25],
  42. [2400, "#ffbc7a", 0.2],
  43. [2800, "#ff7a7a", 0.1]
  44. ];
  45. const STAR_MIN = 3200;
  46. const PARTICLE_MIN = 3;
  47. const PARTICLE_MAX = 20;
  48. const LIFE_MAX = 30;
  49. const EPS = 1e-9;
  50.  
  51. var cj = createjs;
  52. var stage_graph, stage_status;
  53.  
  54. // graph
  55. var panel_shape, border_shape;
  56. var chart_container, line_shape, vertex_shapes, highest_shape;
  57. var n, x_min, x_max, y_min, y_max;
  58.  
  59. // status
  60. var border_status_shape;
  61. var rating_text, place_text, diff_text, date_text, contest_name_text;
  62. var particles;
  63. var standings_url;
  64.  
  65. function initStage(stage, canvas) {
  66. var width = canvas.getAttribute('width');
  67. var height = canvas.getAttribute('height');
  68. if (window.devicePixelRatio) {
  69. canvas.setAttribute('width', Math.round(width * window.devicePixelRatio));
  70. canvas.setAttribute('height', Math.round(height * window.devicePixelRatio));
  71. stage.scaleX = stage.scaleY = window.devicePixelRatio;
  72. }
  73. canvas.style.maxWidth = width+"px";
  74. canvas.style.maxHeight = height+"px";
  75. canvas.style.width = canvas.style.height = "100%";
  76. stage.enableMouseOver();
  77. }
  78.  
  79. function newShape(parent) {
  80. var s = new cj.Shape();
  81. parent.addChild(s);
  82. return s;
  83. }
  84.  
  85. function newText(parent, x, y, font) {
  86. var t = new cj.Text("", font, "#000");
  87. t.x = x;
  88. t.y = y;
  89. t.textAlign = "center";
  90. t.textBaseline = "middle";
  91. parent.addChild(t);
  92. return t;
  93. }
  94.  
  95. function init() {
  96. n = rating_history.length;
  97. if (n == 0) return;
  98.  
  99. stage_graph = new cj.Stage("ratingGraph");
  100. stage_status = new cj.Stage("ratingStatus");
  101. initStage(stage_graph, canvas_graph);
  102. initStage(stage_status, canvas_status);
  103.  
  104. x_min = 100000000000;
  105. x_max = 0;
  106. y_min = 10000;
  107. y_max = 0;
  108. for (var i = 0; i < n; i++) {
  109. x_min = Math.min(x_min, rating_history[i].EndTime);
  110. x_max = Math.max(x_max, rating_history[i].EndTime);
  111. y_min = Math.min(y_min, rating_history[i].NewRating);
  112. y_max = Math.max(y_max, rating_history[i].NewRating);
  113. }
  114. x_min -= MARGIN_VAL_X;
  115. x_max += MARGIN_VAL_X;
  116. y_min = Math.min(1500, Math.max(0, y_min - MARGIN_VAL_Y_LOW));
  117. y_max += MARGIN_VAL_Y_HIGH;
  118.  
  119. initBackground();
  120. initChart();
  121. stage_graph.update();
  122. initStatus();
  123. stage_status.update();
  124.  
  125. cj.Ticker.setFPS(60);
  126. cj.Ticker.addEventListener("tick", handleTick);
  127.  
  128. function handleTick(event) {
  129. updateParticles();
  130. stage_status.update();
  131. }
  132. }
  133.  
  134. function getPer(x, l, r) {
  135. return (x - l) / (r - l);
  136. }
  137.  
  138. function getColor(x) {
  139. for (var i = COLORS.length - 1; i >= 0; i--) {
  140. if (x >= COLORS[i][0]) return COLORS[i];
  141. }
  142. return [-1, "#000000", 0.1];
  143. }
  144.  
  145. function initBackground() {
  146. panel_shape = newShape(stage_graph);
  147. panel_shape.x = OFFSET_X;
  148. panel_shape.y = OFFSET_Y;
  149. panel_shape.alpha = 0.3;
  150. border_shape = newShape(stage_graph);
  151. border_shape.x = OFFSET_X;
  152. border_shape.y = OFFSET_Y;
  153.  
  154. function newLabelY(s, y) {
  155. var t = new cj.Text(s, LABEL_FONT, "#000");
  156. t.x = OFFSET_X - 10;
  157. t.y = OFFSET_Y + y;
  158. t.textAlign = "right";
  159. t.textBaseline = "middle";
  160. stage_graph.addChild(t);
  161. }
  162.  
  163. function newLabelX(s, x, y) {
  164. var t = new cj.Text(s, LABEL_FONT, "#000");
  165. t.x = OFFSET_X + x;
  166. t.y = OFFSET_Y + PANEL_HEIGHT + 2 + y;
  167. t.textAlign = "center";
  168. t.textBaseline = "top";
  169. stage_graph.addChild(t);
  170. }
  171. var y1 = 0;
  172. for (var i = COLORS.length - 1; i >= 0; i--) {
  173. var y2 = PANEL_HEIGHT - PANEL_HEIGHT * getPer(COLORS[i][0], y_min, y_max);
  174. if (y2 > 0 && y1 < PANEL_HEIGHT) {
  175. y1 = Math.max(y1, 0);
  176. panel_shape.graphics.f(COLORS[i][1]).r(0, y1, PANEL_WIDTH, Math.min(y2, PANEL_HEIGHT) - y1);
  177. }
  178. y1 = y2;
  179. }
  180. for (var i = 0; i <= y_max; i += STEP_SIZE) {
  181. if (i >= y_min) {
  182. var y = PANEL_HEIGHT - PANEL_HEIGHT * getPer(i, y_min, y_max);
  183. newLabelY(String(i), y);
  184. border_shape.graphics.s("#FFF").ss(0.5);
  185. if (i == 2000) border_shape.graphics.s("#000");
  186. border_shape.graphics.mt(0, y).lt(PANEL_WIDTH, y);
  187. }
  188. }
  189. border_shape.graphics.s("#FFF").ss(0.5);
  190.  
  191. var month_step = 6;
  192. for (var i = 3; i >= 1; i--) {
  193. if (x_max-x_min <= YEAR_SEC*i + MARGIN_VAL_X*2) month_step = i;
  194. }
  195. var first_flag = true;
  196. for (var i = START_YEAR; i < 3000; i++) {
  197. var break_flag = false;
  198. for (var j = 0; j < 12; j += month_step) {
  199. var month = ('00' + (j+1)).slice(-2);
  200. var unix = Date.parse(String(i)+"-"+month+"-01T00:00:00")/1000;
  201. if (x_min < unix && unix < x_max) {
  202. var x = PANEL_WIDTH * getPer(unix, x_min, x_max);
  203. if (j == 0 || first_flag) {
  204. newLabelX(MONTH_NAMES[j], x, 0);
  205. newLabelX(String(i), x, 13);
  206. first_flag = false;
  207. } else {
  208. newLabelX(MONTH_NAMES[j], x, 0);
  209. }
  210. border_shape.graphics.mt(x, 0).lt(x, PANEL_HEIGHT)
  211. }
  212. if (unix > x_max) { break_flag = true; break;}
  213. }
  214. if (break_flag) break;
  215. }
  216. border_shape.graphics.s("#888").ss(1.5).rr(0, 0, PANEL_WIDTH, PANEL_HEIGHT, 2);
  217. }
  218.  
  219. function initChart() {
  220. chart_container = new cj.Container();
  221. stage_graph.addChild(chart_container);
  222. chart_container.shadow = new cj.Shadow("rgba(0,0,0,0.3)", 1, 2, 3);
  223.  
  224. line_shape = newShape(chart_container);
  225. highest_shape = newShape(chart_container);
  226. vertex_shapes = new Array();
  227.  
  228. function mouseoverVertex(e) {
  229. vertex_shapes[e.target.i].scaleX = vertex_shapes[e.target.i].scaleY = 1.2;
  230. stage_graph.update();
  231. setStatus(rating_history[e.target.i], true);
  232. };
  233.  
  234. function mouseoutVertex(e) {
  235. vertex_shapes[e.target.i].scaleX = vertex_shapes[e.target.i].scaleY = 1;
  236. stage_graph.update();
  237. };
  238. var highest_i = 0;
  239. for (var i = 0; i < n; i++) {
  240. if (rating_history[highest_i].NewRating < rating_history[i].NewRating) {
  241. highest_i = i;
  242. }
  243. }
  244. for (var i = 0; i < n; i++) {
  245. vertex_shapes.push(newShape(chart_container));
  246. vertex_shapes[i].graphics.s("#FFF");
  247. if (i == highest_i) vertex_shapes[i].graphics.s("#000");
  248. vertex_shapes[i].graphics.ss(0.5).f(getColor(rating_history[i].NewRating)[1]).dc(0, 0, 3.5);
  249. vertex_shapes[i].x = OFFSET_X + PANEL_WIDTH * getPer(rating_history[i].EndTime, x_min, x_max);
  250. vertex_shapes[i].y = OFFSET_Y + (PANEL_HEIGHT - PANEL_HEIGHT * getPer(rating_history[i].NewRating, y_min, y_max));
  251. vertex_shapes[i].i = i;
  252. var hitArea = new cj.Shape();
  253. hitArea.graphics.f("#000").dc(1.5, 1.5, 6);
  254. vertex_shapes[i].hitArea = hitArea;
  255. vertex_shapes[i].addEventListener("mouseover", mouseoverVertex);
  256. vertex_shapes[i].addEventListener("mouseout", mouseoutVertex);
  257. }
  258. {
  259. var dx = 80;
  260. if ((x_min + x_max)/2 < rating_history[highest_i].EndTime) dx = -80;
  261. var x = vertex_shapes[highest_i].x + dx;
  262. var y = vertex_shapes[highest_i].y - 16;
  263. highest_shape.graphics.s("#FFF").mt(vertex_shapes[highest_i].x, vertex_shapes[highest_i].y).lt(x, y);
  264. highest_shape.graphics.s("#888").f("#FFF").rr(x - HIGHEST_WIDTH/2, y - HIGHEST_HEIGHT/2, HIGHEST_WIDTH, HIGHEST_HEIGHT, 2);
  265. highest_shape.i = highest_i;
  266. var highest_text = newText(stage_graph, x, y, "12px Lato");
  267. highest_text.text = "Highest: " + rating_history[highest_i].NewRating;
  268. highest_shape.addEventListener("mouseover", mouseoverVertex);
  269. highest_shape.addEventListener("mouseout", mouseoutVertex);
  270. }
  271. for (var j = 0; j < 2; j++) {
  272. if (j == 0) line_shape.graphics.s("#AAA").ss(2);
  273. else line_shape.graphics.s("#FFF").ss(0.5);
  274. line_shape.graphics.mt(vertex_shapes[0].x, vertex_shapes[0].y);
  275. for (var i = 0; i < n; i++) {
  276. line_shape.graphics.lt(vertex_shapes[i].x, vertex_shapes[i].y);
  277. }
  278. }
  279. }
  280.  
  281. function initStatus() {
  282. border_status_shape = newShape(stage_status);
  283. rating_text = newText(stage_status, OFFSET_X + 75, OFFSET_Y + STATUS_HEIGHT / 2, "48px 'Squada One'");
  284. place_text = newText(stage_status, OFFSET_X + 160, OFFSET_Y + STATUS_HEIGHT / 2.7, "16px Lato");
  285. diff_text = newText(stage_status, OFFSET_X + 160, OFFSET_Y + STATUS_HEIGHT / 1.5, "11px Lato");
  286. diff_text.color = '#888';
  287. date_text = newText(stage_status, OFFSET_X + 200, OFFSET_Y + STATUS_HEIGHT / 4, "14px Lato");
  288. contest_name_text = newText(stage_status, OFFSET_X + 200, OFFSET_Y + STATUS_HEIGHT / 1.6, "20px Lato");
  289. date_text.textAlign = contest_name_text.textAlign = "left";
  290. contest_name_text.maxWidth = STATUS_WIDTH - 200 - 10;
  291. {
  292. var hitArea = new cj.Shape(); hitArea.graphics.f("#000").r(0,-12,contest_name_text.maxWidth,24);
  293. contest_name_text.hitArea = hitArea;
  294. contest_name_text.cursor = "pointer";
  295. contest_name_text.addEventListener("click", function(){
  296. location.href = standings_url;
  297. });
  298. }
  299. particles = new Array();
  300. for (var i = 0; i < PARTICLE_MAX; i++) {
  301. particles.push(newText(stage_status, 0, 0, "64px Lato"));
  302. particles[i].visible = false;
  303. }
  304. setStatus(rating_history[rating_history.length-1], false);
  305. }
  306.  
  307. function getRatingPer(x) {
  308. var pre = COLORS[COLORS.length-1][0] + STEP_SIZE;
  309. for (var i = COLORS.length - 1; i >= 0; i--) {
  310. if (x >= COLORS[i][0]) return (x - COLORS[i][0]) / (pre - COLORS[i][0]);
  311. pre = COLORS[i][0];
  312. }
  313. return 0;
  314. }
  315.  
  316. function getOrdinal(x) {
  317. var s = ["th", "st", "nd", "rd"], v = x % 100;
  318. return x + (s[(v - 20) % 10] || s[v] || s[0]);
  319. }
  320. function getDiff(x) {
  321. var sign = x==0?'ツア':(x<0?'-':'+');
  322. return sign + Math.abs(x);
  323. }
  324.  
  325. function setStatus(data, particle_flag) {
  326. var date = new Date(data.EndTime * 1000);
  327. var rating = data.NewRating, old_rating = data.OldRating;
  328. var place = data.Place;
  329. var contest_name = data.ContestName;
  330. var tmp = getColor(rating); var color = tmp[1], alpha = tmp[2];
  331. border_status_shape.graphics.c().s(color).ss(1).rr(OFFSET_X, OFFSET_Y, STATUS_WIDTH, STATUS_HEIGHT, 2);
  332. rating_text.text = rating;
  333. rating_text.color = color;
  334. place_text.text = getOrdinal(place);
  335. diff_text.text = getDiff(rating-old_rating);
  336. date_text.text = date.toLocaleDateString();
  337. contest_name_text.text = contest_name;
  338. if (particle_flag) {
  339. var particle_num = parseInt(Math.pow(getRatingPer(rating), 2) * (PARTICLE_MAX - PARTICLE_MIN) + PARTICLE_MIN);
  340. setParticles(particle_num, color, alpha, rating);
  341. }
  342. standings_url = data.StandingsUrl;
  343. }
  344.  
  345. function setParticle(particle, x, y, color, alpha, star_flag) {
  346. particle.x = x;
  347. particle.y = y;
  348. var ang = Math.random() * Math.PI * 2;
  349. var speed = Math.random() * 4 + 4;
  350. particle.vx = Math.cos(ang) * speed;
  351. particle.vy = Math.sin(ang) * speed;
  352. particle.rot_speed = Math.random()*20+10;
  353. particle.life = LIFE_MAX;
  354. particle.visible = true;
  355. particle.color = color;
  356. if (star_flag) {
  357. particle.text = "笘�";
  358. } else {
  359. particle.text = "@";
  360. }
  361. particle.alpha = alpha;
  362. }
  363.  
  364. function setParticles(num, color, alpha, rating) {
  365. for (var i = 0; i < PARTICLE_MAX; i++) {
  366. if (i < num) {
  367. setParticle(particles[i], rating_text.x, rating_text.y, color, alpha, rating >= STAR_MIN);
  368. } else {
  369. particles[i].life = 0;
  370. particles[i].visible = false;
  371. }
  372. }
  373. }
  374.  
  375. function updateParticle(particle) {
  376. if (particle.life <= 0) {
  377. particle.visible = false;
  378. return;
  379. }
  380. particle.x += particle.vx;
  381. particle.vx *= 0.9;
  382. particle.y += particle.vy;
  383. particle.vy *= 0.9;
  384. particle.life--;
  385. particle.scaleX = particle.scaleY = particle.life / LIFE_MAX;
  386. particle.rotation += particle.rot_speed;
  387. }
  388.  
  389. function updateParticles() {
  390. for (var i = 0; i < PARTICLE_MAX; i++) {
  391. if (particles[i].life > 0) {
  392. updateParticle(particles[i]);
  393. }
  394. }
  395. }
  396.  
  397. $('#rating-graph-expand').click(function() {
  398. canvas_status.style.maxWidth = canvas_status.style.maxHeight = "";
  399. canvas_graph.style.maxWidth = canvas_graph.style.maxHeight = "";
  400. $(this).css('cssText', 'display: none !important;');
  401. });
  402. })();

QingJ © 2025

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