diff --git a/assets/js/scoreboard.js b/assets/js/scoreboard.js index e3ef264..d11da70 100644 --- a/assets/js/scoreboard.js +++ b/assets/js/scoreboard.js @@ -16,7 +16,9 @@ Alpine.data("ScoreboardDetail", () => ({ async update() { this.data = await CTFd.pages.scoreboard.getScoreboardDetail(10); - let option = getOption(CTFd.config.userMode, this.data); + let optionMerge = window.scoreboardChartOptions; + let option = getOption(CTFd.config.userMode, this.data, optionMerge); + embed(this.$refs.scoregraph, option); this.show = Object.keys(this.data).length > 0; }, diff --git a/assets/js/teams/private.js b/assets/js/teams/private.js index bb3515c..32c0e5d 100644 --- a/assets/js/teams/private.js +++ b/assets/js/teams/private.js @@ -191,6 +191,8 @@ Alpine.data("TeamGraphs", () => ({ this.failCount = this.fails.meta.count; this.awardCount = this.awards.meta.count; + let optionMerge = window.teamScoreGraphChartOptions; + embed( this.$refs.scoregraph, getUserScoreOption( @@ -198,6 +200,7 @@ Alpine.data("TeamGraphs", () => ({ CTFd.team.name, this.solves.data, this.awards.data, + optionMerge, ), ); }, diff --git a/assets/js/teams/public.js b/assets/js/teams/public.js index 1dd1c46..c8b494a 100644 --- a/assets/js/teams/public.js +++ b/assets/js/teams/public.js @@ -61,6 +61,8 @@ Alpine.data("TeamGraphs", () => ({ this.failCount = this.fails.meta.count; this.awardCount = this.awards.meta.count; + let optionMerge = window.teamScoreGraphChartOptions; + embed( this.$refs.scoregraph, getUserScoreOption( @@ -68,6 +70,7 @@ Alpine.data("TeamGraphs", () => ({ window.TEAM.name, this.solves.data, this.awards.data, + optionMerge ), ); }, diff --git a/assets/js/users/private.js b/assets/js/users/private.js index 08fca35..2109167 100644 --- a/assets/js/users/private.js +++ b/assets/js/users/private.js @@ -64,6 +64,8 @@ Alpine.data("UserGraphs", () => ({ this.failCount = this.fails.meta.count; this.awardCount = this.awards.meta.count; + let optionMerge = window.userScoreGraphChartOptions; + embed( this.$refs.scoregraph, getUserScoreOption( @@ -71,6 +73,7 @@ Alpine.data("UserGraphs", () => ({ CTFd.user.name, this.solves.data, this.awards.data, + optionMerge, ), ); }, diff --git a/assets/js/users/public.js b/assets/js/users/public.js index e7ed04a..f7dfbad 100644 --- a/assets/js/users/public.js +++ b/assets/js/users/public.js @@ -64,6 +64,8 @@ Alpine.data("UserGraphs", () => ({ this.failCount = this.fails.meta.count; this.awardCount = this.awards.meta.count; + let optionMerge = window.userScoreGraphChartOptions; + embed( this.$refs.scoregraph, getUserScoreOption( @@ -71,6 +73,7 @@ Alpine.data("UserGraphs", () => ({ window.USER.name, this.solves.data, this.awards.data, + optionMerge, ), ); }, diff --git a/assets/js/utils/graphs/echarts/categories.js b/assets/js/utils/graphs/echarts/categories.js index 3933e69..5f19688 100644 --- a/assets/js/utils/graphs/echarts/categories.js +++ b/assets/js/utils/graphs/echarts/categories.js @@ -1,6 +1,7 @@ import { colorHash } from "@ctfdio/ctfd-js/ui"; +import { mergeObjects } from "../../objects"; -export function getOption(solves) { +export function getOption(solves, optionMerge) { let option = { title: { left: "center", @@ -99,5 +100,8 @@ export function getOption(solves) { }); }); + if (optionMerge) { + option = mergeObjects(option, optionMerge); + } return option; } diff --git a/assets/js/utils/graphs/echarts/scoreboard.js b/assets/js/utils/graphs/echarts/scoreboard.js index bf30310..28982f3 100644 --- a/assets/js/utils/graphs/echarts/scoreboard.js +++ b/assets/js/utils/graphs/echarts/scoreboard.js @@ -1,17 +1,9 @@ import { colorHash } from "@ctfdio/ctfd-js/ui"; +import { mergeObjects } from "../../objects"; +import { cumulativeSum } from "../../math"; import dayjs from "dayjs"; -export function cumulativeSum(arr) { - let result = arr.concat(); - for (let i = 0; i < arr.length; i++) { - result[i] = arr.slice(0, i + 1).reduce(function (p, i) { - return p + i; - }); - } - return result; -} - -export function getOption(mode, places) { +export function getOption(mode, places, optionMerge) { let option = { title: { left: "center", @@ -102,5 +94,8 @@ export function getOption(mode, places) { option.series.push(data); } + if (optionMerge) { + option = mergeObjects(option, optionMerge); + } return option; } diff --git a/assets/js/utils/graphs/echarts/solve-percentage.js b/assets/js/utils/graphs/echarts/solve-percentage.js index fcba1f1..98344f6 100644 --- a/assets/js/utils/graphs/echarts/solve-percentage.js +++ b/assets/js/utils/graphs/echarts/solve-percentage.js @@ -1,4 +1,6 @@ -export function getOption(solves, fails) { +import { mergeObjects } from "../../objects"; + +export function getOption(solves, fails, optionMerge) { let option = { title: { left: "center", @@ -77,5 +79,9 @@ export function getOption(solves, fails) { }, ], }; + + if (optionMerge) { + option = mergeObjects(option, optionMerge); + } return option; } diff --git a/assets/js/utils/graphs/echarts/userscore.js b/assets/js/utils/graphs/echarts/userscore.js index 89815a9..6719da2 100644 --- a/assets/js/utils/graphs/echarts/userscore.js +++ b/assets/js/utils/graphs/echarts/userscore.js @@ -1,8 +1,9 @@ import { colorHash } from "@ctfdio/ctfd-js/ui"; -import { cumulativeSum } from "./scoreboard"; +import { cumulativeSum } from "../../math"; +import { mergeObjects } from "../../objects"; import dayjs from "dayjs"; -export function getOption(id, name, solves, awards) { +export function getOption(id, name, solves, awards, optionMerge) { let option = { title: { left: "center", @@ -98,5 +99,9 @@ export function getOption(id, name, solves, awards) { }, data: cumulativeSum(scores), }); + + if (optionMerge) { + option = mergeObjects(option, optionMerge); + } return option; } diff --git a/assets/js/utils/objects.js b/assets/js/utils/objects.js new file mode 100644 index 0000000..d671579 --- /dev/null +++ b/assets/js/utils/objects.js @@ -0,0 +1,11 @@ +export function mergeObjects(target, source) { + // https://stackoverflow.com/a/65817907 + // Iterate through `source` properties and if an `Object` set property to merge of `target` and `source` properties + for (const key of Object.keys(source)) { + if (source[key] instanceof Object) + Object.assign(source[key], mergeObjects(target[key], source[key])); + } + // Join `target` and modified `source` + Object.assign(target || {}, source); + return target; +};