diff --git a/client/src/components/charts/ContestsUserNumStackedArea.jsx b/client/src/components/charts/ContestsUserNumStackedArea.jsx
index e443599..704a74c 100644
--- a/client/src/components/charts/ContestsUserNumStackedArea.jsx
+++ b/client/src/components/charts/ContestsUserNumStackedArea.jsx
@@ -2,7 +2,7 @@ import ReactEcharts from "echarts-for-react";
const ContestsUserNumStackedArea = ({ contests }) => {
contests.sort((a, b) => new Date(a.startTime) - new Date(b.startTime));
- console.log(contests);
+ // console.log(contests);
const titles = contests.map((contest) =>
contest.title.replace(/eekly Contest /g, "")
);
diff --git a/client/src/components/charts/QuestionFinishedChart.jsx b/client/src/components/charts/QuestionFinishedChart.jsx
new file mode 100644
index 0000000..b1ac35c
--- /dev/null
+++ b/client/src/components/charts/QuestionFinishedChart.jsx
@@ -0,0 +1,113 @@
+import ReactEcharts from "echarts-for-react";
+
+const QuestionFinishedChart = ({ questionsRaw }) => {
+ // console.log("QuestionFinishedChart questionsRaw=", questionsRaw);
+ const questions = [...questionsRaw].sort((a, b) =>
+ a.credit === b.credit ? a.qi - b.qi : a.credit - b.credit
+ );
+
+ const real_time_count = [["Minute", "Question", "Count"]];
+ for (let i = 1; i <= questions.length; i++) {
+ for (let j = 1; j <= questions[0].real_time_count?.length; j++) {
+ real_time_count.push([
+ j,
+ `Q${i}`,
+ questions[i - 1].real_time_count[j - 1],
+ ]);
+ }
+ }
+
+ const questionsId = ["Q1", "Q2", "Q3", "Q4"];
+ const datasetWithFilters = [];
+ const seriesList = [];
+
+ questionsId.forEach((id) => {
+ const datasetId = "dataset_" + id;
+ datasetWithFilters.push({
+ id: datasetId,
+ fromDatasetId: "dataset_raw",
+ transform: {
+ type: "filter",
+ config: {
+ and: [{ dimension: "Question", "=": id }],
+ },
+ },
+ });
+ seriesList.push({
+ type: "line",
+ datasetId: datasetId,
+ showSymbol: false,
+ name: id,
+ endLabel: {
+ show: true,
+ formatter: function (params) {
+ return params.value[1] + ": " + params.value[2];
+ },
+ },
+ labelLayout: {
+ moveOverlap: "shiftY",
+ },
+ emphasis: {
+ focus: "series",
+ },
+ encode: {
+ x: "Minute",
+ y: "Count",
+ label: ["Question", "Count"],
+ itemName: "Minute",
+ tooltip: ["Count"],
+ },
+ });
+ });
+
+ const option = {
+ animation: true,
+ animationDuration: 10000,
+ dataset: [
+ {
+ id: "dataset_raw",
+ source: real_time_count,
+ },
+ ...datasetWithFilters,
+ ],
+ title: {
+ text: "Question Finished Count",
+ x: "center",
+ },
+ tooltip: {
+ order: "valueDesc",
+ trigger: "axis",
+ },
+ xAxis: {
+ type: "category",
+ name: "Minute",
+ },
+ yAxis: {
+ name: "Accepted",
+ // axisLabel: {
+ // rotate: 45,
+ // margin: 1
+ // }
+ },
+ grid: {
+ left: "70em",
+ right: "70em",
+ },
+ series: seriesList,
+ };
+
+ // console.log("question option= ", option);
+ return (
+
+ );
+};
+
+export default QuestionFinishedChart;
diff --git a/client/src/components/charts/RealTimeRankChart.jsx b/client/src/components/charts/RealTimeRankChart.jsx
new file mode 100644
index 0000000..95b9475
--- /dev/null
+++ b/client/src/components/charts/RealTimeRankChart.jsx
@@ -0,0 +1,105 @@
+import ReactEcharts from "echarts-for-react";
+
+const RealTimeRankChart = ({ user, rankList }) => {
+ if (!rankList) return null;
+
+ const realTimeRank = [["Minute", "Username", "Rank"]];
+ for (let j = 1; j <= rankList.length; j++) {
+ realTimeRank.push([j, user.username, rankList[j - 1]]);
+ }
+
+ const users = [user.username];
+ const datasetWithFilters = [];
+ const seriesList = [];
+
+ // console.log("users", users);
+ // console.log("realTimeRank", realTimeRank);
+
+ users.forEach((username) => {
+ const datasetId = "dataset_" + username;
+ datasetWithFilters.push({
+ id: datasetId,
+ fromDatasetId: "dataset_raw",
+ transform: {
+ type: "filter",
+ config: {
+ and: [{ dimension: "Username", "=": username }],
+ },
+ },
+ });
+ seriesList.push({
+ type: "line",
+ datasetId: datasetId,
+ showSymbol: false,
+ name: username,
+ endLabel: {
+ show: true,
+ formatter: function (params) {
+ return params.value[1] + ": " + params.value[2];
+ },
+ },
+ labelLayout: {
+ moveOverlap: "shiftY",
+ },
+ emphasis: {
+ focus: "series",
+ },
+ encode: {
+ x: "Minute",
+ y: "Rank",
+ label: ["Username", "Rank"],
+ itemName: "Minute",
+ tooltip: ["Rank"],
+ },
+ });
+ });
+
+ const option = {
+ animationDuration: 10000,
+ dataset: [
+ {
+ id: "dataset_raw",
+ source: realTimeRank,
+ },
+ ...datasetWithFilters,
+ ],
+ title: {
+ text: "User Real Time Rank",
+ x: "center",
+ },
+ tooltip: {
+ order: "valueDesc",
+ trigger: "axis",
+ },
+ xAxis: {
+ type: "category",
+ name: "Minute",
+ },
+ yAxis: {
+ name: "Rank",
+ axisLabel: {
+ rotate: 45,
+ margin: 1,
+ },
+ },
+ grid: {
+ // left:"70em",
+ right: "70em",
+ },
+ series: seriesList,
+ };
+
+ // console.log("realTimeRank option=", option);
+
+ return (
+
+ );
+};
+
+export default RealTimeRankChart;
diff --git a/client/src/pages/Predicted/PredictedRecords.jsx b/client/src/pages/Predicted/PredictedRecords.jsx
index 04c2e08..c3f8195 100644
--- a/client/src/pages/Predicted/PredictedRecords.jsx
+++ b/client/src/pages/Predicted/PredictedRecords.jsx
@@ -1,8 +1,6 @@
import { useState, useEffect } from "react";
import { useParams, useNavigate } from "react-router-dom";
-import ReactEcharts from "echarts-for-react";
-
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import {
faUser,
@@ -12,242 +10,11 @@ import {
import useSWR from "swr";
import Pagination from "../../components/Pagination";
+import QuestionFinishedChart from "../../components/charts/QuestionFinishedChart";
+import RealTimeRankChart from "../../components/charts/RealTimeRankChart";
import { baseUrl } from "../../data/constants";
import { trendColorsHSL } from "../../utils";
-const QuestionFinishedChart = ({ questionsRaw }) => {
- // console.log("QuestionFinishedChart questionsRaw=", questionsRaw);
- const questions = [...questionsRaw].sort((a, b) =>
- a.credit === b.credit ? a.qi - b.qi : a.credit - b.credit
- );
-
- const real_time_count = [["Minute", "Question", "Count"]];
- for (let i = 1; i <= questions.length; i++) {
- for (let j = 1; j <= questions[0].real_time_count?.length; j++) {
- real_time_count.push([
- j,
- `Q${i}`,
- questions[i - 1].real_time_count[j - 1],
- ]);
- }
- }
-
- const questionsId = ["Q1", "Q2", "Q3", "Q4"];
- const datasetWithFilters = [];
- const seriesList = [];
-
- questionsId.forEach((id) => {
- const datasetId = "dataset_" + id;
- datasetWithFilters.push({
- id: datasetId,
- fromDatasetId: "dataset_raw",
- transform: {
- type: "filter",
- config: {
- and: [{ dimension: "Question", "=": id }],
- },
- },
- });
- seriesList.push({
- type: "line",
- datasetId: datasetId,
- showSymbol: false,
- name: id,
- endLabel: {
- show: true,
- formatter: function (params) {
- return params.value[1] + ": " + params.value[2];
- },
- },
- labelLayout: {
- moveOverlap: "shiftY",
- },
- emphasis: {
- focus: "series",
- },
- encode: {
- x: "Minute",
- y: "Count",
- label: ["Question", "Count"],
- itemName: "Minute",
- tooltip: ["Count"],
- },
- });
- });
-
- const option = {
- animation: true,
- animationDuration: 10000,
- dataset: [
- {
- id: "dataset_raw",
- source: real_time_count,
- },
- ...datasetWithFilters,
- ],
- title: {
- text: "Question Finished Count",
- x: "center",
- },
- tooltip: {
- order: "valueDesc",
- trigger: "axis",
- },
- xAxis: {
- type: "category",
- name: "Minute",
- },
- yAxis: {
- name: "Accepted",
- // axisLabel: {
- // rotate: 45,
- // margin: 1
- // }
- },
- grid: {
- left: "70em",
- right: "70em",
- },
- series: seriesList,
- };
-
- // console.log("question option= ", option);
- return (
-
- );
-};
-
-const RealTimeRankChart = ({ user }) => {
- // console.log(`user=${user} ${user?.username} ${user?.data_region}`);
-
- const { titleSlug } = useParams();
-
- const { data } = useSWR(
- [
- `${baseUrl}/contest-records/real-time-rank`,
- JSON.stringify({
- contest_name: titleSlug,
- user: user,
- }),
- ],
- ([url, body]) =>
- fetch(url, {
- method: "POST",
- headers: { "Content-Type": "application/json" },
- body: body,
- }).then((r) => r.json()),
- { revalidateOnFocus: false }
- );
- const rankList = data?.real_time_rank;
- if (!rankList) return null;
-
- const realTimeRank = [["Minute", "Username", "Rank"]];
- for (let j = 1; j <= rankList.length; j++) {
- realTimeRank.push([j, user.username, rankList[j - 1]]);
- }
-
- const users = [user.username];
- const datasetWithFilters = [];
- const seriesList = [];
-
- // console.log("users", users);
- // console.log("realTimeRank", realTimeRank);
-
- users.forEach((username) => {
- const datasetId = "dataset_" + username;
- datasetWithFilters.push({
- id: datasetId,
- fromDatasetId: "dataset_raw",
- transform: {
- type: "filter",
- config: {
- and: [{ dimension: "Username", "=": username }],
- },
- },
- });
- seriesList.push({
- type: "line",
- datasetId: datasetId,
- showSymbol: false,
- name: username,
- endLabel: {
- show: true,
- formatter: function (params) {
- return params.value[1] + ": " + params.value[2];
- },
- },
- labelLayout: {
- moveOverlap: "shiftY",
- },
- emphasis: {
- focus: "series",
- },
- encode: {
- x: "Minute",
- y: "Rank",
- label: ["Username", "Rank"],
- itemName: "Minute",
- tooltip: ["Rank"],
- },
- });
- });
-
- const option = {
- animationDuration: 10000,
- dataset: [
- {
- id: "dataset_raw",
- source: realTimeRank,
- },
- ...datasetWithFilters,
- ],
- title: {
- text: "User Real Time Rank",
- x: "center",
- },
- tooltip: {
- order: "valueDesc",
- trigger: "axis",
- },
- xAxis: {
- type: "category",
- name: "Minute",
- },
- yAxis: {
- name: "Rank",
- axisLabel: {
- rotate: 45,
- margin: 1,
- },
- },
- grid: {
- // left:"70em",
- right: "70em",
- },
- series: seriesList,
- };
-
- // console.log("realTimeRank option=", option);
-
- return (
-
- );
-};
-
const PredictedRecordsSearch = ({
titleSlug,
setPredictedRecordsURL,
@@ -460,6 +227,26 @@ const PredictedRecords = () => {
// if (predictedRecordsURL === null) return;
// console.log(`predictedRecords=${predictedRecords}`);
+ // console.log(`user=${user} ${user?.username} ${user?.data_region}`);
+
+ const { data: rankData } = useSWR(
+ [
+ `${baseUrl}/contest-records/real-time-rank`,
+ JSON.stringify({
+ contest_name: titleSlug,
+ user: user,
+ }),
+ ],
+ ([url, body]) =>
+ fetch(url, {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: body,
+ }).then((r) => r.json()),
+ { revalidateOnFocus: false }
+ );
+ const rankList = rankData?.real_time_rank;
+
if (!predictedRecords || isLoading)
return (
@@ -517,7 +304,7 @@ const PredictedRecords = () => {