mirror of
https://github.com/monkeytypegame/monkeytype.git
synced 2026-01-05 06:54:36 +08:00
added burst heatmap to the result screen
This commit is contained in:
parent
a4dc77d059
commit
43fcaf5950
5 changed files with 186 additions and 9 deletions
|
|
@ -371,6 +371,17 @@ export function mean(array) {
|
|||
}
|
||||
}
|
||||
|
||||
//https://www.w3resource.com/javascript-exercises/fundamental/javascript-fundamental-exercise-88.php
|
||||
export function median (arr) {
|
||||
try{
|
||||
const mid = Math.floor(arr.length / 2),
|
||||
nums = [...arr].sort((a, b) => a - b);
|
||||
return arr.length % 2 !== 0 ? nums[mid] : (nums[mid - 1] + nums[mid]) / 2;
|
||||
}catch(e){
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
export function getReleasesFromGitHub() {
|
||||
$.getJSON(
|
||||
"https://api.github.com/repos/Miodec/monkeytype/releases",
|
||||
|
|
|
|||
|
|
@ -1945,9 +1945,13 @@ export function finish(difficultyFailed = false) {
|
|||
TestUI.setResultCalculating(false);
|
||||
$("#words").empty();
|
||||
ChartController.result.resize();
|
||||
|
||||
if (Config.alwaysShowWordsHistory) {
|
||||
TestUI.toggleResultWords();
|
||||
}
|
||||
if(TestUI.heatmapEnabled){
|
||||
TestUI.applyBurstHeatmap();
|
||||
}
|
||||
$("#testModesNotice").addClass("hidden");
|
||||
},
|
||||
() => {
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import * as ManualRestart from "./manual-restart-tracker";
|
|||
import * as PractiseMissed from "./practise-missed";
|
||||
import * as Replay from "./replay";
|
||||
import * as TestStats from "./test-stats";
|
||||
import * as Misc from './misc';
|
||||
|
||||
export let currentWordElementIndex = 0;
|
||||
export let resultVisible = false;
|
||||
|
|
@ -783,6 +784,88 @@ export function toggleResultWords() {
|
|||
}
|
||||
}
|
||||
}
|
||||
export let heatmapEnabled = false;
|
||||
function toggleBurstHeatmap(){
|
||||
if(!heatmapEnabled){
|
||||
applyBurstHeatmap();
|
||||
}else{
|
||||
//clear all classes
|
||||
$("#resultWordsHistory .heatmapLegend").addClass('hidden');
|
||||
$('#resultWordsHistory .words .word').removeClass("heatmap-0");
|
||||
$('#resultWordsHistory .words .word').removeClass("heatmap-1");
|
||||
$('#resultWordsHistory .words .word').removeClass("heatmap-2");
|
||||
$('#resultWordsHistory .words .word').removeClass("heatmap-3");
|
||||
$('#resultWordsHistory .words .word').removeClass("heatmap-4");
|
||||
|
||||
}
|
||||
heatmapEnabled = !heatmapEnabled;
|
||||
}
|
||||
|
||||
export function applyBurstHeatmap(){
|
||||
$("#resultWordsHistory .heatmapLegend").removeClass('hidden');
|
||||
let min = Math.min(...TestStats.burstHistory);
|
||||
let max = Math.max(...TestStats.burstHistory);
|
||||
// let step = (max - min) / 5;
|
||||
// let steps = [
|
||||
// {
|
||||
// val: min,
|
||||
// class: 'heatmap-0'
|
||||
// },
|
||||
// {
|
||||
// val: min + (step * 1),
|
||||
// class: 'heatmap-1'
|
||||
// },
|
||||
// {
|
||||
// val: min + (step * 2),
|
||||
// class: 'heatmap-2'
|
||||
// },
|
||||
// {
|
||||
// val: min + (step * 3),
|
||||
// class: 'heatmap-3'
|
||||
// },
|
||||
// {
|
||||
// val: min + (step * 4),
|
||||
// class: 'heatmap-4'
|
||||
// },
|
||||
// ];
|
||||
let median = Misc.median(TestStats.burstHistory);
|
||||
let adatm = [];
|
||||
TestStats.burstHistory.forEach(burst => {
|
||||
adatm.push(Math.abs(median - burst));
|
||||
})
|
||||
let step = Misc.mean(adatm);
|
||||
// let step = Misc.stdDev(TestStats.burstHistory)/2;
|
||||
let steps = [
|
||||
{
|
||||
val: 0,
|
||||
class: 'heatmap-0'
|
||||
},
|
||||
{
|
||||
val: median - (step * 1.5),
|
||||
class: 'heatmap-1'
|
||||
},
|
||||
{
|
||||
val: median - (step * 0.5),
|
||||
class: 'heatmap-2'
|
||||
},
|
||||
{
|
||||
val: median + (step * 0.5),
|
||||
class: 'heatmap-3'
|
||||
},
|
||||
{
|
||||
val: median + (step * 1.5),
|
||||
class: 'heatmap-4'
|
||||
},
|
||||
];
|
||||
$('#resultWordsHistory .words .word').each((index, word) => {
|
||||
let wordBurstVal = parseInt($(word).attr('burst'));
|
||||
let cls = '';
|
||||
steps.forEach(step => {
|
||||
if(wordBurstVal > step.val) cls = step.class;
|
||||
})
|
||||
$(word).addClass(cls);
|
||||
})
|
||||
}
|
||||
|
||||
export function highlightBadWord(index, showError) {
|
||||
if (!showError) return;
|
||||
|
|
@ -819,6 +902,11 @@ $(".pageTest #copyWordsListButton").click(async (event) => {
|
|||
}
|
||||
});
|
||||
|
||||
|
||||
$(".pageTest #toggleBurstHeatmap").click(async (event) => {
|
||||
toggleBurstHeatmap();
|
||||
});
|
||||
|
||||
$(document).on("mouseleave", "#resultWordsHistory .words .word", (e) => {
|
||||
$(".wordInputAfter").remove();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1879,6 +1879,43 @@ key {
|
|||
// grid-area: wordsHistory;
|
||||
color: var(--sub-color);
|
||||
grid-column: 1/3;
|
||||
.heatmapLegend{
|
||||
display: inline-grid;
|
||||
grid-template-columns: auto auto auto;
|
||||
gap: 1rem;
|
||||
font-size: .75rem;
|
||||
color: var(--sub-color);
|
||||
width: min-content;
|
||||
.boxes{
|
||||
display: flex;
|
||||
.box{
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
}
|
||||
.box:nth-child(1){
|
||||
background: var(--colorful-error-color);
|
||||
border-radius: var(--roundness) 0 0 var(--roundness);
|
||||
}
|
||||
.box:nth-child(2){
|
||||
background: var(--colorful-error-color);
|
||||
filter: opacity(0.6);
|
||||
}
|
||||
.box:nth-child(3){
|
||||
background: var(--sub-color);
|
||||
}
|
||||
.box:nth-child(4){
|
||||
background: var(--main-color);
|
||||
filter: opacity(0.6);
|
||||
}
|
||||
.box:nth-child(5){
|
||||
background: var(--main-color);
|
||||
border-radius: 0 var(--roundness) var(--roundness) 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
.title{
|
||||
user-select: none;
|
||||
}
|
||||
.words {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
|
@ -1888,6 +1925,32 @@ key {
|
|||
.word {
|
||||
position: relative;
|
||||
margin: 0.18rem 0.6rem 0.15rem 0;
|
||||
letter.correct {
|
||||
color: var(--text-color);
|
||||
}
|
||||
letter.incorrect {
|
||||
color: var(--error-color);
|
||||
}
|
||||
letter.incorrect.extra {
|
||||
color: var(--error-extra-color);
|
||||
}
|
||||
&.heatmap-0 letter{
|
||||
color: var(--colorful-error-color);
|
||||
}
|
||||
&.heatmap-1 letter{
|
||||
color: var(--colorful-error-color);
|
||||
filter: opacity(0.6);
|
||||
}
|
||||
&.heatmap-2 letter{
|
||||
color: var(--sub-color);
|
||||
}
|
||||
&.heatmap-3 letter{
|
||||
color: var(--main-color);
|
||||
filter: opacity(0.6);
|
||||
}
|
||||
&.heatmap-4 letter{
|
||||
color: var(--main-color);
|
||||
}
|
||||
}
|
||||
&.rightToLeftTest {
|
||||
//flex-direction: row-reverse; // no need for hacking 😉, CSS fully support right-to-left languages
|
||||
|
|
@ -1903,15 +1966,6 @@ key {
|
|||
}
|
||||
}
|
||||
}
|
||||
.correct {
|
||||
color: var(--text-color);
|
||||
}
|
||||
.incorrect {
|
||||
color: var(--error-color);
|
||||
}
|
||||
.incorrect.extra {
|
||||
color: var(--error-extra-color);
|
||||
}
|
||||
}
|
||||
|
||||
.chart {
|
||||
|
|
|
|||
|
|
@ -1440,6 +1440,26 @@
|
|||
>
|
||||
<i class="fas fa-copy"></i>
|
||||
</span>
|
||||
<span
|
||||
id="toggleBurstHeatmap"
|
||||
class="icon-button"
|
||||
aria-label="Toggle burst heatmap"
|
||||
data-balloon-pos="up"
|
||||
style="display: inline-block"
|
||||
>
|
||||
<i class="fas fa-fire-alt"></i>
|
||||
</span>
|
||||
<div class="heatmapLegend hidden">
|
||||
<div>slow</div>
|
||||
<div class="boxes">
|
||||
<div class="box"></div>
|
||||
<div class="box"></div>
|
||||
<div class="box"></div>
|
||||
<div class="box"></div>
|
||||
<div class="box"></div>
|
||||
</div>
|
||||
<div>fast</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="words"></div>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue