`;
}
if (input !== wordsList[i]) {
wordEl = `
`;
}
let loop;
if (input.length > wordsList[i].length) {
//input is longer - extra characters possible (loop over input)
loop = input.length;
} else {
//input is shorter or equal (loop over word list)
loop = wordsList[i].length;
}
for (let c = 0; c < loop; c++) {
// input.forEach((inputLetter, inputLetteri) => {
let correctedChar;
try {
correctedChar = correctedHistory[i][c];
} catch (e) {
correctedChar = undefined;
}
let extraCorrected = "";
if (c + 1 === loop && correctedHistory[i].length > input.length) {
extraCorrected = "extraCorrected";
}
if (wordsList[i][c] !== undefined) {
if (input[c] === wordsList[i][c]) {
if (correctedChar === input[c] || correctedChar === undefined) {
wordEl += ``;
} else {
wordEl +=
`";
}
} else {
if (input[c] === currentInput) {
wordEl +=
"" + wordsList[i][c] + "";
} else if (input[c] === undefined) {
wordEl += "" + wordsList[i][c] + "";
} else {
wordEl +=
`";
}
}
} else {
wordEl += '";
}
}
wordEl += "
";
} catch (e) {
try {
wordEl = "
";
for (let c = 0; c < wordsList[i].length; c++) {
wordEl += "" + wordsList[i][c] + "";
}
wordEl += "
";
} catch (e) {}
}
$("#resultWordsHistory .words").append(wordEl);
}
$("#showWordHistoryButton").addClass("loaded");
return true;
}
function flipTestColors(tf) {
if (tf) {
$("#words").addClass("flipped");
} else {
$("#words").removeClass("flipped");
}
}
function applyColorfulMode(tc) {
if (tc) {
$("#words").addClass("colorfulMode");
} else {
$("#words").removeClass("colorfulMode");
}
}
// function applyReadAheadMode(tc) {
// if (tc) {
// $("#words").addClass("readAheadMode");
// } else {
// $("#words").removeClass("readAheadMode");
// }
// }
function showEditTags(action, id, name) {
if (action === "add") {
$("#tagsWrapper #tagsEdit").attr("action", "add");
$("#tagsWrapper #tagsEdit .title").html("Add new tag");
$("#tagsWrapper #tagsEdit .button").html(`
`);
$("#tagsWrapper #tagsEdit input").val("");
$("#tagsWrapper #tagsEdit input").removeClass("hidden");
} else if (action === "edit") {
$("#tagsWrapper #tagsEdit").attr("action", "edit");
$("#tagsWrapper #tagsEdit").attr("tagid", id);
$("#tagsWrapper #tagsEdit .title").html("Edit tag name");
$("#tagsWrapper #tagsEdit .button").html(`
`);
$("#tagsWrapper #tagsEdit input").val(name);
$("#tagsWrapper #tagsEdit input").removeClass("hidden");
} else if (action === "remove") {
$("#tagsWrapper #tagsEdit").attr("action", "remove");
$("#tagsWrapper #tagsEdit").attr("tagid", id);
$("#tagsWrapper #tagsEdit .title").html("Remove tag " + name);
$("#tagsWrapper #tagsEdit .button").html(`
`);
$("#tagsWrapper #tagsEdit input").addClass("hidden");
}
if ($("#tagsWrapper").hasClass("hidden")) {
$("#tagsWrapper")
.stop(true, true)
.css("opacity", 0)
.removeClass("hidden")
.animate({ opacity: 1 }, 100, (e) => {
$("#tagsWrapper #tagsEdit input").focus();
});
}
}
function hideEditTags() {
if (!$("#tagsWrapper").hasClass("hidden")) {
$("#tagsWrapper #tagsEdit").attr("action", "");
$("#tagsWrapper #tagsEdit").attr("tagid", "");
$("#tagsWrapper")
.stop(true, true)
.css("opacity", 1)
.animate(
{
opacity: 0,
},
100,
(e) => {
$("#tagsWrapper").addClass("hidden");
}
);
}
}
function showBackgroundLoader() {
$("#backgroundLoader").stop(true, true).fadeIn(125);
}
function hideBackgroundLoader() {
$("#backgroundLoader").stop(true, true).fadeOut(125);
}
function updateTestModesNotice() {
let anim = false;
if ($(".pageTest #testModesNotice").text() === "") anim = true;
$(".pageTest #testModesNotice").empty();
if (sameWordset) {
$(".pageTest #testModesNotice").append(
`
repeated
`
);
}
if (config.difficulty === "expert") {
$(".pageTest #testModesNotice").append(
`
expert
`
);
} else if (config.difficulty === "master") {
$(".pageTest #testModesNotice").append(
`
master
`
);
}
if (config.blindMode) {
$(".pageTest #testModesNotice").append(
`
blind
`
);
}
if (config.paceCaret !== "off") {
$(".pageTest #testModesNotice").append(
`
${config.paceCaret === "pb" ? "pb" : config.paceCaretCustomSpeed+" wpm"} pace
`
);
}
// if (config.readAheadMode) {
// $(".pageTest #testModesNotice").append(
// `
read ahead
`
// );
// }
if (activeFunBox !== "none") {
$(".pageTest #testModesNotice").append(
`
${activeFunBox.replace(
/_/g,
" "
)}
`
);
}
if (config.confidenceMode === "on") {
$(".pageTest #testModesNotice").append(
`
confidence
`
);
}
if (config.confidenceMode === "max") {
$(".pageTest #testModesNotice").append(
`
max confidence
`
);
}
if (config.stopOnError != "off") {
$(".pageTest #testModesNotice").append(
`
stop on ${config.stopOnError}
`
);
}
if (config.layout !== "default") {
$(".pageTest #testModesNotice").append(
`
${config.layout}
`
);
}
tagsString = "";
// $.each($('.pageSettings .section.tags .tagsList .tag'), (index, tag) => {
// if($(tag).children('.active').attr('active') === 'true'){
// tagsString += $(tag).children('.title').text() + ', ';
// }
// })
try {
dbSnapshot.tags.forEach((tag) => {
if (tag.active === true) {
tagsString += tag.name + ", ";
}
});
if (tagsString !== "") {
$(".pageTest #testModesNotice").append(
`
${tagsString.substring(
0,
tagsString.length - 2
)}
`
);
}
} catch (e) {}
if (anim) {
$(".pageTest #testModesNotice")
.css("transition", "none")
.css("opacity", 0)
.animate(
{
opacity: 1,
},
125,
(e) => {
$(".pageTest #testModesNotice").css("transition", ".125s");
}
);
}
}
$("#tagsWrapper").click((e) => {
if ($(e.target).attr("id") === "tagsWrapper") {
hideEditTags();
}
});
$("#tagsWrapper #tagsEdit .button").click((e) => {
tagsEdit();
});
$("#tagsWrapper #tagsEdit input").keypress((e) => {
if (e.keyCode == 13) {
tagsEdit();
}
});
function tagsEdit() {
let action = $("#tagsWrapper #tagsEdit").attr("action");
let inputVal = $("#tagsWrapper #tagsEdit input").val();
let tagid = $("#tagsWrapper #tagsEdit").attr("tagid");
hideEditTags();
if (action === "add") {
showBackgroundLoader();
addTag({ uid: firebase.auth().currentUser.uid, name: inputVal }).then(
(e) => {
hideBackgroundLoader();
let status = e.data.resultCode;
if (status === 1) {
showNotification("Tag added", 2000);
dbSnapshot.tags.push({
name: inputVal,
id: e.data.id,
});
updateResultEditTagsPanelButtons();
updateSettingsPage();
updateFilterTags();
} else if (status === -1) {
showNotification("Invalid tag name", 3000);
} else if (status < -1) {
showNotification("Unknown error", 3000);
}
}
);
} else if (action === "edit") {
showBackgroundLoader();
editTag({
uid: firebase.auth().currentUser.uid,
name: inputVal,
tagid: tagid,
}).then((e) => {
hideBackgroundLoader();
let status = e.data.resultCode;
if (status === 1) {
showNotification("Tag updated", 2000);
dbSnapshot.tags.forEach((tag) => {
if (tag.id === tagid) {
tag.name = inputVal;
}
});
updateResultEditTagsPanelButtons();
updateSettingsPage();
updateFilterTags();
} else if (status === -1) {
showNotification("Invalid tag name", 3000);
} else if (status < -1) {
showNotification("Unknown error", 3000);
}
});
} else if (action === "remove") {
showBackgroundLoader();
removeTag({ uid: firebase.auth().currentUser.uid, tagid: tagid }).then(
(e) => {
hideBackgroundLoader();
let status = e.data.resultCode;
if (status === 1) {
showNotification("Tag removed", 2000);
dbSnapshot.tags.forEach((tag, index) => {
if (tag.id === tagid) {
dbSnapshot.tags.splice(index, 1);
}
});
updateResultEditTagsPanelButtons();
updateSettingsPage();
updateFilterTags();
updateActiveTags();
} else if (status < -1) {
showNotification("Unknown error", 3000);
}
}
);
}
}
function showCapsWarning() {
if ($("#capsWarning").hasClass("hidden")) {
$("#capsWarning").removeClass("hidden");
}
}
function hideCapsWarning() {
if (!$("#capsWarning").hasClass("hidden")) {
$("#capsWarning").addClass("hidden");
}
}
function showCustomTextPopup() {
if ($("#customTextPopupWrapper").hasClass("hidden")) {
if ($("#customTextPopup .check input").prop("checked")) {
$("#customTextPopup .inputs .wordcount").removeClass("hidden");
} else {
$("#customTextPopup .inputs .wordcount").addClass("hidden");
}
$("#customTextPopupWrapper")
.stop(true, true)
.css("opacity", 0)
.removeClass("hidden")
.animate({ opacity: 1 }, 100, (e) => {
$("#customTextPopup textarea").val(customText.join(" "));
$("#customTextPopup .wordcount input").val(customTextWordCount);
$("#customTextPopup textarea").focus();
});
}
}
function hideCustomTextPopup() {
if (!$("#customTextPopupWrapper").hasClass("hidden")) {
$("#customTextPopupWrapper")
.stop(true, true)
.css("opacity", 1)
.animate(
{
opacity: 0,
},
100,
(e) => {
$("#customTextPopupWrapper").addClass("hidden");
}
);
}
}
$("#customTextPopupWrapper").mousedown((e) => {
if ($(e.target).attr("id") === "customTextPopupWrapper") {
hideCustomTextPopup();
}
});
$("#customTextPopup .inputs .check input").change((e) => {
if ($("#customTextPopup .check input").prop("checked")) {
$("#customTextPopup .inputs .wordcount").removeClass("hidden");
} else {
$("#customTextPopup .inputs .wordcount").addClass("hidden");
}
});
$("#customTextPopup .button").click((e) => {
let text = $("#customTextPopup textarea").val();
text = text.trim();
text = text.replace(/[\n\r\t ]/gm, " ");
text = text.replace(/ +/gm, " ");
if($("#customTextPopup .typographyCheck input").prop("checked")) {
text = cleanTypographySymbols(text)
}
text = text.split(" ");
// if (text.length >= 10000) {
// showNotification("Custom text cannot be longer than 10000 words.", 4000);
// changeMode("time");
// text = "The quick brown fox jumped over the lazy dog".split(" ");
// } else {
customText = text;
customTextIsRandom = $("#customTextPopup .check input").prop("checked");
// if (customTextIsRandom && customText.length < 3) {
// showNotification("Random custom text requires at least 3 words", 4000);
// customTextIsRandom = false;
// }
customTextWordCount = $("#customTextPopup .wordcount input").val();
manualRestart = true;
restartTest();
// }
hideCustomTextPopup();
});
function showCustomMode2Popup(mode) {
if ($("#customMode2PopupWrapper").hasClass("hidden")) {
$("#customMode2PopupWrapper")
.stop(true, true)
.css("opacity", 0)
.removeClass("hidden")
.animate({ opacity: 1 }, 100, (e) => {
if (mode == "time") {
$("#customMode2Popup .text").text("Test length");
$("#customMode2Popup").attr("mode", "time");
} else if (mode == "words") {
$("#customMode2Popup .text").text("Word amount");
$("#customMode2Popup").attr("mode", "words");
}
$("#customMode2Popup input").focus().select();
});
}
}
function hideCustomMode2Popup() {
if (!$("#customMode2PopupWrapper").hasClass("hidden")) {
$("#customMode2PopupWrapper")
.stop(true, true)
.css("opacity", 1)
.animate(
{
opacity: 0,
},
100,
(e) => {
$("#customMode2PopupWrapper").addClass("hidden");
}
);
}
}
function playClickSound() {
if (config.playSoundOnClick === "off") return;
if (clickSounds === null) initClickSounds();
let rand = Math.floor(
Math.random() * clickSounds[config.playSoundOnClick].length
);
let randomSound = clickSounds[config.playSoundOnClick][rand];
randomSound.counter++;
if (randomSound.counter === 2) randomSound.counter = 0;
randomSound.sounds[randomSound.counter].currentTime = 0;
randomSound.sounds[randomSound.counter].play();
// clickSound.currentTime = 0;
// clickSound.play();
}
function playErrorSound() {
if (!config.playSoundOnError) return;
errorSound.currentTime = 0;
errorSound.play();
}
async function initPaceCaret(nosave = false) {
let mode2 = "";
if (config.mode === "time") {
mode2 = config.time;
} else if (config.mode === "words") {
mode2 = config.words;
} else if (config.mode === "custom") {
mode2 = "custom";
} else if (config.mode === "quote") {
mode2 = randomQuote.id;
}
let wpm;
if (config.paceCaret === "pb") {
wpm = await db_getLocalPB(
config.mode,
mode2,
config.punctuation,
config.language,
config.difficulty
);
} else if(config.paceCaret === "custom") {
wpm = config.paceCaretCustomSpeed;
}
if (wpm < 1 || wpm == false || wpm == undefined || Number.isNaN(wpm)) {
paceCaret = null;
return;
}
let characters = wpm * 5;
let cps = characters / 60; //characters per step
let spc = 60 / characters; //seconds per character
updateTestModesNotice();
paceCaret = {
cps: cps,
spc: spc,
correction: 0,
currentWordIndex: 0,
currentLetterIndex: -1,
wordsStatus: {},
timeout: null,
};
}
// function movePaceCaret() {
// if (paceCaret === null) {
// return;
// }
// if ($("#paceCaret").hasClass("hidden")) {
// $("#paceCaret").removeClass("hidden");
// }
// try {
// let currentMove = 0;
// let newCurrentWord = paceCaret.currentWordIndex;
// let newCurrentLetter = paceCaret.currentLetterIndex;
// while (currentMove < paceCaret.cps) {
// let currentWordLen;
// try {
// if (newCurrentLetter < 0) {
// currentWordLen = wordsList[newCurrentWord].length;
// } else {
// currentWordLen = wordsList[newCurrentWord].length - newCurrentLetter;
// }
// } catch (e) {
// //out of words
// paceCaret = null;
// $("#paceCaret").addClass("hidden");
// return;
// }
// if (currentMove + currentWordLen <= paceCaret.cps) {
// //good to move
// currentMove += currentWordLen;
// currentMove++; //space
// newCurrentWord++;
// newCurrentLetter = -1;
// } else {
// //too much, need to go sub
// if (currentWordLen === 1) {
// newCurrentWord++;
// currentMove += paceCaret.cps - currentMove;
// newCurrentLetter = -1;
// } else {
// newCurrentLetter += paceCaret.cps - currentMove;
// currentMove += paceCaret.cps - currentMove;
// }
// // newCurrentWord++;
// }
// }
// paceCaret.currentWordIndex = Math.round(newCurrentWord);
// paceCaret.currentLetterIndex = Math.round(newCurrentLetter);
// let caret = $("#paceCaret");
// let currentLetter;
// let newTop;
// let newLeft;
// try {
// if (paceCaret.currentLetterIndex === -1) {
// currentLetter = document
// .querySelectorAll("#words .word")
// [
// paceCaret.currentWordIndex -
// (currentWordIndex - currentWordElementIndex)
// ].querySelectorAll("letter")[0];
// } else {
// currentLetter = document
// .querySelectorAll("#words .word")
// [
// paceCaret.currentWordIndex -
// (currentWordIndex - currentWordElementIndex)
// ].querySelectorAll("letter")[paceCaret.currentLetterIndex];
// }
// newTop = currentLetter.offsetTop - $(currentLetter).height() / 4;
// newLeft;
// if (paceCaret.currentLetterIndex === -1) {
// newLeft = currentLetter.offsetLeft;
// } else {
// newLeft =
// currentLetter.offsetLeft + $(currentLetter).width() - caret.width() / 2;
// }
// }catch(e){}
// let duration = 0;
// if (newTop > document.querySelector("#paceCaret").offsetTop) {
// duration = 0;
// }
// let smoothlinescroll = $("#words .smoothScroller").height();
// if (smoothlinescroll === undefined) smoothlinescroll = 0;
// $("#paceCaret").css({
// top: newTop - smoothlinescroll,
// });
// caret.stop(true, true).animate(
// {
// left: newLeft,
// },
// duration,
// "linear"
// );
// } catch (e) {
// // $("#paceCaret").animate({ opacity: 0 }, 250, () => {
// console.error(e);
// $("#paceCaret").addClass("hidden");
// // });
// }
// }
function movePaceCaret(expectedStepEnd) {
if (paceCaret === null || !testActive || resultVisible) {
return;
}
if ($("#paceCaret").hasClass("hidden")) {
$("#paceCaret").removeClass("hidden");
}
if ($("#paceCaret").hasClass("off")) {
return;
}
try {
paceCaret.currentLetterIndex++;
if (paceCaret.currentLetterIndex >= wordsList[paceCaret.currentWordIndex].length) {
//go to the next word
paceCaret.currentLetterIndex = -1;
paceCaret.currentWordIndex++;
}
if (!config.blindMode) {
if (paceCaret.correction < 0) {
// paceCaret.correction++;
while (paceCaret.correction < 0) {
paceCaret.currentLetterIndex--;
if (paceCaret.currentLetterIndex <= -2) {
//go to the previous word
paceCaret.currentLetterIndex = wordsList[paceCaret.currentWordIndex - 1].length - 1;
paceCaret.currentWordIndex--;
}
paceCaret.correction++;
}
} else if (paceCaret.correction > 0) {
while (paceCaret.correction > 0) {
paceCaret.currentLetterIndex++;
if (paceCaret.currentLetterIndex >= wordsList[paceCaret.currentWordIndex].length) {
//go to the next word
paceCaret.currentLetterIndex = -1;
paceCaret.currentWordIndex++;
}
paceCaret.correction--;
}
}
}
} catch (e) {
//out of words
paceCaret = null;
$("#paceCaret").addClass("hidden");
return;
}
try{
let caret = $("#paceCaret");
let currentLetter;
let newTop;
let newLeft;
try {
if (paceCaret.currentLetterIndex === -1) {
currentLetter = document
.querySelectorAll("#words .word")
[
paceCaret.currentWordIndex -
(currentWordIndex - currentWordElementIndex)
].querySelectorAll("letter")[0];
} else {
currentLetter = document
.querySelectorAll("#words .word")
[
paceCaret.currentWordIndex -
(currentWordIndex - currentWordElementIndex)
].querySelectorAll("letter")[paceCaret.currentLetterIndex];
}
newTop = currentLetter.offsetTop - $(currentLetter).height() / 4;
newLeft;
if (paceCaret.currentLetterIndex === -1) {
newLeft = currentLetter.offsetLeft;
} else {
newLeft =
currentLetter.offsetLeft + $(currentLetter).width() - caret.width() / 2;
}
caret.removeClass('hidden');
} catch (e) {
caret.addClass('hidden');
}
let smoothlinescroll = $("#words .smoothScroller").height();
if (smoothlinescroll === undefined) smoothlinescroll = 0;
$("#paceCaret").css({
top: newTop - smoothlinescroll,
});
let duration = expectedStepEnd - performance.now();
// console.log(duration);
if (config.smoothCaret) {
caret.stop(true, true).animate(
{
left: newLeft,
},
duration,
"linear"
);
} else {
caret.stop(true, true).animate(
{
left: newLeft,
},
0,
"linear"
)
}
paceCaret.timeout = setTimeout(() => {
movePaceCaret(expectedStepEnd + (paceCaret.spc * 1000));
}, duration);
} catch (e) {
// $("#paceCaret").animate({ opacity: 0 }, 250, () => {
console.error(e);
$("#paceCaret").addClass("hidden");
// });
}
}
function resetPaceCaret() {
if (config.paceCaret === "off") return;
if (!$("#paceCaret").hasClass("hidden")) {
$("#paceCaret").addClass("hidden");
}
let caret = $("#paceCaret");
let firstLetter = document
.querySelector("#words .word")
.querySelector("letter");
caret.stop(true, true).animate(
{
top: firstLetter.offsetTop - $(firstLetter).height() / 4,
left: firstLetter.offsetLeft,
},
0,
"linear"
);
}
$("#customMode2PopupWrapper").click((e) => {
if ($(e.target).attr("id") === "customMode2PopupWrapper") {
hideCustomMode2Popup();
}
});
$("#customMode2Popup input").keypress((e) => {
if (e.keyCode == 13) {
applyMode2Popup();
}
});
$("#customMode2Popup .button").click((e) => {
applyMode2Popup();
});
function updateKeytips() {
if (config.swapEscAndTab) {
$(".pageSettings .tip").html(`
tip: You can also change all these settings quickly using the
command line (
tab
)`);
$("#bottom .keyTips").html(`
esc - restart test
tab - command line`);
} else {
$(".pageSettings .tip").html(`
tip: You can also change all these settings quickly using the
command line (
esc
)`);
$("#bottom .keyTips").html(`
tab - restart test
esc - command line`);
}
}
function applyMode2Popup() {
let mode = $("#customMode2Popup").attr("mode");
let val = $("#customMode2Popup input").val();
if (mode == "time") {
if (val !== null && !isNaN(val) && val > 0) {
changeTimeConfig(val);
manualRestart = true;
restartTest();
if (val >= 1800) {
showNotification("Stay safe and take breaks!", 3000);
}
} else {
showNotification("Custom time must be at least 1", 3000);
}
} else if (mode == "words") {
if (val !== null && !isNaN(val) && val > 0) {
changeWordCount(val);
manualRestart = true;
restartTest();
if (val > 2000) {
showNotification("Stay safe and take breaks!", 3000);
}
} else {
showNotification("Custom word amount must be at least 1", 3000);
}
}
hideCustomMode2Popup();
}
$(document).on("click", "#top .logo", (e) => {
changePage("test");
});
$(document).on("click", "#top .config .wordCount .text-button", (e) => {
wrd = $(e.currentTarget).attr("wordCount");
if (wrd == "custom") {
// let newWrd = prompt("Custom word amount");
// if (newWrd !== null && !isNaN(newWrd) && newWrd > 0 && newWrd <= 10000) {
// changeWordCount(newWrd);
// if (newWrd > 2000) {
// showNotification(
// "Very long tests can cause performance issues or crash the website on some machines!",
// 5000
// );
// }
// } else {
// showNotification(
// "Custom word amount can only be set between 1 and 10000",
// 3000
// );
// }
showCustomMode2Popup("words");
} else {
changeWordCount(wrd);
manualRestart = true;
restartTest();
}
});
$(document).on("click", "#top .config .time .text-button", (e) => {
let mode = $(e.currentTarget).attr("timeConfig");
if (mode == "custom") {
// let newTime = prompt("Custom time in seconds");
// if (newTime !== null && !isNaN(newTime) && newTime > 0 && newTime <= 3600) {
// changeTimeConfig(newTime);
// if (newTime >= 1800) {
// showNotification(
// "Very long tests can cause performance issues or crash the website on some machines!",
// 5000
// );
// }
// } else {
// showNotification("Custom time can only be set between 1 and 3600", 3000);
// }
showCustomMode2Popup("time");
} else {
changeTimeConfig(mode);
manualRestart = true;
restartTest();
}
});
$(document).on("click", "#top .config .quoteLength .text-button", (e) => {
let len = $(e.currentTarget).attr("quoteLength");
changeQuoteLength(len);
manualRestart = true;
restartTest();
});
$(document).on("click", "#top .config .customText .text-button", (e) => {
// changeCustomText();
// restartTest();
showCustomTextPopup();
});
$(document).on("click", "#top .config .punctuationMode .text-button", (e) => {
togglePunctuation();
manualRestart = true;
restartTest();
});
$(document).on("click", "#top .config .numbersMode .text-button", (e) => {
toggleNumbers();
manualRestart = true;
restartTest();
});
$("#wordsWrapper").on("click", (e) => {
focusWords();
});
$(document).on("click", "#top .config .mode .text-button", (e) => {
if ($(e.currentTarget).hasClass("active")) return;
mode = $(e.currentTarget).attr("mode");
changeMode(mode);
manualRestart = true;
restartTest();
});
$(document).on("click", "#top #menu .icon-button", (e) => {
if ($(e.currentTarget).hasClass("discord")) return;
if ($(e.currentTarget).hasClass("leaderboards")) {
showLeaderboards();
} else {
href = $(e.currentTarget).attr("href");
manualRestart = true;
changePage(href.replace("/", ""));
}
});
$(window).on("popstate", (e) => {
let state = e.originalEvent.state;
if (state == "" || state == "/") {
// show test
changePage("test");
} else if (state == "about") {
// show about
changePage("about");
} else if (state == "account" || state == "login") {
if (firebase.auth().currentUser) {
changePage("account");
} else {
changePage("login");
}
}
});
$(document).on("keypress", "#restartTestButton", (event) => {
if (event.keyCode == 13) {
if (
(config.mode === "words" && config.words < 1000) ||
(config.mode === "time" && config.time < 3600) ||
config.mode === "quote" ||
(config.mode === "custom" &&
customTextIsRandom &&
customTextWordCount < 1000) ||
(config.mode === "custom" &&
!customTextIsRandom &&
customText.length < 1000)
) {
if (testActive) {
let testNow = Date.now();
let testSeconds = roundTo2((testNow - testStart) / 1000);
incompleteTestSeconds += testSeconds;
restartCount++;
}
restartTest();
} else {
showNotification("Quick restart disabled for long tests", 2000);
}
}
});
$(document.body).on("click", "#restartTestButton", (event) => {
manualRestart = true;
restartTest();
});
$(document).on("keypress", "#practiseMissedWordsButton", (event) => {
if (event.keyCode == 13) {
if (missedWords.length > 0) {
let currentMode = config.mode;
changeMode("custom");
customText = missedWords;
customTextIsRandom = true;
customTextWordCount = 50;
restartTest();
modeBeforePractise = currentMode;
} else {
showNotification("You haven't missed any words.", 2000);
}
}
});
$(document.body).on("click", "#practiseMissedWordsButton", (event) => {
if (missedWords.length > 0) {
let currentMode = config.mode;
changeMode("custom");
customText = missedWords;
customTextIsRandom = true;
customTextWordCount = 50;
restartTest();
modeBeforePractise = currentMode;
} else {
showNotification("You haven't missed any words.", 2000);
}
});
$(document).on("keypress", "#nextTestButton", (event) => {
if (event.keyCode == 13) {
restartTest();
}
});
$(document.body).on("click", "#nextTestButton", (event) => {
manualRestart = true;
restartTest();
});
$(document).on("keypress", "#showWordHistoryButton", (event) => {
if (event.keyCode == 13) {
toggleResultWordsDisplay();
}
});
$(document.body).on("click", "#showWordHistoryButton", (event) => {
toggleResultWordsDisplay();
});
$(document.body).on("click", "#restartTestButtonWithSameWordset", (event) => {
manualRestart = true;
restartTest(true);
});
$(document).on("keypress", "#restartTestButtonWithSameWordset", (event) => {
if (event.keyCode == 13) {
restartTest(true);
}
});
$(document.body).on("click", "#copyResultToClipboardButton", (event) => {
copyResultToClipboard();
});
$(document.body).on("click", ".version", (event) => {
$("#versionHistoryWrapper")
.css("opacity", 0)
.removeClass("hidden")
.animate({ opacity: 1 }, 125);
});
$(document.body).on("click", "#versionHistoryWrapper", (event) => {
$("#versionHistoryWrapper")
.css("opacity", 1)
.animate({ opacity: 0 }, 125, () => {
$("#versionHistoryWrapper").addClass("hidden");
});
});
$("#wordsInput").keypress((event) => {
event.preventDefault();
});
let outOfFocusTimeouts = [];
function clearTimeouts(timeouts) {
timeouts.forEach((to) => {
clearTimeout(to);
to = null;
});
}
$("#wordsInput").on("focus", (event) => {
if (!resultVisible && config.showOutOfFocusWarning) {
$("#words").css("transition", "none").removeClass("blurred");
$(".outOfFocusWarning").addClass("hidden");
clearTimeouts(outOfFocusTimeouts);
}
showCaret();
});
$("#wordsInput").on("focusout", (event) => {
if (!resultVisible && config.showOutOfFocusWarning) {
outOfFocusTimeouts.push(
setTimeout(() => {
$("#words").css("transition", "0.25s").addClass("blurred");
$(".outOfFocusWarning").removeClass("hidden");
}, 1000)
);
}
hideCaret();
});
$(window).resize(() => {
updateCaretPosition();
});
$(document).mousemove(function (event) {
if (
$("#top").hasClass("focus") &&
(event.originalEvent.movementX > 0 || event.originalEvent.movementY > 0)
) {
setFocus(false);
}
});
$(document).on('click', "#testModesNotice .text-button", (event) => {
let commands = eval($(event.currentTarget).attr("commands"));
if (commands !== undefined) {
currentCommands.push(commands);
showCommandLine();
}
})
//keypresses for the test, using different method to be more responsive
$(document).keypress(function (event) {
event = emulateLayout(event);
if (!$("#wordsInput").is(":focus")) return;
if (event["keyCode"] == 13) return;
if (event["keyCode"] == 32) return;
if (event["keyCode"] == 27) return;
if (event.key == "ContextMenu") return;
//start the test
if (currentInput == "" && inputHistory.length == 0 && !testActive) {
startTest();
} else {
if (!testActive) return;
}
let thisCharCorrect;
let nextCharInWord = wordsList[currentWordIndex].substring(
currentInput.length,
currentInput.length + 1
);
if (
config.language === "russian" &&
(event["key"].toLowerCase() == "e" || event["key"].toLowerCase() == "ё")
) {
if (
nextCharInWord.toLowerCase() == "e" ||
nextCharInWord.toLowerCase() == "ё"
) {
thisCharCorrect = true;
} else {
thisCharCorrect = false;
}
} else {
if (nextCharInWord == event["key"]) {
thisCharCorrect = true;
} else {
thisCharCorrect = false;
}
}
if (!thisCharCorrect) {
accuracyStats.incorrect++;
currentError.count++;
currentError.words.push(currentWordIndex);
thisCharCorrect = false;
if (!missedWords.includes(wordsList[currentWordIndex])) {
missedWords.push(wordsList[currentWordIndex]);
}
} else {
accuracyStats.correct++;
thisCharCorrect = true;
}
if (thisCharCorrect) {
playClickSound();
} else {
if (!config.playSoundOnError || config.blindMode) {
playClickSound();
} else {
playErrorSound();
}
}
if (currentCorrected === "") {
currentCorrected = currentInput + event["key"];
} else {
let cil = currentInput.length;
if (cil >= currentCorrected.length) {
currentCorrected += event["key"];
} else if (!thisCharCorrect) {
currentCorrected =
currentCorrected.substring(0, cil) +
event["key"] +
currentCorrected.substring(cil + 1);
}
}
currentKeypress.count++;
currentKeypress.words.push(currentWordIndex);
if (config.stopOnError == "letter" && !thisCharCorrect) {
if (config.difficulty == "master") {
//failed due to master diff when pressing a key
inputHistory.push(currentInput);
correctedHistory.push(currentCorrected);
lastSecondNotRound = true;
showResult(true);
let testNow = Date.now();
let testSeconds = roundTo2((testNow - testStart) / 1000);
incompleteTestSeconds += testSeconds;
restartCount++;
return;
} else {
return;
}
}
if (currentInput.length < wordsList[currentWordIndex].length + 20)
currentInput += event["key"];
setFocus(true);
stopCaretAnimation();
activeWordTopBeforeJump = activeWordTop;
compareInput(!config.blindMode);
// let newActiveTop = $("#words .word.active").position().top;
// console.time("offcheck1");
let newActiveTop = document.querySelector("#words .word.active").offsetTop;
if (activeWordTopBeforeJump < newActiveTop && !lineTransition) {
activeWordJumped = true;
} else {
activeWordJumped = false;
}
// console.timeEnd("offcheck2");
if (config.keymapMode === "react") {
flashPressedKeymapKey(event.key, thisCharCorrect);
} else if (config.keymapMode === "next") {
updateHighlightedKeymapKey();
}
updateCaretPosition();
});
$(document).keydown((event) => {
keypressStats.duration.current = performance.now();
if ($("#wordsInput").is(":focus")) {
try {
if (
!config.capsLockBackspace &&
event.originalEvent.getModifierState("CapsLock")
) {
showCapsWarning();
} else {
hideCapsWarning();
}
} catch (e) {}
}
});
$(document).keyup((event) => {
let now = performance.now();
let diff = Math.abs(keypressStats.duration.current - now);
if (keypressStats.duration.current !== -1) {
keypressStats.duration.array.push(diff);
}
keypressStats.duration.current = now;
});
window.addEventListener("beforeunload", (event) => {
// Cancel the event as stated by the standard.
if (
(config.mode === "words" && config.words < 1000) ||
(config.mode === "time" && config.time < 3600) ||
config.mode === "quote" ||
(config.mode === "custom" &&
customTextIsRandom &&
customTextWordCount < 1000) ||
(config.mode === "custom" &&
!customTextIsRandom &&
customText.length < 1000)
) {
} else {
if (testActive) {
event.preventDefault();
// Chrome requires returnValue to be set.
event.returnValue = "";
}
}
});
//handle keyboard events
$(document).keydown((event) => {
let now = performance.now();
let diff = Math.abs(keypressStats.spacing.current - now);
if (keypressStats.spacing.current !== -1) {
keypressStats.spacing.array.push(diff);
}
keypressStats.spacing.current = now;
//tab
if (
(event["keyCode"] == 9 && !config.swapEscAndTab) ||
(event["keyCode"] == 27 && config.swapEscAndTab)
) {
if (
!event.ctrlKey &&
config.quickTab &&
!$(".pageLogin").hasClass("active") &&
!resultCalculating
) {
event.preventDefault();
if ($(".pageTest").hasClass("active")) {
if (
(config.mode === "words" && config.words < 1000) ||
(config.mode === "time" && config.time < 3600) ||
config.mode === "quote" ||
(config.mode === "custom" &&
customTextIsRandom &&
customTextWordCount < 1000) ||
(config.mode === "custom" &&
!customTextIsRandom &&
customText.length < 1000)
) {
if (testActive) {
let testNow = Date.now();
let testSeconds = roundTo2((testNow - testStart) / 1000);
incompleteTestSeconds += testSeconds;
restartCount++;
}
restartTest();
} else {
showNotification("Quick restart disabled for long tests", 2000);
}
} else {
changePage("test");
}
}
}
//only for the typing test
if ($("#wordsInput").is(":focus")) {
const isBackspace =
event["keyCode"] === 8 ||
(config.capsLockBackspace && event.key === "CapsLock");
if (isBackspace) {
event.preventDefault();
if (!testActive) return;
if (
currentInput == "" &&
inputHistory.length > 0 &&
currentWordElementIndex > 0
) {
if (
(inputHistory[currentWordIndex - 1] ==
wordsList[currentWordIndex - 1] &&
!config.freedomMode) ||
$($(".word")[currentWordIndex - 1]).hasClass("hidden")
) {
return;
} else {
if (config.confidenceMode === "on" || config.confidenceMode === "max")
return;
if (event["ctrlKey"] || event["altKey"]) {
currentInput = "";
inputHistory.pop();
correctedHistory.pop();
} else {
currentInput = inputHistory.pop();
currentCorrected = correctedHistory.pop();
}
currentWordIndex--;
currentWordElementIndex--;
updateActiveElement();
compareInput(!config.blindMode);
}
} else {
if (config.confidenceMode === "max") return;
if (event["ctrlKey"] || event["altKey"]) {
currentInput = "";
} else {
currentInput = currentInput.substring(0, currentInput.length - 1);
}
compareInput(!config.blindMode);
}
playClickSound();
if (config.keymapMode === "react") {
flashPressedKeymapKey(event.code, true);
} else if (config.keymapMode === "next") {
updateHighlightedKeymapKey();
}
updateCaretPosition();
}
//space
if (event["keyCode"] == 32 || event.key === " ") {
if (!testActive) return;
if (currentInput == "") return;
event.preventDefault();
let currentWord = wordsList[currentWordIndex];
// if (config.mode == "time") {
if (!config.showAllLines || config.mode == "time") {
// let currentTop = Math.floor($($("#words .word")[currentWordIndex]).position().top);
// let nextTop = Math.floor($($("#words .word")[currentWordIndex + 1]).position().top);
let currentTop = Math.floor(
document.querySelectorAll("#words .word")[currentWordElementIndex]
.offsetTop
);
let nextTop;
try {
nextTop = Math.floor(
document.querySelectorAll("#words .word")[
currentWordElementIndex + 1
].offsetTop
);
} catch (e) {
nextTop = 0;
}
if ((nextTop > currentTop || activeWordJumped) && !lineTransition) {
//last word of the line
if (currentTestLine > 0) {
let hideBound = currentTop;
if (activeWordJumped) {
hideBound = activeWordTopBeforeJump;
}
activeWordJumped = false;
let toHide = [];
let wordElements = $("#words .word");
for (let i = 0; i < currentWordElementIndex + 1; i++) {
if ($(wordElements[i]).hasClass("hidden")) continue;
// let forWordTop = Math.floor($(wordElements[i]).position().top);
let forWordTop = Math.floor(wordElements[i].offsetTop);
if (forWordTop < hideBound - 10) {
// $($("#words .word")[i]).addClass("hidden");
toHide.push($($("#words .word")[i]));
}
}
const wordHeight = $(document.querySelector(".word")).outerHeight(
true
);
if (config.smoothLineScroll && toHide.length > 0) {
lineTransition = true;
$("#words").prepend(
`
`
);
$("#words .smoothScroller").animate(
{
height: 0,
},
125,
() => {
$("#words .smoothScroller").remove();
}
);
$("#paceCaret").animate({
top: document.querySelector("#paceCaret").offsetTop - wordHeight,
},125);
$("#words").animate(
{
marginTop: `-${wordHeight}px`,
},
125,
() => {
activeWordTop = document.querySelector("#words .active")
.offsetTop;
currentWordElementIndex -= toHide.length;
lineTransition = false;
toHide.forEach((el) => el.remove());
$("#words").css("marginTop", "0");
}
);
} else {
toHide.forEach((el) => el.remove());
currentWordElementIndex -= toHide.length;
$("#paceCaret").css({
top: document.querySelector("#paceCaret").offsetTop - wordHeight,
});
}
// if (config.smoothLineScroll) {
// let word = $(document.querySelector(".word"));
// $("#words").prepend(
// `
`
// );
// lineTransition = true;
// $("#words .smoothScroller").animate(
// {
// height: 0,
// },
// 100,
// () => {
// $("#words .smoothScroller").remove();
// lineTransition = false;
// $(this).remove();
// activeWordTop = document.querySelector("#words .active")
// .offsetTop;
// }
// );
// }
// toHide.forEach((el) => el.remove());
}
currentTestLine++;
}
} //end of line wrap
if (activeFunBox === "layoutfluid" && config.mode !== "time") {
const layouts = ["qwerty", "dvorak", "colemak"];
let index = 0;
let outof = wordsList.length;
index = Math.floor((inputHistory.length + 1) / (outof / 3));
if (config.layout !== layouts[index] && layouts[index] !== undefined) {
showNotification(`--- !!! ${layouts[index]} !!! ---`, 3000);
}
changeLayout(layouts[index]);
changeKeymapLayout(layouts[index]);
updateHighlightedKeymapKey();
settingsGroups.layout.updateButton();
}
if (config.blindMode) $("#words .word.active letter").addClass("correct");
// document
// .querySelector("#words .word.active")
// .setAttribute("input", currentInput);
if (currentWord == currentInput) {
//correct word
if (paceCaret !== null && paceCaret.wordsStatus[currentWordIndex] === true && !config.blindMode) {
paceCaret.wordsStatus[currentWordIndex] = undefined;
paceCaret.correction -= currentWord.length + 1;
}
accuracyStats.correct++;
inputHistory.push(currentInput);
currentInput = "";
currentWordIndex++;
currentWordElementIndex++;
updateActiveElement();
updateCaretPosition();
currentKeypress.count++;
currentKeypress.words.push(currentWordIndex);
playClickSound();
} else {
//incorrect word
if (paceCaret !== null && paceCaret.wordsStatus[currentWordIndex] === undefined && !config.blindMode) {
paceCaret.wordsStatus[currentWordIndex] = true;
paceCaret.correction += currentWord.length + 1;
}
if (!config.playSoundOnError || config.blindMode) {
playClickSound();
} else {
playErrorSound();
}
accuracyStats.incorrect++;
let cil = currentInput.length;
if (cil < wordsList[currentWordIndex].length) {
if (cil >= currentCorrected.length) {
currentCorrected += "_";
} else {
currentCorrected =
currentCorrected.substring(0, cil) +
"_" +
currentCorrected.substring(cil + 1);
}
}
if (config.stopOnError != "off") {
if (config.difficulty == "expert" || config.difficulty == "master") {
//failed due to diff when pressing space
inputHistory.push(currentInput);
correctedHistory.push(currentCorrected);
lastSecondNotRound = true;
showResult(true);
// if (!afkDetected) {
let testNow = Date.now();
let testSeconds = roundTo2((testNow - testStart) / 1000);
incompleteTestSeconds += testSeconds;
restartCount++;
// }
return;
}
return;
}
inputHistory.push(currentInput);
highlightBadWord(currentWordElementIndex, !config.blindMode);
currentInput = "";
currentWordIndex++;
currentWordElementIndex++;
if (
config.difficulty == "expert" ||
config.difficulty == "master"
) {
correctedHistory.push(currentCorrected);
currentCorrected = "";
//submitted last word incorrect and failed test
lastSecondNotRound = true;
showResult(true);
// if (!afkDetected) {
let testNow = Date.now();
let testSeconds = roundTo2((testNow - testStart) / 1000);
incompleteTestSeconds += testSeconds;
restartCount++;
// }
return;
}else if (currentWordIndex == wordsList.length) {
//submitted last word that is incorrect
lastSecondNotRound = true;
showResult();
return;
}
updateActiveElement();
updateCaretPosition();
currentKeypress.count++;
currentKeypress.words.push(currentWordIndex);
}
correctedHistory.push(currentCorrected);
currentCorrected = "";
if (config.keymapMode === "react") {
flashPressedKeymapKey(event.code, true);
} else if (config.keymapMode === "next") {
updateHighlightedKeymapKey();
}
if (
config.mode === "words" ||
config.mode === "custom" ||
config.mode === "quote"
) {
updateTimer();
}
// if (config.showAllLines) {
// if (config.mode == "time") {
// addWord();
// }
// } else {
if (
config.mode == "time" ||
config.mode == "words" ||
config.mode == "custom"
) {
addWord();
}
// }
}
}
});
if (firebase.app().options.projectId === "monkey-type-dev-67af4") {
$("#top .logo .bottom").text("monkey-dev");
$("head title").text("Monkey Dev");
$("body").append(
`
DEV
DEV
`
);
}
if (window.location.hostname === "localhost") {
window.onerror = function (error) {
this.showNotification(error, 3000);
};
$("#top .logo .top").text("localhost");
$("head title").text($("head title").text() + " (localhost)");
firebase.functions().useFunctionsEmulator("http://localhost:5001");
$("body").append(
`
local
local
`
);
}
loadConfigFromCookie();
getReleasesFromGitHub();
getPatreonNames();
$(document).on("mouseenter", "#resultWordsHistory .words .word", (e) => {
if (resultVisible) {
let input = $(e.currentTarget).attr("input");
if (input != undefined)
$(e.currentTarget).append(`
${input}
`);
}
});
$(document).on("click", "#bottom .leftright .right .current-theme", (e) => {
if (config.customTheme) {
togglePresetCustomTheme();
}
currentCommands.push(commandsThemes);
showCommandLine();
});
$(document).on("mouseleave", "#resultWordsHistory .words .word", (e) => {
$(".wordInputAfter").remove();
});
$("#wpmChart").on("mouseleave", (e) => {
$(".wordInputAfter").remove();
});
$(document).ready(() => {
updateFavicon(32, 14);
$("body").css("transition", ".25s");
manualRestart = true;
restartTest(false,true);
if (config.quickTab) {
$("#restartTestButton").addClass("hidden");
}
$("#centerContent")
.css("opacity", "0")
.removeClass("hidden")
.stop(true, true)
.animate({ opacity: 1 }, 250, () => {
let theme = findGetParameter("customTheme");
if (theme !== null) {
try {
theme = theme.split(",");
config.customThemeColors = theme;
showNotification("Custom theme applied", 1000);
} catch (e) {
showNotification(
"Something went wrong. Reverting to default custom colors.",
3000
);
config.customThemeColors = defaultConfig.customThemeColors;
}
setCustomTheme(true);
setCustomThemeInputs();
applyCustomThemeColors();
}
if (window.location.pathname === "/verify") {
const fragment = new URLSearchParams(window.location.hash.slice(1));
if (fragment.has("access_token")) {
const accessToken = fragment.get("access_token");
const tokenType = fragment.get("token_type");
verifyUserWhenLoggedIn = {
accessToken: accessToken,
tokenType: tokenType
}
history.replaceState("/", null, "/");
}
}else if (window.location.pathname === "/account") {
history.replaceState("/", null, "/");
} else if (window.location.pathname !== "/") {
let page = window.location.pathname.replace("/", "");
changePage(page);
}
});
});
$(".scrollToTopButton").click((event) => {
window.scrollTo(0, 0);
});
$(".pageTest #copyWordsListButton").click(async (event) => {
try {
await navigator.clipboard.writeText(
wordsList.slice(0, inputHistory.length).join(" ")
);
showNotification("Copied to clipboard", 1000);
} catch (e) {
showNotification("Could not copy to clipboard: " + e, 5000);
}
});
let ctx = $("#wpmChart");
let wpmOverTimeChart = new Chart(ctx, {
type: "line",
data: {
labels: [],
datasets: [
{
label: "wpm",
data: [],
// backgroundColor: 'rgba(255, 255, 255, 0.25)',
borderColor: "rgba(125, 125, 125, 1)",
borderWidth: 2,
yAxisID: "wpm",
order: 2,
radius: 2,
},
{
label: "raw",
data: [],
// backgroundColor: 'rgba(255, 255, 255, 0.25)',
borderColor: "rgba(125, 125, 125, 1)",
borderWidth: 2,
yAxisID: "raw",
order: 3,
radius: 2,
},
{
label: "errors",
data: [],
// backgroundColor: 'rgba(255, 255, 255, 0.25)',
borderColor: "rgba(255, 125, 125, 1)",
pointBackgroundColor: "rgba(255, 125, 125, 1)",
borderWidth: 2,
order: 1,
yAxisID: "error",
// barPercentage: 0.1,
maxBarThickness: 10,
type: "scatter",
pointStyle: "crossRot",
radius: function (context) {
var index = context.dataIndex;
var value = context.dataset.data[index];
return value.y <= 0 ? 0 : 3;
},
pointHoverRadius: function (context) {
var index = context.dataIndex;
var value = context.dataset.data[index];
return value.y <= 0 ? 0 : 5;
},
},
],
},
options: {
tooltips: {
titleFontFamily: "Roboto Mono",
bodyFontFamily: "Roboto Mono",
mode: "index",
intersect: false,
callbacks: {
afterLabel: function (ti, data) {
try {
$(".wordInputAfter").remove();
let wordsToHighlight =
keypressPerSecond[parseInt(ti.xLabel) - 1].words;
let unique = [...new Set(wordsToHighlight)];
unique.forEach((wordIndex) => {
let wordEl = $($("#resultWordsHistory .words .word")[wordIndex]);
let input = wordEl.attr("input");
if (input != undefined)
wordEl.append(`
${input}
`);
});
} catch (e) {}
},
},
},
legend: {
display: false,
labels: {
defaultFontFamily: "Roboto Mono",
},
},
responsive: true,
maintainAspectRatio: false,
// hover: {
// mode: 'x',
// intersect: false
// },
scales: {
xAxes: [
{
ticks: {
fontFamily: "Roboto Mono",
autoSkip: true,
autoSkipPadding: 40,
},
display: true,
scaleLabel: {
display: false,
labelString: "Seconds",
fontFamily: "Roboto Mono",
},
},
],
yAxes: [
{
id: "wpm",
display: true,
scaleLabel: {
display: true,
labelString: "Words per Minute",
fontFamily: "Roboto Mono",
},
ticks: {
fontFamily: "Roboto Mono",
beginAtZero: true,
min: 0,
autoSkip: true,
autoSkipPadding: 40,
},
gridLines: {
display: true,
},
},
{
id: "raw",
display: false,
scaleLabel: {
display: true,
labelString: "Raw Words per Minute",
fontFamily: "Roboto Mono",
},
ticks: {
fontFamily: "Roboto Mono",
beginAtZero: true,
min: 0,
autoSkip: true,
autoSkipPadding: 40,
},
gridLines: {
display: false,
},
},
{
id: "error",
display: true,
position: "right",
scaleLabel: {
display: true,
labelString: "Errors",
fontFamily: "Roboto Mono",
},
ticks: {
precision: 0,
fontFamily: "Roboto Mono",
beginAtZero: true,
autoSkip: true,
autoSkipPadding: 40,
},
gridLines: {
display: false,
},
},
],
},
annotation: {
annotations: [
{
enabled: false,
type: "line",
mode: "horizontal",
scaleID: "wpm",
value: "-30",
borderColor: "red",
borderWidth: 1,
borderDash: [2, 2],
label: {
// Background color of label, default below
backgroundColor: "blue",
fontFamily: "Roboto Mono",
// Font size of text, inherits from global
fontSize: 11,
// Font style of text, default below
fontStyle: "normal",
// Font color of text, default below
fontColor: "#fff",
// Padding of label to add left/right, default below
xPadding: 6,
// Padding of label to add top/bottom, default below
yPadding: 6,
// Radius of label rectangle, default below
cornerRadius: 3,
// Anchor position of label on line, can be one of: top, bottom, left, right, center. Default below.
position: "center",
// Whether the label is enabled and should be displayed
enabled: true,
// Text to display in label - default is null. Provide an array to display values on a new line
content: "PB",
},
},
],
},
},
});