From b8827a41b20e193a32c413dced7f74eb67eed5d4 Mon Sep 17 00:00:00 2001 From: Thaddeus Crews Date: Sun, 28 Jul 2024 16:28:09 -0500 Subject: [PATCH] Style: Unify formatting, add `.editorconfig` (#88) --- .editorconfig | 23 ++ .gitattributes | 7 + .gitignore | 32 +- Godot Benchmarks.csproj | 2 +- Godot Benchmarks.sln | 19 +- run-benchmarks.sh | 124 ++++---- server/etc/X11/xorg.conf.d/01-amd.conf | 32 +- web/.gitattributes | 1 - web/.gitignore | 14 - web/src-data/benchmarks/.gitkeep | 0 web/static/graphs.js | 386 ++++++++++++------------- web/static/main.css | 34 +-- 12 files changed, 364 insertions(+), 310 deletions(-) create mode 100644 .editorconfig delete mode 100644 web/.gitattributes delete mode 100644 web/.gitignore delete mode 100644 web/src-data/benchmarks/.gitkeep diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..514ec72 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,23 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_size = 4 +indent_style = tab +insert_final_newline = true +trim_trailing_whitespace = true + +[*.{csproj,sln}] +charset = utf-8-bom +end_of_line = crlf + +[*.{cs,py}] +indent_style = space + +[*.{csproj,yml,yaml}] +indent_size = 2 +indent_style = space + +[*.md] +trim_trailing_whitespace = false diff --git a/.gitattributes b/.gitattributes index 0b93845..85c68ca 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,8 @@ +# Properly detect languages on Github web/static/thirdparty/* linguist-vendored + +# Normalize EOL for all files that Git considers text files +* text=auto eol=lf +# Except for Visual Studio files +*.sln eol=crlf +*.csproj eol=crlf diff --git a/.gitignore b/.gitignore index 34b4ad6..665b82d 100644 --- a/.gitignore +++ b/.gitignore @@ -16,5 +16,35 @@ mono_crash.*.json .directory *~ +# IDE-specific ignores +.fleet/ +.history/ +.idea/ +.vs/ +.vscode/ +*.code-workspace + +# Python-specific ignores +__pycache__/ +*_cache/ +*.pyc +.venv +venv + # Godot Git repository clone (run-benchmarks.sh) -/godot/ +godot/ + +# Output HTML files +web/public/ + +# Temporary lock file while building +web/.hugo_build.lock + +# Generated files +web/content/benchmark/*.md +web/content/graph/*.md +web/data/data.json + +# Untracked source files +web/src-data/benchmarks/*.json +web/src-data/benchmarks/*.md diff --git a/Godot Benchmarks.csproj b/Godot Benchmarks.csproj index 35855fa..92b2c7f 100644 --- a/Godot Benchmarks.csproj +++ b/Godot Benchmarks.csproj @@ -1,4 +1,4 @@ - + net6.0 net7.0 diff --git a/Godot Benchmarks.sln b/Godot Benchmarks.sln index ec6a60f..2495078 100644 --- a/Godot Benchmarks.sln +++ b/Godot Benchmarks.sln @@ -1,12 +1,15 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2012 + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.10.35027.167 +MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Godot Benchmarks", "Godot Benchmarks.csproj", "{A7FD1DC6-AE2B-4F17-B4BA-2FD940E01B47}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - ExportDebug|Any CPU = ExportDebug|Any CPU - ExportRelease|Any CPU = ExportRelease|Any CPU + Debug|Any CPU = Debug|Any CPU + ExportDebug|Any CPU = ExportDebug|Any CPU + ExportRelease|Any CPU = ExportRelease|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {A7FD1DC6-AE2B-4F17-B4BA-2FD940E01B47}.Debug|Any CPU.ActiveCfg = Debug|Any CPU @@ -16,4 +19,10 @@ Global {A7FD1DC6-AE2B-4F17-B4BA-2FD940E01B47}.ExportRelease|Any CPU.ActiveCfg = ExportRelease|Any CPU {A7FD1DC6-AE2B-4F17-B4BA-2FD940E01B47}.ExportRelease|Any CPU.Build.0 = ExportRelease|Any CPU EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {0C32B76F-38AD-4A1A-80F4-46FFBBB4BFB2} + EndGlobalSection EndGlobal diff --git a/run-benchmarks.sh b/run-benchmarks.sh index f4dac52..edbb334 100755 --- a/run-benchmarks.sh +++ b/run-benchmarks.sh @@ -20,19 +20,19 @@ export DISPLAY=":0" ARG1="${1:-''}" if ! command -v git &> /dev/null; then - echo "ERROR: git must be installed and in PATH." - exit 1 + echo "ERROR: git must be installed and in PATH." + exit 1 fi if [[ "$ARG1" == "--help" || "$ARG1" == "-h" ]]; then - echo "Usage: $0 [--skip-build]" - exit + echo "Usage: $0 [--skip-build]" + exit fi GODOT_REPO_DIR="$DIR/godot" if [[ ! -d "$GODOT_REPO_DIR/.git" ]]; then - git clone https://github.com/godotengine/godot.git "$GODOT_REPO_DIR" + git clone https://github.com/godotengine/godot.git "$GODOT_REPO_DIR" fi pushd "$GODOT_REPO_DIR" @@ -48,64 +48,64 @@ latest_commit="$(git -C "$GODOT_REPO_DIR" rev-parse HEAD)" pushd /tmp/godot-benchmarks-results/ for result in 2*.md; do - if [[ "${result:11:9}" == "${latest_commit:0:9}" ]]; then - echo "godot-benchmarks: Skipping benchmark run as the latest Godot commit is already present in the results repository." - exit - fi + if [[ "${result:11:9}" == "${latest_commit:0:9}" ]]; then + echo "godot-benchmarks: Skipping benchmark run as the latest Godot commit is already present in the results repository." + exit + fi done popd GODOT_EMPTY_PROJECT_DIR="$DIR/web/godot-empty-project" if [[ "$ARG1" != "--skip-build" ]]; then - cd "$GODOT_REPO_DIR" + cd "$GODOT_REPO_DIR" - if command -v ccache &> /dev/null; then - # Clear ccache to avoid skewing the build time results. - ccache --clear - fi - touch .gdignore + if command -v ccache &> /dev/null; then + # Clear ccache to avoid skewing the build time results. + ccache --clear + fi + touch .gdignore - # Measure clean build times for debug and release builds (in milliseconds). - # Also create a `.gdignore` file to prevent Godot from importing resources - # within the Godot Git clone. - # WARNING: Any untracked and ignored files included in the repository will be removed! - BEGIN="$(date +%s%3N)" - PEAK_MEMORY_BUILD_DEBUG=$( (/usr/bin/time -f "%M" scons platform=linuxbsd target=editor optimize=debug module_mono_enabled=no progress=no debug_symbols=yes -j$(nproc) 2>&1 || true) | tail -1) - END="$(date +%s%3N)" - TIME_TO_BUILD_DEBUG="$((END - BEGIN))" + # Measure clean build times for debug and release builds (in milliseconds). + # Also create a `.gdignore` file to prevent Godot from importing resources + # within the Godot Git clone. + # WARNING: Any untracked and ignored files included in the repository will be removed! + BEGIN="$(date +%s%3N)" + PEAK_MEMORY_BUILD_DEBUG=$( (/usr/bin/time -f "%M" scons platform=linuxbsd target=editor optimize=debug module_mono_enabled=no progress=no debug_symbols=yes -j$(nproc) 2>&1 || true) | tail -1) + END="$(date +%s%3N)" + TIME_TO_BUILD_DEBUG="$((END - BEGIN))" - git clean -qdfx --exclude bin - if command -v ccache &> /dev/null; then - # Clear ccache to avoid skewing the build time results. - ccache --clear - fi - touch .gdignore + git clean -qdfx --exclude bin + if command -v ccache &> /dev/null; then + # Clear ccache to avoid skewing the build time results. + ccache --clear + fi + touch .gdignore - BEGIN="$(date +%s%3N)" - PEAK_MEMORY_BUILD_RELEASE=$( (/usr/bin/time -f "%M" scons platform=linuxbsd target=template_release optimize=speed lto=full module_mono_enabled=no progress=no debug_symbols=yes -j$(nproc) 2>&1 || true) | tail -1) - END="$(date +%s%3N)" - TIME_TO_BUILD_RELEASE="$((END - BEGIN))" + BEGIN="$(date +%s%3N)" + PEAK_MEMORY_BUILD_RELEASE=$( (/usr/bin/time -f "%M" scons platform=linuxbsd target=template_release optimize=speed lto=full module_mono_enabled=no progress=no debug_symbols=yes -j$(nproc) 2>&1 || true) | tail -1) + END="$(date +%s%3N)" + TIME_TO_BUILD_RELEASE="$((END - BEGIN))" - # FIXME: C# is disabled because the engine crashes on exit after running benchmarks. - # - # Generate Mono glue for C# build to work. - # echo "Generating .NET glue." - # bin/godot.linuxbsd.editor.x86_64.mono --headless --generate-mono-glue modules/mono/glue - # echo "Building .NET assemblies." - # # https://docs.godotengine.org/en/stable/contributing/development/compiling/compiling_with_dotnet.html#nuget-packages - # mkdir -p "$HOME/MyLocalNugetSource" - # # Source may already exist, so allow failure for the command below. - # dotnet nuget add source "$HOME/MyLocalNugetSource" --name MyLocalNugetSource || true - # modules/mono/build_scripts/build_assemblies.py --godot-output-dir=./bin --push-nupkgs-local "$HOME/MyLocalNugetSource" + # FIXME: C# is disabled because the engine crashes on exit after running benchmarks. + # + # Generate Mono glue for C# build to work. + # echo "Generating .NET glue." + # bin/godot.linuxbsd.editor.x86_64.mono --headless --generate-mono-glue modules/mono/glue + # echo "Building .NET assemblies." + # # https://docs.godotengine.org/en/stable/contributing/development/compiling/compiling_with_dotnet.html#nuget-packages + # mkdir -p "$HOME/MyLocalNugetSource" + # # Source may already exist, so allow failure for the command below. + # dotnet nuget add source "$HOME/MyLocalNugetSource" --name MyLocalNugetSource || true + # modules/mono/build_scripts/build_assemblies.py --godot-output-dir=./bin --push-nupkgs-local "$HOME/MyLocalNugetSource" - cd "$DIR" + cd "$DIR" else - echo "run-benchmarks: Skipping engine build as requested on the command line." - TIME_TO_BUILD_DEBUG=1 - TIME_TO_BUILD_RELEASE=1 - PEAK_MEMORY_BUILD_DEBUG=1 - PEAK_MEMORY_BUILD_RELEASE=1 + echo "run-benchmarks: Skipping engine build as requested on the command line." + TIME_TO_BUILD_DEBUG=1 + TIME_TO_BUILD_RELEASE=1 + PEAK_MEMORY_BUILD_DEBUG=1 + PEAK_MEMORY_BUILD_RELEASE=1 fi # Path to the Godot debug binary to run. Used for CPU debug benchmarks. @@ -128,7 +128,7 @@ $GODOT_DEBUG --audio-driver Dummy --gpu-index 1 --path "$GODOT_EMPTY_PROJECT_DIR TOTAL=0 for _ in {0..19}; do BEGIN="$(date +%s%3N)" - echo "Performing benchmark debug startup/shutdown run." + echo "Performing benchmark debug startup/shutdown run." $GODOT_DEBUG --audio-driver Dummy --gpu-index 1 --path "$GODOT_EMPTY_PROJECT_DIR" --quit || true END="$(date +%s%3N)" TOTAL="$((TOTAL + END - BEGIN))" @@ -144,7 +144,7 @@ $GODOT_RELEASE --audio-driver Dummy --path "$GODOT_EMPTY_PROJECT_DIR" --quit || TOTAL=0 for _ in {0..19}; do BEGIN="$(date +%s%3N)" - echo "Performing benchmark release startup/shutdown run." + echo "Performing benchmark release startup/shutdown run." $GODOT_RELEASE --audio-driver Dummy --path "$GODOT_EMPTY_PROJECT_DIR" --quit || true END="$(date +%s%3N)" TOTAL="$((TOTAL + END - BEGIN))" @@ -199,24 +199,24 @@ BINARY_SIZE_RELEASE="$(stat --printf="%s" "$GODOT_RELEASE")" echo "Appending extra JSON at the end of the merged JSON." EXTRA_JSON=$(cat << EOF "binary_size": { - "debug": $BINARY_SIZE_DEBUG, - "release": $BINARY_SIZE_RELEASE + "debug": $BINARY_SIZE_DEBUG, + "release": $BINARY_SIZE_RELEASE }, "build_time": { - "debug": $TIME_TO_BUILD_DEBUG, - "release": $TIME_TO_BUILD_RELEASE + "debug": $TIME_TO_BUILD_DEBUG, + "release": $TIME_TO_BUILD_RELEASE }, "build_peak_memory_usage": { - "debug": $PEAK_MEMORY_BUILD_DEBUG, - "release": $PEAK_MEMORY_BUILD_RELEASE + "debug": $PEAK_MEMORY_BUILD_DEBUG, + "release": $PEAK_MEMORY_BUILD_RELEASE }, "empty_project_startup_shutdown_time": { - "debug": $TIME_TO_STARTUP_SHUTDOWN_DEBUG, - "release": $TIME_TO_STARTUP_SHUTDOWN_RELEASE + "debug": $TIME_TO_STARTUP_SHUTDOWN_DEBUG, + "release": $TIME_TO_STARTUP_SHUTDOWN_RELEASE }, "empty_project_startup_shutdown_peak_memory_usage": { - "debug": $PEAK_MEMORY_STARTUP_SHUTDOWN_DEBUG, - "release": $PEAK_MEMORY_STARTUP_SHUTDOWN_RELEASE + "debug": $PEAK_MEMORY_STARTUP_SHUTDOWN_DEBUG, + "release": $PEAK_MEMORY_STARTUP_SHUTDOWN_RELEASE } EOF ) diff --git a/server/etc/X11/xorg.conf.d/01-amd.conf b/server/etc/X11/xorg.conf.d/01-amd.conf index f420032..96a8fbb 100644 --- a/server/etc/X11/xorg.conf.d/01-amd.conf +++ b/server/etc/X11/xorg.conf.d/01-amd.conf @@ -1,27 +1,27 @@ Section "ServerLayout" - Identifier "default-layout" - Screen 0 "screen" + Identifier "default-layout" + Screen 0 "screen" EndSection Section "Device" - Identifier "amd" - Driver "amdgpu" - BusID "PCI:1:0:0" + Identifier "amd" + Driver "amdgpu" + BusID "PCI:1:0:0" EndSection Section "Monitor" - Identifier "monitor" - Modeline "1920x1200_60.00" 193.25 1920 2056 2256 2592 1200 1203 1209 1245 -hsync +vsync - Option "PreferredMode" "1920x1080_60.00" + Identifier "monitor" + Modeline "1920x1200_60.00" 193.25 1920 2056 2256 2592 1200 1203 1209 1245 -hsync +vsync + Option "PreferredMode" "1920x1080_60.00" EndSection Section "Screen" - Identifier "screen" - Device "amd" - Monitor "monitor" - DefaultDepth 24 - SubSection "Display" - Depth 24 - Modes "1920x1080" - EndSubSection + Identifier "screen" + Device "amd" + Monitor "monitor" + DefaultDepth 24 + SubSection "Display" + Depth 24 + Modes "1920x1080" + EndSubSection EndSection diff --git a/web/.gitattributes b/web/.gitattributes deleted file mode 100644 index d5138ea..0000000 --- a/web/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -static/thirdparty/* linguist-vendored diff --git a/web/.gitignore b/web/.gitignore deleted file mode 100644 index 466d74f..0000000 --- a/web/.gitignore +++ /dev/null @@ -1,14 +0,0 @@ -# Output HTML files -public/ - -# Temporary lock file while building -.hugo_build.lock - -# Generated files -content/benchmark/*.md -content/graph/*.md -data/data.json - -# Untracked source files -src-data/benchmarks/*.md -src-data/benchmarks/*.json diff --git a/web/src-data/benchmarks/.gitkeep b/web/src-data/benchmarks/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/web/static/graphs.js b/web/static/graphs.js index 99f38a2..633bda8 100644 --- a/web/static/graphs.js +++ b/web/static/graphs.js @@ -1,209 +1,209 @@ function getAllowedMetrics() { - const allowedMetrics = new Set(); - Database.benchmarks.forEach((benchmark) => { - benchmark.benchmarks.forEach((instance) => { - Object.entries(instance.results).forEach(([key, value]) => { - allowedMetrics.add(key); - }); - }); - }); - return allowedMetrics; + const allowedMetrics = new Set(); + Database.benchmarks.forEach((benchmark) => { + benchmark.benchmarks.forEach((instance) => { + Object.entries(instance.results).forEach(([key, value]) => { + allowedMetrics.add(key); + }); + }); + }); + return allowedMetrics; } function displayGraph(targetDivID, graphID, type = "full", filter = "") { - if (!["full", "compact"].includes(type)) { - throw Error("Unknown chart type"); - } + if (!["full", "compact"].includes(type)) { + throw Error("Unknown chart type"); + } - // Include benchmark data JSON to generate graphs. - const allBenchmarks = Database.benchmarks.sort( - (a, b) => `${a.date}.${a.commit}` > `${b.date}.${b.commit}`, - ); - const graph = Database.graphs.find((g) => g.id == graphID); - if (!graph) { - throw new Error("Invalid graph ID"); - } - // Group by series. - const xAxis = []; - const series = new Map(); - const processResult = (path, data, process) => { - Object.entries(data).forEach(([key, value]) => { - if (typeof value === "object") { - processResult(path + "/" + key, value, process); - } else { - // Number - process(path + "/" + key, value); - } - }); - }; + // Include benchmark data JSON to generate graphs. + const allBenchmarks = Database.benchmarks.sort( + (a, b) => `${a.date}.${a.commit}` > `${b.date}.${b.commit}`, + ); + const graph = Database.graphs.find((g) => g.id == graphID); + if (!graph) { + throw new Error("Invalid graph ID"); + } + // Group by series. + const xAxis = []; + const series = new Map(); + const processResult = (path, data, process) => { + Object.entries(data).forEach(([key, value]) => { + if (typeof value === "object") { + processResult(path + "/" + key, value, process); + } else { + // Number + process(path + "/" + key, value); + } + }); + }; - // Get list all series and fill it in. - allBenchmarks.forEach((benchmark, count) => { - // Process a day/commit - xAxis.push(benchmark.date + "." + benchmark.commit); + // Get list all series and fill it in. + allBenchmarks.forEach((benchmark, count) => { + // Process a day/commit + xAxis.push(benchmark.date + "." + benchmark.commit); - // Get all series. - benchmark.benchmarks.forEach((instance) => { - let instanceKey = instance.path.join("/"); - if (!instanceKey.startsWith(graph["benchmark-path-prefix"])) { - return; - } - instanceKey = instanceKey.slice( - graph["benchmark-path-prefix"].length + 1, - ); + // Get all series. + benchmark.benchmarks.forEach((instance) => { + let instanceKey = instance.path.join("/"); + if (!instanceKey.startsWith(graph["benchmark-path-prefix"])) { + return; + } + instanceKey = instanceKey.slice( + graph["benchmark-path-prefix"].length + 1, + ); - processResult(instanceKey, instance.results, (path, value) => { - // Filter out paths that do not fit the filter - if (filter && !path.includes(filter)) { - return; - } - if (!series.has(path)) { - series.set(path, Array(count).fill(null)); - } - series.get(path).push(value); - }); - }); - }); + processResult(instanceKey, instance.results, (path, value) => { + // Filter out paths that do not fit the filter + if (filter && !path.includes(filter)) { + return; + } + if (!series.has(path)) { + series.set(path, Array(count).fill(null)); + } + series.get(path).push(value); + }); + }); + }); - let customColor = undefined; + let customColor = undefined; - if (type === "compact") { - // Kind of "normalize" the series, dividing by the average. - series.forEach((serie, key) => { - let count = 0; - let mean = 0.0; - serie.forEach((el) => { - if (el != null) { - mean += el; - count += 1; - } - }); - mean = mean / count; + if (type === "compact") { + // Kind of "normalize" the series, dividing by the average. + series.forEach((serie, key) => { + let count = 0; + let mean = 0.0; + serie.forEach((el) => { + if (el != null) { + mean += el; + count += 1; + } + }); + mean = mean / count; - //const std = Math.sqrt(input.map(x => Math.pow(x - mean, 2)).reduce((a, b) => a + b) / n) - series.set( - key, - serie.map((v) => { - if (v != null) { - return v / mean; // Devide by the mean. - } - return null; - }), - ); - }); - // Combine all into a single, averaged serie. - const outputSerie = []; - for (let i = 0; i < allBenchmarks.length; i++) { - let count = 0; - let sum = 0; - series.forEach((serie, key) => { - if (serie[i] != null) { - count += 1; - sum += serie[i]; - } - }); - let point = null; - if (count >= 1) { - point = Math.round((sum * 1000) / count) / 10; // Round to 3 decimals. - } - outputSerie.push(point); - } - series.clear(); - series.set("Average", outputSerie); + //const std = Math.sqrt(input.map(x => Math.pow(x - mean, 2)).reduce((a, b) => a + b) / n) + series.set( + key, + serie.map((v) => { + if (v != null) { + return v / mean; // Devide by the mean. + } + return null; + }), + ); + }); + // Combine all into a single, averaged serie. + const outputSerie = []; + for (let i = 0; i < allBenchmarks.length; i++) { + let count = 0; + let sum = 0; + series.forEach((serie, key) => { + if (serie[i] != null) { + count += 1; + sum += serie[i]; + } + }); + let point = null; + if (count >= 1) { + point = Math.round((sum * 1000) / count) / 10; // Round to 3 decimals. + } + outputSerie.push(point); + } + series.clear(); + series.set("Average", outputSerie); - // Detect whether we went down or not on the last 10 benchmarks. - const lastElementsCount = 3; - const totalConsideredCount = 10; - const lastElements = outputSerie.slice(-lastElementsCount); - const comparedTo = outputSerie.slice( - -totalConsideredCount, - -lastElementsCount, - ); - const avgLast = lastElements.reduce((a, b) => a + b) / lastElements.length; - const avgComparedTo = - comparedTo.reduce((a, b) => a + b) / comparedTo.length; - const trend = avgLast - avgComparedTo; + // Detect whether we went down or not on the last 10 benchmarks. + const lastElementsCount = 3; + const totalConsideredCount = 10; + const lastElements = outputSerie.slice(-lastElementsCount); + const comparedTo = outputSerie.slice( + -totalConsideredCount, + -lastElementsCount, + ); + const avgLast = lastElements.reduce((a, b) => a + b) / lastElements.length; + const avgComparedTo = + comparedTo.reduce((a, b) => a + b) / comparedTo.length; + const trend = avgLast - avgComparedTo; - if (trend > 10) { - customColor = "#E20000"; - } else if (trend < -10) { - customColor = "#00E200"; - } - } + if (trend > 10) { + customColor = "#E20000"; + } else if (trend < -10) { + customColor = "#00E200"; + } + } - var options = { - series: Array.from(series.entries()).map(([key, value]) => ({ - name: key, - data: value, - })), - chart: { - foreColor: "var(--text-bright)", - background: "var(--background)", - height: type === "compact" ? 200 : 600, - type: "line", - zoom: { - enabled: false, - }, - toolbar: { - show: false, - }, - animations: { - enabled: false, - }, - }, - tooltip: { - theme: "dark", - y: { - formatter: (value, opts) => (type === "compact" ? value + "%" : value), - }, - }, - dataLabels: { - enabled: false, - }, - stroke: { - curve: "straight", - width: 2, - }, - theme: { - palette: "palette4", - }, - fill: - type === "compact" - ? { - type: "gradient", - gradient: { - shade: "dark", - gradientToColors: ["#4ecdc4"], - shadeIntensity: 1, - type: "horizontal", - opacityFrom: 1, - opacityTo: 1, - stops: [0, 100], - }, - } - : {}, - colors: - type === "compact" - ? customColor - ? [customColor] - : ["#4ecdc4"] - : undefined, - xaxis: { - categories: xAxis, - labels: { - show: type !== "compact", - }, - }, - yaxis: { - tickAmount: 4, - min: type === "compact" ? 0 : undefined, - max: type === "compact" ? 200 : undefined, - }, - legend: { - show: type !== "compact", - }, - }; + var options = { + series: Array.from(series.entries()).map(([key, value]) => ({ + name: key, + data: value, + })), + chart: { + foreColor: "var(--text-bright)", + background: "var(--background)", + height: type === "compact" ? 200 : 600, + type: "line", + zoom: { + enabled: false, + }, + toolbar: { + show: false, + }, + animations: { + enabled: false, + }, + }, + tooltip: { + theme: "dark", + y: { + formatter: (value, opts) => (type === "compact" ? value + "%" : value), + }, + }, + dataLabels: { + enabled: false, + }, + stroke: { + curve: "straight", + width: 2, + }, + theme: { + palette: "palette4", + }, + fill: + type === "compact" + ? { + type: "gradient", + gradient: { + shade: "dark", + gradientToColors: ["#4ecdc4"], + shadeIntensity: 1, + type: "horizontal", + opacityFrom: 1, + opacityTo: 1, + stops: [0, 100], + }, + } + : {}, + colors: + type === "compact" + ? customColor + ? [customColor] + : ["#4ecdc4"] + : undefined, + xaxis: { + categories: xAxis, + labels: { + show: type !== "compact", + }, + }, + yaxis: { + tickAmount: 4, + min: type === "compact" ? 0 : undefined, + max: type === "compact" ? 200 : undefined, + }, + legend: { + show: type !== "compact", + }, + }; - var chart = new ApexCharts(document.querySelector(targetDivID), options); - chart.render(); + var chart = new ApexCharts(document.querySelector(targetDivID), options); + chart.render(); } diff --git a/web/static/main.css b/web/static/main.css index f7d24ab..baf4cab 100644 --- a/web/static/main.css +++ b/web/static/main.css @@ -1,39 +1,39 @@ /* See `thirdparty/water.css` for CSS variables that can be used here. */ p, li { - line-height: 1.6; + line-height: 1.6; } footer { - text-align: center; + text-align: center; } header { - background-color: var(--background); - border-radius: 0 0 6px 6px; - padding: .75rem 2rem; - margin-top: -1.25rem; - margin-bottom: 2rem; + background-color: var(--background); + border-radius: 0 0 6px 6px; + padding: .75rem 2rem; + margin-top: -1.25rem; + margin-bottom: 2rem; } .site-title { - color: var(--text-bright); - font-weight: bold; - font-size: 1.25rem; - border-radius: 6px; + color: var(--text-bright); + font-weight: bold; + font-size: 1.25rem; + border-radius: 6px; } /* Automatically resize the left column to take as little space as required. */ .table-first-column-align-right { - width: auto; + width: auto; } /* Align first column to the right to improve readability in some situations. */ .table-first-column-align-right tr td:first-of-type { - text-align: right; - width: 1%; - white-space: nowrap; - /* Style the first column as headings. */ - font-weight: bold; + text-align: right; + width: 1%; + white-space: nowrap; + /* Style the first column as headings. */ + font-weight: bold; }