Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions frontend/src/html/pages/test-result.html
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,10 @@
</div>
<div class="chart">
<div class="chartLegend">
<button class="text active" tabindex="-1" data-id="scale">
<i class="fas fa-chart-line"></i>
<div class="text">scale</div>
</button>
<button class="text" tabindex="-1" data-id="pbLine">
<i class="fas fa-crown"></i>
<div class="text">pb</div>
Expand Down
4 changes: 3 additions & 1 deletion frontend/src/ts/pages/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -753,7 +753,9 @@ function toggleSettingsGroup(groupName: string): void {

const groupEl = qs(`.pageSettings .settingsGroup.${groupName}`);
if (!groupEl?.hasClass("slideup")) {
void groupEl?.slideUp(250);
void groupEl?.slideUp(250, {
hide: false,
});
groupEl?.addClass("slideup");
$(`.pageSettings .sectionGroupTitle[group=${groupName}]`).addClass(
"rotateIcon",
Expand Down
155 changes: 99 additions & 56 deletions frontend/src/ts/test/result.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//TODO: use Format
import { Chart, type PluginChartOptions } from "chart.js";
import Config from "../config";
import Config, { setConfig } from "../config";
import * as AdController from "../controllers/ad-controller";
import * as ChartController from "../controllers/chart-controller";
import QuotesController, { Quote } from "../controllers/quotes-controller";
Expand Down Expand Up @@ -50,6 +50,7 @@ import * as ConnectionState from "../states/connection";
import { currentQuote } from "./test-words";

let result: CompletedEvent;
let minChartVal: number;
let maxChartVal: number;

let useSmoothedBurst = true;
Expand All @@ -62,7 +63,7 @@ export function toggleSmoothedBurst(): void {
useSmoothedBurst = !useSmoothedBurst;
Notifications.add(useSmoothedBurst ? "on" : "off", 1);
if (TestState.resultVisible) {
void updateGraph().then(() => {
void updateChartData().then(() => {
ChartController.result.update("resize");
});
}
Expand All @@ -72,15 +73,15 @@ export function toggleUserFakeChartData(): void {
useFakeChartData = !useFakeChartData;
Notifications.add(useFakeChartData ? "on" : "off", 1);
if (TestState.resultVisible) {
void updateGraph().then(() => {
void updateChartData().then(() => {
ChartController.result.update("resize");
});
}
}

let resultAnnotation: AnnotationOptions<"line">[] = [];

async function updateGraph(): Promise<void> {
async function updateChartData(): Promise<void> {
if (result.chartData === "toolong") return;

const typingSpeedUnit = getTypingSpeedUnit(Config.typingSpeedUnit);
Expand Down Expand Up @@ -130,29 +131,6 @@ async function updateGraph(): Promise<void> {
chartData2.pop();
}

maxChartVal = Math.max(
...[
Math.max(...chartData1),
Math.max(...chartData2),
Math.max(...chartData3),
],
);

let minChartVal = 0;

if (!Config.startGraphsAtZero) {
minChartVal = Math.min(
...[
Math.min(...chartData1),
Math.min(...chartData2),
Math.min(...chartData3),
],
);

// Round down to nearest multiple of 10
minChartVal = Math.floor(minChartVal / 10) * 10;
}

const subcolor = await ThemeColors.get("sub");

if (Config.funbox.length > 0) {
Expand Down Expand Up @@ -197,16 +175,10 @@ async function updateGraph(): Promise<void> {

ChartController.result.getDataset("wpm").data = chartData1;
ChartController.result.getDataset("wpm").label = Config.typingSpeedUnit;
ChartController.result.getScale("wpm").min = minChartVal;
ChartController.result.getScale("wpm").max = maxChartVal;

ChartController.result.getDataset("raw").data = chartData2;
ChartController.result.getScale("raw").min = minChartVal;
ChartController.result.getScale("raw").max = maxChartVal;

ChartController.result.getDataset("burst").data = chartData3;
ChartController.result.getScale("burst").min = minChartVal;
ChartController.result.getScale("burst").max = maxChartVal;

ChartController.result.getDataset("error").data = result.chartData.err;
ChartController.result.getScale("error").max = Math.max(
Expand Down Expand Up @@ -302,7 +274,7 @@ function applyFakeChartData(): void {
ChartController.result.getScale("error").max = Math.max(...fakeChartData.err);
}

export async function updateGraphPBLine(): Promise<void> {
export async function updateChartPBLine(): Promise<void> {
const themecolors = await ThemeColors.getAll();
const localPb = await DB.getLocalPB(
result.mode,
Expand Down Expand Up @@ -346,17 +318,6 @@ export async function updateGraphPBLine(): Promise<void> {
display: true,
},
});
const lpbRange = typingSpeedUnit.fromWpm(20);
if (
maxChartVal >= parseFloat(chartlpb) - lpbRange &&
maxChartVal <= parseFloat(chartlpb) + lpbRange
) {
maxChartVal = Math.round(parseFloat(chartlpb) + lpbRange);
}

ChartController.result.getScale("wpm").max = maxChartVal;
ChartController.result.getScale("raw").max = maxChartVal;
ChartController.result.getScale("burst").max = maxChartVal;
}

function updateWpmAndAcc(): void {
Expand Down Expand Up @@ -1021,10 +982,12 @@ export async function update(
updateQuoteSource(randomQuote);
updateQuoteFavorite(randomQuote);
await updateCrown(dontSave);
await updateGraph();
await updateGraphPBLine();
await updateTags(dontSave);
await updateChartData();
updateResultChartDataVisibility();
updateMinMaxChartValues();
await updateChartPBLine();
applyMinMaxChartValues();
await updateTags(dontSave);
updateOther(difficultyFailed, failReason, afkDetected, isRepeated, tooShort);

((ChartController.result.options as PluginChartOptions<"line" | "scatter">)
Expand Down Expand Up @@ -1166,7 +1129,73 @@ const resultChartDataVisibility = new LocalStorageWithSchema({
},
});

function updateResultChartDataVisibility(update = false): void {
function updateMinMaxChartValues(): void {
const values = [];

const datasets = {
wpm: ChartController.result.getDataset("wpm"),
burst: ChartController.result.getDataset("burst"),
raw: ChartController.result.getDataset("raw"),
};

if (!datasets.wpm.hidden) {
values.push(...datasets.wpm.data);
}
if (!datasets.burst.hidden) {
values.push(...datasets.burst.data);
}
if (!datasets.raw.hidden) {
values.push(...datasets.raw.data);
}

maxChartVal = Math.max(...values);

let maxAnnotation: null | number = null;
for (const annotation of resultAnnotation) {
if ((annotation.display ?? false) === false) continue;
if (annotation.value === undefined) continue;
// values.push(annotation.value as number);
if (
maxAnnotation === null ||
parseFloat(annotation.value as string) > maxAnnotation
) {
maxAnnotation = parseFloat(annotation.value as string);
}
}

if (maxAnnotation !== null) {
const typingSpeedUnit = getTypingSpeedUnit(Config.typingSpeedUnit);
const lpbRange = typingSpeedUnit.fromWpm(20);
if (
maxChartVal >= maxAnnotation - lpbRange &&
maxChartVal <= maxAnnotation + lpbRange
) {
maxChartVal = Math.round(maxAnnotation + lpbRange);
}
}

maxChartVal = Math.ceil(maxChartVal / 10) * 10;

minChartVal = 0;

if (!Config.startGraphsAtZero) {
minChartVal = Math.min(...values);

// Round down to nearest multiple of 10
minChartVal = Math.floor(minChartVal / 10) * 10;
}
}

function applyMinMaxChartValues(): void {
ChartController.result.getScale("wpm").min = minChartVal;
ChartController.result.getScale("wpm").max = maxChartVal;
ChartController.result.getScale("raw").min = minChartVal;
ChartController.result.getScale("raw").max = maxChartVal;
ChartController.result.getScale("burst").min = minChartVal;
ChartController.result.getScale("burst").max = maxChartVal;
}

function updateResultChartDataVisibility(): void {
const vis = resultChartDataVisibility.get();
ChartController.result.getDataset("raw").hidden = !vis.raw;
ChartController.result.getDataset("burst").hidden = !vis.burst;
Expand All @@ -1180,8 +1209,6 @@ function updateResultChartDataVisibility(update = false): void {
}
}

if (update) ChartController.result.update();

const buttons = $(".pageTest #result .chart .chartLegend button");

// Check if there are any tag PB annotations
Expand All @@ -1192,14 +1219,18 @@ function updateResultChartDataVisibility(update = false): void {
for (const button of buttons) {
const id = $(button).data("id") as string;

if (id === "scale") {
continue;
}

if (
id !== "raw" &&
id !== "burst" &&
id !== "errors" &&
id !== "pbLine" &&
id !== "tagPbLine"
) {
return;
continue;
}

$(button).toggleClass("active", vis[id]);
Expand Down Expand Up @@ -1270,10 +1301,15 @@ export function updateTagsAfterEdit(
);
}

$(".pageTest #result .chart .chartLegend button").on("click", (event) => {
$(".pageTest #result .chart .chartLegend button").on("click", async (event) => {
const $target = $(event.target);
const id = $target.data("id") as string;

if (id === "scale") {
setConfig("startGraphsAtZero", !Config.startGraphsAtZero);
return;
}

if (
id !== "raw" &&
id !== "burst" &&
Expand All @@ -1287,7 +1323,11 @@ $(".pageTest #result .chart .chartLegend button").on("click", (event) => {
vis[id] = !vis[id];
resultChartDataVisibility.set(vis);

updateResultChartDataVisibility(true);
updateResultChartDataVisibility();
updateMinMaxChartValues();
applyMinMaxChartValues();
void ChartController.result.updateColors();
ChartController.result.update();
});

$(".pageTest #favoriteQuoteButton").on("click", async () => {
Expand Down Expand Up @@ -1347,8 +1387,11 @@ ConfigEvent.subscribe(async ({ key }) => {
resultAnnotation = [];

updateWpmAndAcc();
await updateGraph();
await updateGraphPBLine();
await updateChartData();
await updateChartPBLine();
updateResultChartDataVisibility();
updateMinMaxChartValues();
applyMinMaxChartValues();
void TestUI.applyBurstHeatmap();

((ChartController.result.options as PluginChartOptions<"line" | "scatter">)
Expand Down
51 changes: 35 additions & 16 deletions frontend/src/ts/utils/dom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -686,16 +686,24 @@ export class ElementWithUtils<T extends HTMLElement = HTMLElement> {
overflow: "hidden",
marginTop: "",
marginBottom: "",
paddingTop: "",
paddingBottom: "",
});
const { height, marginTop, marginBottom, paddingTop, paddingBottom } =
getComputedStyle(this.native);
this.setStyle({
height: "0px",
marginTop: "0px",
marginBottom: "0px",
paddingTop: "0px",
paddingBottom: "0px",
});
const height = this.getOffsetHeight();
const computed = getComputedStyle(this.native);
const marginTop = computed.marginTop;
const marginBottom = computed.marginBottom;
this.setStyle({ height: "0px", marginTop: "0px", marginBottom: "0px" });
await this.promiseAnimate({
height: [0, height],
marginTop: [0, marginTop],
marginBottom: [0, marginBottom],
paddingTop: [0, paddingTop],
paddingBottom: [0, paddingBottom],
duration,
onComplete: () => {
this.setStyle({
Expand All @@ -712,29 +720,40 @@ export class ElementWithUtils<T extends HTMLElement = HTMLElement> {
* Animate the element sliding up (collapsing height from full height to 0)
* @param duration The duration of the animation in milliseconds (default: 250ms)
*/
async slideUp(duration = 250): Promise<void> {
async slideUp(
duration = 250,
options?: {
hide?: boolean;
},
): Promise<void> {
this.show().setStyle({
overflow: "hidden",
height: "",
marginTop: "",
marginBottom: "",
paddingTop: "",
paddingBottom: "",
});
const height = this.getOffsetHeight();
const computed = getComputedStyle(this.native);
const marginTop = computed.marginTop;
const marginBottom = computed.marginBottom;
const { height, marginTop, marginBottom, paddingTop, paddingBottom } =
getComputedStyle(this.native);
await this.promiseAnimate({
height: [height, 0],
marginTop: [marginTop, 0],
marginBottom: [marginBottom, 0],
paddingTop: [paddingTop, 0],
paddingBottom: [paddingBottom, 0],
duration,
onComplete: () => {
this.setStyle({
height: "",
overflow: "",
marginTop: "",
marginBottom: "",
}).hide();
if (options?.hide ?? true) {
this.hide().setStyle({
height: "",
overflow: "",
marginTop: "",
marginBottom: "",
paddingTop: "",
paddingBottom: "",
});
}
},
});
}
Expand Down
Loading
Loading