UNPKG

@xcpcio/board-app

Version:
218 lines (207 loc) 4.63 kB
import type { RatingUser } from "@xcpcio/core"; import { RatingLevelToString, RatingUtility } from "@xcpcio/core"; interface RatingGraphData { x: number; y: number; rank: number; diffRating: string; ratingTitle: string; contestName: string; contestTime: string; teamName: string; link?: string; } function getDiffRating(oldRating: number, newRating: number) { const diff = newRating - oldRating; if (newRating > oldRating) { return `+${diff.toString()}`; } else { return diff.toString(); } } export function getRatingGraphOptions( ratingUser: RatingUser, ) { const data: RatingGraphData[] = []; { let oldRating = 0; for (const h of ratingUser.ratingHistories) { const d: RatingGraphData = {} as RatingGraphData; d.x = h.contestTime.unix() * 1000; d.y = h.rating; d.diffRating = getDiffRating(oldRating, h.rating); d.rank = h.rank; d.contestName = h.contestName; d.link = `/board/${h.contestID}`; d.contestTime = h.contestTime.format("YYYY-MM-DD HH:mm:ss"); d.teamName = h.teamName; d.ratingTitle = RatingLevelToString[RatingUtility.getRatingLevel(h.rating)]; data.push(d); oldRating = h.rating; } } let tickPositions = [ 1200, 1400, 1600, 1900, 2100, 2300, 2400, 2600, 3000, ]; { const gap = 100; let minRating = Math.max(0, ratingUser.minRating - gap); let maxRating = ratingUser.maxRating + gap; for (let i = 0; i < tickPositions.length; ++i) { if (tickPositions[i] > maxRating) { maxRating = tickPositions[i]; break; } } for (let i = tickPositions.length - 1; i >= 0; --i) { if (tickPositions[i] < minRating) { minRating = tickPositions[i]; break; } } if (minRating < 1200) { tickPositions = [minRating, ...tickPositions]; } if (maxRating > 3000) { tickPositions.push(maxRating); } tickPositions = tickPositions.filter( x => x >= minRating && x <= maxRating, ); } const options = { chart: { type: "line", height: "408px", }, title: { text: null, }, xAxis: { tickWidth: 0, gridLineWidth: 0.4, minRange: 30 * 24 * 60 * 60 * 1000, type: "datetime", showFirstLabel: true, showLastLabel: true, dateTimeLabelFormats: { month: "%b %Y", }, }, yAxis: { showEmpty: false, showFirstLabel: false, showLastLabel: false, tickPositions, tickWidth: 0, gridLineWidth: 0.6, labels: { enabled: true, format: "{value}", }, title: { text: null, }, plotBands: [ { from: 0, to: 1199, color: "#CCCCCC", }, { from: 1200, to: 1399, color: "#98FA87", }, { from: 1400, to: 1599, color: "#90DABD", }, { from: 1600, to: 1899, color: "#A9ACF9", }, { from: 1900, to: 2099, color: "#EF91F9", }, { from: 2100, to: 2299, color: "#F7CD91", }, { from: 2300, to: 2399, color: "#F5BD67", }, { from: 2400, to: 2599, color: "#Ef7F7B", }, { from: 2600, to: 2999, color: "#EB483F", }, { from: 3000, to: 0x3F3F3F3F, color: "#9C1E14", }, ], }, credits: { enabled: false, }, plotOptions: { line: { color: "#ffec3d", dataLabels: { enabled: false, }, enableMouseTracking: true, marker: { enabled: true, fillColor: "#fffb8f", }, }, }, tooltip: { enabled: true, headerFormat: "", useHTML: true, shared: true, shadow: true, followPointer: false, followTouchMove: false, pointFormat: `= {point.y} ({point.diffRating}), {point.ratingTitle} <br/>Rank: {point.rank} <br/>TeamName: {point.teamName} <br/>ContestTime: {point.contestTime} <br/><a href="{point.link}">{point.contestName}</a> <br/>`, }, series: [ { showInLegend: false, allowPointSelect: true, // name: ratingUser.name, data, }, ], }; return options; }