@xcpcio/core 0.31.1 → 0.33.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +39 -12
- package/dist/index.d.ts +6 -2
- package/dist/index.mjs +38 -13
- package/package.json +6 -2
- package/src/balloon.ts +4 -0
- package/src/problem.ts +17 -18
- package/src/rank.ts +4 -0
- package/src/submission.ts +7 -1
- package/src/utils/color.ts +16 -0
- package/src/utils/index.ts +1 -0
package/dist/index.cjs
CHANGED
|
@@ -15,6 +15,8 @@ const relativeTime = require('dayjs/plugin/relativeTime');
|
|
|
15
15
|
const _ = require('lodash');
|
|
16
16
|
const XLSX = require('xlsx-js-style');
|
|
17
17
|
const stringWidth = require('string-width');
|
|
18
|
+
const colorDiff = require('color-diff');
|
|
19
|
+
const chroma = require('chroma-js');
|
|
18
20
|
|
|
19
21
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e["default"] : e; }
|
|
20
22
|
|
|
@@ -42,6 +44,7 @@ const relativeTime__default = /*#__PURE__*/_interopDefaultLegacy(relativeTime);
|
|
|
42
44
|
const ___default = /*#__PURE__*/_interopDefaultLegacy(_);
|
|
43
45
|
const XLSX__namespace = /*#__PURE__*/_interopNamespace(XLSX);
|
|
44
46
|
const stringWidth__default = /*#__PURE__*/_interopDefaultLegacy(stringWidth);
|
|
47
|
+
const chroma__default = /*#__PURE__*/_interopDefaultLegacy(chroma);
|
|
45
48
|
|
|
46
49
|
function stringToSubmissionStatus(status) {
|
|
47
50
|
status = status.toUpperCase().replace(" ", "_");
|
|
@@ -462,6 +465,18 @@ function calcDirt(attemptedNum, solvedNum) {
|
|
|
462
465
|
return Math.floor((attemptedNum - solvedNum) * 100 / attemptedNum);
|
|
463
466
|
}
|
|
464
467
|
|
|
468
|
+
function getWhiteOrBlackColor(background) {
|
|
469
|
+
const [R, G, B] = chroma__default(background).rgb();
|
|
470
|
+
const color = { R, G, B };
|
|
471
|
+
const palette = [{ R: 0, G: 0, B: 0 }, { R: 255, G: 255, B: 255 }];
|
|
472
|
+
const f = colorDiff.furthest(color, palette);
|
|
473
|
+
if (f.R === 0 && f.G === 0 && f.B === 0) {
|
|
474
|
+
return "#000";
|
|
475
|
+
} else {
|
|
476
|
+
return "#fff";
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
|
|
465
480
|
class ProblemStatistics {
|
|
466
481
|
constructor() {
|
|
467
482
|
this.acceptedNum = 0;
|
|
@@ -496,6 +511,10 @@ class Problem {
|
|
|
496
511
|
this.label = "";
|
|
497
512
|
this.name = "";
|
|
498
513
|
this.statistics = new ProblemStatistics();
|
|
514
|
+
this.balloonColor = {
|
|
515
|
+
background_color: "#a0f0a0",
|
|
516
|
+
color: "#000"
|
|
517
|
+
};
|
|
499
518
|
}
|
|
500
519
|
}
|
|
501
520
|
function createProblem(problemJSON) {
|
|
@@ -505,20 +524,14 @@ function createProblem(problemJSON) {
|
|
|
505
524
|
p.name = problemJSON.name ?? "";
|
|
506
525
|
p.timeLimit = problemJSON.time_limit;
|
|
507
526
|
p.memoryLimit = problemJSON.memory_limit;
|
|
508
|
-
|
|
527
|
+
if (problemJSON.balloon_color) {
|
|
528
|
+
p.balloonColor = problemJSON.balloon_color;
|
|
529
|
+
}
|
|
530
|
+
p.balloonColor.color = getWhiteOrBlackColor(p.balloonColor.background_color);
|
|
509
531
|
return p;
|
|
510
532
|
}
|
|
511
533
|
function createProblems(problemsJSON) {
|
|
512
|
-
return problemsJSON.map((pJSON) =>
|
|
513
|
-
const p = new Problem();
|
|
514
|
-
p.id = pJSON.id;
|
|
515
|
-
p.label = pJSON.label;
|
|
516
|
-
p.name = pJSON.name ?? "";
|
|
517
|
-
p.timeLimit = pJSON.time_limit;
|
|
518
|
-
p.memoryLimit = pJSON.memory_limit;
|
|
519
|
-
p.balloonColor = pJSON.balloon_color;
|
|
520
|
-
return p;
|
|
521
|
-
});
|
|
534
|
+
return problemsJSON.map((pJSON) => createProblem(pJSON));
|
|
522
535
|
}
|
|
523
536
|
function createProblemsByProblemIds(problemIds, balloonColors) {
|
|
524
537
|
const problems = problemIds.map((label, index) => {
|
|
@@ -532,6 +545,9 @@ function createProblemsByProblemIds(problemIds, balloonColors) {
|
|
|
532
545
|
problems[index].balloonColor = balloonColors[index];
|
|
533
546
|
}
|
|
534
547
|
}
|
|
548
|
+
problems.forEach((p) => {
|
|
549
|
+
p.balloonColor.color = getWhiteOrBlackColor(p.balloonColor.background_color);
|
|
550
|
+
});
|
|
535
551
|
return problems;
|
|
536
552
|
}
|
|
537
553
|
class TeamProblemStatistics {
|
|
@@ -826,7 +842,13 @@ class Submission {
|
|
|
826
842
|
return 1;
|
|
827
843
|
}
|
|
828
844
|
}
|
|
829
|
-
|
|
845
|
+
if (lhs.id < rhs.id) {
|
|
846
|
+
return -1;
|
|
847
|
+
} else if (lhs.id === rhs.id) {
|
|
848
|
+
return 0;
|
|
849
|
+
} else {
|
|
850
|
+
return 1;
|
|
851
|
+
}
|
|
830
852
|
}
|
|
831
853
|
}
|
|
832
854
|
function createSubmission(submissionJSON) {
|
|
@@ -865,6 +887,9 @@ class Balloon {
|
|
|
865
887
|
get key() {
|
|
866
888
|
return `balloon-${this.team.id}-${this.problem.id}`;
|
|
867
889
|
}
|
|
890
|
+
static compare(lhs, rhs) {
|
|
891
|
+
return Submission.compare(lhs.submission, rhs.submission);
|
|
892
|
+
}
|
|
868
893
|
}
|
|
869
894
|
|
|
870
895
|
class Group {
|
|
@@ -1184,6 +1209,7 @@ class RankOptions {
|
|
|
1184
1209
|
this.filterOrganizationMap = /* @__PURE__ */ new Map();
|
|
1185
1210
|
this.filterTeams = [];
|
|
1186
1211
|
this.filterTeamMap = /* @__PURE__ */ new Map();
|
|
1212
|
+
this.enableAnimatedSubmissions = false;
|
|
1187
1213
|
}
|
|
1188
1214
|
setWidth(width, contest) {
|
|
1189
1215
|
this.width = width;
|
|
@@ -1639,6 +1665,7 @@ exports.createTeams = createTeams;
|
|
|
1639
1665
|
exports.getImageSource = getImageSource;
|
|
1640
1666
|
exports.getTimeDiff = getTimeDiff;
|
|
1641
1667
|
exports.getTimestamp = getTimestamp;
|
|
1668
|
+
exports.getWhiteOrBlackColor = getWhiteOrBlackColor;
|
|
1642
1669
|
exports.isAccepted = isAccepted;
|
|
1643
1670
|
exports.isNotCalculatedPenaltyStatus = isNotCalculatedPenaltyStatus;
|
|
1644
1671
|
exports.isPending = isPending;
|
package/dist/index.d.ts
CHANGED
|
@@ -47,7 +47,7 @@ declare class Problem {
|
|
|
47
47
|
name: string;
|
|
48
48
|
timeLimit?: string;
|
|
49
49
|
memoryLimit?: string;
|
|
50
|
-
balloonColor
|
|
50
|
+
balloonColor: BalloonColor;
|
|
51
51
|
statistics: ProblemStatistics;
|
|
52
52
|
constructor();
|
|
53
53
|
}
|
|
@@ -83,6 +83,8 @@ declare class TeamProblemStatistics {
|
|
|
83
83
|
|
|
84
84
|
declare function calcDirt(attemptedNum: number, solvedNum: number): number;
|
|
85
85
|
|
|
86
|
+
declare function getWhiteOrBlackColor(background: string): "#000" | "#fff";
|
|
87
|
+
|
|
86
88
|
declare function createDayJS(time?: Date | string | number | undefined): dayjs.Dayjs;
|
|
87
89
|
declare function getTimestamp(time: number | dayjs.Dayjs): number;
|
|
88
90
|
declare function getTimeDiff(seconds: number): string;
|
|
@@ -210,6 +212,7 @@ declare class Balloon {
|
|
|
210
212
|
submission: Submission;
|
|
211
213
|
constructor();
|
|
212
214
|
get key(): string;
|
|
215
|
+
static compare(lhs: Balloon, rhs: Balloon): number;
|
|
213
216
|
}
|
|
214
217
|
type Balloons = Array<Balloon>;
|
|
215
218
|
|
|
@@ -227,6 +230,7 @@ declare class RankOptions {
|
|
|
227
230
|
filterOrganizationMap: Map<string, SelectOptionItem>;
|
|
228
231
|
filterTeams: Array<SelectOptionItem>;
|
|
229
232
|
filterTeamMap: Map<string, SelectOptionItem>;
|
|
233
|
+
enableAnimatedSubmissions: boolean;
|
|
230
234
|
constructor();
|
|
231
235
|
setWidth(width: number, contest: Contest): void;
|
|
232
236
|
disableFilterSubmissionByTimestamp(): void;
|
|
@@ -320,4 +324,4 @@ declare function isRejected(status: SubmissionStatus): boolean;
|
|
|
320
324
|
declare function isPending(status: SubmissionStatus): boolean;
|
|
321
325
|
declare function isNotCalculatedPenaltyStatus(status: SubmissionStatus): boolean;
|
|
322
326
|
|
|
323
|
-
export { Award, Awards, Balloon, Balloons, CodeforcesGymGhostDATConverter, Contest, ContestIndex, ContestIndexConfig, ContestIndexList, ContestOptions, GeneralExcelConverter, MedalType, PlaceChartPointData, Problem, ProblemStatistics, Problems, Rank, RankOptions, RankStatistics, Resolver, SelectOptionItem, Submission, Submissions, Team, TeamProblemStatistics, Teams, calcDirt, createContest, createContestIndex, createContestIndexList, createDayJS, createProblem, createProblems, createProblemsByProblemIds, createSubmission, createSubmissions, createTeam, createTeams, getImageSource, getTimeDiff, getTimestamp, isAccepted, isNotCalculatedPenaltyStatus, isPending, isRejected, isValidMedalType, stringToSubmissionStatus };
|
|
327
|
+
export { Award, Awards, Balloon, Balloons, CodeforcesGymGhostDATConverter, Contest, ContestIndex, ContestIndexConfig, ContestIndexList, ContestOptions, GeneralExcelConverter, MedalType, PlaceChartPointData, Problem, ProblemStatistics, Problems, Rank, RankOptions, RankStatistics, Resolver, SelectOptionItem, Submission, Submissions, Team, TeamProblemStatistics, Teams, calcDirt, createContest, createContestIndex, createContestIndexList, createDayJS, createProblem, createProblems, createProblemsByProblemIds, createSubmission, createSubmissions, createTeam, createTeams, getImageSource, getTimeDiff, getTimestamp, getWhiteOrBlackColor, isAccepted, isNotCalculatedPenaltyStatus, isPending, isRejected, isValidMedalType, stringToSubmissionStatus };
|
package/dist/index.mjs
CHANGED
|
@@ -12,6 +12,8 @@ import relativeTime from 'dayjs/plugin/relativeTime';
|
|
|
12
12
|
import _ from 'lodash';
|
|
13
13
|
import * as XLSX from 'xlsx-js-style';
|
|
14
14
|
import stringWidth from 'string-width';
|
|
15
|
+
import { furthest } from 'color-diff';
|
|
16
|
+
import chroma from 'chroma-js';
|
|
15
17
|
|
|
16
18
|
function stringToSubmissionStatus(status) {
|
|
17
19
|
status = status.toUpperCase().replace(" ", "_");
|
|
@@ -432,6 +434,18 @@ function calcDirt(attemptedNum, solvedNum) {
|
|
|
432
434
|
return Math.floor((attemptedNum - solvedNum) * 100 / attemptedNum);
|
|
433
435
|
}
|
|
434
436
|
|
|
437
|
+
function getWhiteOrBlackColor(background) {
|
|
438
|
+
const [R, G, B] = chroma(background).rgb();
|
|
439
|
+
const color = { R, G, B };
|
|
440
|
+
const palette = [{ R: 0, G: 0, B: 0 }, { R: 255, G: 255, B: 255 }];
|
|
441
|
+
const f = furthest(color, palette);
|
|
442
|
+
if (f.R === 0 && f.G === 0 && f.B === 0) {
|
|
443
|
+
return "#000";
|
|
444
|
+
} else {
|
|
445
|
+
return "#fff";
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
435
449
|
class ProblemStatistics {
|
|
436
450
|
constructor() {
|
|
437
451
|
this.acceptedNum = 0;
|
|
@@ -466,6 +480,10 @@ class Problem {
|
|
|
466
480
|
this.label = "";
|
|
467
481
|
this.name = "";
|
|
468
482
|
this.statistics = new ProblemStatistics();
|
|
483
|
+
this.balloonColor = {
|
|
484
|
+
background_color: "#a0f0a0",
|
|
485
|
+
color: "#000"
|
|
486
|
+
};
|
|
469
487
|
}
|
|
470
488
|
}
|
|
471
489
|
function createProblem(problemJSON) {
|
|
@@ -475,20 +493,14 @@ function createProblem(problemJSON) {
|
|
|
475
493
|
p.name = problemJSON.name ?? "";
|
|
476
494
|
p.timeLimit = problemJSON.time_limit;
|
|
477
495
|
p.memoryLimit = problemJSON.memory_limit;
|
|
478
|
-
|
|
496
|
+
if (problemJSON.balloon_color) {
|
|
497
|
+
p.balloonColor = problemJSON.balloon_color;
|
|
498
|
+
}
|
|
499
|
+
p.balloonColor.color = getWhiteOrBlackColor(p.balloonColor.background_color);
|
|
479
500
|
return p;
|
|
480
501
|
}
|
|
481
502
|
function createProblems(problemsJSON) {
|
|
482
|
-
return problemsJSON.map((pJSON) =>
|
|
483
|
-
const p = new Problem();
|
|
484
|
-
p.id = pJSON.id;
|
|
485
|
-
p.label = pJSON.label;
|
|
486
|
-
p.name = pJSON.name ?? "";
|
|
487
|
-
p.timeLimit = pJSON.time_limit;
|
|
488
|
-
p.memoryLimit = pJSON.memory_limit;
|
|
489
|
-
p.balloonColor = pJSON.balloon_color;
|
|
490
|
-
return p;
|
|
491
|
-
});
|
|
503
|
+
return problemsJSON.map((pJSON) => createProblem(pJSON));
|
|
492
504
|
}
|
|
493
505
|
function createProblemsByProblemIds(problemIds, balloonColors) {
|
|
494
506
|
const problems = problemIds.map((label, index) => {
|
|
@@ -502,6 +514,9 @@ function createProblemsByProblemIds(problemIds, balloonColors) {
|
|
|
502
514
|
problems[index].balloonColor = balloonColors[index];
|
|
503
515
|
}
|
|
504
516
|
}
|
|
517
|
+
problems.forEach((p) => {
|
|
518
|
+
p.balloonColor.color = getWhiteOrBlackColor(p.balloonColor.background_color);
|
|
519
|
+
});
|
|
505
520
|
return problems;
|
|
506
521
|
}
|
|
507
522
|
class TeamProblemStatistics {
|
|
@@ -796,7 +811,13 @@ class Submission {
|
|
|
796
811
|
return 1;
|
|
797
812
|
}
|
|
798
813
|
}
|
|
799
|
-
|
|
814
|
+
if (lhs.id < rhs.id) {
|
|
815
|
+
return -1;
|
|
816
|
+
} else if (lhs.id === rhs.id) {
|
|
817
|
+
return 0;
|
|
818
|
+
} else {
|
|
819
|
+
return 1;
|
|
820
|
+
}
|
|
800
821
|
}
|
|
801
822
|
}
|
|
802
823
|
function createSubmission(submissionJSON) {
|
|
@@ -835,6 +856,9 @@ class Balloon {
|
|
|
835
856
|
get key() {
|
|
836
857
|
return `balloon-${this.team.id}-${this.problem.id}`;
|
|
837
858
|
}
|
|
859
|
+
static compare(lhs, rhs) {
|
|
860
|
+
return Submission.compare(lhs.submission, rhs.submission);
|
|
861
|
+
}
|
|
838
862
|
}
|
|
839
863
|
|
|
840
864
|
class Group {
|
|
@@ -1154,6 +1178,7 @@ class RankOptions {
|
|
|
1154
1178
|
this.filterOrganizationMap = /* @__PURE__ */ new Map();
|
|
1155
1179
|
this.filterTeams = [];
|
|
1156
1180
|
this.filterTeamMap = /* @__PURE__ */ new Map();
|
|
1181
|
+
this.enableAnimatedSubmissions = false;
|
|
1157
1182
|
}
|
|
1158
1183
|
setWidth(width, contest) {
|
|
1159
1184
|
this.width = width;
|
|
@@ -1574,4 +1599,4 @@ class Resolver extends Rank {
|
|
|
1574
1599
|
}
|
|
1575
1600
|
}
|
|
1576
1601
|
|
|
1577
|
-
export { Award, Balloon, CodeforcesGymGhostDATConverter, Contest, ContestIndex, ContestIndexConfig, ContestOptions, GeneralExcelConverter, MedalType, PlaceChartPointData, Problem, ProblemStatistics, Rank, RankOptions, RankStatistics, Resolver, Submission, Team, TeamProblemStatistics, calcDirt, createContest, createContestIndex, createContestIndexList, createDayJS, createProblem, createProblems, createProblemsByProblemIds, createSubmission, createSubmissions, createTeam, createTeams, getImageSource, getTimeDiff, getTimestamp, isAccepted, isNotCalculatedPenaltyStatus, isPending, isRejected, isValidMedalType, stringToSubmissionStatus };
|
|
1602
|
+
export { Award, Balloon, CodeforcesGymGhostDATConverter, Contest, ContestIndex, ContestIndexConfig, ContestOptions, GeneralExcelConverter, MedalType, PlaceChartPointData, Problem, ProblemStatistics, Rank, RankOptions, RankStatistics, Resolver, Submission, Team, TeamProblemStatistics, calcDirt, createContest, createContestIndex, createContestIndexList, createDayJS, createProblem, createProblems, createProblemsByProblemIds, createSubmission, createSubmissions, createTeam, createTeams, getImageSource, getTimeDiff, getTimestamp, getWhiteOrBlackColor, isAccepted, isNotCalculatedPenaltyStatus, isPending, isRejected, isValidMedalType, stringToSubmissionStatus };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xcpcio/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.33.0",
|
|
4
4
|
"description": "XCPCIO Core",
|
|
5
5
|
"author": "Dup4 <lyuzhi.pan@gmail.com>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -40,14 +40,18 @@
|
|
|
40
40
|
"dist"
|
|
41
41
|
],
|
|
42
42
|
"dependencies": {
|
|
43
|
+
"chroma-js": "^2.4.2",
|
|
44
|
+
"color-diff": "^1.4.0",
|
|
43
45
|
"dayjs": "^1.11.8",
|
|
44
46
|
"lodash": "^4.17.21",
|
|
45
47
|
"string-width": "^6.1.0",
|
|
46
48
|
"xlsx-js-style": "^1.2.0",
|
|
47
|
-
"@xcpcio/types": "0.
|
|
49
|
+
"@xcpcio/types": "0.33.0"
|
|
48
50
|
},
|
|
49
51
|
"devDependencies": {
|
|
50
52
|
"@babel/types": "^7.22.4",
|
|
53
|
+
"@types/chroma-js": "^2.4.2",
|
|
54
|
+
"@types/color-diff": "^1.2.3",
|
|
51
55
|
"@types/lodash": "^4.14.195",
|
|
52
56
|
"@types/node": "^17.0.45",
|
|
53
57
|
"@typescript-eslint/eslint-plugin": "^5.59.9",
|
package/src/balloon.ts
CHANGED
|
@@ -16,6 +16,10 @@ export class Balloon {
|
|
|
16
16
|
get key() {
|
|
17
17
|
return `balloon-${this.team.id}-${this.problem.id}`;
|
|
18
18
|
}
|
|
19
|
+
|
|
20
|
+
static compare(lhs: Balloon, rhs: Balloon): number {
|
|
21
|
+
return Submission.compare(lhs.submission, rhs.submission);
|
|
22
|
+
}
|
|
19
23
|
}
|
|
20
24
|
|
|
21
25
|
export type Balloons = Array<Balloon>;
|
package/src/problem.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { BalloonColor, Problem as IProblem, Problems as IProblems } from "@xcpcio/types";
|
|
2
2
|
|
|
3
3
|
import type { Submissions } from "./submission";
|
|
4
|
-
import { calcDirt } from "./utils";
|
|
4
|
+
import { calcDirt, getWhiteOrBlackColor } from "./utils";
|
|
5
5
|
|
|
6
6
|
export class ProblemStatistics {
|
|
7
7
|
acceptedNum: number;
|
|
@@ -59,7 +59,7 @@ export class Problem {
|
|
|
59
59
|
timeLimit?: string;
|
|
60
60
|
memoryLimit?: string;
|
|
61
61
|
|
|
62
|
-
balloonColor
|
|
62
|
+
balloonColor: BalloonColor;
|
|
63
63
|
|
|
64
64
|
statistics: ProblemStatistics;
|
|
65
65
|
|
|
@@ -70,6 +70,11 @@ export class Problem {
|
|
|
70
70
|
this.name = "";
|
|
71
71
|
|
|
72
72
|
this.statistics = new ProblemStatistics();
|
|
73
|
+
|
|
74
|
+
this.balloonColor = {
|
|
75
|
+
background_color: "#a0f0a0",
|
|
76
|
+
color: "#000",
|
|
77
|
+
};
|
|
73
78
|
}
|
|
74
79
|
}
|
|
75
80
|
|
|
@@ -86,27 +91,17 @@ export function createProblem(problemJSON: IProblem): Problem {
|
|
|
86
91
|
p.timeLimit = problemJSON.time_limit;
|
|
87
92
|
p.memoryLimit = problemJSON.memory_limit;
|
|
88
93
|
|
|
89
|
-
|
|
94
|
+
if (problemJSON.balloon_color) {
|
|
95
|
+
p.balloonColor = problemJSON.balloon_color;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
p.balloonColor.color = getWhiteOrBlackColor(p.balloonColor.background_color as string);
|
|
90
99
|
|
|
91
100
|
return p;
|
|
92
101
|
}
|
|
93
102
|
|
|
94
103
|
export function createProblems(problemsJSON: IProblems): Problems {
|
|
95
|
-
return problemsJSON.map(
|
|
96
|
-
const p = new Problem();
|
|
97
|
-
|
|
98
|
-
p.id = pJSON.id;
|
|
99
|
-
p.label = pJSON.label;
|
|
100
|
-
|
|
101
|
-
p.name = pJSON.name ?? "";
|
|
102
|
-
|
|
103
|
-
p.timeLimit = pJSON.time_limit;
|
|
104
|
-
p.memoryLimit = pJSON.memory_limit;
|
|
105
|
-
|
|
106
|
-
p.balloonColor = pJSON.balloon_color;
|
|
107
|
-
|
|
108
|
-
return p;
|
|
109
|
-
});
|
|
104
|
+
return problemsJSON.map(pJSON => createProblem(pJSON));
|
|
110
105
|
}
|
|
111
106
|
|
|
112
107
|
export function createProblemsByProblemIds(problemIds: string[], balloonColors?: BalloonColor[]): Problems {
|
|
@@ -124,6 +119,10 @@ export function createProblemsByProblemIds(problemIds: string[], balloonColors?:
|
|
|
124
119
|
}
|
|
125
120
|
}
|
|
126
121
|
|
|
122
|
+
problems.forEach((p) => {
|
|
123
|
+
p.balloonColor.color = getWhiteOrBlackColor(p.balloonColor.background_color as string);
|
|
124
|
+
});
|
|
125
|
+
|
|
127
126
|
return problems;
|
|
128
127
|
}
|
|
129
128
|
|
package/src/rank.ts
CHANGED
|
@@ -29,6 +29,8 @@ export class RankOptions {
|
|
|
29
29
|
filterTeams: Array<SelectOptionItem>;
|
|
30
30
|
filterTeamMap: Map<string, SelectOptionItem>;
|
|
31
31
|
|
|
32
|
+
enableAnimatedSubmissions: boolean;
|
|
33
|
+
|
|
32
34
|
constructor() {
|
|
33
35
|
this.enableFilterSubmissionsByTimestamp = false;
|
|
34
36
|
this.width = 0;
|
|
@@ -42,6 +44,8 @@ export class RankOptions {
|
|
|
42
44
|
|
|
43
45
|
this.filterTeams = [];
|
|
44
46
|
this.filterTeamMap = new Map<string, SelectOptionItem>();
|
|
47
|
+
|
|
48
|
+
this.enableAnimatedSubmissions = false;
|
|
45
49
|
}
|
|
46
50
|
|
|
47
51
|
setWidth(width: number, contest: Contest) {
|
package/src/submission.ts
CHANGED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { furthest } from "color-diff";
|
|
2
|
+
import chroma from "chroma-js";
|
|
3
|
+
|
|
4
|
+
export function getWhiteOrBlackColor(background: string) {
|
|
5
|
+
const [R, G, B] = chroma(background).rgb();
|
|
6
|
+
const color = { R, G, B };
|
|
7
|
+
const palette = [{ R: 0, G: 0, B: 0 }, { R: 255, G: 255, B: 255 }];
|
|
8
|
+
|
|
9
|
+
const f = furthest(color, palette);
|
|
10
|
+
|
|
11
|
+
if (f.R === 0 && f.G === 0 && f.B === 0) {
|
|
12
|
+
return "#000";
|
|
13
|
+
} else {
|
|
14
|
+
return "#fff";
|
|
15
|
+
}
|
|
16
|
+
}
|
package/src/utils/index.ts
CHANGED