mirror of
https://github.com/monkeytypegame/monkeytype.git
synced 2025-10-08 14:42:46 +08:00
Account graph (#4049) albertying
* Create graph with ao10, ao100, and pb * Display best ao10 and 100 * Fix ts errors * Remove old graph * Remove smoothing slider and toggle chart style button * Clean up code * Populate graph if chartData > 0 * Fix filter not displaying data correctly * Fix wpm cpm labels * Update colors using theme colors * brought back accuracy averages * different colors * Add toggle ao10 and ao100 * Change opacity based on toggles * Persist on refresh * Fix accountActivity chart point color not updating when changing theme in the command line * Refactor * Keep pb color consistent * removed dot * smaller buttons, in one row, media queries * hiding bottom scale * connected the config properties into 1 * Refactor * Combine into one loop * cleanup removed unused functions reduced repeating code removed comments removed console logs * removed highest avg 10 and 100 stats * sweep --------- Co-authored-by: Miodec <jack@monkeytype.com>
This commit is contained in:
parent
239c43f240
commit
7ed088a13e
10 changed files with 422 additions and 144 deletions
|
@ -87,8 +87,9 @@ const CONFIG_SCHEMA = joi.object({
|
|||
paceCaretCustomSpeed: joi.number().min(0),
|
||||
repeatedPace: joi.boolean(),
|
||||
pageWidth: joi.string().valid("100", "125", "150", "200", "max"),
|
||||
chartAccuracy: joi.boolean(),
|
||||
chartStyle: joi.string().valid("line", "scatter"),
|
||||
accountChart: joi.array().items(joi.string()),
|
||||
chartAccuracy: joi.boolean().optional(), //remove after a bit
|
||||
chartStyle: joi.string().valid("line", "scatter").optional(), //remove after a bit
|
||||
minWpm: joi.string().valid("off", "custom"),
|
||||
minWpmCustomSpeed: joi.number().min(0),
|
||||
highlightMode: joi.string().valid("off", "letter", "word"),
|
||||
|
|
|
@ -231,28 +231,16 @@
|
|||
color: var(--sub-color);
|
||||
margin-top: 1rem;
|
||||
display: grid;
|
||||
grid-template-columns: auto 300px;
|
||||
grid-template-columns: auto 400px;
|
||||
align-items: center;
|
||||
.text {
|
||||
height: min-content;
|
||||
}
|
||||
.buttons {
|
||||
font-size: 0.75rem;
|
||||
display: grid;
|
||||
gap: 0.5rem;
|
||||
.smoothing {
|
||||
display: grid;
|
||||
gap: 0.25rem;
|
||||
grid-template-columns: 1fr auto;
|
||||
grid-template-rows: auto auto;
|
||||
justify-items: start;
|
||||
color: var(--text-color);
|
||||
.title {
|
||||
color: var(--text-color);
|
||||
}
|
||||
input[type="range"] {
|
||||
grid-column: 1/3;
|
||||
}
|
||||
}
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
}
|
||||
}
|
||||
.chart {
|
||||
|
|
|
@ -448,6 +448,13 @@
|
|||
}
|
||||
}
|
||||
|
||||
.pageAccount {
|
||||
.group.chart .below {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.pageSettings {
|
||||
.section.themes .tabContent.customTheme {
|
||||
}
|
||||
|
@ -496,10 +503,6 @@
|
|||
display: none;
|
||||
}
|
||||
}
|
||||
.group.chart .below {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
.group.topFilters .buttonsAndTitle .buttons {
|
||||
display: grid;
|
||||
justify-content: unset;
|
||||
|
|
|
@ -299,32 +299,64 @@ export function setBlindMode(blind: boolean, nosave?: boolean): boolean {
|
|||
return true;
|
||||
}
|
||||
|
||||
export function setChartAccuracy(
|
||||
chartAccuracy: boolean,
|
||||
export function setAccountChart(
|
||||
array: MonkeyTypes.AccountChart,
|
||||
nosave?: boolean
|
||||
): boolean {
|
||||
if (!isConfigValueValid("chart accuracy", chartAccuracy, ["boolean"])) {
|
||||
if (
|
||||
!isConfigValueValid("account chart", array, [["on", "off"], "stringArray"])
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
config.chartAccuracy = chartAccuracy;
|
||||
saveToLocalStorage("chartAccuracy", nosave);
|
||||
ConfigEvent.dispatch("chartAccuracy", config.chartAccuracy);
|
||||
config.accountChart = array;
|
||||
saveToLocalStorage("accountChart", nosave);
|
||||
ConfigEvent.dispatch("accountChart", config.accountChart);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export function setChartStyle(
|
||||
chartStyle: MonkeyTypes.ChartStyle,
|
||||
export function setAccountChartAccuracy(
|
||||
value: boolean,
|
||||
nosave?: boolean
|
||||
): boolean {
|
||||
if (!isConfigValueValid("chart style", chartStyle, [["line", "scatter"]])) {
|
||||
if (!isConfigValueValid("account chart accuracy", value, ["boolean"])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
config.chartStyle = chartStyle;
|
||||
saveToLocalStorage("chartStyle", nosave);
|
||||
ConfigEvent.dispatch("chartStyle", config.chartStyle);
|
||||
config.accountChart[0] = value ? "on" : "off";
|
||||
saveToLocalStorage("accountChart", nosave);
|
||||
ConfigEvent.dispatch("accountChart", config.accountChart);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export function setAccountChartAvg10(
|
||||
value: boolean,
|
||||
nosave?: boolean
|
||||
): boolean {
|
||||
if (!isConfigValueValid("account chart avg 10", value, ["boolean"])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
config.accountChart[1] = value ? "on" : "off";
|
||||
saveToLocalStorage("accountChart", nosave);
|
||||
ConfigEvent.dispatch("accountChart", config.accountChart);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export function setAccountChartAvg100(
|
||||
value: boolean,
|
||||
nosave?: boolean
|
||||
): boolean {
|
||||
if (!isConfigValueValid("account chart avg 100", value, ["boolean"])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
config.accountChart[2] = value ? "on" : "off";
|
||||
saveToLocalStorage("accountChart", nosave);
|
||||
ConfigEvent.dispatch("accountChart", config.accountChart);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1824,8 +1856,7 @@ export function apply(
|
|||
setPaceCaretCustomSpeed(configObj.paceCaretCustomSpeed, true);
|
||||
setRepeatedPace(configObj.repeatedPace, true);
|
||||
setPageWidth(configObj.pageWidth, true);
|
||||
setChartAccuracy(configObj.chartAccuracy, true);
|
||||
setChartStyle(configObj.chartStyle, true);
|
||||
setAccountChart(configObj.accountChart, true);
|
||||
setMinBurst(configObj.minBurst, true);
|
||||
setMinBurstCustomSpeed(configObj.minBurstCustomSpeed, true);
|
||||
setMinWpm(configObj.minWpm, true);
|
||||
|
|
|
@ -69,8 +69,7 @@ export default <MonkeyTypes.Config>{
|
|||
paceCaretCustomSpeed: 100,
|
||||
repeatedPace: true,
|
||||
pageWidth: "125",
|
||||
chartAccuracy: true,
|
||||
chartStyle: "line",
|
||||
accountChart: ["on", "on", "on"],
|
||||
minWpm: "off",
|
||||
minWpmCustomSpeed: 100,
|
||||
highlightMode: "letter",
|
||||
|
|
|
@ -243,38 +243,76 @@ export let accountHistoryActiveIndex: number;
|
|||
|
||||
export const accountHistory: ChartWithUpdateColors<
|
||||
"line",
|
||||
MonkeyTypes.HistoryChartData[] | MonkeyTypes.AccChartData[],
|
||||
| MonkeyTypes.HistoryChartData[]
|
||||
| MonkeyTypes.AccChartData[]
|
||||
| MonkeyTypes.OtherChartData[],
|
||||
string
|
||||
> = new ChartWithUpdateColors($(".pageAccount #accountHistoryChart"), {
|
||||
type: "line",
|
||||
data: {
|
||||
labels: [],
|
||||
datasets: [
|
||||
{
|
||||
yAxisID: "wpm",
|
||||
label: "wpm",
|
||||
fill: false,
|
||||
data: [],
|
||||
borderColor: "#f44336",
|
||||
borderWidth: 2,
|
||||
trendlineLinear: {
|
||||
style: "rgba(255,105,180, .8)",
|
||||
lineStyle: "dotted",
|
||||
width: 4,
|
||||
},
|
||||
fill: false,
|
||||
borderWidth: 0,
|
||||
order: 3,
|
||||
},
|
||||
{
|
||||
yAxisID: "pb",
|
||||
data: [],
|
||||
fill: false,
|
||||
stepped: true,
|
||||
pointRadius: 0,
|
||||
pointHoverRadius: 0,
|
||||
order: 4,
|
||||
},
|
||||
{
|
||||
yAxisID: "acc",
|
||||
label: "acc",
|
||||
fill: false,
|
||||
data: [],
|
||||
borderColor: "#cccccc",
|
||||
borderWidth: 2,
|
||||
pointStyle: "triangle",
|
||||
borderWidth: 0,
|
||||
pointRadius: 3.5,
|
||||
order: 3,
|
||||
},
|
||||
{
|
||||
yAxisID: "wpmAvgTen",
|
||||
data: [],
|
||||
fill: false,
|
||||
pointRadius: 0,
|
||||
pointHoverRadius: 0,
|
||||
order: 2,
|
||||
},
|
||||
{
|
||||
yAxisID: "accAvgTen",
|
||||
data: [],
|
||||
fill: false,
|
||||
pointRadius: 0,
|
||||
pointHoverRadius: 0,
|
||||
order: 2,
|
||||
},
|
||||
{
|
||||
yAxisID: "wpmAvgHundred",
|
||||
data: [],
|
||||
fill: false,
|
||||
pointRadius: 0,
|
||||
pointHoverRadius: 0,
|
||||
order: 1,
|
||||
},
|
||||
{
|
||||
yAxisID: "accAvgHundred",
|
||||
label: "accAvgHundred",
|
||||
data: [],
|
||||
fill: false,
|
||||
pointRadius: 0,
|
||||
pointHoverRadius: 0,
|
||||
order: 1,
|
||||
},
|
||||
],
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
// responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
hover: {
|
||||
mode: "nearest",
|
||||
|
@ -283,13 +321,18 @@ export const accountHistory: ChartWithUpdateColors<
|
|||
scales: {
|
||||
x: {
|
||||
axis: "x",
|
||||
type: "timeseries",
|
||||
bounds: "ticks",
|
||||
type: "linear",
|
||||
min: 0,
|
||||
ticks: {
|
||||
stepSize: 10,
|
||||
},
|
||||
display: false,
|
||||
offset: true,
|
||||
title: {
|
||||
display: true,
|
||||
text: "Test Number",
|
||||
},
|
||||
grid: {
|
||||
display: false,
|
||||
text: "Date",
|
||||
},
|
||||
},
|
||||
wpm: {
|
||||
|
@ -306,21 +349,86 @@ export const accountHistory: ChartWithUpdateColors<
|
|||
},
|
||||
position: "right",
|
||||
},
|
||||
pb: {
|
||||
axis: "y",
|
||||
beginAtZero: true,
|
||||
min: 0,
|
||||
ticks: {
|
||||
stepSize: 10,
|
||||
},
|
||||
display: false,
|
||||
},
|
||||
acc: {
|
||||
axis: "y",
|
||||
beginAtZero: true,
|
||||
min: 0,
|
||||
max: 100,
|
||||
reverse: true,
|
||||
ticks: {
|
||||
stepSize: 10,
|
||||
},
|
||||
display: true,
|
||||
position: "left",
|
||||
title: {
|
||||
display: true,
|
||||
text: "Error rate (100 - accuracy)",
|
||||
text: "Accuracy",
|
||||
},
|
||||
grid: {
|
||||
display: false,
|
||||
},
|
||||
position: "left",
|
||||
},
|
||||
wpmAvgTen: {
|
||||
axis: "y",
|
||||
beginAtZero: true,
|
||||
min: 0,
|
||||
ticks: {
|
||||
stepSize: 10,
|
||||
},
|
||||
display: false,
|
||||
grid: {
|
||||
display: false,
|
||||
},
|
||||
},
|
||||
accAvgTen: {
|
||||
axis: "y",
|
||||
beginAtZero: true,
|
||||
min: 0,
|
||||
reverse: true,
|
||||
ticks: {
|
||||
stepSize: 10,
|
||||
},
|
||||
display: false,
|
||||
grid: {
|
||||
display: false,
|
||||
},
|
||||
},
|
||||
wpmAvgHundred: {
|
||||
axis: "y",
|
||||
beginAtZero: true,
|
||||
min: 0,
|
||||
ticks: {
|
||||
stepSize: 10,
|
||||
},
|
||||
display: false,
|
||||
grid: {
|
||||
display: false,
|
||||
},
|
||||
},
|
||||
accAvgHundred: {
|
||||
axis: "y",
|
||||
beginAtZero: true,
|
||||
min: 0,
|
||||
reverse: true,
|
||||
ticks: {
|
||||
stepSize: 10,
|
||||
},
|
||||
display: false,
|
||||
grid: {
|
||||
display: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
plugins: {
|
||||
annotation: {
|
||||
annotations: [],
|
||||
|
@ -329,15 +437,26 @@ export const accountHistory: ChartWithUpdateColors<
|
|||
animation: { duration: 250 },
|
||||
// Disable the on-canvas tooltip
|
||||
enabled: true,
|
||||
|
||||
intersect: false,
|
||||
external: function (ctx): void {
|
||||
if (!ctx) return;
|
||||
ctx.tooltip.options.displayColors = false;
|
||||
},
|
||||
filter: function (tooltipItem): boolean {
|
||||
return (
|
||||
tooltipItem.datasetIndex !== 1 &&
|
||||
tooltipItem.datasetIndex !== 3 &&
|
||||
tooltipItem.datasetIndex !== 4 &&
|
||||
tooltipItem.datasetIndex !== 5 &&
|
||||
tooltipItem.datasetIndex !== 6
|
||||
);
|
||||
},
|
||||
callbacks: {
|
||||
title: function (): string {
|
||||
return "";
|
||||
},
|
||||
|
||||
beforeLabel: function (tooltipItem): string {
|
||||
if (tooltipItem.datasetIndex !== 0) {
|
||||
const resultData = tooltipItem.dataset.data[
|
||||
|
@ -828,21 +947,55 @@ export const miniResult: ChartWithUpdateColors<
|
|||
});
|
||||
|
||||
function updateAccuracy(): void {
|
||||
accountHistory.data.datasets[1].hidden = !Config.chartAccuracy;
|
||||
const accOn = Config.accountChart[0] === "on";
|
||||
const avg10On = Config.accountChart[1] === "on";
|
||||
const avg100On = Config.accountChart[2] === "on";
|
||||
|
||||
if (avg10On && avg100On) {
|
||||
accountHistory.data.datasets[2].hidden = !accOn;
|
||||
accountHistory.data.datasets[4].hidden = !accOn;
|
||||
accountHistory.data.datasets[6].hidden = !accOn;
|
||||
} else if (avg10On) {
|
||||
accountHistory.data.datasets[2].hidden = !accOn;
|
||||
accountHistory.data.datasets[4].hidden = !accOn;
|
||||
} else if (Config.accountChart[2] === "on") {
|
||||
accountHistory.data.datasets[2].hidden = !accOn;
|
||||
accountHistory.data.datasets[6].hidden = !accOn;
|
||||
} else {
|
||||
accountHistory.data.datasets[2].hidden = !accOn;
|
||||
}
|
||||
|
||||
(accountHistory.options as ScaleChartOptions<"line">).scales["acc"].display =
|
||||
Config.chartAccuracy;
|
||||
accOn;
|
||||
accountHistory.update();
|
||||
}
|
||||
|
||||
function updateStyle(): void {
|
||||
if (Config.chartStyle == "scatter") {
|
||||
accountHistory.data.datasets[0].showLine = false;
|
||||
accountHistory.data.datasets[1].showLine = false;
|
||||
function updateAverage10(): void {
|
||||
const accOn = Config.accountChart[0] === "on";
|
||||
const avg10On = Config.accountChart[1] === "on";
|
||||
|
||||
if (accOn) {
|
||||
accountHistory.data.datasets[3].hidden = !avg10On;
|
||||
accountHistory.data.datasets[4].hidden = !avg10On;
|
||||
} else {
|
||||
accountHistory.data.datasets[0].showLine = true;
|
||||
accountHistory.data.datasets[1].showLine = true;
|
||||
accountHistory.data.datasets[3].hidden = !avg10On;
|
||||
}
|
||||
accountHistory.updateColors();
|
||||
accountHistory.update();
|
||||
}
|
||||
|
||||
function updateAverage100(): void {
|
||||
const accOn = Config.accountChart[0] === "on";
|
||||
const avg100On = Config.accountChart[2] === "on";
|
||||
|
||||
if (accOn) {
|
||||
accountHistory.data.datasets[5].hidden = !avg100On;
|
||||
accountHistory.data.datasets[6].hidden = !avg100On;
|
||||
} else {
|
||||
accountHistory.data.datasets[5].hidden = !avg100On;
|
||||
}
|
||||
accountHistory.updateColors();
|
||||
accountHistory.update();
|
||||
}
|
||||
|
||||
export async function updateColors<
|
||||
|
@ -866,6 +1019,7 @@ export async function updateColors<
|
|||
const color = isPb ? textcolor : maincolor;
|
||||
return color;
|
||||
};
|
||||
|
||||
if (chart.data.datasets[1]) {
|
||||
chart.data.datasets[1].borderColor = subcolor;
|
||||
}
|
||||
|
@ -910,6 +1064,60 @@ export async function updateColors<
|
|||
)[1].pointBackgroundColor = subcolor;
|
||||
}
|
||||
}
|
||||
if (chart.data.datasets.length === 2) {
|
||||
chart.data.datasets[1].borderColor = (): string => {
|
||||
const color = subcolor;
|
||||
return color;
|
||||
};
|
||||
}
|
||||
|
||||
if (chart.data.datasets.length === 7) {
|
||||
chart.data.datasets[2].borderColor = (): string => {
|
||||
const color = subcolor;
|
||||
return color;
|
||||
};
|
||||
const avg10On = Config.accountChart[1] === "on";
|
||||
const avg100On = Config.accountChart[2] === "on";
|
||||
|
||||
const text02 = Misc.blendTwoHexColors(bgcolor, textcolor, 0.2);
|
||||
const main02 = Misc.blendTwoHexColors(bgcolor, maincolor, 0.2);
|
||||
const main04 = Misc.blendTwoHexColors(bgcolor, maincolor, 0.4);
|
||||
|
||||
const sub02 = Misc.blendTwoHexColors(bgcolor, subcolor, 0.2);
|
||||
const sub04 = Misc.blendTwoHexColors(bgcolor, subcolor, 0.4);
|
||||
|
||||
const [
|
||||
wpmDataset,
|
||||
pbDataset,
|
||||
accDataset,
|
||||
ao10wpmDataset,
|
||||
ao10accDataset,
|
||||
ao100wpmDataset,
|
||||
ao100accDataset,
|
||||
] = chart.data.datasets as ChartDataset<"line", TData>[];
|
||||
|
||||
if (avg10On && avg100On) {
|
||||
wpmDataset.pointBackgroundColor = main02;
|
||||
pbDataset.borderColor = text02;
|
||||
accDataset.pointBackgroundColor = sub02;
|
||||
ao10wpmDataset.borderColor = main04;
|
||||
ao10accDataset.borderColor = sub04;
|
||||
ao100wpmDataset.borderColor = maincolor;
|
||||
ao100accDataset.borderColor = subcolor;
|
||||
} else if ((avg10On && !avg100On) || (!avg10On && avg100On)) {
|
||||
pbDataset.borderColor = text02;
|
||||
wpmDataset.pointBackgroundColor = main04;
|
||||
accDataset.pointBackgroundColor = sub04;
|
||||
ao10wpmDataset.borderColor = maincolor;
|
||||
ao100wpmDataset.borderColor = maincolor;
|
||||
ao10accDataset.borderColor = subcolor;
|
||||
ao100accDataset.borderColor = subcolor;
|
||||
} else {
|
||||
pbDataset.borderColor = text02;
|
||||
wpmDataset.pointBackgroundColor = maincolor;
|
||||
accDataset.pointBackgroundColor = subcolor;
|
||||
}
|
||||
}
|
||||
|
||||
const chartScaleOptions = chart.options as ScaleChartOptions<TType>;
|
||||
Object.keys(chartScaleOptions.scales).forEach((scaleID) => {
|
||||
|
@ -923,10 +1131,6 @@ export async function updateColors<
|
|||
chart.data.datasets[0]
|
||||
.trendlineLinear as TrendlineLinearPlugin.TrendlineLinearOptions
|
||||
).style = subcolor;
|
||||
(
|
||||
chart.data.datasets[1]
|
||||
.trendlineLinear as TrendlineLinearPlugin.TrendlineLinearOptions
|
||||
).style = subcolor;
|
||||
} catch {}
|
||||
|
||||
(
|
||||
|
@ -958,7 +1162,10 @@ export function updateAllChartColors(): void {
|
|||
}
|
||||
|
||||
ConfigEvent.subscribe((eventKey, eventValue) => {
|
||||
if (eventKey === "chartAccuracy") updateAccuracy();
|
||||
if (eventKey === "chartStyle") updateStyle();
|
||||
if (eventKey === "accountChart") {
|
||||
updateAccuracy();
|
||||
updateAverage10();
|
||||
updateAverage100();
|
||||
}
|
||||
if (eventKey === "fontFamily") setDefaultFontFamily(eventValue as string);
|
||||
});
|
||||
|
|
|
@ -196,53 +196,17 @@ export function reset(): void {
|
|||
ChartController.accountActivity.data.datasets[1].data = [];
|
||||
ChartController.accountHistory.data.datasets[0].data = [];
|
||||
ChartController.accountHistory.data.datasets[1].data = [];
|
||||
ChartController.accountHistory.data.datasets[2].data = [];
|
||||
ChartController.accountHistory.data.datasets[3].data = [];
|
||||
ChartController.accountHistory.data.datasets[4].data = [];
|
||||
ChartController.accountHistory.data.datasets[5].data = [];
|
||||
ChartController.accountHistory.data.datasets[6].data = [];
|
||||
}
|
||||
|
||||
let totalSecondsFiltered = 0;
|
||||
let chartData: MonkeyTypes.HistoryChartData[] = [];
|
||||
let accChartData: MonkeyTypes.AccChartData[] = [];
|
||||
|
||||
export function smoothHistory(factor: number): void {
|
||||
const smoothedWpmData = Misc.smooth(
|
||||
chartData.map((a) => a.y),
|
||||
factor
|
||||
);
|
||||
const smoothedAccData = Misc.smooth(
|
||||
accChartData.map((a) => a.y),
|
||||
factor
|
||||
);
|
||||
|
||||
const chartData2 = chartData.map((a, i) => {
|
||||
const ret = Object.assign({}, a);
|
||||
ret.y = smoothedWpmData[i];
|
||||
return ret;
|
||||
});
|
||||
|
||||
const accChartData2 = accChartData.map((a, i) => {
|
||||
const ret = Object.assign({}, a);
|
||||
ret.y = smoothedAccData[i];
|
||||
return ret;
|
||||
});
|
||||
|
||||
ChartController.accountHistory.data.datasets[0].data = chartData2;
|
||||
ChartController.accountHistory.data.datasets[1].data = accChartData2;
|
||||
|
||||
if (chartData2.length || accChartData2.length) {
|
||||
ChartController.accountHistory.options.animation = false;
|
||||
ChartController.accountHistory.update();
|
||||
delete ChartController.accountHistory.options.animation;
|
||||
}
|
||||
}
|
||||
|
||||
async function applyHistorySmoothing(): Promise<void> {
|
||||
const smoothing = $(
|
||||
".pageAccount .content .below .smoothing input"
|
||||
).val() as string;
|
||||
$(".pageAccount .content .below .smoothing .value").text(smoothing);
|
||||
smoothHistory(parseInt(smoothing));
|
||||
await Misc.sleep(0);
|
||||
}
|
||||
|
||||
function fillContent(): void {
|
||||
LoadingPage.updateText("Displaying stats...");
|
||||
LoadingPage.updateBar(100);
|
||||
|
@ -310,6 +274,9 @@ function fillContent(): void {
|
|||
|
||||
filteredResults = [];
|
||||
$(".pageAccount .history table tbody").empty();
|
||||
|
||||
let testNum = DB.getSnapshot()?.results?.length || 0;
|
||||
|
||||
DB.getSnapshot()?.results?.forEach(
|
||||
(result: MonkeyTypes.Result<MonkeyTypes.Mode>) => {
|
||||
// totalSeconds += tt;
|
||||
|
@ -634,7 +601,7 @@ function fillContent(): void {
|
|||
}
|
||||
|
||||
chartData.push({
|
||||
x: result.timestamp,
|
||||
x: testNum,
|
||||
y: Config.alwaysShowCPM ? Misc.roundTo2(result.wpm * 5) : result.wpm,
|
||||
wpm: Config.alwaysShowCPM ? Misc.roundTo2(result.wpm * 5) : result.wpm,
|
||||
acc: result.acc,
|
||||
|
@ -653,11 +620,13 @@ function fillContent(): void {
|
|||
wpmChartData.push(result.wpm);
|
||||
|
||||
accChartData.push({
|
||||
x: result.timestamp,
|
||||
y: 100 - result.acc,
|
||||
x: testNum,
|
||||
y: result.acc,
|
||||
errorRate: 100 - result.acc,
|
||||
});
|
||||
|
||||
testNum--;
|
||||
|
||||
if (result.wpm > topWpm) {
|
||||
const puncsctring = result.punctuation ? ",<br>with punctuation" : "";
|
||||
const numbsctring = result.numbers
|
||||
|
@ -759,8 +728,76 @@ function fillContent(): void {
|
|||
accountHistoryScaleOptions["wpm"].title.text = "Words per Minute";
|
||||
}
|
||||
|
||||
ChartController.accountHistory.data.datasets[0].data = chartData;
|
||||
ChartController.accountHistory.data.datasets[1].data = accChartData;
|
||||
if (chartData.length > 0) {
|
||||
chartData.reverse();
|
||||
accChartData.reverse();
|
||||
|
||||
// get pb points
|
||||
let currentPb = 0;
|
||||
const pb: { x: number; y: number }[] = [];
|
||||
|
||||
chartData.forEach((a) => {
|
||||
if (a.y > currentPb) {
|
||||
currentPb = a.y;
|
||||
pb.push(a);
|
||||
}
|
||||
});
|
||||
|
||||
// add last point to pb
|
||||
const xMax = chartData.length;
|
||||
|
||||
pb.push({
|
||||
x: xMax,
|
||||
y: pb[pb.length - 1].y,
|
||||
});
|
||||
|
||||
const avgTen = [];
|
||||
const avgTenAcc = [];
|
||||
const avgHundred = [];
|
||||
const avgHundredAcc = [];
|
||||
|
||||
for (let i = 0; i < chartData.length; i++) {
|
||||
// calculate 10 subset averages
|
||||
const startIdxTen = i < 10 ? 0 : i - 9;
|
||||
const subsetTen = chartData.slice(startIdxTen, i + 1);
|
||||
const accSubsetTen = accChartData.slice(startIdxTen, i + 1);
|
||||
const avgTenValue =
|
||||
subsetTen.reduce((acc, { y }) => acc + y, 0) / subsetTen.length;
|
||||
const accAvgTenValue =
|
||||
accSubsetTen.reduce((acc, { y }) => acc + y, 0) / subsetTen.length;
|
||||
|
||||
// add values to arrays
|
||||
avgTen.push({ x: i + 1, y: avgTenValue });
|
||||
avgTenAcc.push({ x: i + 1, y: accAvgTenValue });
|
||||
|
||||
// calculate 100 subset averages
|
||||
const startIdxHundred = i < 100 ? 0 : i - 99;
|
||||
const subsetHundred = chartData.slice(startIdxHundred, i + 1);
|
||||
const accSubsetHundred = accChartData.slice(startIdxHundred, i + 1);
|
||||
const avgHundredValue =
|
||||
subsetHundred.reduce((acc, { y }) => acc + y, 0) / subsetHundred.length;
|
||||
const accAvgHundredValue =
|
||||
accSubsetHundred.reduce((acc, { y }) => acc + y, 0) /
|
||||
subsetHundred.length;
|
||||
|
||||
// add values to arrays
|
||||
avgHundred.push({ x: i + 1, y: avgHundredValue });
|
||||
avgHundredAcc.push({ x: i + 1, y: accAvgHundredValue });
|
||||
}
|
||||
|
||||
ChartController.accountHistory.data.datasets[0].data = chartData;
|
||||
ChartController.accountHistory.data.datasets[1].data = pb;
|
||||
ChartController.accountHistory.data.datasets[2].data = accChartData;
|
||||
ChartController.accountHistory.data.datasets[3].data = avgTen;
|
||||
ChartController.accountHistory.data.datasets[4].data = avgTenAcc;
|
||||
ChartController.accountHistory.data.datasets[5].data = avgHundred;
|
||||
ChartController.accountHistory.data.datasets[6].data = avgHundredAcc;
|
||||
|
||||
accountHistoryScaleOptions["x"].max = xMax + 1;
|
||||
|
||||
chartData.reverse();
|
||||
accChartData.reverse();
|
||||
}
|
||||
|
||||
const wpms = chartData.map((r) => r.y);
|
||||
const minWpmChartVal = Math.min(...wpms);
|
||||
|
@ -769,6 +806,12 @@ function fillContent(): void {
|
|||
// let accuracies = accChartData.map((r) => r.y);
|
||||
accountHistoryScaleOptions["wpm"].max =
|
||||
Math.floor(maxWpmChartVal) + (10 - (Math.floor(maxWpmChartVal) % 10));
|
||||
accountHistoryScaleOptions["pb"].max =
|
||||
Math.floor(maxWpmChartVal) + (10 - (Math.floor(maxWpmChartVal) % 10));
|
||||
accountHistoryScaleOptions["wpmAvgTen"].max =
|
||||
Math.floor(maxWpmChartVal) + (10 - (Math.floor(maxWpmChartVal) % 10));
|
||||
accountHistoryScaleOptions["wpmAvgHundred"].max =
|
||||
Math.floor(maxWpmChartVal) + (10 - (Math.floor(maxWpmChartVal) % 10));
|
||||
|
||||
if (!Config.startGraphsAtZero) {
|
||||
accountHistoryScaleOptions["wpm"].min = Math.floor(minWpmChartVal);
|
||||
|
@ -800,8 +843,6 @@ function fillContent(): void {
|
|||
Misc.secondsToString(Math.round(totalSecondsFiltered), true, true)
|
||||
);
|
||||
|
||||
const wpmCpm = Config.alwaysShowCPM ? "cpm" : "wpm";
|
||||
|
||||
let highestSpeed: number | string = topWpm;
|
||||
if (Config.alwaysShowCPM) {
|
||||
highestSpeed = topWpm * 5;
|
||||
|
@ -812,6 +853,8 @@ function fillContent(): void {
|
|||
highestSpeed = Math.round(highestSpeed);
|
||||
}
|
||||
|
||||
const wpmCpm = Config.alwaysShowCPM ? "cpm" : "wpm";
|
||||
|
||||
$(".pageAccount .highestWpm .title").text(`highest ${wpmCpm}`);
|
||||
$(".pageAccount .highestWpm .val").text(highestSpeed);
|
||||
|
||||
|
@ -981,12 +1024,17 @@ function fillContent(): void {
|
|||
Misc.roundTo2(
|
||||
Config.alwaysShowCPM ? wpmChangePerHour * 5 : wpmChangePerHour
|
||||
)
|
||||
} ${Config.alwaysShowCPM ? "cpm" : "wpm"}.`
|
||||
} ${Config.alwaysShowCPM ? "cpm" : "wpm"}`
|
||||
);
|
||||
|
||||
$(".pageAccount .estimatedWordsTyped .val").text(totalEstimatedWords);
|
||||
|
||||
applyHistorySmoothing();
|
||||
if (chartData.length || accChartData.length) {
|
||||
ChartController.accountHistory.options.animation = false;
|
||||
ChartController.accountHistory.update();
|
||||
delete ChartController.accountHistory.options.animation;
|
||||
}
|
||||
|
||||
ChartController.accountActivity.update();
|
||||
ChartController.accountHistogram.update();
|
||||
LoadingPage.updateBar(100, true);
|
||||
|
@ -1117,15 +1165,15 @@ function sortAndRefreshHistory(
|
|||
}
|
||||
|
||||
$(".pageAccount .toggleAccuracyOnChart").on("click", () => {
|
||||
UpdateConfig.setChartAccuracy(!Config.chartAccuracy);
|
||||
UpdateConfig.setAccountChartAccuracy(!(Config.accountChart[0] == "on"));
|
||||
});
|
||||
|
||||
$(".pageAccount .toggleChartStyle").on("click", () => {
|
||||
if (Config.chartStyle == "line") {
|
||||
UpdateConfig.setChartStyle("scatter");
|
||||
} else {
|
||||
UpdateConfig.setChartStyle("line");
|
||||
}
|
||||
$(".pageAccount .toggleAverage10OnChart").on("click", () => {
|
||||
UpdateConfig.setAccountChartAvg10(!(Config.accountChart[1] == "on"));
|
||||
});
|
||||
|
||||
$(".pageAccount .toggleAverage100OnChart").on("click", () => {
|
||||
UpdateConfig.setAccountChartAvg100(!(Config.accountChart[2] == "on"));
|
||||
});
|
||||
|
||||
$(".pageAccount .loadMoreButton").on("click", () => {
|
||||
|
@ -1232,10 +1280,6 @@ $(".pageAccount .group.presetFilterButtons").on(
|
|||
}
|
||||
);
|
||||
|
||||
$(".pageAccount .content .below .smoothing input").on("input", () => {
|
||||
applyHistorySmoothing();
|
||||
});
|
||||
|
||||
$(".pageAccount .content .group.aboveHistory .exportCSV").on("click", () => {
|
||||
Misc.downloadResultsCSV(filteredResults);
|
||||
});
|
||||
|
|
10
frontend/src/ts/types/types.d.ts
vendored
10
frontend/src/ts/types/types.d.ts
vendored
|
@ -119,7 +119,7 @@ declare namespace MonkeyTypes {
|
|||
|
||||
type PageWidth = "100" | "125" | "150" | "200" | "max";
|
||||
|
||||
type ChartStyle = "line" | "scatter";
|
||||
type AccountChart = ("off" | "on")[];
|
||||
|
||||
type MinimumWordsPerMinute = "off" | "custom";
|
||||
|
||||
|
@ -177,6 +177,11 @@ declare namespace MonkeyTypes {
|
|||
errorRate: number;
|
||||
}
|
||||
|
||||
interface OtherChartData {
|
||||
x: number;
|
||||
y: number;
|
||||
}
|
||||
|
||||
interface ActivityChartDataPoint {
|
||||
x: number;
|
||||
y: number;
|
||||
|
@ -448,8 +453,7 @@ declare namespace MonkeyTypes {
|
|||
paceCaretCustomSpeed: number;
|
||||
repeatedPace: boolean;
|
||||
pageWidth: PageWidth;
|
||||
chartAccuracy: boolean;
|
||||
chartStyle: ChartStyle;
|
||||
accountChart: AccountChart;
|
||||
minWpm: MinimumWordsPerMinute;
|
||||
minWpmCustomSpeed: number;
|
||||
highlightMode: HighlightMode;
|
||||
|
|
|
@ -288,6 +288,7 @@ function hexToRgb(hex: string):
|
|||
} else {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return { r, g, b };
|
||||
}
|
||||
|
||||
|
|
|
@ -430,21 +430,21 @@
|
|||
<div class="chart">
|
||||
<canvas id="accountHistoryChart"></canvas>
|
||||
</div>
|
||||
|
||||
<div class="below">
|
||||
<div class="text"></div>
|
||||
<div class="buttons">
|
||||
<div class="smoothing">
|
||||
<div class="title">smoothing</div>
|
||||
<div class="value">0</div>
|
||||
<input type="range" min="0" max="20" value="0" step="1" />
|
||||
</div>
|
||||
<div class="toggleAccuracyOnChart button">
|
||||
<i class="fas fa-bullseye"></i>
|
||||
Toggle Accuracy
|
||||
Accuracy
|
||||
</div>
|
||||
<div class="toggleChartStyle button">
|
||||
<div class="toggleAverage10OnChart button">
|
||||
<i class="fas fa-chart-line"></i>
|
||||
Toggle Chart Style
|
||||
Avg of 10
|
||||
</div>
|
||||
<div class="toggleAverage100OnChart button">
|
||||
<i class="fas fa-chart-line"></i>
|
||||
Avg of 100
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
Loading…
Add table
Reference in a new issue