added consistency stat, updated the result page layout

This commit is contained in:
Jack 2020-07-30 16:52:38 +01:00
parent a3025e310f
commit 7b1ccdf17b
3 changed files with 173 additions and 87 deletions

View file

@ -1038,14 +1038,21 @@ key {
#result {
display: grid;
// height: 200px;
gap: 1rem;
grid-template-columns: auto 1fr;
justify-content: center;
column-gap: 1rem;
// grid-template-columns: auto 1fr;
// justify-content: center;
align-items: center;
grid-template-columns: auto 1fr;
grid-template-areas: "stats chart"
"morestats morestats"
"login login";
.chart {
grid-area: chart;
width: 100%;
canvas {
width: 100%;
width: 100% !important;
height: 100%;
}
@ -1062,23 +1069,49 @@ key {
grid-column: 1/3;
text-align: center;
color: var(--sub-color);
grid-area: login;
}
.stats {
grid-area: stats;
display: grid;
column-gap: 0.5rem;
// column-gap: 0.5rem;
gap: .5rem;
justify-content: center;
align-items: center;
grid-template-areas:
"wpm acc"
"wpm key"
"raw time"
"source source"
"leaderboards leaderboards"
"testType infoAndTags";
// grid-template-areas:
// "wpm acc"
// "wpm key"
// "raw time"
// "consistency consistency"
// "source source"
// "leaderboards leaderboards"
// "testType infoAndTags";
// grid-template-areas:
// "wpm acc key consistency testType leaderboards source"
// "wpm raw time nothing infoAndTags leaderboards source";
grid-template-areas: "wpm"
"acc";
&.morestats {
display: grid;
grid-auto-flow: column;
grid-template-areas: none;
align-items: flex-start;
justify-content: flex-start;
column-gap: 2rem;
grid-area: morestats;
// grid-template-areas: "raw consistency testType infoAndTags leaderboards source"
// "key time testType infoAndTags leaderboards source";
.subgroup {
display: grid;
gap: .5rem;
}
}
.group {
margin-bottom: 0.5rem;
// margin-bottom: 0.5rem;
.top {
color: var(--sub-color);
@ -1093,60 +1126,12 @@ key {
}
}
.testType {
align-self: baseline;
grid-area: testType;
color: var(--sub-color);
.top {
font-size: 1rem;
line-height: 1.25rem;
}
.bottom {
font-size: 1rem;
line-height: 1rem;
}
}
.leaderboards {
align-self: baseline;
grid-area: leaderboards;
color: var(--sub-color);
.top {
font-size: 1rem;
line-height: 1.25rem;
}
.bottom {
font-size: 1rem;
line-height: 1rem;
}
}
.source {
align-self: baseline;
grid-area: source;
color: var(--sub-color);
max-width: 15rem;
.top {
font-size: 1rem;
line-height: 1.25rem;
}
.bottom {
font-size: 1rem;
line-height: 1rem;
}
}
.infoAndTags {
display: grid;
gap: 0.5rem;
align-self: baseline;
grid-area: infoAndTags;
// grid-area: infoAndTags;
color: var(--sub-color);
.top {
@ -1164,17 +1149,18 @@ key {
grid-area: wpm;
.top {
font-size: 3rem;
line-height: 3rem;
font-size: 2rem;
line-height: 1rem;
display: flex;
margin-top: -0.5rem;
// margin-top: -0.5rem;
.crownWrapper {
width: 1.7rem;
overflow: hidden;
height: 1.7rem;
margin-left: 0.5rem;
margin-top: 0.98rem;
// margin-top: 0.98rem;
margin-top: -0.5rem;
.crown {
font-size: 0.7rem;
@ -1196,21 +1182,39 @@ key {
}
}
.testType,
.leaderboards {
.bottom {
font-size: 1rem;
line-height: 1rem;
}
}
.acc {
grid-area: acc;
.top {
font-size: 2rem;
line-height: 1rem;
}
.bottom {
font-size: 4rem;
line-height: 4rem;
}
}
.key {
grid-area: key;
}
// .key {
// grid-area: key;
// }
.time {
grid-area: time;
}
// .time {
// grid-area: time;
// }
.raw {
grid-area: raw;
}
// .raw {
// grid-area: raw;
// }
}
}

View file

@ -671,18 +671,32 @@
<div class="top">acc</div>
<div class="bottom" aria-label="" data-balloon-pos="up">-</div>
</div>
<div class="group key">
<div class="top">char</div>
<div class="bottom">-</div>
</div>
<div class="stats morestats">
<div class="subgroup">
<div class="group key">
<div class="top">char</div>
<div class="bottom">-</div>
</div>
<div class="group raw">
<div class="top">raw</div>
<div class="bottom" aria-label="" data-balloon-pos="up">-</div>
</div>
</div>
<div class="group time">
<div class="top">time</div>
<div class="bottom">-</div>
</div>
<div class="group raw">
<div class="top">raw</div>
<div class="bottom" aria-label="" data-balloon-pos="up">-</div>
<div class="subgroup">
<div class="group flat consistency">
<div class="top">consistency</div>
<div class="bottom" aria-label="" data-balloon-pos="up">-</div>
</div>
<div class="group time">
<div class="top">time</div>
<div class="bottom">-</div>
</div>
</div>
<div class="group testType">
<div class="top">test type</div>
<div class="bottom">-</div>

View file

@ -79,6 +79,28 @@ function smooth(arr, windowSize, getter = (value) => value, setter) {
return result;
}
function stdDev(array) {
try {
const n = array.length;
const mean = array.reduce((a, b) => a + b) / n;
return Math.sqrt(
array.map((x) => Math.pow(x - mean, 2)).reduce((a, b) => a + b) / n
);
} catch (e) {
return 0;
}
}
function mean(array) {
try {
return (
array.reduce((previous, current) => (current += previous)) / array.length
);
} catch (e) {
return 0;
}
}
function showNotification(text, time) {
let noti = $(".notification");
noti.text(text);
@ -665,7 +687,13 @@ function compareInput(showError) {
) {
inputHistory.push(input);
currentInput = "";
if (!resultVisible) showResult();
//last character typed, show result
if (!resultVisible) {
if (keypressPerSecond.length === 0) {
keypressPerSecond.push(currentKeypressCount);
}
showResult();
}
}
// liveWPM()
}
@ -1336,6 +1364,23 @@ function showResult(difficultyFailed = false) {
rawWpmPerSecond = smooth(rawWpmPerSecond, 1);
let stddev = stdDev(rawWpmPerSecond);
let avg = mean(rawWpmPerSecond);
function kogasa(cov) {
return (
100 * (1 - Math.tanh(cov + Math.pow(cov, 3) / 3 + Math.pow(cov, 5) / 5))
);
}
let consistency = roundTo2(kogasa(stddev / avg));
$("#result .stats .consistency .bottom").text(Math.round(consistency) + "%");
$("#result .stats .consistency .bottom").attr(
"aria-label",
consistency + "%"
);
wpmOverTimeChart.data.datasets[0].borderColor = mainColor;
wpmOverTimeChart.data.datasets[0].data = wpmHistory;
wpmOverTimeChart.data.datasets[1].borderColor = subColor;
@ -1349,6 +1394,13 @@ function showResult(difficultyFailed = false) {
...[Math.max(...rawWpmPerSecond), Math.max(...wpmHistory)]
);
let minChartVal = Math.min(
...[Math.min(...rawWpmPerSecond), Math.min(...wpmHistory)]
);
// wpmOverTimeChart.options.scales.yAxes[0].ticks.min = Math.round(minChartVal);
// wpmOverTimeChart.options.scales.yAxes[1].ticks.min = Math.round(minChartVal);
let errorsNoZero = [];
for (let i = 0; i < errorsPerSecond.length; i++) {
@ -1396,6 +1448,7 @@ function showResult(difficultyFailed = false) {
tags: activeTags,
keySpacing: keypressStats.spacing.array,
keyDuration: keypressStats.duration.array,
consistency: consistency,
};
if (
config.difficulty == "normal" ||
@ -1727,6 +1780,15 @@ function showResult(difficultyFailed = false) {
$("#result .stats .tags .bottom").html(tagsText);
}
if (
$("#result .stats .tags").hasClass("hidden") &&
$("#result .stats .info").hasClass("hidden")
) {
$("#result .stats .infoAndTags").addClass("hidden");
} else {
$("#result .stats .infoAndTags").removeClass("hidden");
}
if (config.mode === "quote") {
$("#result .stats .source").removeClass("hidden");
$("#result .stats .source .bottom").html(randomQuote.source);
@ -1738,6 +1800,7 @@ function showResult(difficultyFailed = false) {
wpmOverTimeChart.options.scales.yAxes[1].ticks.max = maxChartVal;
wpmOverTimeChart.update({ duration: 0 });
swapElements($("#words"), $("#result"), 250, () => {
$("#words").empty();
// if (config.blindMode) {
@ -2885,6 +2948,7 @@ $(document).keypress(function (event) {
}
if (config.mode == "time") {
if (time >= config.time) {
//times up
clearIntervals();
hideCaret();
testActive = false;
@ -2915,6 +2979,7 @@ $(document).keypress(function (event) {
if (config.stopOnError && !thisCharCorrect) {
if (config.difficulty == "master") {
//failed due to master diff when pressing a key
showResult(true);
if (!afkDetected) {
let testNow = Date.now();
@ -3110,6 +3175,7 @@ $(document).keydown((event) => {
} else {
if (config.stopOnError) {
if (config.difficulty == "expert" || config.difficulty == "master") {
//failed due to diff when pressing space
showResult(true);
if (!afkDetected) {
let testNow = Date.now();
@ -3127,12 +3193,14 @@ $(document).keydown((event) => {
currentWordIndex++;
currentWordElementIndex++;
if (currentWordIndex == wordsList.length) {
//submitted last word that is incorrect
showResult();
return;
} else if (
config.difficulty == "expert" ||
config.difficulty == "master"
) {
//submitted last word incorrect and failed test
showResult(true);
if (!afkDetected) {
let testNow = Date.now();
@ -3314,7 +3382,7 @@ let wpmOverTimeChart = new Chart(ctx, {
},
display: true,
scaleLabel: {
display: true,
display: false,
labelString: "Seconds",
fontFamily: "Roboto Mono",
},