From b2e2aa17b803fe12a5104027f6c865afd655afd1 Mon Sep 17 00:00:00 2001 From: gaetan Date: Thu, 23 Apr 2026 10:37:14 +0200 Subject: [PATCH 01/17] Format with Biome --- keyboard_svg.js | 5954 +++++++++++++++++++++++++++++------------------ 1 file changed, 3673 insertions(+), 2281 deletions(-) diff --git a/keyboard_svg.js b/keyboard_svg.js index f5de4fa..ca8be36 100644 --- a/keyboard_svg.js +++ b/keyboard_svg.js @@ -1,13 +1,12 @@ - const params = new Proxy(new URLSearchParams(window.location.search), { - get: (searchParams, prop) => searchParams.get(prop), + get: (searchParams, prop) => searchParams.get(prop), }); var url_layout = params.layout; var swidth = 1000; var sheight = 180; const w = 38; -const inv_w = 1.0 / 38 +const inv_w = 1.0 / 38; const nb_row = 3; const nb_columns = 12; const gap = 8; @@ -26,247 +25,273 @@ var sh_scroll_amount = 0; var trigram_scroll_amount = 0; var green = 128; var mode = params.mode; -if (!mode){ mode = "ergo" } +if (!mode) { + mode = "ergo"; +} var thumb = params.thumb; -if (!thumb){ thumb = "l" } +if (!thumb) { + thumb = "l"; +} var lang = "english"; var needs_update = true; -function scroll(event){ - event.preventDefault(); - // - const svgRect = el.getBoundingClientRect(); - const mouseX = event.clientX - svgRect.left; - const mouseY = event.clientY - svgRect.top; - if (mouseX > 570 && mouseX < 770 && mouseY > 345){ - hw_scroll_amount += Math.sign(event.deltaY); - if (hw_scroll_amount < 0){hw_scroll_amount = 0;} - } else if (mouseX > 200 && mouseX < 430 && mouseY > 345){ - sh_scroll_amount += Math.sign(event.deltaY); - if (sh_scroll_amount < 0){sh_scroll_amount = 0;} - } else if (mouseX > 780 && mouseX < 970 && mouseY > 345){ - trigram_scroll_amount += Math.sign(event.deltaY); - if (trigram_scroll_amount < 0){trigram_scroll_amount = 0;} - } else { - scroll_amount += Math.sign(event.deltaY); - if (scroll_amount < 0){scroll_amount = 0;} - if (scroll_amount > 50){scroll_amount = 50;} - } - generatePlots(); +function scroll(event) { + event.preventDefault(); + // + const svgRect = el.getBoundingClientRect(); + const mouseX = event.clientX - svgRect.left; + const mouseY = event.clientY - svgRect.top; + if (mouseX > 570 && mouseX < 770 && mouseY > 345) { + hw_scroll_amount += Math.sign(event.deltaY); + if (hw_scroll_amount < 0) { + hw_scroll_amount = 0; + } + } else if (mouseX > 200 && mouseX < 430 && mouseY > 345) { + sh_scroll_amount += Math.sign(event.deltaY); + if (sh_scroll_amount < 0) { + sh_scroll_amount = 0; + } + } else if (mouseX > 780 && mouseX < 970 && mouseY > 345) { + trigram_scroll_amount += Math.sign(event.deltaY); + if (trigram_scroll_amount < 0) { + trigram_scroll_amount = 0; + } + } else { + scroll_amount += Math.sign(event.deltaY); + if (scroll_amount < 0) { + scroll_amount = 0; + } + if (scroll_amount > 50) { + scroll_amount = 50; + } + } + generatePlots(); } -var svg = d3.select("#svglayout").append("svg").attr("xmlns","http://www.w3.org/2000/svg").attr("width", swidth).attr("height", sheight); +var svg = d3 + .select("#svglayout") + .append("svg") + .attr("xmlns", "http://www.w3.org/2000/svg") + .attr("width", swidth) + .attr("height", sheight); -var stats = d3.select("#svgstats").append("svg").attr("width", swidth).attr("height", 600) +var stats = d3 + .select("#svgstats") + .append("svg") + .attr("width", swidth) + .attr("height", 600); const el = document.querySelector("#svgstats"); el.onwheel = scroll; -const word_list_url = 'words-'+lang+'.json'; -const dictionary_url = 'dictionary.json'; -const effort_url = 'bigram_effort.json'; +const word_list_url = `words-${lang}.json`; +const dictionary_url = "dictionary.json"; +const effort_url = "bigram_effort.json"; let words = {}; let dictionary = []; var dictionaryloaded = false; var effortloaded = false; let bigram_effort = {}; -function fetchData(){ - fetch(word_list_url) - .then(response => response.json()) - .then(data => { - words = data; // Assign data to the global variable - console.log("fetchData"); - dataloaded = true; - needs_update = true; - }) - .catch(error => console.error('Error loading JSON file:', error)); +function fetchData() { + fetch(word_list_url) + .then((response) => response.json()) + .then((data) => { + words = data; // Assign data to the global variable + console.log("fetchData"); + dataloaded = true; + needs_update = true; + }) + .catch((error) => console.error("Error loading JSON file:", error)); } -function fetchDictionary(){ - fetch(dictionary_url) - .then(response => response.json()) - .then(data => { - if (data["dictionary"]){ - dictionary = data["dictionary"]; // Assign data to the global variable - } else { - console.log("something went wrong with loading the dictionary"); - } - console.log("fetchDictionary"); - dictionaryloaded = true; - needs_update = true; - }) - .catch(error => console.error('Error loading dictionary JSON file:', error)); +function fetchDictionary() { + fetch(dictionary_url) + .then((response) => response.json()) + .then((data) => { + if (data.dictionary) { + dictionary = data.dictionary; // Assign data to the global variable + } else { + console.log("something went wrong with loading the dictionary"); + } + console.log("fetchDictionary"); + dictionaryloaded = true; + needs_update = true; + }) + .catch((error) => + console.error("Error loading dictionary JSON file:", error), + ); } async function loadAllData() { - try { - const [wordsData, dictionaryData, effortData] = await Promise.all([ - fetch(word_list_url).then(response => response.json()), - fetch(dictionary_url).then(response => response.json()), - fetch(effort_url).then(response => response.json()) - ]); - - // Assign the data to the global variables - words = wordsData; - dictionary = dictionaryData.dictionary || []; - bigram_effort = effortData; - - console.log("All data loaded successfully!"); - - dataloaded = true; - dictionaryloaded = true; - effortloaded = true; - setMode(); - generateCoords(); - measureDictionary(); - measureWords(); - generateLayout(); - generatePlots(); - - } catch (error) { - console.error('Error loading data:', error); - } + try { + const [wordsData, dictionaryData, effortData] = await Promise.all([ + fetch(word_list_url).then((response) => response.json()), + fetch(dictionary_url).then((response) => response.json()), + fetch(effort_url).then((response) => response.json()), + ]); + + // Assign the data to the global variables + words = wordsData; + dictionary = dictionaryData.dictionary || []; + bigram_effort = effortData; + + console.log("All data loaded successfully!"); + + dataloaded = true; + dictionaryloaded = true; + effortloaded = true; + setMode(); + generateCoords(); + measureDictionary(); + measureWords(); + generateLayout(); + generatePlots(); + } catch (error) { + console.error("Error loading data:", error); + } } function selectLanguage(lan, event) { - lang = lan - var queryParams = new URLSearchParams(window.location.search); - queryParams.set("lan",lang) - history.replaceState(null, null, "?"+queryParams.toString()); - - var word_list = 'words-'+lan+'.json'; - console.log("============ "+lan.toUpperCase()+" ============") - fetch(word_list) - .then(response => response.json()) - .then(data => { - if (event && event.ctrlKey){ - console.log("adding "+lan+" to words") - for (let word in data) { - if (words[word]){ - words[word] += data[word] - } else { - words[word] = data[word] - } - } - document.getElementById("langDropDown").innerHTML += ("+"+lan.charAt(0).toUpperCase() + lan.substr(1).toLowerCase()); - } else { - words = data; // Assign data to the global variable - document.getElementById("langDropDown").innerHTML = lan.charAt(0).toUpperCase() + lan.substr(1).toLowerCase(); - } - needs_update = true; - console.log("fetchData"); - dataloaded = true; - updateRcData(lan); - setMode(); - getDictionaryFromWords(); - dictionaryloaded = true; - measureDictionary(); - measureWords(); - generateLayout(); - generatePlots(); - }) - .catch(error => console.error('Error loading JSON file:', error)); + lang = lan; + var queryParams = new URLSearchParams(window.location.search); + queryParams.set("lan", lang); + history.replaceState(null, null, "?" + queryParams.toString()); + + var word_list = `words-${lan}.json`; + console.log(`============ ${lan.toUpperCase()} ============`); + fetch(word_list) + .then((response) => response.json()) + .then((data) => { + if (event?.ctrlKey) { + console.log("adding " + lan + " to words"); + for (const word in data) { + if (words[word]) { + words[word] += data[word]; + } else { + words[word] = data[word]; + } + } + document.getElementById("langDropDown").innerHTML += + "+" + lan.charAt(0).toUpperCase() + lan.substr(1).toLowerCase(); + } else { + words = data; // Assign data to the global variable + document.getElementById("langDropDown").innerHTML = + lan.charAt(0).toUpperCase() + lan.substr(1).toLowerCase(); + } + needs_update = true; + console.log("fetchData"); + dataloaded = true; + updateRcData(lan); + setMode(); + getDictionaryFromWords(); + dictionaryloaded = true; + measureDictionary(); + measureWords(); + generateLayout(); + generatePlots(); + }) + .catch((error) => console.error("Error loading JSON file:", error)); } makeDraggable(svg.node()); // col 0 1 2 3 4 5 6 7 8 9 10 11 var fingerAssignment = [ - [1, 1, 2, 3, 4, 4, 7, 7, 8, 9, 10, 10, 10], - [1, 1, 2, 3, 4, 4, 7, 7, 8, 9, 10, 10, 10], - [1, 1, 2, 3, 4, 4, 7, 7, 8, 9, 10, 10, 10] - ] + [1, 1, 2, 3, 4, 4, 7, 7, 8, 9, 10, 10, 10], + [1, 1, 2, 3, 4, 4, 7, 7, 8, 9, 10, 10, 10], + [1, 1, 2, 3, 4, 4, 7, 7, 8, 9, 10, 10, 10], +]; // var hand = [1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2] // char, row, col, freq, y, x, width, keyname var rcdata = [ - ["q", 0, 1, 0.06607202, 0, 0, 1, 0], - ["w", 0, 2, 2.775025, 0, 0, 1, 1], - ["e", 0, 3, 11.870939, 0, 0, 1, 2], - ["r", 0, 4, 4.988437, 0, 0, 1, 3], - ["t", 0, 5, 9.547406, 0, 0, 1, 4], - ["y", 0, 6, 1.7949564, 0, 0, 1, 5], - ["u", 0, 7, 2.7419887, 0, 0, 1, 6], - ["i", 0, 8, 6.177734, 0, 0, 1, 7], - ["o", 0, 9, 7.6643543, 0, 0, 1, 8], - ["p", 0, 10, 1.4425724, 0, 0, 1, 9], - ["-", 0, 11, 0.2753001, 0, 0, 1, 10], - ["a", 1, 1, 7.466138, 0, 0, 1, 11], - ["s", 1, 2, 5.5720735, 0, 0, 1, 12], - ["d", 1, 3, 4.2616453, 0, 0, 1, 13], - ["f", 1, 4, 2.0482326, 0, 0, 1, 14], - ["g", 1, 5, 2.2244246, 0, 0, 1, 15], - ["h", 1, 6, 6.519106, 0, 0, 1, 16], - ["j", 1, 7, 0.06607202, 0, 0, 1, 17], - ["k", 1, 8, 1.0571523, 0, 0, 1, 18], - ["l", 1, 9, 4.6030173, 0, 0, 1, 19], - [";", 1, 10, 0.4184561, 0, 0, 1, 20], - ["'", 1, 11, 0.3523841, 0, 0, 1, 21], - ["z", 2, 1, 0.04404801, 0, 0, 1, 22], - ["x", 2, 2, 0.07708402, 0, 0, 1, 23], - ["c", 2, 3, 1.8830525, 0, 0, 1, 24], - ["v", 2, 4, 0.7488162, 0, 0, 1, 25], - ["b", 2, 5, 1.5526924, 0, 0, 1, 26], - ["n", 2, 6, 6.1446977, 0, 0, 1, 27], - ["m", 2, 7, 1.5857284, 0, 0, 1, 28], - [",", 2, 8, 1.9601365, 0, 0, 1, 29], - [".", 2, 9, 0.48452812, 0, 0, 1, 30], - ["/", 2, 10, 0.14315604, 0, 0, 1, 31], - ["\\", 2, 0, 0, 0, 0, 1, 32], - ["^", 3, 4, 0, 0, 0, 1, 33], - ["tab", 0, 0, 0, 0, 0, 1, 34], - ["$", 1, 0, 0, 0, 0, 1, 35], - ["enter", 2, 11, 0, 0, 0, 1, 36], - ["mod", 3, 5, 0, 0, 0, 1, 37], - ["back", 3, 6, 0, 0, 0, 1, 38], - ["space", 3, 7, 0, 0, 0, 1, 39], -] -const rcdata_len = rcdata.length // Compute once + ["q", 0, 1, 0.06607202, 0, 0, 1, 0], + ["w", 0, 2, 2.775025, 0, 0, 1, 1], + ["e", 0, 3, 11.870939, 0, 0, 1, 2], + ["r", 0, 4, 4.988437, 0, 0, 1, 3], + ["t", 0, 5, 9.547406, 0, 0, 1, 4], + ["y", 0, 6, 1.7949564, 0, 0, 1, 5], + ["u", 0, 7, 2.7419887, 0, 0, 1, 6], + ["i", 0, 8, 6.177734, 0, 0, 1, 7], + ["o", 0, 9, 7.6643543, 0, 0, 1, 8], + ["p", 0, 10, 1.4425724, 0, 0, 1, 9], + ["-", 0, 11, 0.2753001, 0, 0, 1, 10], + ["a", 1, 1, 7.466138, 0, 0, 1, 11], + ["s", 1, 2, 5.5720735, 0, 0, 1, 12], + ["d", 1, 3, 4.2616453, 0, 0, 1, 13], + ["f", 1, 4, 2.0482326, 0, 0, 1, 14], + ["g", 1, 5, 2.2244246, 0, 0, 1, 15], + ["h", 1, 6, 6.519106, 0, 0, 1, 16], + ["j", 1, 7, 0.06607202, 0, 0, 1, 17], + ["k", 1, 8, 1.0571523, 0, 0, 1, 18], + ["l", 1, 9, 4.6030173, 0, 0, 1, 19], + [";", 1, 10, 0.4184561, 0, 0, 1, 20], + ["'", 1, 11, 0.3523841, 0, 0, 1, 21], + ["z", 2, 1, 0.04404801, 0, 0, 1, 22], + ["x", 2, 2, 0.07708402, 0, 0, 1, 23], + ["c", 2, 3, 1.8830525, 0, 0, 1, 24], + ["v", 2, 4, 0.7488162, 0, 0, 1, 25], + ["b", 2, 5, 1.5526924, 0, 0, 1, 26], + ["n", 2, 6, 6.1446977, 0, 0, 1, 27], + ["m", 2, 7, 1.5857284, 0, 0, 1, 28], + [",", 2, 8, 1.9601365, 0, 0, 1, 29], + [".", 2, 9, 0.48452812, 0, 0, 1, 30], + ["/", 2, 10, 0.14315604, 0, 0, 1, 31], + ["\\", 2, 0, 0, 0, 0, 1, 32], + ["^", 3, 4, 0, 0, 0, 1, 33], + ["tab", 0, 0, 0, 0, 0, 1, 34], + ["$", 1, 0, 0, 0, 0, 1, 35], + ["enter", 2, 11, 0, 0, 0, 1, 36], + ["mod", 3, 5, 0, 0, 0, 1, 37], + ["back", 3, 6, 0, 0, 0, 1, 38], + ["space", 3, 7, 0, 0, 0, 1, 39], +]; +const rcdata_len = rcdata.length; // Compute once var effort = [ - [ - 5, // column 0 tab - 3, // column 1 q - 2, // column 2 w - 1, // column 3 e - 2, // column 4 r - 7, // column 5 t - 7, // column 6 y - 2, // column 7 u - 1, // column 8 i - 2, // column 9 o - 3, // column 10 p - 5, // column 11 [ - ], - [ - 5, // column 0 ctrl - 1, // column 1 a - 0, // column 2 s - 0, // column 3 d - 0, // column 4 - 5, // column 5 - 5, // column 6 - 0, // column 7 - 0, // column 8 - 0, // column 9 - 1, // column 10 - 5, // column 11 - ], - [ - 7, // column 0 - 3, // column 1 - 2, // column 2 - 2, // column 3 - 1, // column 4 - 8, // column 5 - 8, // column 6 - 1, // column 7 - 2, // column 8 - 2, // column 9 - 3, // column 10 - 7, // column 11 - ], + [ + 5, // column 0 tab + 3, // column 1 q + 2, // column 2 w + 1, // column 3 e + 2, // column 4 r + 7, // column 5 t + 7, // column 6 y + 2, // column 7 u + 1, // column 8 i + 2, // column 9 o + 3, // column 10 p + 5, // column 11 - + ], + [ + 5, // column 0 ctrl + 1, // column 1 a + 0, // column 2 s + 0, // column 3 d + 0, // column 4 f + 5, // column 5 g + 5, // column 6 h + 0, // column 7 j + 0, // column 8 k + 0, // column 9 l + 1, // column 10 ; + 5, // column 11 ' + ], + [ + 7, // column 0 + 3, // column 1 z + 2, // column 2 x + 2, // column 3 c + 1, // column 4 v + 8, // column 5 b + 8, // column 6 n + 1, // column 7 m + 2, // column 8 , + 2, // column 9 . + 3, // column 10 / + 7, // column 11 enter + ], ]; // var bigram_effort = { @@ -285,792 +310,1057 @@ var effort = [ // 2 \ z x c v b n m , . / function openPopup() { - for (let row = 0; row < nb_row; row++){ - for (let col = 0; col < nb_columns; col++){ - var name = "textInput-" + row + "-" + col - document.getElementById(name).value = effort[row][col]; - } - } - document.getElementById('popup').style.display = 'flex'; + for (let row = 0; row < nb_row; row++) { + for (let col = 0; col < nb_columns; col++) { + const name = "textInput-" + row + "-" + col; + document.getElementById(name).value = effort[row][col]; + } + } + document.getElementById("popup").style.display = "flex"; } function openImportPopup() { - document.getElementById('importPopup').style.display = 'flex'; + document.getElementById("importPopup").style.display = "flex"; } function openCorpusPopup() { - document.getElementById('corpusPopup').style.display = 'flex'; + document.getElementById("corpusPopup").style.display = "flex"; } function deepCopy(arr) { - return arr.map(item => Array.isArray(item) ? deepCopy(item) : item); + return arr.map((item) => (Array.isArray(item) ? deepCopy(item) : item)); } -function strCount(str,char) { - for(var count=-1,index=-2; index != -1; count++,index=str.indexOf(char,index+1) ); - return count +function strCount(str, char) { + return str.split(char).length - 1; } function closeImportPopup() { - var importString = document.getElementById('importText').value; - importString = importString.replace(/\s+/g, ''); - if (importString.length == 0) { - document.getElementById('importPopup').style.display = 'none'; - return - } - if (importString.length == 30){ // probably cmini - if (strCount(importString,"-")==0 && strCount(importString,"'")==0){ - importString = importString.slice(0, 10) + "-" + importString.slice(10,20) + "'" + importString.slice(20) + "\\^"; - } else if (strCount(importString,"-")==0 && strCount(importString,";")==0 ) { - importString = importString.slice(0, 10) + "-" + importString.slice(10,20) + ";" + importString.slice(20) + "\\^"; - } else if (strCount(importString,"'")==0 && strCount(importString,";")==0 ) { - importString = importString.slice(0, 10) + ";" + importString.slice(10,20) + "'" + importString.slice(20) + "\\^"; - } else if (strCount(importString,"'")==0 && strCount(importString,"/")==0 ) { - importString = importString.slice(0, 10) + "/" + importString.slice(10,20) + "'" + importString.slice(20) + "\\^"; - } else if (strCount(importString,";")==0 && strCount(importString,"/")==0 ) { - importString = importString.slice(0, 10) + "/" + importString.slice(10,20) + ";" + importString.slice(20) + "\\^"; - } else if (strCount(importString,";")==0 && strCount(importString,"'")==0 ) { - importString = importString.slice(0, 10) + ";" + importString.slice(10,20) + "'" + importString.slice(20) + "\\^"; - } else if (strCount(importString,"/")==0 && strCount(importString,"-")==0 ) { - importString = importString.slice(0, 10) + "/" + importString.slice(10,20) + "-" + importString.slice(20) + "\\^"; - } else { - importString = importString.slice(0, 10) + "+" + importString.slice(10,20) + "*" + importString.slice(20) + "\\^"; - } - } - const letters = importString.toUpperCase().match(/[A-Z\.\,\/\-\'\;]/g) || []; - // Count occurrences of each letter - const letterCount = {}; - letters.forEach(letter => { - letterCount[letter] = (letterCount[letter] || 0) + 1; - }); - const allLetters = Array.from({length: 26}, (_, i) => String.fromCharCode(65 + i)).concat(['.', ',',';','/','-','\'']); - const missing = allLetters.filter(letter => !letterCount[letter]); - const duplicates = Object.keys(letterCount).filter(letter => letterCount[letter] > 1); - var message = "" - if (missing.length > 0){ - message = message + "These letters are missing: "+missing.join(" ")+"\n" - } - if (duplicates.length > 0){ - message = message + "These letters are duplicated: "+duplicates.join(" ")+"\n" - } - if (message.length > 0){ - document.getElementById('importMessage').innerText = message - return - } else { - if ((mode == "iso" || mode == "ansi") && importString.length >= 33) { - document.getElementById('importMessage').innerText = "You can't have layouts with thumb letters on ISO/ANSI" - } else if (importString.length <= 35) { - needs_update = true; - importLayout(importString); - var queryParams = new URLSearchParams(window.location.search); - queryParams.set("layout", exportLayout()); - queryParams.set("mode",mode) - queryParams.set("lan",lang) - history.replaceState(null, null, "?"+queryParams.toString()); - generateCoords(); - measureDictionary(); - measureWords(); - generateLayout(); - generatePlots(); - document.getElementById('importPopup').style.display = 'none'; - } else { - document.getElementById('importMessage').innerText = "Input string contains too many characters" - console.log("input string is length "+ importString.length + " " + importString); - return - } - } - - needs_update = true; + var importString = document.getElementById("importText").value; + importString = importString.replace(/\s+/g, ""); + if (importString.length == 0) { + document.getElementById("importPopup").style.display = "none"; + return; + } + if (importString.length == 30) { + // probably cmini + if (strCount(importString, "-") == 0 && strCount(importString, "'") == 0) { + importString = + importString.slice(0, 10) + + "-" + + importString.slice(10, 20) + + "'" + + importString.slice(20) + + "\\^"; + } else if ( + strCount(importString, "-") == 0 && + strCount(importString, ";") == 0 + ) { + importString = + importString.slice(0, 10) + + "-" + + importString.slice(10, 20) + + ";" + + importString.slice(20) + + "\\^"; + } else if ( + strCount(importString, "'") == 0 && + strCount(importString, ";") == 0 + ) { + importString = + importString.slice(0, 10) + + ";" + + importString.slice(10, 20) + + "'" + + importString.slice(20) + + "\\^"; + } else if ( + strCount(importString, "'") == 0 && + strCount(importString, "/") == 0 + ) { + importString = + importString.slice(0, 10) + + "/" + + importString.slice(10, 20) + + "'" + + importString.slice(20) + + "\\^"; + } else if ( + strCount(importString, ";") == 0 && + strCount(importString, "/") == 0 + ) { + importString = + importString.slice(0, 10) + + "/" + + importString.slice(10, 20) + + ";" + + importString.slice(20) + + "\\^"; + } else if ( + strCount(importString, ";") == 0 && + strCount(importString, "'") == 0 + ) { + importString = + importString.slice(0, 10) + + ";" + + importString.slice(10, 20) + + "'" + + importString.slice(20) + + "\\^"; + } else if ( + strCount(importString, "/") == 0 && + strCount(importString, "-") == 0 + ) { + importString = + importString.slice(0, 10) + + "/" + + importString.slice(10, 20) + + "-" + + importString.slice(20) + + "\\^"; + } else { + importString = + importString.slice(0, 10) + + "+" + + importString.slice(10, 20) + + "*" + + importString.slice(20) + + "\\^"; + } + } + const letters = importString.toUpperCase().match(/[A-Z.,/\-';]/g) || []; + // Count occurrences of each letter + const letterCount = {}; + letters.forEach((letter) => { + letterCount[letter] = (letterCount[letter] || 0) + 1; + }); + const allLetters = Array.from({ length: 26 }, (_, i) => + String.fromCharCode(65 + i), + ).concat([".", ",", ";", "/", "-", "'"]); + const missing = allLetters.filter((letter) => !letterCount[letter]); + const duplicates = Object.keys(letterCount).filter( + (letter) => letterCount[letter] > 1, + ); + var message = ""; + if (missing.length > 0) { + message = + message + "These letters are missing: " + missing.join(" ") + "\n"; + } + if (duplicates.length > 0) { + message = + message + "These letters are duplicated: " + duplicates.join(" ") + "\n"; + } + if (message.length > 0) { + document.getElementById("importMessage").innerText = message; + return; + } else { + if ((mode == "iso" || mode == "ansi") && importString.length >= 33) { + document.getElementById("importMessage").innerText = + "You can't have layouts with thumb letters on ISO/ANSI"; + } else if (importString.length <= 35) { + needs_update = true; + importLayout(importString); + const queryParams = new URLSearchParams(window.location.search); + queryParams.set("layout", exportLayout()); + queryParams.set("mode", mode); + queryParams.set("lan", lang); + history.replaceState(null, null, "?" + queryParams.toString()); + generateCoords(); + measureDictionary(); + measureWords(); + generateLayout(); + generatePlots(); + document.getElementById("importPopup").style.display = "none"; + } else { + document.getElementById("importMessage").innerText = + "Input string contains too many characters"; + console.log( + "input string is length " + importString.length + " " + importString, + ); + return; + } + } + + needs_update = true; } function closeCorpusPopup() { - var massive_string = document.getElementById('corpusText').value; - massive_string = massive_string.toLowerCase().replace(/\s+/g, ' '); - words = {}; - if (massive_string.length == 0) { - document.getElementById('corpusPopup').style.display = 'none'; - return; - } - if (massive_string.length < 1000) { - document.getElementById('corpusMessage').innerText = "Input text not large enough"; - return; - } - list = massive_string.split(" ") - var regex = /\d/; - list.forEach(element => { - // i don't know what to do with these at the moment. just replacing them for now - element = element.replace("ä","a") - element = element.replace("å","a") - element = element.replace("á","a") - element = element.replace("à","a") - element = element.replace("â","a") - element = element.replace("ö","o") - element = element.replace("ó","o") - element = element.replace("í","i") - element = element.replace("ü","u") - element = element.replace("é","e") - element = element.replace("è","e") - element = element.replace("ç","c") - element = element.replace("æ","ae") - element = element.replace("ß","ss") - element = element.replace("ğ","g") - if (regex.test(element)){ - - } else { - if (words[element]) { - words[element] += 1 - } else { - words[element] = 1 - } - } - }); - dictionary = []; - count = 0; - for(var word in words) { - dictionary.push(word) - count += 1 - } - // console.log(count); - - document.getElementById('corpusPopup').style.display = 'none'; - needs_update = true; - measureWords(); - measureDictionary(); - generatePlots(); + var massive_string = document.getElementById("corpusText").value; + massive_string = massive_string.toLowerCase().replace(/\s+/g, " "); + words = {}; + if (massive_string.length == 0) { + document.getElementById("corpusPopup").style.display = "none"; + return; + } + if (massive_string.length < 1000) { + document.getElementById("corpusMessage").innerText = + "Input text not large enough"; + return; + } + list = massive_string.split(" "); + var regex = /\d/; + list.forEach((element) => { + // i don't know what to do with these at the moment. just replacing them for now + element = element.replace("ä", "a"); + element = element.replace("å", "a"); + element = element.replace("á", "a"); + element = element.replace("à", "a"); + element = element.replace("â", "a"); + element = element.replace("ö", "o"); + element = element.replace("ó", "o"); + element = element.replace("í", "i"); + element = element.replace("ü", "u"); + element = element.replace("é", "e"); + element = element.replace("è", "e"); + element = element.replace("ç", "c"); + element = element.replace("æ", "ae"); + element = element.replace("ß", "ss"); + element = element.replace("ğ", "g"); + if (regex.test(element)) { + } else { + if (words[element]) { + words[element] += 1; + } else { + words[element] = 1; + } + } + }); + dictionary = []; + count = 0; + for (var word in words) { + dictionary.push(word); + count += 1; + } + // console.log(count); + + document.getElementById("corpusPopup").style.display = "none"; + needs_update = true; + measureWords(); + measureDictionary(); + generatePlots(); } function closePopup() { - for (let row = 0; row < nb_row; row++){ - for (let col = 0; col < nb_columns; col++){ - var name = "textInput-" + row + "-" + col - effort[row][col] = document.getElementById(name).value; - } - } - document.getElementById('popup').style.display = 'none'; - needs_update = true; - measureWords(); - generateLayout(); + for (let row = 0; row < nb_row; row++) { + for (let col = 0; col < nb_columns; col++) { + const name = "textInput-" + row + "-" + col; + effort[row][col] = document.getElementById(name).value; + } + } + document.getElementById("popup").style.display = "none"; + needs_update = true; + measureWords(); + generateLayout(); } function copyEffortGridToClipboard() { - values = [] - for (let row = 0; row < 3; row++){ - for (let col = 0; col < 12; col++){ - const name = "textInput-" + row + "-" + col - values.push(document.getElementById(name).value); - } - } - var str = values.join(","); - - if (!navigator.clipboard) { - console.error("Clipboard API not supported"); - return; - } - - navigator.clipboard.writeText(str) - .then( - // console.log("copied!") - ) - .catch(err => { - console.error("Failed to copy to clipboard contents:", err); - }); - + values = []; + for (let row = 0; row < 3; row++) { + for (let col = 0; col < 12; col++) { + const name = "textInput-" + row + "-" + col; + values.push(document.getElementById(name).value); + } + } + var str = values.join(","); + + if (!navigator.clipboard) { + console.error("Clipboard API not supported"); + return; + } + + navigator.clipboard + .writeText(str) + .then( + // console.log("copied!") + ) + .catch((err) => { + console.error("Failed to copy to clipboard contents:", err); + }); } function pasteEffortGridFromClipboard() { - if (!navigator.clipboard) { - console.error("Clipboard API not supported"); - return; - } - // Retrieve clipboard content - navigator.clipboard.readText() - .then(text => { - // console.log("Clipboard content:", text); - var numbersArray = text.split(",").map(Number); - if (numbersArray.length != 36) { - return - } - - for (let row = 0; row < 3; row++){ - for (let col = 0; col < 12; col++){ - const name = "textInput-" + row + "-" + col - document.getElementById(name).value = numbersArray[row * 12 + col] - } - } - }) - .catch(err => { - console.error("Failed to read clipboard contents:", err); - }); + if (!navigator.clipboard) { + console.error("Clipboard API not supported"); + return; + } + // Retrieve clipboard content + navigator.clipboard + .readText() + .then((text) => { + // console.log("Clipboard content:", text); + var numbersArray = text.split(",").map(Number); + if (numbersArray.length != 36) { + return; + } + + for (let row = 0; row < 3; row++) { + for (let col = 0; col < 12; col++) { + const name = "textInput-" + row + "-" + col; + document.getElementById(name).value = numbersArray[row * 12 + col]; + } + } + }) + .catch((err) => { + console.error("Failed to read clipboard contents:", err); + }); } -function getEffort(row, column){ - if (row == -1 || column == -1) { return 0; } - return effort[row][column]; +function getEffort(row, column) { + if (effort[row]) { + if (effort[row][column]) { + return effort[row][column]; + } + } + return 0; } var skip_toggle = false; function skipToggle() { - skip_toggle = !skip_toggle - generatePlots(); + skip_toggle = !skip_toggle; + generatePlots(); } var scissors_toggle = 0; function scissorsToggle(v) { - scissors_toggle += v - if (scissors_toggle > 2){ - scissors_toggle = 0 - } - if (scissors_toggle < 0){ - scissors_toggle = 2 - } - generatePlots(); + scissors_toggle += v; + if (scissors_toggle > 2) { + scissors_toggle = 0; + } + if (scissors_toggle < 0) { + scissors_toggle = 2; + } + generatePlots(); } var lsb_toggle = 0; function lsbToggle() { - lsb_toggle += 1 - if (lsb_toggle > 1){ - lsb_toggle = 0 - } - generatePlots(); + lsb_toggle += 1; + if (lsb_toggle > 1) { + lsb_toggle = 0; + } + generatePlots(); } var sfb_toggle = 0; function sfbToggle(v) { - sfb_toggle += v - if (sfb_toggle > 2){ - sfb_toggle = 0 - } - if (sfb_toggle < 0){ - sfb_toggle = 2 - } - generatePlots(); + sfb_toggle += v; + if (sfb_toggle > 2) { + sfb_toggle = 0; + } + if (sfb_toggle < 0) { + sfb_toggle = 2; + } + generatePlots(); } var trigram_toggle = 0; function trigramToggle(v) { - trigram_toggle += v - if (trigram_toggle > 4){ - trigram_toggle = 0 - } - if (trigram_toggle < 0){ - trigram_toggle = 4 - } - generatePlots(); + trigram_toggle += v; + if (trigram_toggle > 4) { + trigram_toggle = 0; + } + if (trigram_toggle < 0) { + trigram_toggle = 4; + } + generatePlots(); } function showTooltip(evt, text) { - let tooltip = document.getElementById("tooltip"); - tooltip.innerHTML = text; - tooltip.style.display = "block"; - tooltip.style.left = evt.pageX + 10 + 'px'; - tooltip.style.top = evt.pageY + 10 + 'px'; + const tooltip = document.getElementById("tooltip"); + tooltip.innerHTML = text; + tooltip.style.display = "block"; + tooltip.style.left = evt.pageX + 10 + "px"; + tooltip.style.top = evt.pageY + 10 + "px"; } function hideTooltip() { - var tooltip = document.getElementById("tooltip"); - tooltip.style.display = "none"; + var tooltip = document.getElementById("tooltip"); + tooltip.style.display = "none"; } function setMode() { - if (dataloaded == false || dictionaryloaded == false || effortloaded == false) {return;} - console.log("setMode to "+mode); - if (mode == "ergo") { - setErgo() - } else if (mode == "ansi") { - setAnsi() - } else if (mode == "iso") { - setIso() - } - generateCoords() + if ( + dataloaded == false || + dictionaryloaded == false || + effortloaded == false + ) { + return; + } + console.log("setMode to " + mode); + if (mode == "ergo") { + setErgo(); + } else if (mode == "ansi") { + setAnsi(); + } else if (mode == "iso") { + setIso(); + } + generateCoords(); } function activateErgo() { - needs_update = true; - setErgo(); - generateCoords(); - measureDictionary(); - measureWords(); - generateLayout(); - generatePlots(); + needs_update = true; + setErgo(); + generateCoords(); + measureDictionary(); + measureWords(); + generateLayout(); + generatePlots(); } function setErgo() { - if (dataloaded == false || dictionaryloaded == false || effortloaded == false) {return;} - console.log("activateErgo"); - rcdata[32][1] = 2 - rcdata[32][2] = 0 - rcdata[32][6] = 1 - rcdata[33][1] = 3 - rcdata[33][2] = 4 - rcdata[33][6] = 1 - rcdata[34] = ["tab", 0, 0, 0, 0, 0, 1, 34] - rcdata[35] = [rcdata[35][0], 1, 0, 0, 0, 0, 1, rcdata[35][7]] - rcdata[36] = ["enter", 2, 11, 0, 0, 0, 1, 36] - rcdata[37] = ["mod", 3, 5, 0, 0, 0, 1, 37] - rcdata[38] = ["back", 3, 6, 0, 0, 0, 1, 38] - rcdata[39] = [rcdata[39][0], 3, 7, 0, 0, 0, 1, rcdata[39][7]] - mode = "ergo" - fingerAssignment = [ - [1, 1, 2, 3, 4, 4, 7, 7, 8, 9, 10, 10, 10], - [1, 1, 2, 3, 4, 4, 7, 7, 8, 9, 10, 10, 10], - [1, 1, 2, 3, 4, 4, 7, 7, 8, 9, 10, 10, 10] - ] - - var queryParams = new URLSearchParams(window.location.search); - queryParams.set("layout", exportLayout()); - queryParams.set("mode",mode) - queryParams.set("lan",lang) - queryParams.set("thumb",thumb) - history.replaceState(null, null, "?"+queryParams.toString()); + if ( + dataloaded == false || + dictionaryloaded == false || + effortloaded == false + ) { + return; + } + console.log("activateErgo"); + rcdata[32][1] = 2; + rcdata[32][2] = 0; + rcdata[32][6] = 1; + rcdata[33][1] = 3; + rcdata[33][2] = 4; + rcdata[33][6] = 1; + rcdata[34] = ["tab", 0, 0, 0, 0, 0, 1, 34]; + rcdata[35] = [rcdata[35][0], 1, 0, 0, 0, 0, 1, rcdata[35][7]]; + rcdata[36] = ["enter", 2, 11, 0, 0, 0, 1, 36]; + rcdata[37] = ["mod", 3, 5, 0, 0, 0, 1, 37]; + rcdata[38] = ["back", 3, 6, 0, 0, 0, 1, 38]; + rcdata[39] = [rcdata[39][0], 3, 7, 0, 0, 0, 1, rcdata[39][7]]; + mode = "ergo"; + fingerAssignment = [ + [1, 1, 2, 3, 4, 4, 7, 7, 8, 9, 10, 10, 10], + [1, 1, 2, 3, 4, 4, 7, 7, 8, 9, 10, 10, 10], + [1, 1, 2, 3, 4, 4, 7, 7, 8, 9, 10, 10, 10], + ]; + + var queryParams = new URLSearchParams(window.location.search); + queryParams.set("layout", exportLayout()); + queryParams.set("mode", mode); + queryParams.set("lan", lang); + queryParams.set("thumb", thumb); + history.replaceState(null, null, "?" + queryParams.toString()); } function activateIso(anglemod) { - needs_update = true; - setIso(anglemod); - generateCoords(); - measureDictionary(); - measureWords(); - generateLayout(); - generatePlots(); + needs_update = true; + setIso(anglemod); + generateCoords(); + measureDictionary(); + measureWords(); + generateLayout(); + generatePlots(); } function setIso(anglemod) { - if (dataloaded == false || dictionaryloaded == false || effortloaded == false) {return;} - hasshift = false - for(let i = 0; i < 34; i++){ - if (rcdata[i][0] == "shift" || rcdata[i][0] == "^") { - hasshift = true - } - } - if (hasshift == true) { - rcdata[32][1] = 2 - rcdata[32][2] = 0 - rcdata[32][6] = 1 - rcdata[33][1] = 2 - rcdata[33][2] = -1 - rcdata[33][6] = 1.25 - rcdata[34] = ["tab", 0, 0, 0, 0, 0, 1.5, 34] - rcdata[35] = ["back", 0, 12, 0, 0, 0, 2.25, 35] - rcdata[36] = ["$", 1, 0, 0, 0, 0, 1.75, 36] - rcdata[37] = ["enter", 1, 12, 0, 0, 0, 2, 37] - rcdata[38] = ["rshift", 2, 12, 0, 0, 0, 2.5, 38] - rcdata[39] = ["space", 3, 3, 0, 0, 0, 6.5, 39] - if (anglemod){ - fingerAssignment = [ // angle mod - [1, 1, 2, 3, 4, 4, 7, 7, 8, 9, 10, 10, 10], - [1, 1, 2, 3, 4, 4, 7, 7, 8, 9, 10, 10, 10], - [1, 2, 3, 4, 4, 4, 7, 7, 8, 9, 10, 10, 10] - ] - } else { - fingerAssignment = [ - [1, 1, 2, 3, 4, 4, 7, 7, 8, 9, 10, 10, 10], - [1, 1, 2, 3, 4, 4, 7, 7, 8, 9, 10, 10, 10], - [1, 1, 2, 3, 4, 4, 7, 7, 8, 9, 10, 10, 10] - ] - } - mode = "iso" - var queryParams = new URLSearchParams(window.location.search); - queryParams.set("layout", exportLayout()); - queryParams.set("mode",mode) - queryParams.set("lan",lang) - history.replaceState(null, null, "?"+queryParams.toString()); - } else { - console.log("You can't have layouts with thumb letters on ISO/ANSI") - } + if ( + dataloaded == false || + dictionaryloaded == false || + effortloaded == false + ) { + return; + } + hasshift = false; + for (let i = 0; i < 34; i++) { + if (rcdata[i][0] == "shift" || rcdata[i][0] == "^") { + hasshift = true; + } + } + if (hasshift == true) { + rcdata[32][1] = 2; + rcdata[32][2] = 0; + rcdata[32][6] = 1; + rcdata[33][1] = 2; + rcdata[33][2] = -1; + rcdata[33][6] = 1.25; + rcdata[34] = ["tab", 0, 0, 0, 0, 0, 1.5, 34]; + rcdata[35] = ["back", 0, 12, 0, 0, 0, 2.25, 35]; + rcdata[36] = ["$", 1, 0, 0, 0, 0, 1.75, 36]; + rcdata[37] = ["enter", 1, 12, 0, 0, 0, 2, 37]; + rcdata[38] = ["rshift", 2, 12, 0, 0, 0, 2.5, 38]; + rcdata[39] = ["space", 3, 3, 0, 0, 0, 6.5, 39]; + if (anglemod) { + fingerAssignment = [ + // angle mod + [1, 1, 2, 3, 4, 4, 7, 7, 8, 9, 10, 10, 10], + [1, 1, 2, 3, 4, 4, 7, 7, 8, 9, 10, 10, 10], + [1, 2, 3, 4, 4, 4, 7, 7, 8, 9, 10, 10, 10], + ]; + } else { + fingerAssignment = [ + [1, 1, 2, 3, 4, 4, 7, 7, 8, 9, 10, 10, 10], + [1, 1, 2, 3, 4, 4, 7, 7, 8, 9, 10, 10, 10], + [1, 1, 2, 3, 4, 4, 7, 7, 8, 9, 10, 10, 10], + ]; + } + mode = "iso"; + var queryParams = new URLSearchParams(window.location.search); + queryParams.set("layout", exportLayout()); + queryParams.set("mode", mode); + queryParams.set("lan", lang); + history.replaceState(null, null, "?" + queryParams.toString()); + } else { + console.log("You can't have layouts with thumb letters on ISO/ANSI"); + } } function activateAnsi() { - needs_update = true; - setAnsi(); - generateCoords(); - measureDictionary(); - measureWords(); - generateLayout(); - generatePlots(); + needs_update = true; + setAnsi(); + generateCoords(); + measureDictionary(); + measureWords(); + generateLayout(); + generatePlots(); } function setAnsi() { - if (dataloaded == false || dictionaryloaded == false || effortloaded == false) {return;} - hasshift = false - for(let i = 0; i < 34; i++){ - if (rcdata[i][0] == "shift" || rcdata[i][0] == "^") { - hasshift = true - } - } - if (hasshift == true) { - // rcdata[32] = [rcdata[32][0], 0, 12, 0.2753001, 0, 0, 1, rcdata[32][7]] - // rcdata[33] = [rcdata[33][0], 2, -1, 0, 0, 0, 2.25, rcdata[33][7]] - - // backslash key - rcdata[32][1] = 0 - rcdata[32][2] = 12 - rcdata[32][6] = 1 - - // left shift key - rcdata[33][1] = 2 - rcdata[33][2] = -1 - rcdata[33][6] = 2.25 - - rcdata[34] = ["tab", 0, 0, 0, 0, 0, 1.5, 34] - rcdata[35] = ["back", 0, 13, 0, 0, 0, 1.25, 35] - rcdata[36] = ["$", 1, 0, 0, 0, 0, 1.75, 36] - rcdata[37] = ["enter", 1, 12, 0, 0, 0, 2, 37] - rcdata[38] = ["rshift", 2, 11, 0, 0, 0, 2.5, 38] - rcdata[39] = ["space", 3, 3, 0, 0, 0, 6.5, 39] - fingerAssignment = [ - [1, 1, 2, 3, 4, 4, 7, 7, 8, 9, 10, 10, 10], - [1, 1, 2, 3, 4, 4, 7, 7, 8, 9, 10, 10, 10], - [1, 1, 2, 3, 4, 4, 7, 7, 8, 9, 10, 10, 10] - ] - mode = "ansi" - var queryParams = new URLSearchParams(window.location.search); - queryParams.set("layout", exportLayout()); - queryParams.set("mode",mode) - queryParams.set("lan",lang) - history.replaceState(null, null, "?"+queryParams.toString()); - } else { - console.log("You can't have layouts with thumb letters on ISO/ANSI") - } + if ( + dataloaded === false || + dictionaryloaded === false || + effortloaded === false + ) { + return; + } + hasshift = false; + for (let i = 0; i < 34; i++) { + if (rcdata[i][0] === "shift" || rcdata[i][0] === "^") { + hasshift = true; + } + } + if (hasshift === true) { + // rcdata[32] = [rcdata[32][0], 0, 12, 0.2753001, 0, 0, 1, rcdata[32][7]] + // rcdata[33] = [rcdata[33][0], 2, -1, 0, 0, 0, 2.25, rcdata[33][7]] + + // backslash key + rcdata[32][1] = 0; + rcdata[32][2] = 12; + rcdata[32][6] = 1; + + // left shift key + rcdata[33][1] = 2; + rcdata[33][2] = -1; + rcdata[33][6] = 2.25; + + rcdata[34] = ["tab", 0, 0, 0, 0, 0, 1.5, 34]; + rcdata[35] = ["back", 0, 13, 0, 0, 0, 1.25, 35]; + rcdata[36] = ["$", 1, 0, 0, 0, 0, 1.75, 36]; + rcdata[37] = ["enter", 1, 12, 0, 0, 0, 2, 37]; + rcdata[38] = ["rshift", 2, 11, 0, 0, 0, 2.5, 38]; + rcdata[39] = ["space", 3, 3, 0, 0, 0, 6.5, 39]; + fingerAssignment = [ + [1, 1, 2, 3, 4, 4, 7, 7, 8, 9, 10, 10, 10], + [1, 1, 2, 3, 4, 4, 7, 7, 8, 9, 10, 10, 10], + [1, 1, 2, 3, 4, 4, 7, 7, 8, 9, 10, 10, 10], + ]; + mode = "ansi"; + const queryParams = new URLSearchParams(window.location.search); + queryParams.set("layout", exportLayout()); + queryParams.set("mode", mode); + queryParams.set("lan", lang); + history.replaceState(null, null, "?" + queryParams.toString()); + } else { + console.log("You can't have layouts with thumb letters on ISO/ANSI"); + } } function importLayout(layout) { - if (layout.length == 35) { - var decodedString = decodeURIComponent(layout); - console.log("importing: "+decodedString) - layout = decodedString - // change shift to = - for (let i = 0; i < 34; i++) { - if (rcdata[i][0] == "^") { - rcdata[i][0] = "*" - } - } - // change ctrl to * - for (let i = 0; i < 37; i++) { - if (rcdata[i][0] == "$") { - rcdata[i][0] = "=" - console.log("setting "+i+" to *") - } - } - // - for (let i = 0; i < 34; i++) { // qwertyuiop-asdfghjkl;'zxcvbnm,./\^ - 34 - for (let j = 0; j < 34; j++) { - if (layout.charAt(i) == rcdata[j][0]) { - // console.log("swap "+layout.charAt(i)+" at " + i + " with position " + j) - // swap - indices = [0, 3, 7] // letter, freq, keyname - for (let id = 0; id < indices.length; id++){ - var k = indices[id]; - tmp = rcdata[i][k]; - rcdata[i][k] = rcdata[j][k]; - rcdata[j][k] = tmp; - } - } - } - } - // last letter - var swap1 = 0 - var swap2 = 0 - for (let i = 0; i < 36; i++) { - if (rcdata[i][7] == 35) { - swap1 = i - } - } - for (let i = 0; i < 36; i++) { - if (rcdata[i][0] == layout.charAt(34)) { - swap2 = i - } - } - indices = [0, 3, 7] // letter, freq, keyname - for (let id = 0; id < indices.length; id++){ - var k = indices[id]; - tmp = rcdata[swap1][k]; - rcdata[swap1][k] = rcdata[swap2][k]; - rcdata[swap2][k] = tmp; - } - } else { - var decodedString = decodeURIComponent(layout); - console.log("importing: "+decodedString) - layout = decodedString - for (let i = 0; i < 34; i++) { // qwertyuiop-asdfghjkl;'zxcvbnm,./\^ - 34 - for (let j = 0; j < 34; j++) { - if (layout.charAt(i) == rcdata[j][0]) { - // console.log("swap "+layout.charAt(i)+" at " + i + " with position " + j) - // swap - indices = [0, 3, 7] // letter, freq, keyname - for (let id = 0; id < indices.length; id++){ - var k = indices[id]; - tmp = rcdata[i][k]; - rcdata[i][k] = rcdata[j][k]; - rcdata[j][k] = tmp; - } - } - } - } - for (let i = 0; i < 34; i++) { - if (rcdata[i][0] == "^") { - if (rcdata[i][1] == 3 && rcdata[i][2] == 4) { - // cool - } else { - rcdata[i][0] = "=" - } - } - } - } - if (thumb == "r") { - indices = [0, 3, 7] // letter, freq, keyname - for (let id = 0; id < indices.length; id++){ - var k = indices[id]; - tmp = rcdata[33][k]; - rcdata[33][k] = rcdata[39][k]; - rcdata[39][k] = tmp; - } - } - var queryParams = new URLSearchParams(window.location.search); - queryParams.set("layout", exportLayout()); - queryParams.set("mode",mode) - queryParams.set("lan",lang) - queryParams.set("thumb",thumb) - history.replaceState(null, null, "?"+queryParams.toString()); + if (layout.length == 35) { + const decodedString = decodeURIComponent(layout); + console.log("importing: " + decodedString); + layout = decodedString; + // change shift to = + for (let i = 0; i < 34; i++) { + if (rcdata[i][0] == "^") { + rcdata[i][0] = "*"; + } + } + // change ctrl to * + for (let i = 0; i < 37; i++) { + if (rcdata[i][0] == "$") { + rcdata[i][0] = "="; + console.log("setting " + i + " to *"); + } + } + // + for (let i = 0; i < 34; i++) { + // qwertyuiop-asdfghjkl;'zxcvbnm,./\^ - 34 + for (let j = 0; j < 34; j++) { + if (layout.charAt(i) == rcdata[j][0]) { + // console.log("swap "+layout.charAt(i)+" at " + i + " with position " + j) + // swap + indices = [0, 3, 7]; // letter, freq, keyname + for (let id = 0; id < indices.length; id++) { + const k = indices[id]; + tmp = rcdata[i][k]; + rcdata[i][k] = rcdata[j][k]; + rcdata[j][k] = tmp; + } + } + } + } + // last letter + let swap1 = 0; + let swap2 = 0; + for (let i = 0; i < 36; i++) { + if (rcdata[i][7] == 35) { + swap1 = i; + } + } + for (let i = 0; i < 36; i++) { + if (rcdata[i][0] == layout.charAt(34)) { + swap2 = i; + } + } + indices = [0, 3, 7]; // letter, freq, keyname + for (let id = 0; id < indices.length; id++) { + const k = indices[id]; + tmp = rcdata[swap1][k]; + rcdata[swap1][k] = rcdata[swap2][k]; + rcdata[swap2][k] = tmp; + } + } else { + const decodedString = decodeURIComponent(layout); + console.log("importing: " + decodedString); + layout = decodedString; + for (let i = 0; i < 34; i++) { + // qwertyuiop-asdfghjkl;'zxcvbnm,./\^ - 34 + for (let j = 0; j < 34; j++) { + if (layout.charAt(i) == rcdata[j][0]) { + // console.log("swap "+layout.charAt(i)+" at " + i + " with position " + j) + // swap + indices = [0, 3, 7]; // letter, freq, keyname + for (let id = 0; id < indices.length; id++) { + const k = indices[id]; + tmp = rcdata[i][k]; + rcdata[i][k] = rcdata[j][k]; + rcdata[j][k] = tmp; + } + } + } + } + for (let i = 0; i < 34; i++) { + if (rcdata[i][0] == "^") { + if (rcdata[i][1] == 3 && rcdata[i][2] == 4) { + // cool + } else { + rcdata[i][0] = "="; + } + } + } + } + if (thumb == "r") { + indices = [0, 3, 7]; // letter, freq, keyname + for (let id = 0; id < indices.length; id++) { + const k = indices[id]; + tmp = rcdata[33][k]; + rcdata[33][k] = rcdata[39][k]; + rcdata[39][k] = tmp; + } + } + var queryParams = new URLSearchParams(window.location.search); + queryParams.set("layout", exportLayout()); + queryParams.set("mode", mode); + queryParams.set("lan", lang); + queryParams.set("thumb", thumb); + history.replaceState(null, null, "?" + queryParams.toString()); } function exportLayout() { - var str = ""; - for (let i = 0; i <= 32; i++) { - str += rcdata[i][0] - } - - maybe_space = rcdata[33][0] - if (maybe_space == "space"){ - str += "space"; - thumb = "r" - } else { - thumb = "l" - str += maybe_space - } - - ch35 = rcdata[35][0] - if (ch35 != "$") { - str += ch35; - } - return str; + var str = ""; + for (let i = 0; i <= 32; i++) { + str += rcdata[i][0]; + } + + maybe_space = rcdata[33][0]; + if (maybe_space === "space") { + str += "space"; + thumb = "r"; + } else { + thumb = "l"; + str += maybe_space; + } + + ch35 = rcdata[35][0]; + if (ch35 !== "$") { + str += ch35; + } + return str; } function getX(name, row, col) { - dx = 55; - if (mode == "iso") { - if (row == 0){ - if (name === "tab") { - off = 0 - } else { - off = w*0.5; - } - } else if (row == 1) { - if (name === "$") { - off = 0; - } else { - off = w*0.75; - } - } else if (row >= 2) { - if (col == -1) { - return dx - } else { - if (name === "space") { - off = 0; - } else if (name == "rshift") { - off = w*0.25; - } else { - off = w*1.25; - } - } - } - return dx + off + col * w - } else if (mode == "ansi") { - if (row == 0){ - if (name === "tab") { - off = 0 - } else { - off = w*0.5; - } - } else if (row == 1){ - if (name === "$") { - off = 0; - } else { - off = w*0.75; - } - } else if (row >= 2){ - if (col == -1) { - return dx - } else { - if (name === "space") { - off = 0; - } else { - off = w*1.25; - } - } - } - return dx + off + col * w - } else if (mode == "ergo") { - if (col > 5) { - dx = dx + 40; - } - return dx + col * w - } + dx = 55; + if (mode === "iso") { + if (row === 0) { + if (name === "tab") { + off = 0; + } else { + off = w * 0.5; + } + } else if (row === 1) { + if (name === "$") { + off = 0; + } else { + off = w * 0.75; + } + } else if (row >= 2) { + if (col === -1) { + return dx; + } else { + if (name === "space") { + off = 0; + } else if (name == "rshift") { + off = w * 0.25; + } else { + off = w * 1.25; + } + } + } + return dx + off + col * w; + } else if (mode === "ansi") { + if (row === 0) { + if (name === "tab") { + off = 0; + } else { + off = w * 0.5; + } + } else if (row === 1) { + if (name === "$") { + off = 0; + } else { + off = w * 0.75; + } + } else if (row >= 2) { + if (col == -1) { + return dx; + } else { + if (name === "space") { + off = 0; + } else { + off = w * 1.25; + } + } + } + return dx + off + col * w; + } else if (mode == "ergo") { + if (col > 5) { + dx = dx + 40; + } + return dx + col * w; + } } function getY(name, row, col) { - return 10 + row * w + return 10 + row * w; } function getCol(letter) { - for (let i = 0; i < rcdata_len; i++) { - const key = rcdata[i]; - if (key[0] === letter) { - return key[2]; - } - } - return -1; + for (let i = 0; i < rcdata_len; i++) { + const key = rcdata[i]; + if (key[0] === letter) { + return key[2]; + } + } + return -1; } function getRow(letter) { - for (let i = 0; i < rcdata_len; i++) { - const key = rcdata[i]; - if (key[0] === letter) { - return key[1]; - } - } - return -1; + for (let i = 0; i < rcdata_len; i++) { + const key = rcdata[i]; + if (key[0] === letter) { + return key[1]; + } + } + return -1; } -function getChar(row,col) { - for (let i = 0; i < rcdata_len; i++) { - const key = rcdata[i]; - if (key[1] == row && key[2] == col) { - return key[0]; - } - } - return "!"; +function getChar(row, col) { + for (let i = 0; i < rcdata_len; i++) { + const key = rcdata[i]; + if (key[1] == row && key[2] == col) { + return key[0]; + } + } + return "!"; } function getFinger(row, col) { - if (row > 2) { - if (col <= 4) { - return 5 - } else { - return 6 - } - } else { - return fingerAssignment[row][col]; - } + if (row > 2) { + if (col <= 4) { + return 5; + } else { + return 6; + } + } else { + return fingerAssignment[row][col]; + } } function dist(x1, y1, x2, y2) { - dx = x1 - x2 - dy = y1 - y2 - return inv_w * Math.sqrt(dx*dx + dy*dy); // pow is slow + dx = x1 - x2; + dy = y1 - y2; + return inv_w * Math.sqrt(dx * dx + dy * dy); // pow is slow } function generateCoords() { - console.log("generateCoords") - for (let i = 0; i < rcdata_len; i++) { - rcdata[i][4] = getY(rcdata[i][0], rcdata[i][1],rcdata[i][2]); // Y - rcdata[i][5] = getX(rcdata[i][0], rcdata[i][1],rcdata[i][2]); // X - } + console.log("generateCoords"); + for (let i = 0; i < rcdata_len; i++) { + rcdata[i][4] = getY(rcdata[i][0], rcdata[i][1], rcdata[i][2]); // Y + rcdata[i][5] = getX(rcdata[i][0], rcdata[i][1], rcdata[i][2]); // X + } } function generateLayout() { - if (dataloaded == false || dictionaryloaded == false || effortloaded == false) {return;} - console.log("generateLayout") - svg.selectAll("*").remove(); - if (mode == "iso" || mode == "ansi") { - outlinewidth = 572; - } else { - outlinewidth = 510; - } - svg.append("rect").attr("x", 45).attr("y", 0).attr("width", outlinewidth).attr("height", 170) - .attr("stroke", "#777777").attr("fill", "#1b1c1f").attr("fill-opactiy", "0.0").attr("rx", 8).attr("ry", 8) - for (let i = 0; i < rcdata_len; i++) { - dtx = 0; - letter = rcdata[i][0]; - if (letter == "^"){ - letter = "shift" - } - x = rcdata[i][5]; - y = rcdata[i][4]; - per = rcdata[i][3]; - keywidth = rcdata[i][6]; - red = Math.floor(127 * per * inv_default_max) + 128 - if (red < 16) { red = 16; } - if (red > 255) { red = 255;} - hex_red = red.toString(16); - hex_bg = green.toString(16); - - fontsize = 16; - if (letter == "$") { letter = "ctrl"} - if (letter.length > 1) { fontsize = 10; } - if (letter.length > 4 && mode == "ergo") { fontsize = 9; } - - svg.append("rect").attr("x", x).attr("y", y) - .attr("width", keywidth*w-gap).attr("height", w-gap).attr("rx", 4).attr("ry", 4) - .attr("fill", "#" + hex_red + hex_bg + hex_bg).attr("stroke", "black") - .attr("stroke-width", "1").attr("class", "draggable"); - if (letter.length > 1 && mode != "ergo") { - svg.append("text").attr("x", x + 5).attr("y", y + 19) - .attr("font-size", fontsize).attr("font-family", "Roboto Mono") - .attr("text-anchor", "left").attr("class", "draggable legend").text(letter); - } else { - svg.append("text").attr("x", x + 15).attr("y", y + 19) - .attr("font-size", fontsize).attr("font-family", "Roboto Mono") - .attr("text-anchor", "middle").attr("class", "draggable legend").text(letter); - } - } - // - if (m_total_word_effort == 0){ - // console.log("m_total_word_effort == 0") - measureDictionary(); - measureWords(); - } - svg.append("text").attr("x", 640).attr("y", 135).attr("font-size", 16).attr("font-family", "Sans,Arial").attr("fill", "#dfe2eb").attr("text-anchor", "left").text("Total Word Effort "+(m_total_word_effort/100.0).toFixed(1)) - // effort text - svg.append("text").attr("x", 640).attr("y", 165).attr("font-size", 16).attr("font-family", "Sans,Arial").attr("fill", "#dfe2eb").attr("text-anchor", "left").text("Effort " + (577 * m_effort * inv_m_input_length).toFixed(2)) - // edit button - svg.append("rect").attr("x", 760).attr("y", 147).attr("width", 40).attr("height", 25).attr("rx",0).attr("ry",0) - .attr("fill","#777777").attr("stroke","black").attr("stroke-width","1").attr("onclick", "openPopup()") - .attr("onmouseover", "showTooltip(evt,'Edit effort values for each key')").attr("onmouseout", "hideTooltip()") - - svg.append("text").attr("x", 760+20).attr("y", 164).attr("font-size", 16).attr("font-family", "Sans,Arial") - .attr("fill", "#111111").attr("text-anchor", "middle").attr("pointer-events","none").text("Edit") - - - // ergo button - svg.append("rect").attr("x", 640).attr("y", 10).attr("width", 46).attr("height", 25).attr("rx",0).attr("ry",0) - .attr("fill","#777777").attr("stroke","black").attr("stroke-width","1").attr("onclick", "activateErgo()") - .attr("onmouseover", "showTooltip(evt,'Switch layout to Ergo')").attr("onmouseout", "hideTooltip()") - svg.append("text").attr("x", 640+23).attr("y", 10+18).attr("font-size", 16).attr("font-family", "Sans,Arial") - .attr("fill", "#111111").attr("text-anchor", "middle").attr("pointer-events","none").text("Ergo") - // iso button - svg.append("rect").attr("x", 640).attr("y", 10+35).attr("width", 46).attr("height", 25).attr("rx",0).attr("ry",0) - .attr("fill","#777777").attr("stroke","black").attr("stroke-width","1").attr("onclick", "activateIso(false)") - .attr("onmouseover", "showTooltip(evt,'Switch layout to ISO')").attr("onmouseout", "hideTooltip()") - svg.append("text").attr("x", 640+23).attr("y", 10+18+35).attr("font-size", 16).attr("font-family", "Sans,Arial") - .attr("fill", "#111111").attr("text-anchor", "middle").attr("pointer-events","none").text("ISO") - - // anglemod button - svg.append("rect").attr("x", 695).attr("y", 10+35).attr("width", 80).attr("height", 25).attr("rx",0).attr("ry",0) - .attr("fill","#777777").attr("stroke","black").attr("stroke-width","1").attr("onclick", "activateIso(true)") - .attr("onmouseover", "showTooltip(evt,'Switch layout to ISO with angle mod')").attr("onmouseout", "hideTooltip()") - svg.append("text").attr("x", 695+40).attr("y", 10+18+35).attr("font-size", 16).attr("font-family", "Sans,Arial") - .attr("fill", "#111111").attr("text-anchor", "middle").attr("pointer-events","none").text("anglemod") - - // ansi button - svg.append("rect").attr("x", 640).attr("y", 10+35+35).attr("width", 46).attr("height", 25).attr("rx",0).attr("ry",0) - .attr("fill","#777777").attr("stroke","black").attr("stroke-width","1").attr("onclick", "activateAnsi()") - .attr("onmouseover", "showTooltip(evt,'Switch layout to ANSI')").attr("onmouseout", "hideTooltip()") - svg.append("text").attr("x", 640+23).attr("y", 10+18+35+35).attr("font-size", 16).attr("font-family", "Sans,Arial") - .attr("fill", "#111111").attr("text-anchor", "middle").attr("pointer-events","none").text("ANSI") - + if ( + dataloaded == false || + dictionaryloaded == false || + effortloaded == false + ) { + return; + } + console.log("generateLayout"); + svg.selectAll("*").remove(); + if (mode == "iso" || mode == "ansi") { + outlinewidth = 572; + } else { + outlinewidth = 510; + } + svg + .append("rect") + .attr("x", 45) + .attr("y", 0) + .attr("width", outlinewidth) + .attr("height", 170) + .attr("stroke", "#777777") + .attr("fill", "#1b1c1f") + .attr("fill-opactiy", "0.0") + .attr("rx", 8) + .attr("ry", 8); + for (let i = 0; i < rcdata_len; i++) { + dtx = 0; + letter = rcdata[i][0]; + if (letter == "^") { + letter = "shift"; + } + x = rcdata[i][5]; + y = rcdata[i][4]; + per = rcdata[i][3]; + keywidth = rcdata[i][6]; + red = Math.floor(127 * per * inv_default_max) + 128; + if (red < 16) { + red = 16; + } + if (red > 255) { + red = 255; + } + hex_red = red.toString(16); + hex_bg = green.toString(16); + + fontsize = 16; + if (letter == "$") { + letter = "ctrl"; + } + if (letter.length > 1) { + fontsize = 10; + } + if (letter.length > 4 && mode == "ergo") { + fontsize = 9; + } + + svg + .append("rect") + .attr("x", x) + .attr("y", y) + .attr("width", keywidth * w - gap) + .attr("height", w - gap) + .attr("rx", 4) + .attr("ry", 4) + .attr("fill", "#" + hex_red + hex_bg + hex_bg) + .attr("stroke", "black") + .attr("stroke-width", "1") + .attr("class", "draggable"); + if (letter.length > 1 && mode != "ergo") { + svg + .append("text") + .attr("x", x + 5) + .attr("y", y + 19) + .attr("font-size", fontsize) + .attr("font-family", "Roboto Mono") + .attr("text-anchor", "left") + .attr("class", "draggable legend") + .text(letter); + } else { + svg + .append("text") + .attr("x", x + 15) + .attr("y", y + 19) + .attr("font-size", fontsize) + .attr("font-family", "Roboto Mono") + .attr("text-anchor", "middle") + .attr("class", "draggable legend") + .text(letter); + } + } + // + if (m_total_word_effort == 0) { + // console.log("m_total_word_effort == 0") + measureDictionary(); + measureWords(); + } + svg + .append("text") + .attr("x", 640) + .attr("y", 135) + .attr("font-size", 16) + .attr("font-family", "Sans,Arial") + .attr("fill", "#dfe2eb") + .attr("text-anchor", "left") + .text("Total Word Effort " + (m_total_word_effort / 100.0).toFixed(1)); + // effort text + svg + .append("text") + .attr("x", 640) + .attr("y", 165) + .attr("font-size", 16) + .attr("font-family", "Sans,Arial") + .attr("fill", "#dfe2eb") + .attr("text-anchor", "left") + .text("Effort " + (577 * m_effort * inv_m_input_length).toFixed(2)); + // edit button + svg + .append("rect") + .attr("x", 760) + .attr("y", 147) + .attr("width", 40) + .attr("height", 25) + .attr("rx", 0) + .attr("ry", 0) + .attr("fill", "#777777") + .attr("stroke", "black") + .attr("stroke-width", "1") + .attr("onclick", "openPopup()") + .attr("onmouseover", "showTooltip(evt,'Edit effort values for each key')") + .attr("onmouseout", "hideTooltip()"); + + svg + .append("text") + .attr("x", 760 + 20) + .attr("y", 164) + .attr("font-size", 16) + .attr("font-family", "Sans,Arial") + .attr("fill", "#111111") + .attr("text-anchor", "middle") + .attr("pointer-events", "none") + .text("Edit"); + + // ergo button + svg + .append("rect") + .attr("x", 640) + .attr("y", 10) + .attr("width", 46) + .attr("height", 25) + .attr("rx", 0) + .attr("ry", 0) + .attr("fill", "#777777") + .attr("stroke", "black") + .attr("stroke-width", "1") + .attr("onclick", "activateErgo()") + .attr("onmouseover", "showTooltip(evt,'Switch layout to Ergo')") + .attr("onmouseout", "hideTooltip()"); + svg + .append("text") + .attr("x", 640 + 23) + .attr("y", 10 + 18) + .attr("font-size", 16) + .attr("font-family", "Sans,Arial") + .attr("fill", "#111111") + .attr("text-anchor", "middle") + .attr("pointer-events", "none") + .text("Ergo"); + // iso button + svg + .append("rect") + .attr("x", 640) + .attr("y", 10 + 35) + .attr("width", 46) + .attr("height", 25) + .attr("rx", 0) + .attr("ry", 0) + .attr("fill", "#777777") + .attr("stroke", "black") + .attr("stroke-width", "1") + .attr("onclick", "activateIso(false)") + .attr("onmouseover", "showTooltip(evt,'Switch layout to ISO')") + .attr("onmouseout", "hideTooltip()"); + svg + .append("text") + .attr("x", 640 + 23) + .attr("y", 10 + 18 + 35) + .attr("font-size", 16) + .attr("font-family", "Sans,Arial") + .attr("fill", "#111111") + .attr("text-anchor", "middle") + .attr("pointer-events", "none") + .text("ISO"); + + // anglemod button + svg + .append("rect") + .attr("x", 695) + .attr("y", 10 + 35) + .attr("width", 80) + .attr("height", 25) + .attr("rx", 0) + .attr("ry", 0) + .attr("fill", "#777777") + .attr("stroke", "black") + .attr("stroke-width", "1") + .attr("onclick", "activateIso(true)") + .attr( + "onmouseover", + "showTooltip(evt,'Switch layout to ISO with angle mod')", + ) + .attr("onmouseout", "hideTooltip()"); + svg + .append("text") + .attr("x", 695 + 40) + .attr("y", 10 + 18 + 35) + .attr("font-size", 16) + .attr("font-family", "Sans,Arial") + .attr("fill", "#111111") + .attr("text-anchor", "middle") + .attr("pointer-events", "none") + .text("anglemod"); + + // ansi button + svg + .append("rect") + .attr("x", 640) + .attr("y", 10 + 35 + 35) + .attr("width", 46) + .attr("height", 25) + .attr("rx", 0) + .attr("ry", 0) + .attr("fill", "#777777") + .attr("stroke", "black") + .attr("stroke-width", "1") + .attr("onclick", "activateAnsi()") + .attr("onmouseover", "showTooltip(evt,'Switch layout to ANSI')") + .attr("onmouseout", "hideTooltip()"); + svg + .append("text") + .attr("x", 640 + 23) + .attr("y", 10 + 18 + 35 + 35) + .attr("font-size", 16) + .attr("font-family", "Sans,Arial") + .attr("fill", "#111111") + .attr("text-anchor", "middle") + .attr("pointer-events", "none") + .text("ANSI"); } var m_column_usage = {}; var m_finger_usage = {}; var m_finger_distance = {}; var m_finger_pairs = {}; -var m_same_finger = {}; // per bigram +var m_same_finger = {}; // per bigram var m_same_finger2 = {}; // per finger var m_same_finger3 = {}; // per bigram 2u var m_skip_bigram = {}; @@ -1094,1426 +1384,2528 @@ var inv_m_input_length = 1; var m_effort = 0; var m_total_word_effort = 0; // var m_simple_effort = {}; -var finger_pos = [[0, 0], [1, 1], [1, 2], [1, 3], [1, 4], [3, 4], [3, 7], [1, 7], [1, 8], [1, 9], [1, 10]]; +var finger_pos = [ + [0, 0], + [1, 1], + [1, 2], + [1, 3], + [1, 4], + [3, 4], + [3, 7], + [1, 7], + [1, 8], + [1, 9], + [1, 10], +]; -var word_effort = Object.create(null) +var word_effort = Object.create(null); var samehandstrings = {}; var samehandcount = {}; function measureDictionary() { - if (dataloaded == false || dictionaryloaded == false || effortloaded == false) {return;} - console.log("measureDictionary"); - // console.log("measuring effort of each word in the dictionary"); - var total=0, word, char1, char2, col1, row1, col2, row2, hand1, hand2, samehand,count = 0; - word_effort = Object.create(null) - for(var wordi in dictionary) { - count += 1; - total = 0.0; - word = dictionary[wordi]; - word_len = word.length // Compute once - char1 = word.charAt(0); - samehand = `${char1}`; - for (let i = 1; i < word_len; i++) { - char1 = word.charAt(i-1); - char2 = word.charAt(i); - col1 = getCol(char1); - row1 = getRow(char1); - col2 = getCol(char2); - row2 = getRow(char2); - if (bigram_effort[col1]) { - if (bigram_effort[col1][row1]) { - if (bigram_effort[col1][row1][col2]) { - if (bigram_effort[col1][row1][col2][row2]) { - var e = bigram_effort[col1][row1][col2][row2] - total += e; - } - } - } - } - } - char1 = word.charAt(word_len-1); - char2 = "_" - col1 = getCol(char1); - row1 = getRow(char1); - col2 = 6; - row2 = 3; - if (bigram_effort[col1]) { - if (bigram_effort[col1][row1]) { - if (bigram_effort[col1][row1][col2]) { - if (bigram_effort[col1][row1][col2][row2]) { - var e = bigram_effort[col1][row1][col2][row2] - total += e; - } - } - } - } - - for (let i = 2; i < word_len; i++) { - char1 = word.charAt(i-2); - char2 = word.charAt(i); - col1 = getCol(char1); - row1 = getRow(char1); - col2 = getCol(char2); - row2 = getRow(char2); - if (bigram_effort[col1]) { - if (bigram_effort[col1][row1]) { - if (bigram_effort[col1][row1][col2]) { - if (bigram_effort[col1][row1][col2][row2]) { - var e = bigram_effort[col1][row1][col2][row2] - total += 0.2 * e; - } - } - } - } - } - char1 = word.charAt(word_len-2); - char2 = "_" - col1 = getCol(char1); - row1 = getRow(char1); - col2 = 6; - row2 = 3; - if (bigram_effort[col1]) { - if (bigram_effort[col1][row1]) { - if (bigram_effort[col1][row1][col2]) { - if (bigram_effort[col1][row1][col2][row2]) { - var e = bigram_effort[col1][row1][col2][row2] - total += 0.2 * e; - } - } - } - } - if (isNaN(total)){ - console.log(word + " gives NaN for effort") - } - word_effort[word] = 0.1 * total; - } + if ( + dataloaded == false || + dictionaryloaded == false || + effortloaded == false + ) { + return; + } + console.log("measureDictionary"); + // console.log("measuring effort of each word in the dictionary"); + var total = 0, + word, + char1, + char2, + col1, + row1, + col2, + row2, + hand1, + hand2, + samehand, + count = 0; + word_effort = Object.create(null); + for (var wordi in dictionary) { + count += 1; + total = 0.0; + word = dictionary[wordi]; + word_len = word.length; // Compute once + char1 = word.charAt(0); + samehand = `${char1}`; + for (let i = 1; i < word_len; i++) { + char1 = word.charAt(i - 1); + char2 = word.charAt(i); + col1 = getCol(char1); + row1 = getRow(char1); + col2 = getCol(char2); + row2 = getRow(char2); + if (bigram_effort[col1]) { + if (bigram_effort[col1][row1]) { + if (bigram_effort[col1][row1][col2]) { + if (bigram_effort[col1][row1][col2][row2]) { + var e = bigram_effort[col1][row1][col2][row2]; + total += e; + } + } + } + } + } + char1 = word.charAt(word_len - 1); + char2 = "_"; + col1 = getCol(char1); + row1 = getRow(char1); + col2 = 6; + row2 = 3; + if (bigram_effort[col1]) { + if (bigram_effort[col1][row1]) { + if (bigram_effort[col1][row1][col2]) { + if (bigram_effort[col1][row1][col2][row2]) { + var e = bigram_effort[col1][row1][col2][row2]; + total += e; + } + } + } + } + + for (let i = 2; i < word_len; i++) { + char1 = word.charAt(i - 2); + char2 = word.charAt(i); + col1 = getCol(char1); + row1 = getRow(char1); + col2 = getCol(char2); + row2 = getRow(char2); + if (bigram_effort[col1]) { + if (bigram_effort[col1][row1]) { + if (bigram_effort[col1][row1][col2]) { + if (bigram_effort[col1][row1][col2][row2]) { + var e = bigram_effort[col1][row1][col2][row2]; + total += 0.2 * e; + } + } + } + } + } + char1 = word.charAt(word_len - 2); + char2 = "_"; + col1 = getCol(char1); + row1 = getRow(char1); + col2 = 6; + row2 = 3; + if (bigram_effort[col1]) { + if (bigram_effort[col1][row1]) { + if (bigram_effort[col1][row1][col2]) { + if (bigram_effort[col1][row1][col2][row2]) { + var e = bigram_effort[col1][row1][col2][row2]; + total += 0.2 * e; + } + } + } + } + if (isNaN(total)) { + console.log(word + " gives NaN for effort"); + } + word_effort[word] = 0.1 * total; + } } function getDictionaryFromWords() { - console.log("getDictionaryFromWords"); - dictionary = []; - for (let word in words) { - if (words[word] > 100) { - dictionary.push(word); - } - } + console.log("getDictionaryFromWords"); + dictionary = []; + for (const word in words) { + if (words[word] > 100) { + dictionary.push(word); + } + } } -function getIndexOfKey(name){ - var x = -1; - for (let i = 0; i < 34; i++) { - if (rcdata[i][7] == name) { - x = i; - } - } - return x; +function getIndexOfKey(name) { + var x = -1; + for (let i = 0; i < 34; i++) { + if (rcdata[i][7] == name) { + x = i; + } + } + return x; } function updateRcData(lan) { - // what are the 33 letters ? - var letters = [] - for (let word in words) { - if (letters.length>=32){ - break; - } - var wordLetters = word.split(""); // Split the word into individual letters - for (let i = 0; i < wordLetters.length; i++) { - if (letters.indexOf(wordLetters[i]) === -1) { - letters.push(wordLetters[i]); // Add letter to the list if not already present - } - } - } - // my new idea for fixing this issue still didn't work - // the problem is that the keys that I want to change when switching languages aren't in a consistent position in the grid, or at a consistent position in the array, - // or have a consistent letter on them. Even the index I added to try to make them consistent didn't work because of the way the import process works - if (lan == 'german'){ - // letters = ['q', 'w', 'e', 'r', 't', 'z', 'u', 'i', 'o', 'p', 'ü', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'ö', 'ä', 'y','x', 'c', 'v', 'b', 'n', 'm', ',', '.', '\'', 'ß'] - if (getIndexOfKey(10) >= 0) { rcdata[getIndexOfKey(10)][0] = 'ü' } - if (getIndexOfKey(20) >= 0) { rcdata[getIndexOfKey(20)][0] = 'ö' } - if (getIndexOfKey(21) >= 0) { rcdata[getIndexOfKey(21)][0] = '\'' } - if (getIndexOfKey(31) >= 0) { rcdata[getIndexOfKey(31)][0] = 'ä' } - if (getIndexOfKey(32) >= 0) { rcdata[getIndexOfKey(32)][0] = 'ß' } - } else if (lan == 'english') { - // letters = ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '-', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/','\\'] - if (getIndexOfKey(10) >= 0) { rcdata[getIndexOfKey(10)][0] = '-' } - if (getIndexOfKey(20) >= 0) { rcdata[getIndexOfKey(20)][0] = ';' } - if (getIndexOfKey(21) >= 0) { rcdata[getIndexOfKey(21)][0] = '\'' } - if (getIndexOfKey(31) >= 0) { rcdata[getIndexOfKey(31)][0] = '/' } - if (getIndexOfKey(32) >= 0) { rcdata[getIndexOfKey(32)][0] = '\\' } - } else if (lan == 'dutch') { - // letters = ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '-', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/','\\'] - if (getIndexOfKey(10) >= 0) { rcdata[getIndexOfKey(10)][0] = '-' } - if (getIndexOfKey(20) >= 0) { rcdata[getIndexOfKey(20)][0] = ';' } - if (getIndexOfKey(21) >= 0) { rcdata[getIndexOfKey(21)][0] = '\'' } - if (getIndexOfKey(31) >= 0) { rcdata[getIndexOfKey(31)][0] = '/' } - if (getIndexOfKey(32) >= 0) { rcdata[getIndexOfKey(32)][0] = '\\' } - } else if (lan == 'french') { - // letters = ['a', 'z', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', 'é', 'q', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'è', '\'', 'w', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', 'ç', 'à'] - if (getIndexOfKey(10) >= 0) { rcdata[getIndexOfKey(10)][0] = 'é' } - if (getIndexOfKey(20) >= 0) { rcdata[getIndexOfKey(20)][0] = 'è' } - if (getIndexOfKey(21) >= 0) { rcdata[getIndexOfKey(21)][0] = '\'' } - if (getIndexOfKey(31) >= 0) { rcdata[getIndexOfKey(31)][0] = 'ç' } - if (getIndexOfKey(32) >= 0) { rcdata[getIndexOfKey(32)][0] = 'à' } - } else if (lan == 'italian') { - // letters = ['a', 'z', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', 'é', 'q', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'è', '\'', 'w', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', 'ç', 'à'] - if (getIndexOfKey(10) >= 0) { rcdata[getIndexOfKey(10)][0] = 'è' } - if (getIndexOfKey(20) >= 0) { rcdata[getIndexOfKey(20)][0] = 'à' } - if (getIndexOfKey(21) >= 0) { rcdata[getIndexOfKey(21)][0] = 'ù' } - if (getIndexOfKey(31) >= 0) { rcdata[getIndexOfKey(31)][0] = 'ò' } - if (getIndexOfKey(32) >= 0) { rcdata[getIndexOfKey(32)][0] = 'ì' } - } else if (lan == 'swedish') { - // letters = ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', 'å', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'ö', 'ä', 'z', 'x', 'c', 'v', 'b','n', 'm', '.', ',', '\'', '\\'] - if (getIndexOfKey(10) >= 0) { rcdata[getIndexOfKey(10)][0] = 'å' } - if (getIndexOfKey(20) >= 0) { rcdata[getIndexOfKey(20)][0] = 'ö' } - if (getIndexOfKey(21) >= 0) { rcdata[getIndexOfKey(21)][0] = 'ä' } - if (getIndexOfKey(31) >= 0) { rcdata[getIndexOfKey(31)][0] = '\'' } - if (getIndexOfKey(32) >= 0) { rcdata[getIndexOfKey(32)][0] = '\\' } - } else if (lan == 'spanish') { - // letters = ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '-', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'ñ', '\'', 'z','x', 'c', 'v', 'b', 'n', 'm',',', '.', '/', '\\'] - if (getIndexOfKey(10) >= 0) { rcdata[getIndexOfKey(10)][0] = '-' } - if (getIndexOfKey(20) >= 0) { rcdata[getIndexOfKey(20)][0] = 'ñ' } - if (getIndexOfKey(21) >= 0) { rcdata[getIndexOfKey(21)][0] = '\'' } - if (getIndexOfKey(31) >= 0) { rcdata[getIndexOfKey(31)][0] = '/' } - if (getIndexOfKey(32) >= 0) { rcdata[getIndexOfKey(32)][0] = '\\' } - } else if (lan == 'portuguese') { - // letters = ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '-', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'ç', '\'', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/','\\'] - if (getIndexOfKey(10) >= 0) { rcdata[getIndexOfKey(10)][0] = '-' } - if (getIndexOfKey(20) >= 0) { rcdata[getIndexOfKey(20)][0] = 'ç' } - if (getIndexOfKey(21) >= 0) { rcdata[getIndexOfKey(21)][0] = '\'' } - if (getIndexOfKey(31) >= 0) { rcdata[getIndexOfKey(31)][0] = '/' } - if (getIndexOfKey(32) >= 0) { rcdata[getIndexOfKey(32)][0] = '\\' } - } else if (lan == 'norweigan') { - // letters = ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', 'å', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'ø', 'æ', 'z', 'x','c','v', 'b', 'm', 'n', '.', ',', '\'', '\\'] - if (getIndexOfKey(10) >= 0) { rcdata[getIndexOfKey(10)][0] = 'å' } - if (getIndexOfKey(20) >= 0) { rcdata[getIndexOfKey(20)][0] = 'ø' } - if (getIndexOfKey(21) >= 0) { rcdata[getIndexOfKey(21)][0] = 'æ' } - if (getIndexOfKey(31) >= 0) { rcdata[getIndexOfKey(31)][0] = '\'' } - if (getIndexOfKey(32) >= 0) { rcdata[getIndexOfKey(32)][0] = '\\' } - } else if (lan == 'finnish') { - // letters = ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', 'å', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'ö', 'ä', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '\'', '\\'] - if (getIndexOfKey(10) >= 0) { rcdata[getIndexOfKey(10)][0] = 'å' } - if (getIndexOfKey(20) >= 0) { rcdata[getIndexOfKey(20)][0] = 'ö' } - if (getIndexOfKey(21) >= 0) { rcdata[getIndexOfKey(21)][0] = 'ä' } - if (getIndexOfKey(31) >= 0) { rcdata[getIndexOfKey(31)][0] = '\'' } - if (getIndexOfKey(32) >= 0) { rcdata[getIndexOfKey(32)][0] = '\\' } - } else if (lan == 'estonian') { - if (getIndexOfKey(10) >= 0) { rcdata[getIndexOfKey(10)][0] = 'ä' } - if (getIndexOfKey(20) >= 0) { rcdata[getIndexOfKey(20)][0] = 'õ' } - if (getIndexOfKey(21) >= 0) { rcdata[getIndexOfKey(21)][0] = '\'' } - if (getIndexOfKey(31) >= 0) { rcdata[getIndexOfKey(31)][0] = 'ü' } - if (getIndexOfKey(32) >= 0) { rcdata[getIndexOfKey(32)][0] = 'ö' } - } else if (lan == 'hungarian') { - // letters = ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '-', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/','\\'] - if (getIndexOfKey(10) >= 0) { rcdata[getIndexOfKey(10)][0] = '-' } - if (getIndexOfKey(20) >= 0) { rcdata[getIndexOfKey(20)][0] = ';' } - if (getIndexOfKey(21) >= 0) { rcdata[getIndexOfKey(21)][0] = '\'' } - if (getIndexOfKey(31) >= 0) { rcdata[getIndexOfKey(31)][0] = '/' } - if (getIndexOfKey(32) >= 0) { rcdata[getIndexOfKey(32)][0] = '\\' } - } else if (lan == 'polish') { - if (getIndexOfKey(10) >= 0) { rcdata[getIndexOfKey(10)][0] = '-' } - if (getIndexOfKey(20) >= 0) { rcdata[getIndexOfKey(20)][0] = ';' } - if (getIndexOfKey(21) >= 0) { rcdata[getIndexOfKey(21)][0] = '\'' } - if (getIndexOfKey(31) >= 0) { rcdata[getIndexOfKey(31)][0] = '/' } - if (getIndexOfKey(32) >= 0) { rcdata[getIndexOfKey(32)][0] = '\\' } - } + // what are the 33 letters ? + var letters = []; + for (const word in words) { + if (letters.length >= 32) { + break; + } + var wordLetters = word.split(""); // Split the word into individual letters + for (let i = 0; i < wordLetters.length; i++) { + if (letters.indexOf(wordLetters[i]) === -1) { + letters.push(wordLetters[i]); // Add letter to the list if not already present + } + } + } + // my new idea for fixing this issue still didn't work + // the problem is that the keys that I want to change when switching languages aren't in a consistent position in the grid, or at a consistent position in the array, + // or have a consistent letter on them. Even the index I added to try to make them consistent didn't work because of the way the import process works + if (lan == "german") { + // letters = ['q', 'w', 'e', 'r', 't', 'z', 'u', 'i', 'o', 'p', 'ü', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'ö', 'ä', 'y','x', 'c', 'v', 'b', 'n', 'm', ',', '.', '\'', 'ß'] + if (getIndexOfKey(10) >= 0) { + rcdata[getIndexOfKey(10)][0] = "ü"; + } + if (getIndexOfKey(20) >= 0) { + rcdata[getIndexOfKey(20)][0] = "ö"; + } + if (getIndexOfKey(21) >= 0) { + rcdata[getIndexOfKey(21)][0] = "'"; + } + if (getIndexOfKey(31) >= 0) { + rcdata[getIndexOfKey(31)][0] = "ä"; + } + if (getIndexOfKey(32) >= 0) { + rcdata[getIndexOfKey(32)][0] = "ß"; + } + } else if (lan == "english") { + // letters = ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '-', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/','\\'] + if (getIndexOfKey(10) >= 0) { + rcdata[getIndexOfKey(10)][0] = "-"; + } + if (getIndexOfKey(20) >= 0) { + rcdata[getIndexOfKey(20)][0] = ";"; + } + if (getIndexOfKey(21) >= 0) { + rcdata[getIndexOfKey(21)][0] = "'"; + } + if (getIndexOfKey(31) >= 0) { + rcdata[getIndexOfKey(31)][0] = "/"; + } + if (getIndexOfKey(32) >= 0) { + rcdata[getIndexOfKey(32)][0] = "\\"; + } + } else if (lan == "dutch") { + // letters = ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '-', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/','\\'] + if (getIndexOfKey(10) >= 0) { + rcdata[getIndexOfKey(10)][0] = "-"; + } + if (getIndexOfKey(20) >= 0) { + rcdata[getIndexOfKey(20)][0] = ";"; + } + if (getIndexOfKey(21) >= 0) { + rcdata[getIndexOfKey(21)][0] = "'"; + } + if (getIndexOfKey(31) >= 0) { + rcdata[getIndexOfKey(31)][0] = "/"; + } + if (getIndexOfKey(32) >= 0) { + rcdata[getIndexOfKey(32)][0] = "\\"; + } + } else if (lan == "french") { + // letters = ['a', 'z', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', 'é', 'q', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'è', '\'', 'w', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', 'ç', 'à'] + if (getIndexOfKey(10) >= 0) { + rcdata[getIndexOfKey(10)][0] = "é"; + } + if (getIndexOfKey(20) >= 0) { + rcdata[getIndexOfKey(20)][0] = "è"; + } + if (getIndexOfKey(21) >= 0) { + rcdata[getIndexOfKey(21)][0] = "'"; + } + if (getIndexOfKey(31) >= 0) { + rcdata[getIndexOfKey(31)][0] = "ç"; + } + if (getIndexOfKey(32) >= 0) { + rcdata[getIndexOfKey(32)][0] = "à"; + } + } else if (lan == "italian") { + // letters = ['a', 'z', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', 'é', 'q', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'è', '\'', 'w', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', 'ç', 'à'] + if (getIndexOfKey(10) >= 0) { + rcdata[getIndexOfKey(10)][0] = "è"; + } + if (getIndexOfKey(20) >= 0) { + rcdata[getIndexOfKey(20)][0] = "à"; + } + if (getIndexOfKey(21) >= 0) { + rcdata[getIndexOfKey(21)][0] = "ù"; + } + if (getIndexOfKey(31) >= 0) { + rcdata[getIndexOfKey(31)][0] = "ò"; + } + if (getIndexOfKey(32) >= 0) { + rcdata[getIndexOfKey(32)][0] = "ì"; + } + } else if (lan == "swedish") { + // letters = ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', 'å', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'ö', 'ä', 'z', 'x', 'c', 'v', 'b','n', 'm', '.', ',', '\'', '\\'] + if (getIndexOfKey(10) >= 0) { + rcdata[getIndexOfKey(10)][0] = "å"; + } + if (getIndexOfKey(20) >= 0) { + rcdata[getIndexOfKey(20)][0] = "ö"; + } + if (getIndexOfKey(21) >= 0) { + rcdata[getIndexOfKey(21)][0] = "ä"; + } + if (getIndexOfKey(31) >= 0) { + rcdata[getIndexOfKey(31)][0] = "'"; + } + if (getIndexOfKey(32) >= 0) { + rcdata[getIndexOfKey(32)][0] = "\\"; + } + } else if (lan == "spanish") { + // letters = ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '-', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'ñ', '\'', 'z','x', 'c', 'v', 'b', 'n', 'm',',', '.', '/', '\\'] + if (getIndexOfKey(10) >= 0) { + rcdata[getIndexOfKey(10)][0] = "-"; + } + if (getIndexOfKey(20) >= 0) { + rcdata[getIndexOfKey(20)][0] = "ñ"; + } + if (getIndexOfKey(21) >= 0) { + rcdata[getIndexOfKey(21)][0] = "'"; + } + if (getIndexOfKey(31) >= 0) { + rcdata[getIndexOfKey(31)][0] = "/"; + } + if (getIndexOfKey(32) >= 0) { + rcdata[getIndexOfKey(32)][0] = "\\"; + } + } else if (lan == "portuguese") { + // letters = ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '-', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'ç', '\'', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/','\\'] + if (getIndexOfKey(10) >= 0) { + rcdata[getIndexOfKey(10)][0] = "-"; + } + if (getIndexOfKey(20) >= 0) { + rcdata[getIndexOfKey(20)][0] = "ç"; + } + if (getIndexOfKey(21) >= 0) { + rcdata[getIndexOfKey(21)][0] = "'"; + } + if (getIndexOfKey(31) >= 0) { + rcdata[getIndexOfKey(31)][0] = "/"; + } + if (getIndexOfKey(32) >= 0) { + rcdata[getIndexOfKey(32)][0] = "\\"; + } + } else if (lan == "norweigan") { + // letters = ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', 'å', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'ø', 'æ', 'z', 'x','c','v', 'b', 'm', 'n', '.', ',', '\'', '\\'] + if (getIndexOfKey(10) >= 0) { + rcdata[getIndexOfKey(10)][0] = "å"; + } + if (getIndexOfKey(20) >= 0) { + rcdata[getIndexOfKey(20)][0] = "ø"; + } + if (getIndexOfKey(21) >= 0) { + rcdata[getIndexOfKey(21)][0] = "æ"; + } + if (getIndexOfKey(31) >= 0) { + rcdata[getIndexOfKey(31)][0] = "'"; + } + if (getIndexOfKey(32) >= 0) { + rcdata[getIndexOfKey(32)][0] = "\\"; + } + } else if (lan == "finnish") { + // letters = ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', 'å', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'ö', 'ä', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '\'', '\\'] + if (getIndexOfKey(10) >= 0) { + rcdata[getIndexOfKey(10)][0] = "å"; + } + if (getIndexOfKey(20) >= 0) { + rcdata[getIndexOfKey(20)][0] = "ö"; + } + if (getIndexOfKey(21) >= 0) { + rcdata[getIndexOfKey(21)][0] = "ä"; + } + if (getIndexOfKey(31) >= 0) { + rcdata[getIndexOfKey(31)][0] = "'"; + } + if (getIndexOfKey(32) >= 0) { + rcdata[getIndexOfKey(32)][0] = "\\"; + } + } else if (lan == "estonian") { + if (getIndexOfKey(10) >= 0) { + rcdata[getIndexOfKey(10)][0] = "ä"; + } + if (getIndexOfKey(20) >= 0) { + rcdata[getIndexOfKey(20)][0] = "õ"; + } + if (getIndexOfKey(21) >= 0) { + rcdata[getIndexOfKey(21)][0] = "'"; + } + if (getIndexOfKey(31) >= 0) { + rcdata[getIndexOfKey(31)][0] = "ü"; + } + if (getIndexOfKey(32) >= 0) { + rcdata[getIndexOfKey(32)][0] = "ö"; + } + } else if (lan == "hungarian") { + // letters = ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '-', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/','\\'] + if (getIndexOfKey(10) >= 0) { + rcdata[getIndexOfKey(10)][0] = "-"; + } + if (getIndexOfKey(20) >= 0) { + rcdata[getIndexOfKey(20)][0] = ";"; + } + if (getIndexOfKey(21) >= 0) { + rcdata[getIndexOfKey(21)][0] = "'"; + } + if (getIndexOfKey(31) >= 0) { + rcdata[getIndexOfKey(31)][0] = "/"; + } + if (getIndexOfKey(32) >= 0) { + rcdata[getIndexOfKey(32)][0] = "\\"; + } + } else if (lan == "polish") { + if (getIndexOfKey(10) >= 0) { + rcdata[getIndexOfKey(10)][0] = "-"; + } + if (getIndexOfKey(20) >= 0) { + rcdata[getIndexOfKey(20)][0] = ";"; + } + if (getIndexOfKey(21) >= 0) { + rcdata[getIndexOfKey(21)][0] = "'"; + } + if (getIndexOfKey(31) >= 0) { + rcdata[getIndexOfKey(31)][0] = "/"; + } + if (getIndexOfKey(32) >= 0) { + rcdata[getIndexOfKey(32)][0] = "\\"; + } + } } function measureWords() { - if (dataloaded == false || dictionaryloaded == false || effortloaded == false) {return;} - console.log("measureWords"); - if (!needs_update){return;} - m_column_usage = {}; - m_finger_usage = {}; - m_finger_distance = {}; - m_skip_bigram = {}; - m_skip_bigram2 = {}; - m_redirects = {}; - m_scissors = {}; - m_all_scissors = {}; - m_pinky_scissors = {}; - m_same_finger = {}; - m_same_finger2 = {}; - m_same_finger3 = {}; - m_lat_stretch = {}; - m_lat_stretch2 = {}; - m_letter_freq = {}; - m_row_usage = {}; - m_trigram_count = {}; - m_trigram_count_alt = {}; - m_trigram_count_red = {}; - m_trigram_count_roll_in = {}; - m_trigram_count_roll_out = {}; - m_finger_pairs = {}; - samehandstrings = {}; - samehandcount = {}; - m_pinky_off = 0; - m_input_length = 0; - m_effort = 0; - m_total_word_effort = 0; - var char = ""; - var prevchar = ""; - var prevfinger = -1; - var ppchar = ""; - var ppfinger = -1; - var bigram, trigram, cat, cat2, skip; - var prevcol = -1; - var prevrow = -1; - var pprow = -1; - var col,row,hand,prevhand; - var m_effort_per_letter = {}; - var m_effort_per_word = {}; - var word_count = 0 - for (let word in words) { - if (word_count > 40000){break;} - word_count += 1 - finger_pos = [[0, 0], [1, 1], [1, 2], [1, 3], [1, 4], [3, 4], [3, 7], [1, 7], [1, 8], [1, 9], [1, 10]]; - const count = words[word]; - word_len = word.length // Compute once - m_input_length += count * (word_len + 1); - - if (word_effort[word]){ - // console.log(word +" "+word_effort[word]); - m_total_word_effort += word_effort[word] * count; - } - - char = word.charAt(0); - samehand = char - for (let i = 0; i < word_len; i++) { - char = word.charAt(i); - if (i > 0){prevchar = word.charAt(i-1);} - // freq // - if (!m_letter_freq[char]) { - m_letter_freq[char] = 0; - } - m_letter_freq[char] += count; - // finger usage // - row = getRow(char); - col = getCol(char); - if (i > 0){prevcol = getCol(prevchar);} - if (col <= 5){ - hand = "L" - } else { - hand = "R" - } - if (col < 0) { continue; } // this is the part that just skips numbers and other characters - if (!m_column_usage[col]) { - m_column_usage[col] = 0; - } - if ((row == 0 && col == 1)||(row == 2 && col == 1)||(row == 0 && col == 10)||(row == 2 && col == 10)||(row == 0 && col == 11)||(row == 1 && col == 11)) { - m_pinky_off += count - } - if (row < 3){ m_column_usage[col] += count;} - // finger usage // - // effort - if (!m_effort_per_letter[char]){ - m_effort_per_letter[char] = 0 - } - m_effort_per_letter[char] += count * getEffort(row,col) - if (!m_effort_per_word[word]){ - m_effort_per_word[word] = 0 - } - m_effort_per_word[word] += count * getEffort(row,col) - - m_effort += count * getEffort(row, col); - - var finger = getFinger(row, col); - if (!m_finger_usage[finger]) { - m_finger_usage[finger] = 0; - } - m_finger_usage[finger] += count; - // finger travel distance - if (row < 0) { break; } - // d = dist(col, row, finger_pos[finger][1], finger_pos[finger][0]); - x1 = getX(char,row,col) - y1 = getY(char,row,col) - x2 = getX(getChar(finger_pos[finger][0],finger_pos[finger][1]),finger_pos[finger][0],finger_pos[finger][1]) - y2 = getY(getChar(finger_pos[finger][0],finger_pos[finger][1]),finger_pos[finger][0],finger_pos[finger][1]) - d = dist(x1, y1, x2, y2); - if (!m_finger_distance[finger]) { - m_finger_distance[finger] = 0; - } - m_finger_distance[finger] += d * count; - - finger_pos[finger] = [row, col]; // move finger to new position - - // finger row // - if (!m_row_usage[row]) { - m_row_usage[row] = 0; - } - m_row_usage[row] += count; - - // bigram stuff - if (i > 0 && prevcol >= 0) { - bigram = prevchar + char; - if (finger == prevfinger && prevchar != char) { - if (!m_same_finger[bigram]) { - m_same_finger[bigram] = 0; - } - m_same_finger[bigram] += count; - - if (!m_same_finger2[finger]) { - m_same_finger2[finger] = 0; - } - m_same_finger2[finger] += count; - - if (Math.abs(row-prevrow) >= 2) { - if (!m_same_finger3[bigram]) { - m_same_finger3[bigram] = 0; - } - m_same_finger3[bigram] += count; - } - } - // lsbs - if ((prevcol == 3 && col == 5) || (prevcol == 8 && col == 6) || (prevcol == 5 && col == 3) || (prevcol == 6 && col == 8)) { - if (!m_lat_stretch[bigram]) { - m_lat_stretch[bigram] = 0; - } - m_lat_stretch[bigram] += count; - } - if ((prevcol == 2 && col == 5) || (prevcol == 9 && col == 6) || (prevcol == 5 && col == 2) || (prevcol == 6 && col == 9)) { - if (!m_lat_stretch2[bigram]) { - m_lat_stretch2[bigram] = 0; - } - m_lat_stretch2[bigram] += count; - } - // scissors - if (Math.abs(col-prevcol) == 1 && Math.abs(row-prevrow) >= 2 && ((finger <= 4 && prevfinger <= 4 &&finger!=prevfinger)||(finger >=7 && prevfinger>=7&&finger!=prevfinger))) { - if (!m_scissors[bigram]) { - m_scissors[bigram] = 0; - } - m_scissors[bigram] += count; - } - // all 2u scissors wide scissors - if (Math.abs(row-prevrow) >= 2 && Math.abs(col-prevcol)>=1 && ((finger <= 4 && prevfinger <= 4)||(finger >=7 && prevfinger>=7))) { - if (!m_all_scissors[bigram]) { - m_all_scissors[bigram] = 0; - } - m_all_scissors[bigram] += count; - } - // pinky/ring scissors - if (Math.abs(col-prevcol) == 1 && Math.abs(row-prevrow) >= 1 && (finger == 1 ||finger == 10||prevfinger==1||prevfinger==10)) { - if (!m_pinky_scissors[bigram]) { - m_pinky_scissors[bigram] = 0; - } - m_pinky_scissors[bigram] += count; - } - // same hand strings - if (prevhand == hand) { - samehand = samehand + char; - } else { - if (samehand.length >= 4) { - if (!samehandstrings[samehand]) { - samehandstrings[samehand] = 0; - } - samehandstrings[samehand] += count; - } - if (!samehandcount[samehand.length]){ - samehandcount[samehand.length] = 0; - } - samehandcount[samehand.length] += count - samehand = char; - } - // finger pairs - if (!m_finger_pairs[prevfinger]) { - m_finger_pairs[prevfinger] = {}; - } - if (!m_finger_pairs[prevfinger][finger]) { - m_finger_pairs[prevfinger][finger] = 0; - } - if (char != prevchar){ - m_finger_pairs[prevfinger][finger] += count; - } - } - // trigram stuff - if (i > 1 && prevcol >= 0) { - skip = ppchar + "_" + char; - trigram = ppchar + prevchar + char; - if (finger == ppfinger && ppchar != char) { - if (!m_skip_bigram[skip]) { - m_skip_bigram[skip] = 0; - } - m_skip_bigram[skip] += count; - - if (Math.abs(getRow(ppchar)-row) >= 2) { - if (!m_skip_bigram2[skip]) { - m_skip_bigram2[skip] = 0 - } - m_skip_bigram2[skip] += count; - } - } - cat = "other"; - // cat2 = "other"; - if (ppfinger <= 5 && prevfinger <= 5 && finger <= 5) { // left hand - if (ppfinger < prevfinger && prevfinger < finger) { - cat = "roll in" - } else if (ppfinger > prevfinger && prevfinger > finger) { - cat = "roll out" - } else if ((ppfinger < prevfinger && finger < prevfinger && finger != ppfinger) || (ppfinger > prevfinger && finger > prevfinger && finger != ppfinger)) { - cat = "redirect" - // if (!m_redirects[trigram]) { - // m_redirects[trigram] = 0; - // } - // m_redirects[trigram] += count; - if (ppfinger == 4 || prevfinger == 4 || finger == 4) { - } else { - cat = "weak redirect" - } - } - } - if (ppfinger >= 6 && prevfinger >= 6 && finger >= 6) { // right hand - if (ppfinger > prevfinger && prevfinger > finger) { - cat = "roll in" - } else if (ppfinger < prevfinger && prevfinger < finger) { - cat = "roll out" - } else if ((ppfinger > prevfinger && finger > prevfinger && finger != ppfinger) || (ppfinger < prevfinger && finger < prevfinger && finger != ppfinger)) { - cat = "redirect" - // if (!m_redirects[trigram]) { - // m_redirects[trigram] = 0; - // } - // m_redirects[trigram] += count; - if (ppfinger == 7 || prevfinger == 7 || finger == 7) { - } else { - cat = "weak redirect" - } - } - } // - if ((ppfinger <= 5 && prevfinger >= 6 && finger <= 5) || (ppfinger >= 6 && prevfinger <= 5 && finger >= 6)) { - cat = "alt" - if (ppfinger == finger && ppchar != char) { - cat = "alt sfs" - } - // 1 2 3 - } else if (ppfinger <= 5 && prevfinger <= 5 && finger >= 6 && ppfinger < prevfinger) { // LLR - cat = "bigram roll in" // LEFT - } - else if (ppfinger >= 6 && prevfinger <= 5 && finger <= 5 && prevfinger < finger) { // RLL - cat = "bigram roll in" // LEFT - } - else if (ppfinger <= 5 && prevfinger <= 5 && finger >= 6 && ppfinger > prevfinger) { // LLR - cat = "bigram roll out" // LEFT - } - else if (ppfinger >= 6 && prevfinger <= 5 && finger <= 5 && prevfinger > finger) { // RLL - cat = "bigram roll out"; // LEFT - } - else if (ppfinger >= 6 && prevfinger >= 6 && finger <= 5 && ppfinger > prevfinger) { // RRL - cat = "bigram roll in" // RIGHT - } - else if (ppfinger <= 5 && prevfinger >= 6 && finger >= 6 && prevfinger > finger) { // LRR - cat = "bigram roll in" // RIGHT - } - else if (ppfinger >= 6 && prevfinger >= 6 && finger <= 5 && ppfinger < prevfinger) { // RRL - cat = "bigram roll out" // RIGHT - } - else if (ppfinger <= 5 && prevfinger >= 6 && finger >= 6 && prevfinger < finger) { // LRR - cat = "bigram roll out" // RIGHT - } - if (!m_trigram_count[cat]) { - m_trigram_count[cat] = 0; - } - m_trigram_count[cat] += count; - if (cat == "alt"){ - if (!m_trigram_count_alt[trigram]) { - m_trigram_count_alt[trigram] = 0; - } - // if (count > 20){ - m_trigram_count_alt[trigram] += count; - // } - // if (count > 10){ console.log(trigram + " "+ count);} - } - if (cat == "redirect" || cat == "weak redirect"){ - if (!m_trigram_count_red[trigram]) { - m_trigram_count_red[trigram] = 0; - } - // if (count > 20){ - m_trigram_count_red[trigram] += count; - // } - } - if (cat == "roll in" || cat == "bigram roll in"){ - if (!m_trigram_count_roll_in[trigram]) { - m_trigram_count_roll_in[trigram] = 0; - } - // if (count > 20){ - m_trigram_count_roll_in[trigram] += count; - // } - } - if (cat == "roll out" || cat == "bigram roll out"){ - if (!m_trigram_count_roll_out[trigram]) { - m_trigram_count_roll_out[trigram] = 0; - } - // if (count > 20){ - m_trigram_count_roll_out[trigram] += count; - // } - } - } - pprow = prevrow - prevcol = col; - prevrow = row; - prevhand = hand; - ppchar = prevchar; - ppfinger = prevfinger; - prevchar = char; - prevfinger = finger; - } - if (samehand.length >= 4) { - if (!samehandstrings[samehand]) { - samehandstrings[samehand] = 0; - } - samehandstrings[samehand] += count; - } - if (!samehandcount[samehand.length]){ - samehandcount[samehand.length] = 0; - } - samehandcount[samehand.length] += count - } - inv_m_input_length = 1.0 / m_input_length; - var scale = 1006393 * inv_m_input_length; - m_total_word_effort *= scale; - // console.log("word count "+word_count) - var sum = 0; - for (let letter in m_letter_freq) { - sum += m_letter_freq[letter] - } - const hundred_inv_sum = 100.0 / sum; - for (let letter in m_letter_freq) { - for (let i = 0; i < rcdata_len; i++) { - if (rcdata[i][0] == letter) { - rcdata[i][3] = hundred_inv_sum * m_letter_freq[letter] - } - } - } - needs_update = false; + if ( + dataloaded == false || + dictionaryloaded == false || + effortloaded == false + ) { + return; + } + console.log("measureWords"); + if (!needs_update) { + return; + } + m_column_usage = {}; + m_finger_usage = {}; + m_finger_distance = {}; + m_skip_bigram = {}; + m_skip_bigram2 = {}; + m_redirects = {}; + m_scissors = {}; + m_all_scissors = {}; + m_pinky_scissors = {}; + m_same_finger = {}; + m_same_finger2 = {}; + m_same_finger3 = {}; + m_lat_stretch = {}; + m_lat_stretch2 = {}; + m_letter_freq = {}; + m_row_usage = {}; + m_trigram_count = {}; + m_trigram_count_alt = {}; + m_trigram_count_red = {}; + m_trigram_count_roll_in = {}; + m_trigram_count_roll_out = {}; + m_finger_pairs = {}; + samehandstrings = {}; + samehandcount = {}; + m_pinky_off = 0; + m_input_length = 0; + m_effort = 0; + m_total_word_effort = 0; + var char = ""; + var prevchar = ""; + var prevfinger = -1; + var ppchar = ""; + var ppfinger = -1; + var bigram, trigram, cat, cat2, skip; + var prevcol = -1; + var prevrow = -1; + var pprow = -1; + var col, row, hand, prevhand; + var m_effort_per_letter = {}; + var m_effort_per_word = {}; + var word_count = 0; + for (const word in words) { + if (word_count > 40000) { + break; + } + word_count += 1; + finger_pos = [ + [0, 0], + [1, 1], + [1, 2], + [1, 3], + [1, 4], + [3, 4], + [3, 7], + [1, 7], + [1, 8], + [1, 9], + [1, 10], + ]; + const count = words[word]; + word_len = word.length; // Compute once + m_input_length += count * (word_len + 1); + + if (word_effort[word]) { + // console.log(word +" "+word_effort[word]); + m_total_word_effort += word_effort[word] * count; + } + + char = word.charAt(0); + samehand = char; + for (let i = 0; i < word_len; i++) { + char = word.charAt(i); + if (i > 0) { + prevchar = word.charAt(i - 1); + } + // freq // + if (!m_letter_freq[char]) { + m_letter_freq[char] = 0; + } + m_letter_freq[char] += count; + // finger usage // + row = getRow(char); + col = getCol(char); + if (i > 0) { + prevcol = getCol(prevchar); + } + if (col <= 5) { + hand = "L"; + } else { + hand = "R"; + } + if (col < 0) { + continue; + } // this is the part that just skips numbers and other characters + if (!m_column_usage[col]) { + m_column_usage[col] = 0; + } + if ( + (row == 0 && col == 1) || + (row == 2 && col == 1) || + (row == 0 && col == 10) || + (row == 2 && col == 10) || + (row == 0 && col == 11) || + (row == 1 && col == 11) + ) { + m_pinky_off += count; + } + if (row < 3) { + m_column_usage[col] += count; + } + // finger usage // + // effort + if (!m_effort_per_letter[char]) { + m_effort_per_letter[char] = 0; + } + m_effort_per_letter[char] += count * getEffort(row, col); + if (!m_effort_per_word[word]) { + m_effort_per_word[word] = 0; + } + m_effort_per_word[word] += count * getEffort(row, col); + + m_effort += count * getEffort(row, col); + + var finger = getFinger(row, col); + if (!m_finger_usage[finger]) { + m_finger_usage[finger] = 0; + } + m_finger_usage[finger] += count; + // finger travel distance + if (row < 0) { + break; + } + // d = dist(col, row, finger_pos[finger][1], finger_pos[finger][0]); + x1 = getX(char, row, col); + y1 = getY(char, row, col); + x2 = getX( + getChar(finger_pos[finger][0], finger_pos[finger][1]), + finger_pos[finger][0], + finger_pos[finger][1], + ); + y2 = getY( + getChar(finger_pos[finger][0], finger_pos[finger][1]), + finger_pos[finger][0], + finger_pos[finger][1], + ); + d = dist(x1, y1, x2, y2); + if (!m_finger_distance[finger]) { + m_finger_distance[finger] = 0; + } + m_finger_distance[finger] += d * count; + + finger_pos[finger] = [row, col]; // move finger to new position + + // finger row // + if (!m_row_usage[row]) { + m_row_usage[row] = 0; + } + m_row_usage[row] += count; + + // bigram stuff + if (i > 0 && prevcol >= 0) { + bigram = prevchar + char; + if (finger == prevfinger && prevchar != char) { + if (!m_same_finger[bigram]) { + m_same_finger[bigram] = 0; + } + m_same_finger[bigram] += count; + + if (!m_same_finger2[finger]) { + m_same_finger2[finger] = 0; + } + m_same_finger2[finger] += count; + + if (Math.abs(row - prevrow) >= 2) { + if (!m_same_finger3[bigram]) { + m_same_finger3[bigram] = 0; + } + m_same_finger3[bigram] += count; + } + } + // lsbs + if ( + (prevcol == 3 && col == 5) || + (prevcol == 8 && col == 6) || + (prevcol == 5 && col == 3) || + (prevcol == 6 && col == 8) + ) { + if (!m_lat_stretch[bigram]) { + m_lat_stretch[bigram] = 0; + } + m_lat_stretch[bigram] += count; + } + if ( + (prevcol == 2 && col == 5) || + (prevcol == 9 && col == 6) || + (prevcol == 5 && col == 2) || + (prevcol == 6 && col == 9) + ) { + if (!m_lat_stretch2[bigram]) { + m_lat_stretch2[bigram] = 0; + } + m_lat_stretch2[bigram] += count; + } + // scissors + if ( + Math.abs(col - prevcol) == 1 && + Math.abs(row - prevrow) >= 2 && + ((finger <= 4 && prevfinger <= 4 && finger != prevfinger) || + (finger >= 7 && prevfinger >= 7 && finger != prevfinger)) + ) { + if (!m_scissors[bigram]) { + m_scissors[bigram] = 0; + } + m_scissors[bigram] += count; + } + // all 2u scissors wide scissors + if ( + Math.abs(row - prevrow) >= 2 && + Math.abs(col - prevcol) >= 1 && + ((finger <= 4 && prevfinger <= 4) || (finger >= 7 && prevfinger >= 7)) + ) { + if (!m_all_scissors[bigram]) { + m_all_scissors[bigram] = 0; + } + m_all_scissors[bigram] += count; + } + // pinky/ring scissors + if ( + Math.abs(col - prevcol) == 1 && + Math.abs(row - prevrow) >= 1 && + (finger == 1 || finger == 10 || prevfinger == 1 || prevfinger == 10) + ) { + if (!m_pinky_scissors[bigram]) { + m_pinky_scissors[bigram] = 0; + } + m_pinky_scissors[bigram] += count; + } + // same hand strings + if (prevhand == hand) { + samehand = samehand + char; + } else { + if (samehand.length >= 4) { + if (!samehandstrings[samehand]) { + samehandstrings[samehand] = 0; + } + samehandstrings[samehand] += count; + } + if (!samehandcount[samehand.length]) { + samehandcount[samehand.length] = 0; + } + samehandcount[samehand.length] += count; + samehand = char; + } + // finger pairs + if (!m_finger_pairs[prevfinger]) { + m_finger_pairs[prevfinger] = {}; + } + if (!m_finger_pairs[prevfinger][finger]) { + m_finger_pairs[prevfinger][finger] = 0; + } + if (char != prevchar) { + m_finger_pairs[prevfinger][finger] += count; + } + } + // trigram stuff + if (i > 1 && prevcol >= 0) { + skip = ppchar + "_" + char; + trigram = ppchar + prevchar + char; + if (finger == ppfinger && ppchar != char) { + if (!m_skip_bigram[skip]) { + m_skip_bigram[skip] = 0; + } + m_skip_bigram[skip] += count; + + if (Math.abs(getRow(ppchar) - row) >= 2) { + if (!m_skip_bigram2[skip]) { + m_skip_bigram2[skip] = 0; + } + m_skip_bigram2[skip] += count; + } + } + cat = "other"; + // cat2 = "other"; + if (ppfinger <= 5 && prevfinger <= 5 && finger <= 5) { + // left hand + if (ppfinger < prevfinger && prevfinger < finger) { + cat = "roll in"; + } else if (ppfinger > prevfinger && prevfinger > finger) { + cat = "roll out"; + } else if ( + (ppfinger < prevfinger && + finger < prevfinger && + finger != ppfinger) || + (ppfinger > prevfinger && finger > prevfinger && finger != ppfinger) + ) { + cat = "redirect"; + // if (!m_redirects[trigram]) { + // m_redirects[trigram] = 0; + // } + // m_redirects[trigram] += count; + if (ppfinger == 4 || prevfinger == 4 || finger == 4) { + } else { + cat = "weak redirect"; + } + } + } + if (ppfinger >= 6 && prevfinger >= 6 && finger >= 6) { + // right hand + if (ppfinger > prevfinger && prevfinger > finger) { + cat = "roll in"; + } else if (ppfinger < prevfinger && prevfinger < finger) { + cat = "roll out"; + } else if ( + (ppfinger > prevfinger && + finger > prevfinger && + finger != ppfinger) || + (ppfinger < prevfinger && finger < prevfinger && finger != ppfinger) + ) { + cat = "redirect"; + // if (!m_redirects[trigram]) { + // m_redirects[trigram] = 0; + // } + // m_redirects[trigram] += count; + if (ppfinger == 7 || prevfinger == 7 || finger == 7) { + } else { + cat = "weak redirect"; + } + } + } // + if ( + (ppfinger <= 5 && prevfinger >= 6 && finger <= 5) || + (ppfinger >= 6 && prevfinger <= 5 && finger >= 6) + ) { + cat = "alt"; + if (ppfinger == finger && ppchar != char) { + cat = "alt sfs"; + } + // 1 2 3 + } else if ( + ppfinger <= 5 && + prevfinger <= 5 && + finger >= 6 && + ppfinger < prevfinger + ) { + // LLR + cat = "bigram roll in"; // LEFT + } else if ( + ppfinger >= 6 && + prevfinger <= 5 && + finger <= 5 && + prevfinger < finger + ) { + // RLL + cat = "bigram roll in"; // LEFT + } else if ( + ppfinger <= 5 && + prevfinger <= 5 && + finger >= 6 && + ppfinger > prevfinger + ) { + // LLR + cat = "bigram roll out"; // LEFT + } else if ( + ppfinger >= 6 && + prevfinger <= 5 && + finger <= 5 && + prevfinger > finger + ) { + // RLL + cat = "bigram roll out"; // LEFT + } else if ( + ppfinger >= 6 && + prevfinger >= 6 && + finger <= 5 && + ppfinger > prevfinger + ) { + // RRL + cat = "bigram roll in"; // RIGHT + } else if ( + ppfinger <= 5 && + prevfinger >= 6 && + finger >= 6 && + prevfinger > finger + ) { + // LRR + cat = "bigram roll in"; // RIGHT + } else if ( + ppfinger >= 6 && + prevfinger >= 6 && + finger <= 5 && + ppfinger < prevfinger + ) { + // RRL + cat = "bigram roll out"; // RIGHT + } else if ( + ppfinger <= 5 && + prevfinger >= 6 && + finger >= 6 && + prevfinger < finger + ) { + // LRR + cat = "bigram roll out"; // RIGHT + } + if (!m_trigram_count[cat]) { + m_trigram_count[cat] = 0; + } + m_trigram_count[cat] += count; + if (cat == "alt") { + if (!m_trigram_count_alt[trigram]) { + m_trigram_count_alt[trigram] = 0; + } + // if (count > 20){ + m_trigram_count_alt[trigram] += count; + // } + // if (count > 10){ console.log(trigram + " "+ count);} + } + if (cat == "redirect" || cat == "weak redirect") { + if (!m_trigram_count_red[trigram]) { + m_trigram_count_red[trigram] = 0; + } + // if (count > 20){ + m_trigram_count_red[trigram] += count; + // } + } + if (cat == "roll in" || cat == "bigram roll in") { + if (!m_trigram_count_roll_in[trigram]) { + m_trigram_count_roll_in[trigram] = 0; + } + // if (count > 20){ + m_trigram_count_roll_in[trigram] += count; + // } + } + if (cat == "roll out" || cat == "bigram roll out") { + if (!m_trigram_count_roll_out[trigram]) { + m_trigram_count_roll_out[trigram] = 0; + } + // if (count > 20){ + m_trigram_count_roll_out[trigram] += count; + // } + } + } + pprow = prevrow; + prevcol = col; + prevrow = row; + prevhand = hand; + ppchar = prevchar; + ppfinger = prevfinger; + prevchar = char; + prevfinger = finger; + } + if (samehand.length >= 4) { + if (!samehandstrings[samehand]) { + samehandstrings[samehand] = 0; + } + samehandstrings[samehand] += count; + } + if (!samehandcount[samehand.length]) { + samehandcount[samehand.length] = 0; + } + samehandcount[samehand.length] += count; + } + inv_m_input_length = 1.0 / m_input_length; + var scale = 1006393 * inv_m_input_length; + m_total_word_effort *= scale; + // console.log("word count "+word_count) + var sum = 0; + for (const letter in m_letter_freq) { + sum += m_letter_freq[letter]; + } + const hundred_inv_sum = 100.0 / sum; + for (const letter in m_letter_freq) { + for (let i = 0; i < rcdata_len; i++) { + if (rcdata[i][0] == letter) { + rcdata[i][3] = hundred_inv_sum * m_letter_freq[letter]; + } + } + } + needs_update = false; } function generatePlots() { - if (dataloaded == false || dictionaryloaded == false || effortloaded == false) {return;} - console.log("generatePlots") - stats.selectAll("*").remove(); - /////////////////////////////////////// C O L U M N U S A G E //////////////////////////////////////////// - var x = 500; - var y = 0; - stats.append("text").attr("x", x + 40).attr("y", 16).attr("font-size", 16).attr("font-family", "Sans,Arial").attr("fill", "#dfe2eb").attr("text-anchor", "left").text("Column Usage") - var sum_col_usage = 0; - for (let col in m_column_usage) { - sum_col_usage += m_column_usage[col]; - } - const inv_sum_col_usage = 1.0 / sum_col_usage; - for (let col in m_column_usage) { - var height = 300 * m_column_usage[col] * inv_sum_col_usage; - var tip = parseFloat(100 * m_column_usage[col] * inv_sum_col_usage).toFixed(2); - var red = Math.floor(275 * m_column_usage[col] * inv_sum_col_usage) + 128 - var green = 128; - if (red < 16) { red = 16; } - if (red > 255) { red = 255; } - var hex_red = red.toString(16); - var hex_bg = green.toString(16); - - stats.append("rect").attr("x", x + col * 20).attr("y", 100 - height).attr("width", 15).attr("height", height) - .attr("fill", "#" + hex_red + hex_bg + hex_bg).attr("stroke", "#453033").attr("stroke-width", 1) - .attr("onmouseover", "showTooltip(evt,'" + tip + "%')").attr("onmouseout", "hideTooltip()") - stats.append("text").attr("x", x + col * 20 + 7).attr("y", 111).attr("fill", "#dfe2eb").attr("font-size", 10).attr("font-family", "Sans,Arial").attr("text-anchor", "middle").text(col) - //\n" - } - - /////////////////////////////////////// R O W U S A G E //////////////////////////////////////////// - var x = 770; - var y = 0; - stats.append("text").attr("x", x + 40).attr("y", 16).attr("font-size", 16).attr("font-family", "Sans,Arial").attr("fill", "#dfe2eb").attr("text-anchor", "left").text("Row Usage") - var sum_row_usage = 0; - for (let row in m_row_usage) { - sum_row_usage += m_row_usage[row]; - } - const inv_sum_row_usage = 1.0 / sum_row_usage; - for (let row in m_row_usage) { - var height = 200 * m_row_usage[row] * inv_sum_row_usage; - var tip = parseFloat(100 * m_row_usage[row] * inv_sum_row_usage).toFixed(2); - var red = Math.floor(190 * m_row_usage[row] * inv_sum_row_usage) + 128 - var green = 128; - if (red < 16) { red = 16; } - if (red > 255) { red = 255; } - var hex_red = red.toString(16); - var hex_bg = green.toString(16); - - stats.append("rect").attr("x", x + 19).attr("y", y + 40 + row * 20).attr("width", height).attr("height", 14) - .attr("fill", "#" + hex_red + hex_bg + hex_bg).attr("stroke", "#453033").attr("stroke-width", 1) - .attr("onmouseover", "showTooltip(evt,'" + tip + "%')").attr("onmouseout", "hideTooltip()") - stats.append("text").attr("x", x + 9).attr("y", y + 51 + row * 20).attr("fill", "#dfe2eb").attr("font-size", 10).attr("font-family", "Sans,Arial").attr("text-anchor", "middle").text(parseInt(row) + 1) - //\n" - } - /////////////////////////////////////// F I N G E R U S A G E ////////////////////////////////////// - var x = 0; - var y = 0; - stats.append("text").attr("x", x + 40).attr("y", 16).attr("font-size", 16).attr("font-family", "Sans,Arial").attr("fill", "#dfe2eb").attr("text-anchor", "left").text("Finger Usage") - var sum = 0; - var left = 0; - var right = 0; - for (let finger in m_finger_usage) { - sum += m_finger_usage[finger]; - if (finger <= 4) { - left += m_finger_usage[finger]; - } - if (finger >= 7) { - right += m_finger_usage[finger]; - } - } - var inv_sum = 1.0 / sum; - for (let finger in m_finger_usage) { - var norm_finger_usage = m_finger_usage[finger] * inv_sum - var height = 300 * norm_finger_usage; - var tip = parseFloat(100 * norm_finger_usage).toFixed(2); - var red = Math.floor(275 * norm_finger_usage) + 128 - var green = 128; - if (red < 16) { red = 16; } - if (red > 255) { red = 255; } - var hex_red = red.toString(16); - var hex_bg = green.toString(16); - stats.append("rect").attr("x", x + finger * 20).attr("y", 100 - height).attr("width", 15).attr("height", height) - .attr("fill", "#" + hex_red + hex_bg + hex_bg).attr("stroke", "#453033").attr("stroke-width", 1) - .attr("onmouseover", "showTooltip(evt,'" + tip + "%')").attr("onmouseout", "hideTooltip()") - stats.append("text").attr("x", x + finger * 20 + 7).attr("y", 111).attr("fill", "#dfe2eb").attr("font-size", 10) - .attr("font-family", "Sans,Arial").attr("text-anchor", "middle").text(finger) - } - stats.append("text").attr("x", x + 57).attr("y", 124).attr("fill", "#dfe2eb").attr("font-size", 11).attr("font-family", "Sans,Arial").attr("text-anchor", "middle").text(parseFloat(100 * left * inv_sum).toFixed(2) + "%"); - stats.append("text").attr("x", x + 177).attr("y", 124).attr("fill", "#dfe2eb").attr("font-size", 11).attr("font-family", "Sans,Arial").attr("text-anchor", "middle").text(parseFloat(100 * right * inv_sum).toFixed(2) + "%"); - /////////////////////////////////////// F I N G E R D I S T A N C E ////////////////////////////////// - var x = 250; - var y = 0; - var max = m_input_length / 5.110882176; // this might be shadowing 'max' above - sum = 0 - left = 0; - right = 0; - for (let finger in m_finger_distance) { - sum += m_finger_distance[finger]; - if (finger <= 4) { - left += m_finger_distance[finger]; - } - if (finger >= 7) { - right += m_finger_distance[finger]; - } - } - var inv_max = 1.0 / max; - inv_sum = 1.0 / sum; - stats.append("text").attr("x", x + 40).attr("y", 16).attr("font-size", 16).attr("font-family", "Sans,Arial").attr("fill", "#dfe2eb").attr("text-anchor", "left").text("Finger Distance") - for (let finger in m_finger_distance) { - if (m_finger_distance[finger] > 0) { - var norm_finger_distance = m_finger_distance[finger] * inv_max; - var height = 75 * norm_finger_distance; - var tip = parseFloat(100 * norm_finger_distance).toFixed(2); - var red = Math.floor(128 * norm_finger_distance) + 128 - var green = 128; - if (red < 16) { red = 16; } - if (red > 255) { red = 255; } - var hex_red = red.toString(16); - var hex_bg = green.toString(16); - stats.append("rect").attr("x", x + finger * 20).attr("y", 100 - height).attr("width", 15).attr("height", height) - .attr("fill", "#" + hex_red + hex_bg + hex_bg).attr("stroke", "#453033").attr("stroke-width", 1) - .attr("onmouseover", "showTooltip(evt,'" + tip + "')").attr("onmouseout", "hideTooltip()") - stats.append("text").attr("x", x + finger * 20 + 7).attr("y", 111).attr("fill", "#dfe2eb").attr("font-size", 10).attr("font-family", "Sans,Arial").attr("text-anchor", "middle").text(finger) - //\n" - } - } - stats.append("text").attr("x", x + 57).attr("y", 124).attr("fill", "#dfe2eb").attr("font-size", 11).attr("font-family", "Sans,Arial").attr("text-anchor", "middle").text(parseFloat(100 * left * inv_sum).toFixed(2) + "%"); - stats.append("text").attr("x", x + 177).attr("y", 124).attr("fill", "#dfe2eb").attr("font-size", 11).attr("font-family", "Sans,Arial").attr("text-anchor", "middle").text(parseFloat(100 * right * inv_sum).toFixed(2) + "%"); - stats.append("text").attr("x", x + 117).attr("y", 124).attr("fill", "#dfe2eb").attr("font-size", 11).attr("font-family", "Sans,Arial").attr("text-anchor", "middle").text(parseFloat(100 * sum * inv_max).toFixed(1)); - // (100*sum/max).toFixed(1) - /////////////////////////////////// S A M E F I N G E R B I G R A M S /////////////////////////////// - var x = 0; - var y = 180; - sum = 0; - // toggle button - stats.append("path").attr("d", `M ${x + 15} ${y - 24} L ${x + 35} ${y - 24} L ${x + 25} ${y - 34} Z`) - .attr("fill", "#777777").attr("stroke", "#989898").attr("stroke-width", 1).attr("onmouseover","showTooltip(evt,'Toggle between showing same finger bigrams for each bigram, and for each finger')") - .attr("onmouseout","hideTooltip()").attr("onclick","sfbToggle(-1)") - .on("mouseover", function() { d3.select(this).attr("fill", "#bbbbbb"); }) .on("mouseout", function() { d3.select(this).attr("fill", "#777777"); }); - - stats.append("path").attr("d", `M ${x + 15} ${y - 20} L ${x + 35} ${y - 20} L ${x + 25} ${y - 10} Z`) - .attr("fill", "#777777").attr("stroke", "#989898").attr("stroke-width", 1).attr("onmouseover","showTooltip(evt,'Toggle between showing same finger bigrams for each bigram, and for each finger')") - .attr("onmouseout","hideTooltip()").attr("onclick","sfbToggle(1)") - .on("mouseover", function() { d3.select(this).attr("fill", "#bbbbbb"); }) .on("mouseout", function() { d3.select(this).attr("fill", "#777777"); }); - if(sfb_toggle == 0) { - var keyValueArray = Object.entries(m_same_finger); - keyValueArray.sort((a, b) => b[1] - a[1]); - m_same_finger = Object.fromEntries(keyValueArray); - - for (let bigram in m_same_finger) { - sum += m_same_finger[bigram] * inv_m_input_length; - } - stats.append("text").attr("x", x + 40).attr("y", y - 16).attr("font-size", 16).attr("font-family", "Sans,Arial").attr("fill", "#dfe2eb").attr("text-anchor", "left").text("Same Finger Bigrams " + parseFloat(100 * sum).toFixed(2) + "%") - // stats.append("text").attr("x",x+40).attr("y",y+200).attr("font-size",16).attr("font-family","Sans,Arial").attr("fill","#dfe2eb").attr("text-anchor","left").text("Input Length "+m_input_length); - - var i = 0; - var t = scroll_amount; - for (let bigram in m_same_finger) { - if (t > 0){ - t -= 1; - continue; - } - var width = 18000 * m_same_finger[bigram] * inv_m_input_length; - if (width > 200) { width = 200; } - stats.append("rect").attr("x", x + 40).attr("y", y + i * 15).attr("width", width).attr("height", 10).attr("fill", "#7777bb").attr("stroke", "#9898d6").attr("stroke-width", 1) - stats.append("text").attr("x", x + 20).attr("y", y + i * 15 + 8).attr("fill", "#dfe2eb").attr("font-size", 10).attr("font-family", "Roboto Mono").attr("text-anchor", "right").text(bigram); - stats.append("text").attr("x", x + 200).attr("y", y + i * 15 + 8).attr("fill", "#dfe2eb").attr("font-size", 10).attr("font-family", "Sans,Arial").attr("text-anchor", "left").text(parseFloat("" + (100 * m_same_finger[bigram] * inv_m_input_length)).toFixed(2) + "%"); - //\n" - i += 1; - if (i > 10) { break; } - } - } else if(sfb_toggle == 1){ - for (let finger in m_same_finger2) { - sum += m_same_finger2[finger] * inv_m_input_length; - } - stats.append("text").attr("x", x + 40).attr("y", y - 16).attr("font-size", 16).attr("font-family", "Sans,Arial") - .attr("fill", "#dfe2eb").attr("text-anchor", "left").text("Same Finger Bigrams " + parseFloat(100 * sum).toFixed(2) + "%") - for (let finger in m_same_finger2) { - var height = 30000 * m_same_finger2[finger] * inv_m_input_length; - if (height > 150) { height = 150;} - var tip = parseFloat(100 * m_same_finger2[finger] * inv_m_input_length).toFixed(2); - var red = Math.floor(6000 * m_same_finger2[finger] * inv_m_input_length) + 128 - var green = 128; - if (red < 16) { red = 16; } - if (red > 255) { red = 255; } - var hex_red = red.toString(16); - var hex_bg = green.toString(16); - stats.append("rect").attr("x", x + finger * 20).attr("y", y+155 - height).attr("width", 15).attr("height", height) - .attr("fill", "#" + hex_red + hex_bg + hex_bg).attr("stroke", "#453033").attr("stroke-width", 1) - .attr("onmouseover", "showTooltip(evt,'" + tip + "%')").attr("onmouseout", "hideTooltip()") - - stats.append("text").attr("x", x + finger * 20 + 7).attr("y", y+166).attr("fill", "#dfe2eb").attr("font-size", 10) - .attr("font-family", "Sans,Arial").attr("text-anchor", "middle").text(finger) - } - - } else { - var keyValueArray = Object.entries(m_same_finger3); - keyValueArray.sort((a, b) => b[1] - a[1]); - m_same_finger3 = Object.fromEntries(keyValueArray); - - for (let bigram in m_same_finger3) { - sum += m_same_finger3[bigram] * inv_m_input_length; - } - stats.append("text").attr("x", x + 40).attr("y", y - 16).attr("font-size", 16).attr("font-family", "Sans,Arial").attr("fill", "#dfe2eb").attr("text-anchor", "left").text("2u Same Finger Bigrams " + parseFloat(100 * sum).toFixed(2) + "%") - // stats.append("text").attr("x",x+40).attr("y",y+200).attr("font-size",16).attr("font-family","Sans,Arial").attr("fill","#dfe2eb").attr("text-anchor","left").text("Input Length "+m_input_length); - - var i = 0; - var t = scroll_amount; - for (let bigram in m_same_finger3) { - if (t > 0){ - t -= 1; - continue; - } - var width = 18000 * m_same_finger3[bigram] * inv_m_input_length; - if (width > 200) { width = 200; } - stats.append("rect").attr("x", x + 40).attr("y", y + i * 15).attr("width", width).attr("height", 10).attr("fill", "#7777bb").attr("stroke", "#9898d6").attr("stroke-width", 1) - stats.append("text").attr("x", x + 20).attr("y", y + i * 15 + 8).attr("fill", "#dfe2eb").attr("font-size", 10).attr("font-family", "Roboto Mono").attr("text-anchor", "right").text(bigram); - stats.append("text").attr("x", x + 200).attr("y", y + i * 15 + 8).attr("fill", "#dfe2eb").attr("font-size", 10).attr("font-family", "Sans,Arial").attr("text-anchor", "left").text(parseFloat("" + (100 * m_same_finger3[bigram] * inv_m_input_length)).toFixed(2) + "%"); - //\n" - i += 1; - if (i > 10) { break; } - } - - } - /////////////////////////////////// S K I P F I N G E R B I G R A M S /////////////////////////////// - var x = 250; - var y = 180; - sum = 0; - var tmp; - if (skip_toggle) { - var keyValueArray = Object.entries(m_skip_bigram); - keyValueArray.sort((a, b) => b[1] - a[1]); - tmp = Object.fromEntries(keyValueArray); - for (let bigram in tmp) { - sum += tmp[bigram] * inv_m_input_length; - } - stats.append("text").attr("x", x + 40).attr("y", y - 16).attr("font-size", 16).attr("font-family", "Sans,Arial").attr("fill", "#dfe2eb").attr("text-anchor", "left").text("Skip Bigrams " + parseFloat(100 * sum).toFixed(2) + "%") - } else { - var keyValueArray = Object.entries(m_skip_bigram2); - keyValueArray.sort((a, b) => b[1] - a[1]); - tmp = Object.fromEntries(keyValueArray); - for (let bigram in tmp) { - sum += tmp[bigram] * inv_m_input_length; - } - stats.append("text").attr("x", x + 40).attr("y", y - 16).attr("font-size", 16).attr("font-family", "Sans,Arial").attr("fill", "#dfe2eb").attr("text-anchor", "left").text("Skip Bigrams (2u) " + parseFloat(100 * sum).toFixed(2) + "%") - } - - stats.append("path").attr("d", `M ${x + 15} ${y - 24} L ${x + 35} ${y - 24} L ${x + 25} ${y - 34} Z`) - .attr("fill", "#777777").attr("stroke", "#989898").attr("stroke-width", 1).attr("onmouseover","showTooltip(evt,'Toggle between showing all skip bigrams and only those with a 2u step between 1 and 3')").attr("onmouseout","hideTooltip()").attr("onclick","skipToggle()") - .on("mouseover", function() { d3.select(this).attr("fill", "#bbbbbb"); }) .on("mouseout", function() { d3.select(this).attr("fill", "#777777"); }); - - stats.append("path").attr("d", `M ${x + 15} ${y - 20} L ${x + 35} ${y - 20} L ${x + 25} ${y - 10} Z`) - .attr("fill", "#777777").attr("stroke", "#989898").attr("stroke-width", 1).attr("onmouseover","showTooltip(evt,'Toggle between showing all skip bigrams and only those with a 2u step between 1 and 3')").attr("onmouseout","hideTooltip()").attr("onclick","skipToggle()") - .on("mouseover", function() { d3.select(this).attr("fill", "#bbbbbb"); }) .on("mouseout", function() { d3.select(this).attr("fill", "#777777"); }); - var i = 0; - var t = scroll_amount; - for (let bigram in tmp) { - if (t > 0){ - t -= 1; - continue; - } - var height = 36000 * tmp[bigram] * inv_m_input_length; - if (height > 200) { height = 200; } - stats.append("rect").attr("x", x + 40).attr("y", y + i * 15).attr("width", height).attr("height", 10) - .attr("fill", "#7777bb").attr("stroke", "#9898d6").attr("stroke-width", 1) - stats.append("text").attr("x", x + 17).attr("y", y + i * 15 + 8).attr("fill", "#dfe2eb").attr("font-size", 10).attr("font-family", "Roboto Mono").attr("text-anchor", "right").text(bigram); - stats.append("text").attr("x", x + 200).attr("y", y + i * 15 + 8).attr("fill", "#dfe2eb").attr("font-size", 10).attr("font-family", "Sans,Arial").attr("text-anchor", "left").text(parseFloat("" + (100 * tmp[bigram] * inv_m_input_length)).toFixed(2) + "%"); - //\n" - i += 1; - if (i > 10) { break; } - } - //////////////////////////// L A T E R A L S T R E T C H B I G R A M S /////////////////////////////// - var x = 500; - var y = 180; - sum = 0; - if (lsb_toggle == 0){ - var keyValueArray = Object.entries(m_lat_stretch); - keyValueArray.sort((a, b) => b[1] - a[1]); - tmp = Object.fromEntries(keyValueArray); - for (let bigram in tmp) { - sum += tmp[bigram] * inv_m_input_length; - } - stats.append("text").attr("x", x + 40).attr("y", y - 16).attr("font-size", 16).attr("font-family", "Sans,Arial").attr("fill", "#dfe2eb").attr("text-anchor", "left").text("Lat Stretch Bigrams " + parseFloat(100 * sum).toFixed(2) + "%") - } else { - var keyValueArray = Object.entries(m_lat_stretch2); - keyValueArray.sort((a, b) => b[1] - a[1]); - tmp = Object.fromEntries(keyValueArray); - for (let bigram in tmp) { - sum += tmp[bigram] * inv_m_input_length; - } - stats.append("text").attr("x", x + 40).attr("y", y - 16).attr("font-size", 16).attr("font-family", "Sans,Arial").attr("fill", "#dfe2eb").attr("text-anchor", "left").text("Ring LSBs " + parseFloat(100 * sum).toFixed(2) + "%") - } - - stats.append("path").attr("d", `M ${x + 15} ${y - 24} L ${x + 35} ${y - 24} L ${x + 25} ${y - 34} Z`) - .attr("fill", "#777777").attr("stroke", "#989898").attr("stroke-width", 1).attr("onmouseover","showTooltip(evt,'Toggle between showing lateral stretches from the middle finger to ring finger')").attr("onmouseout","hideTooltip()").attr("onclick","lsbToggle()") - .on("mouseover", function() { d3.select(this).attr("fill", "#bbbbbb"); }) .on("mouseout", function() { d3.select(this).attr("fill", "#777777"); }); - - stats.append("path").attr("d", `M ${x + 15} ${y - 20} L ${x + 35} ${y - 20} L ${x + 25} ${y - 10} Z`) - .attr("fill", "#777777").attr("stroke", "#989898").attr("stroke-width", 1).attr("onmouseover","showTooltip(evt,'Toggle between showing lateral stretches from the middle finger to ring finger')").attr("onmouseout","hideTooltip()").attr("onclick","lsbToggle()") - .on("mouseover", function() { d3.select(this).attr("fill", "#bbbbbb"); }) .on("mouseout", function() { d3.select(this).attr("fill", "#777777"); }); - var i = 0; - var t = scroll_amount; - for (let bigram in tmp) { - if (t > 0){ - t -= 1; - continue; - } - var height = 10000 * tmp[bigram] * inv_m_input_length; - if (height > 200) { height = 200; } - stats.append("rect").attr("x", x + 40).attr("y", y + i * 15).attr("width", height).attr("height", 10) - .attr("fill", "#7777bb").attr("stroke", "#9898d6").attr("stroke-width", 1) - stats.append("text").attr("x", x + 20).attr("y", y + i * 15 + 8).attr("fill", "#dfe2eb").attr("font-size", 10).attr("font-family", "Roboto Mono").attr("text-anchor", "right").text(bigram); - stats.append("text").attr("x", x + 200).attr("y", y + i * 15 + 8).attr("fill", "#dfe2eb").attr("font-size", 10).attr("font-family", "Sans,Arial").attr("text-anchor", "left").text(parseFloat("" + (100 * tmp[bigram] * inv_m_input_length)).toFixed(2) + "%"); - //\n" - i += 1; - if (i > 10) { break; } - } - //////////////////////////// S C I S S O R S /////////////////////////////// - var x = 760; - var y = 180; - sum = 0; - - if (scissors_toggle == 1) { - var keyValueArray = Object.entries(m_pinky_scissors); - keyValueArray.sort((a, b) => b[1] - a[1]); - tmp = Object.fromEntries(keyValueArray); - for (let bigram in tmp) { - sum += tmp[bigram] * inv_m_input_length; - } - stats.append("text").attr("x", x + 40).attr("y", y - 16).attr("font-size", 16).attr("font-family", "Sans,Arial").attr("fill", "#dfe2eb").attr("text-anchor", "left").text("Pinky/Ring Scissors " + parseFloat(100 * sum).toFixed(2) + "%") - } else if (scissors_toggle == 0){ - var keyValueArray = Object.entries(m_scissors); - keyValueArray.sort((a, b) => b[1] - a[1]); - tmp = Object.fromEntries(keyValueArray); - for (let bigram in tmp) { - sum += tmp[bigram] * inv_m_input_length; - } - stats.append("text").attr("x", x + 40).attr("y", y - 16).attr("font-size", 16).attr("font-family", "Sans,Arial").attr("fill", "#dfe2eb").attr("text-anchor", "left").text("Scissors " + parseFloat(100 * sum).toFixed(2) + "%") - } else { - var keyValueArray = Object.entries(m_all_scissors); - keyValueArray.sort((a, b) => b[1] - a[1]); - tmp = Object.fromEntries(keyValueArray); - for (let bigram in tmp) { - sum += tmp[bigram] * inv_m_input_length; - } - stats.append("text").attr("x", x + 40).attr("y", y - 16).attr("font-size", 16).attr("font-family", "Sans,Arial").attr("fill", "#dfe2eb").attr("text-anchor", "left").text("Wide Scissors " + parseFloat(100 * sum).toFixed(2) + "%") - } - stats.append("path").attr("d", `M ${x + 15} ${y - 24} L ${x + 35} ${y - 24} L ${x + 25} ${y - 34} Z`) - .attr("fill", "#777777").attr("stroke", "#989898").attr("stroke-width", 1).attr("onmouseover","showTooltip(evt,'Toggle between showing scissors on ring and pinky, and all 2u scissors')").attr("onmouseout","hideTooltip()").attr("onclick","scissorsToggle(-1)") - .on("mouseover", function() { d3.select(this).attr("fill", "#bbbbbb"); }) .on("mouseout", function() { d3.select(this).attr("fill", "#777777"); }); - - stats.append("path").attr("d", `M ${x + 15} ${y - 20} L ${x + 35} ${y - 20} L ${x + 25} ${y - 10} Z`) - .attr("fill", "#777777").attr("stroke", "#989898").attr("stroke-width", 1).attr("onmouseover","showTooltip(evt,'Toggle between showing scissors on ring and pinky, and all 2u scissors')").attr("onmouseout","hideTooltip()").attr("onclick","scissorsToggle(1)") - .on("mouseover", function() { d3.select(this).attr("fill", "#bbbbbb"); }) .on("mouseout", function() { d3.select(this).attr("fill", "#777777"); }); - var i = 0; - var t = scroll_amount; - for (let bigram in tmp) { - if (t > 0){ - t -= 1; - continue; - } - var height = 36000 * tmp[bigram] * inv_m_input_length; - if (height > 180) { height = 180; } - stats.append("rect").attr("x", x + 40).attr("y", y + i * 15).attr("width", height).attr("height", 10) - .attr("fill", "#7777bb").attr("stroke", "#9898d6").attr("stroke-width", 1) - stats.append("text").attr("x", x + 20).attr("y", y + i * 15 + 8).attr("fill", "#dfe2eb").attr("font-size", 10).attr("font-family", "Roboto Mono").attr("text-anchor", "right").text(bigram); - stats.append("text").attr("x", x + 190).attr("y", y + i * 15 + 8).attr("fill", "#dfe2eb").attr("font-size", 10).attr("font-family", "Sans,Arial").attr("text-anchor", "left").text(parseFloat("" + (100 * tmp[bigram] * inv_m_input_length)).toFixed(2) + "%"); - //\n" - i += 1; - if (i > 10) { break; } - } - /////////////////////////////////// T R I G R A M S T A T S /////////////////////////////// - var x = 760; - var y = 390; - dx = 105; - sum = 0; - scale = 1; - var trigram_title = "Trigram Stats" - - if (trigram_toggle == 0) { - var keyValueArray = Object.entries(m_trigram_count); - keyValueArray.sort((a, b) => b[1] - a[1]); - tmp = Object.fromEntries(keyValueArray); - for (let cat in tmp) { - sum += tmp[cat] - } - trigram_title = "Trigram Stats" - scale = 1; - dx = 105; - } else if (trigram_toggle == 1) { - var keyValueArray = Object.entries(m_trigram_count_alt); - keyValueArray.sort((a, b) => b[1] - a[1]); - tmp = Object.fromEntries(keyValueArray); - for (let cat in tmp) { - sum += tmp[cat] - } - trigram_title = "Trigram Stats (alts)" - scale = 3; - dx = 47; - } else if (trigram_toggle == 2) { - var keyValueArray = Object.entries(m_trigram_count_red); - keyValueArray.sort((a, b) => b[1] - a[1]); - tmp = Object.fromEntries(keyValueArray); - for (let cat in tmp) { - sum += tmp[cat] - } - trigram_title = "Trigram Stats (redirects)" - scale = 3; - dx = 47; - } else if (trigram_toggle == 3) { - var keyValueArray = Object.entries(m_trigram_count_roll_in); - keyValueArray.sort((a, b) => b[1] - a[1]); - tmp = Object.fromEntries(keyValueArray); - for (let cat in tmp) { - sum += tmp[cat] - } - trigram_title = "Trigram Stats (roll in)" - scale = 3; - dx = 47; - } else if (trigram_toggle == 4) { - var keyValueArray = Object.entries(m_trigram_count_roll_out); - keyValueArray.sort((a, b) => b[1] - a[1]); - tmp = Object.fromEntries(keyValueArray); - for (let cat in tmp) { - sum += tmp[cat] - } - trigram_title = "Trigram Stats (roll out)" - scale = 3; - dx = 47; - } - const trigram_desc = { - "alt":"the hands used to type the trigram are either LRL or RLR", - "alt sfs":"trigram is typed LRL or RLR but finger1 and finger3 are the same and type a different character", - "bigram roll in":"two adjacent characters in the trigram are typed with the same hand and the first is outside the second", - "bigram roll out":"two adjacent characters in the trigram are typed with the same hand and the first is inside the second", - "weak redirect":"a redirect but none of the fingers used are the index finger", - "redirect":"the three characters of the trigram are typed with the same hand and the direction changes", - "roll out":"the three characters of the trigram are typed with the same hand and go from the inside to the outside", - "roll in":"the three characters of the trigram are typed with the same hand and go from the outside to the inside", - "other":"all other trigrams that don\\'t fit into any of the other categories", - // "bigram same row":"two adjacent characters in the trigram are typed on the same row", - // "trigram same row":"the three characters in the trigram are typed on the same row", - // "double jump":"trigram is typed top, bottom, top or bottom, top, bottom", - }; - // for(var tri in m_redirects){ - // if (m_redirects[tri] > 40){ - // console.log(tri + " " + m_redirects[tri]); - // // trigram_desc["redirect"] = trigram_desc["redirect"].concat(" "+tri); - // } - // } - stats.append("path").attr("d", `M ${x + 15} ${y - 20} L ${x + 35} ${y - 20} L ${x + 25} ${y - 10} Z`) - .attr("fill", "#777777").attr("stroke", "#989898").attr("stroke-width", 1).attr("onmouseover","showTooltip(evt,'Change pages to see different trigram stats')").attr("onmouseout","hideTooltip()").attr("onclick","trigramToggle(-1)") - .on("mouseover", function() { d3.select(this).attr("fill", "#bbbbbb"); }) .on("mouseout", function() { d3.select(this).attr("fill", "#777777"); }); - - stats.append("path").attr("d", `M ${x + 15} ${y - 24} L ${x + 35} ${y - 24} L ${x + 25} ${y - 34} Z`) - .attr("fill", "#777777").attr("stroke", "#989898").attr("stroke-width", 1).attr("onmouseover","showTooltip(evt,'Change pages to see different trigram stats')").attr("onmouseout","hideTooltip()").attr("onclick","trigramToggle(1)") - .on("mouseover", function() { d3.select(this).attr("fill", "#bbbbbb"); }) .on("mouseout", function() { d3.select(this).attr("fill", "#777777"); }); - - stats.append("text").attr("x", x + 40).attr("y", y - 16).attr("font-size", 16).attr("font-family", "Sans,Arial").attr("fill", "#dfe2eb").attr("text-anchor", "left").text(trigram_title) - - var i = 0 - var t = trigram_scroll_amount; - inv_sum = 1.0 / sum; - for (let cat in tmp) { - if (t > 0){ - t -= 1; - continue; - } - var tmp_cat_inv_sum = tmp[cat] * inv_sum; - var width = scale * 200 * tmp_cat_inv_sum; - if (width > 200) { width = 200; } - stats.append("rect").attr("x", x + dx).attr("y", y + i * 15).attr("width", width).attr("height", 10) - .attr("fill", "#7777bb").attr("stroke", "#9898d6").attr("stroke-width", 1) - .attr("onmouseover","showTooltip(evt,'"+trigram_desc[cat]+"')").attr("onmouseout","hideTooltip()") - stats.append("text").attr("x", x + 20).attr("y", y + i * 15 + 8).attr("fill", "#dfe2eb").attr("font-size", 9).attr("font-family", "Roboto Mono").attr("text-anchor", "right").text(cat); - stats.append("text").attr("x", x + 190).attr("y", y + i * 15 + 8).attr("fill", "#dfe2eb").attr("font-size", 10).attr("font-family", "Sans,Arial").attr("text-anchor", "left").text(parseFloat("" + (100 * tmp_cat_inv_sum)).toFixed(2) + "%"); - //\n" - i += 1; - if (i > 10) { break; } - } - - /////////////////////////////////// S A M E H A N D S T R I N G S /////////////////////////////// - var x = 250; - var y = 390; - sum = 0; - - var keyValueArray = Object.entries(samehandstrings); - keyValueArray.sort((a, b) => b[1]*b[0].length - a[1]*a[0].length); - samehandstrings = Object.fromEntries(keyValueArray); - - scale = 30191.79 * inv_m_input_length - // console.log("input length: "+m_input_length) - // console.log("scale : "+scale) - stats.append("text").attr("x", x + 20).attr("y", y - 16).attr("font-size", 16).attr("font-family", "Sans,Arial").attr("fill", "#dfe2eb").attr("text-anchor", "left").text("Same Hand Strings") - var i = 0 - t = sh_scroll_amount; - for (let word in samehandstrings) { - if (t > 0){ - t -= 1; - continue; - } - var count = samehandstrings[word]; - // console.log(word + " " + count) - word_len = word.length - var word_len_count = word_len * count; - var width = scale * word_len_count; - if (width > 100) {width = 100;} - stats.append("rect").attr("x", x + 70).attr("y", y + i * 15).attr("width", width).attr("height", 10).attr("fill", "#7777bb").attr("stroke", "#9898d6").attr("stroke-width", 1) - stats.append("text").attr("x", x + 20).attr("y", y + i * 15 + 8).attr("fill", "#dfe2eb").attr("font-size", 10).attr("font-family", "Roboto Mono").attr("text-anchor", "right").text(word); - stats.append("text").attr("x", x + 135).attr("y", y + i * 15 + 8).attr("fill", "#dfe2eb").attr("font-size", 10).attr("font-family", "Sans,Arial").attr("text-anchor", "left").text(parseFloat("" + (word_len_count)).toFixed(0));// - i += 1; - if (i > 10) { break; } - } - - /////////////////////////////////// S A M E H A N D C O U N T S /////////////////////////////// - var x = 415; - var y = 390; - sum = 0; - - // var keyValueArray = Object.entries(samehandcount); - // keyValueArray.sort((a, b) => b - a); - // samehandcount = Object.fromEntries(keyValueArray); - scale = 140.89502 * inv_m_input_length - // console.log("input length: "+m_input_length) - // console.log("scale : "+scale) - stats.append("text").attr("x", x + 20).attr("y", y - 16).attr("font-size", 16).attr("font-family", "Sans,Arial").attr("fill", "#dfe2eb").attr("text-anchor", "left").text("Same Hand Count") - var i = 0 - for (let len in samehandcount) { - var count = samehandcount[len]; - var width = scale * count; - if (width > 100) {width = 100;} - stats.append("rect").attr("x", x + 40).attr("y", y + i * 15).attr("width", width).attr("height", 10).attr("fill", "#7777bb").attr("stroke", "#9898d6").attr("stroke-width", 1) - stats.append("text").attr("x", x + 20).attr("y", y + i * 15 + 8).attr("fill", "#dfe2eb").attr("font-size", 10).attr("font-family", "Roboto Mono").attr("text-anchor", "right").text(len); - stats.append("text").attr("x", x + 135).attr("y", y + i * 15 + 8).attr("fill", "#dfe2eb").attr("font-size", 10).attr("font-family", "Sans,Arial").attr("text-anchor", "left").text((scale*7.14285714285714285714285*count).toFixed(1)); - // stats.append("text").attr("x", x + 135).attr("y", y + i * 15 + 8).attr("fill", "#dfe2eb").attr("font-size", 10).attr("font-family", "Sans,Arial").attr("text-anchor", "left").text(count); - i += 1; - if (i > 10) { break; } - } - - /////////////////////////////////// H A R D W O R D S /////////////////////////////// - var x = 580; - var y = 390; - sum = 0; - var keyValueArray = Object.entries(word_effort); - keyValueArray.sort((a, b) => b[1]/b[0].length - a[1]/a[0].length); - word_effort = Object.fromEntries(keyValueArray); - stats.append("text").attr("x", x + 40).attr("y", y - 16).attr("font-size", 16).attr("font-family", "Sans,Arial").attr("fill", "#dfe2eb").attr("text-anchor", "left").text("Hard Words ") - var i = 0 - t = hw_scroll_amount; - for (let word in word_effort) { - word_len = word.length - if (word_len > 3 && words[word] > 4){ - if (t > 0){ - t -= 1; - continue; - } - var height = 100*word_effort[word] / word_len; - stats.append("rect").attr("x", x + 80).attr("y", y + i * 15).attr("width", height).attr("height", 10).attr("fill", "#7777bb").attr("stroke", "#9898d6").attr("stroke-width", 1) - stats.append("text").attr("x", x + 20).attr("y", y + i * 15 + 8).attr("fill", "#dfe2eb").attr("font-size", 10).attr("font-family", "Roboto Mono").attr("text-anchor", "right").text(word); - stats.append("text").attr("x", x + 165).attr("y", y + i * 15 + 8).attr("fill", "#dfe2eb").attr("font-size", 10).attr("font-family", "Sans,Arial").attr("text-anchor", "left").text(parseFloat("" + (word_effort[word])).toFixed(2)); - i += 1; - if (i > 10) { break; } - } - } - /////////////////////////////////// E A S Y W O R D S /////////////////////////////// - // var x = 610; - // var y = 390; - // sum = 0; - // var keyValueArray = Object.entries(word_effort); - // keyValueArray.sort((a, b) => a[1] - b[1]); - // word_effort = Object.fromEntries(keyValueArray); - // stats.append("text").attr("x", x + 40).attr("y", y - 16).attr("font-size", 16).attr("font-family", "Sans,Arial").attr("fill", "#dfe2eb").attr("text-anchor", "left").text("Easy Words ") - // var i = 0 - // for (var word in word_effort) { - // var height = 10*word_effort[word]; - // if (word.length > 3){ - // stats.append("rect").attr("x", x + 80).attr("y", y + i * 15).attr("width", height).attr("height", 10) - // .attr("fill", "#7777bb").attr("stroke", "#9898d6").attr("stroke-width", 1) - // stats.append("text").attr("x", x + 20).attr("y", y + i * 15 + 8).attr("fill", "#dfe2eb").attr("font-size", 10).attr("font-family", "Sans,Arial").attr("text-anchor", "right").text(word); - // stats.append("text").attr("x", x + 125).attr("y", y + i * 15 + 8).attr("fill", "#dfe2eb").attr("font-size", 10).attr("font-family", "Sans,Arial").attr("text-anchor", "left").text(parseFloat("" + (word_effort[word])).toFixed(2)); - // i += 1; - // if (i > 10) { break; } - // } - // } - - - /////////////////////////////////// F I N G E R P A I R S /////////////////////////////// - var x = 10; - var y = 370; - var box_x = 26; - var box_y = 20; - var per = 0; - var finger1 = i; - var finger2 = j; - var sum = 0; - stats.append("text").attr("x",0).attr("y",0).attr("font-size",10).attr("font-family","Sans,Arial") - .attr("fill","#dfe2eb").attr("text-anchor","middle") - .attr("transform",`translate(${x+2},${y+100}) rotate(-90)`) - .text("First Finger"); - stats.append("text").attr("x",x+130).attr("y",y).attr("font-size",10).attr("font-family","Sans,Arial") - .attr("fill","#dfe2eb").attr("text-anchor","middle") - .text("Second Finger"); - for(var i = 0; i <= 8; i++){ - sum = 0; - for(var j = 1; j <= 8; j++){ - finger1 = i; - finger2 = j; - if (i > 4){finger1 += 2;} - if (j > 4){finger2 += 2;} - if (m_finger_pairs[finger1]){ - if (m_finger_pairs[finger1][finger2]){ - sum += m_finger_pairs[finger1][finger2]; - } - } - } - for(var j = 0; j <= 8; j++){ - finger1 = i; - finger2 = j; - if (i > 4){finger1 += 2;} - if (j > 4){finger2 += 2;} - if (i == 0 && j == 0){ - - } else if (i == 0 && j > 0) { - stats.append("text").attr("x",x+box_x*j+14).attr("y",y+box_y*i+14).attr("font-size",10).attr("font-family","Sans,Arial").attr("fill","#dfe2eb").attr("text-anchor","middle").text(finger2); - } else if (i > 0 && j == 0) { - stats.append("text").attr("x",x+box_x*j+14).attr("y",y+box_y*i+14).attr("font-size",10).attr("font-family","Sans,Arial").attr("fill","#dfe2eb").attr("text-anchor","middle").text(finger1); - } else { - if (m_finger_pairs[finger1]){ - if (m_finger_pairs[finger1][finger2]){ - if (sum > 0){ - per = parseFloat(100 * m_finger_pairs[finger1][finger2] / sum).toFixed(0); - } else { per = -1;} - red = Math.floor(128 + 3 * per); - if (red > 255) {red = 255;} - hex_red = red.toString(16); - - stats.append("rect").attr("x",x+box_x*j).attr("y",y+box_y*i).attr("width",box_x).attr("height",box_y).attr("fill","#"+hex_red+hex_bg+hex_bg).attr("stroke","black").attr("stroke-width","0.5"); - stats.append("text").attr("x",x+box_x*j+14).attr("y",y+box_y*i+14).attr("font-size",10).attr("font-family","Sans,Arial").attr("fill","black").attr("text-anchor","middle").text(per+"%"); - } - } - } - } - } + if ( + dataloaded == false || + dictionaryloaded == false || + effortloaded == false + ) { + return; + } + console.log("generatePlots"); + stats.selectAll("*").remove(); + /////////////////////////////////////// C O L U M N U S A G E //////////////////////////////////////////// + var x = 500; + var y = 0; + stats + .append("text") + .attr("x", x + 40) + .attr("y", 16) + .attr("font-size", 16) + .attr("font-family", "Sans,Arial") + .attr("fill", "#dfe2eb") + .attr("text-anchor", "left") + .text("Column Usage"); + var sum_col_usage = 0; + for (const col in m_column_usage) { + sum_col_usage += m_column_usage[col]; + } + const inv_sum_col_usage = 1.0 / sum_col_usage; + for (const col in m_column_usage) { + var height = 300 * m_column_usage[col] * inv_sum_col_usage; + var tip = parseFloat(100 * m_column_usage[col] * inv_sum_col_usage).toFixed( + 2, + ); + var red = Math.floor(275 * m_column_usage[col] * inv_sum_col_usage) + 128; + var green = 128; + if (red < 16) { + red = 16; + } + if (red > 255) { + red = 255; + } + var hex_red = red.toString(16); + var hex_bg = green.toString(16); + + stats + .append("rect") + .attr("x", x + col * 20) + .attr("y", 100 - height) + .attr("width", 15) + .attr("height", height) + .attr("fill", "#" + hex_red + hex_bg + hex_bg) + .attr("stroke", "#453033") + .attr("stroke-width", 1) + .attr("onmouseover", "showTooltip(evt,'" + tip + "%')") + .attr("onmouseout", "hideTooltip()"); + stats + .append("text") + .attr("x", x + col * 20 + 7) + .attr("y", 111) + .attr("fill", "#dfe2eb") + .attr("font-size", 10) + .attr("font-family", "Sans,Arial") + .attr("text-anchor", "middle") + .text(col); + //\n" + } + + /////////////////////////////////////// R O W U S A G E //////////////////////////////////////////// + var x = 770; + var y = 0; + stats + .append("text") + .attr("x", x + 40) + .attr("y", 16) + .attr("font-size", 16) + .attr("font-family", "Sans,Arial") + .attr("fill", "#dfe2eb") + .attr("text-anchor", "left") + .text("Row Usage"); + var sum_row_usage = 0; + for (const row in m_row_usage) { + sum_row_usage += m_row_usage[row]; + } + const inv_sum_row_usage = 1.0 / sum_row_usage; + for (const row in m_row_usage) { + var height = 200 * m_row_usage[row] * inv_sum_row_usage; + var tip = parseFloat(100 * m_row_usage[row] * inv_sum_row_usage).toFixed(2); + var red = Math.floor(190 * m_row_usage[row] * inv_sum_row_usage) + 128; + var green = 128; + if (red < 16) { + red = 16; + } + if (red > 255) { + red = 255; + } + var hex_red = red.toString(16); + var hex_bg = green.toString(16); + + stats + .append("rect") + .attr("x", x + 19) + .attr("y", y + 40 + row * 20) + .attr("width", height) + .attr("height", 14) + .attr("fill", "#" + hex_red + hex_bg + hex_bg) + .attr("stroke", "#453033") + .attr("stroke-width", 1) + .attr("onmouseover", "showTooltip(evt,'" + tip + "%')") + .attr("onmouseout", "hideTooltip()"); + stats + .append("text") + .attr("x", x + 9) + .attr("y", y + 51 + row * 20) + .attr("fill", "#dfe2eb") + .attr("font-size", 10) + .attr("font-family", "Sans,Arial") + .attr("text-anchor", "middle") + .text(parseInt(row) + 1); + //\n" + } + /////////////////////////////////////// F I N G E R U S A G E ////////////////////////////////////// + var x = 0; + var y = 0; + stats + .append("text") + .attr("x", x + 40) + .attr("y", 16) + .attr("font-size", 16) + .attr("font-family", "Sans,Arial") + .attr("fill", "#dfe2eb") + .attr("text-anchor", "left") + .text("Finger Usage"); + var sum = 0; + var left = 0; + var right = 0; + for (const finger in m_finger_usage) { + sum += m_finger_usage[finger]; + if (finger <= 4) { + left += m_finger_usage[finger]; + } + if (finger >= 7) { + right += m_finger_usage[finger]; + } + } + var inv_sum = 1.0 / sum; + for (const finger in m_finger_usage) { + var norm_finger_usage = m_finger_usage[finger] * inv_sum; + var height = 300 * norm_finger_usage; + var tip = parseFloat(100 * norm_finger_usage).toFixed(2); + var red = Math.floor(275 * norm_finger_usage) + 128; + var green = 128; + if (red < 16) { + red = 16; + } + if (red > 255) { + red = 255; + } + var hex_red = red.toString(16); + var hex_bg = green.toString(16); + stats + .append("rect") + .attr("x", x + finger * 20) + .attr("y", 100 - height) + .attr("width", 15) + .attr("height", height) + .attr("fill", "#" + hex_red + hex_bg + hex_bg) + .attr("stroke", "#453033") + .attr("stroke-width", 1) + .attr("onmouseover", "showTooltip(evt,'" + tip + "%')") + .attr("onmouseout", "hideTooltip()"); + stats + .append("text") + .attr("x", x + finger * 20 + 7) + .attr("y", 111) + .attr("fill", "#dfe2eb") + .attr("font-size", 10) + .attr("font-family", "Sans,Arial") + .attr("text-anchor", "middle") + .text(finger); + } + stats + .append("text") + .attr("x", x + 57) + .attr("y", 124) + .attr("fill", "#dfe2eb") + .attr("font-size", 11) + .attr("font-family", "Sans,Arial") + .attr("text-anchor", "middle") + .text(parseFloat(100 * left * inv_sum).toFixed(2) + "%"); + stats + .append("text") + .attr("x", x + 177) + .attr("y", 124) + .attr("fill", "#dfe2eb") + .attr("font-size", 11) + .attr("font-family", "Sans,Arial") + .attr("text-anchor", "middle") + .text(parseFloat(100 * right * inv_sum).toFixed(2) + "%"); + /////////////////////////////////////// F I N G E R D I S T A N C E ////////////////////////////////// + var x = 250; + var y = 0; + var max = m_input_length / 5.110882176; // this might be shadowing 'max' above + sum = 0; + left = 0; + right = 0; + for (const finger in m_finger_distance) { + sum += m_finger_distance[finger]; + if (finger <= 4) { + left += m_finger_distance[finger]; + } + if (finger >= 7) { + right += m_finger_distance[finger]; + } + } + var inv_max = 1.0 / max; + inv_sum = 1.0 / sum; + stats + .append("text") + .attr("x", x + 40) + .attr("y", 16) + .attr("font-size", 16) + .attr("font-family", "Sans,Arial") + .attr("fill", "#dfe2eb") + .attr("text-anchor", "left") + .text("Finger Distance"); + for (const finger in m_finger_distance) { + if (m_finger_distance[finger] > 0) { + var norm_finger_distance = m_finger_distance[finger] * inv_max; + var height = 75 * norm_finger_distance; + var tip = parseFloat(100 * norm_finger_distance).toFixed(2); + var red = Math.floor(128 * norm_finger_distance) + 128; + var green = 128; + if (red < 16) { + red = 16; + } + if (red > 255) { + red = 255; + } + var hex_red = red.toString(16); + var hex_bg = green.toString(16); + stats + .append("rect") + .attr("x", x + finger * 20) + .attr("y", 100 - height) + .attr("width", 15) + .attr("height", height) + .attr("fill", "#" + hex_red + hex_bg + hex_bg) + .attr("stroke", "#453033") + .attr("stroke-width", 1) + .attr("onmouseover", "showTooltip(evt,'" + tip + "')") + .attr("onmouseout", "hideTooltip()"); + stats + .append("text") + .attr("x", x + finger * 20 + 7) + .attr("y", 111) + .attr("fill", "#dfe2eb") + .attr("font-size", 10) + .attr("font-family", "Sans,Arial") + .attr("text-anchor", "middle") + .text(finger); + //\n" + } + } + stats + .append("text") + .attr("x", x + 57) + .attr("y", 124) + .attr("fill", "#dfe2eb") + .attr("font-size", 11) + .attr("font-family", "Sans,Arial") + .attr("text-anchor", "middle") + .text(parseFloat(100 * left * inv_sum).toFixed(2) + "%"); + stats + .append("text") + .attr("x", x + 177) + .attr("y", 124) + .attr("fill", "#dfe2eb") + .attr("font-size", 11) + .attr("font-family", "Sans,Arial") + .attr("text-anchor", "middle") + .text(parseFloat(100 * right * inv_sum).toFixed(2) + "%"); + stats + .append("text") + .attr("x", x + 117) + .attr("y", 124) + .attr("fill", "#dfe2eb") + .attr("font-size", 11) + .attr("font-family", "Sans,Arial") + .attr("text-anchor", "middle") + .text(parseFloat(100 * sum * inv_max).toFixed(1)); + // (100*sum/max).toFixed(1) + /////////////////////////////////// S A M E F I N G E R B I G R A M S /////////////////////////////// + var x = 0; + var y = 180; + sum = 0; + // toggle button + stats + .append("path") + .attr( + "d", + `M ${x + 15} ${y - 24} L ${x + 35} ${y - 24} L ${x + 25} ${y - 34} Z`, + ) + .attr("fill", "#777777") + .attr("stroke", "#989898") + .attr("stroke-width", 1) + .attr( + "onmouseover", + "showTooltip(evt,'Toggle between showing same finger bigrams for each bigram, and for each finger')", + ) + .attr("onmouseout", "hideTooltip()") + .attr("onclick", "sfbToggle(-1)") + .on("mouseover", function () { + d3.select(this).attr("fill", "#bbbbbb"); + }) + .on("mouseout", function () { + d3.select(this).attr("fill", "#777777"); + }); + + stats + .append("path") + .attr( + "d", + `M ${x + 15} ${y - 20} L ${x + 35} ${y - 20} L ${x + 25} ${y - 10} Z`, + ) + .attr("fill", "#777777") + .attr("stroke", "#989898") + .attr("stroke-width", 1) + .attr( + "onmouseover", + "showTooltip(evt,'Toggle between showing same finger bigrams for each bigram, and for each finger')", + ) + .attr("onmouseout", "hideTooltip()") + .attr("onclick", "sfbToggle(1)") + .on("mouseover", function () { + d3.select(this).attr("fill", "#bbbbbb"); + }) + .on("mouseout", function () { + d3.select(this).attr("fill", "#777777"); + }); + if (sfb_toggle == 0) { + var keyValueArray = Object.entries(m_same_finger); + keyValueArray.sort((a, b) => b[1] - a[1]); + m_same_finger = Object.fromEntries(keyValueArray); + + for (const bigram in m_same_finger) { + sum += m_same_finger[bigram] * inv_m_input_length; + } + stats + .append("text") + .attr("x", x + 40) + .attr("y", y - 16) + .attr("font-size", 16) + .attr("font-family", "Sans,Arial") + .attr("fill", "#dfe2eb") + .attr("text-anchor", "left") + .text("Same Finger Bigrams " + parseFloat(100 * sum).toFixed(2) + "%"); + // stats.append("text").attr("x",x+40).attr("y",y+200).attr("font-size",16).attr("font-family","Sans,Arial").attr("fill","#dfe2eb").attr("text-anchor","left").text("Input Length "+m_input_length); + + var i = 0; + var t = scroll_amount; + for (const bigram in m_same_finger) { + if (t > 0) { + t -= 1; + continue; + } + var width = 18000 * m_same_finger[bigram] * inv_m_input_length; + if (width > 200) { + width = 200; + } + stats + .append("rect") + .attr("x", x + 40) + .attr("y", y + i * 15) + .attr("width", width) + .attr("height", 10) + .attr("fill", "#7777bb") + .attr("stroke", "#9898d6") + .attr("stroke-width", 1); + stats + .append("text") + .attr("x", x + 20) + .attr("y", y + i * 15 + 8) + .attr("fill", "#dfe2eb") + .attr("font-size", 10) + .attr("font-family", "Roboto Mono") + .attr("text-anchor", "right") + .text(bigram); + stats + .append("text") + .attr("x", x + 200) + .attr("y", y + i * 15 + 8) + .attr("fill", "#dfe2eb") + .attr("font-size", 10) + .attr("font-family", "Sans,Arial") + .attr("text-anchor", "left") + .text( + parseFloat( + "" + 100 * m_same_finger[bigram] * inv_m_input_length, + ).toFixed(2) + "%", + ); + //\n" + i += 1; + if (i > 10) { + break; + } + } + } else if (sfb_toggle == 1) { + for (const finger in m_same_finger2) { + sum += m_same_finger2[finger] * inv_m_input_length; + } + stats + .append("text") + .attr("x", x + 40) + .attr("y", y - 16) + .attr("font-size", 16) + .attr("font-family", "Sans,Arial") + .attr("fill", "#dfe2eb") + .attr("text-anchor", "left") + .text("Same Finger Bigrams " + parseFloat(100 * sum).toFixed(2) + "%"); + for (const finger in m_same_finger2) { + var height = 30000 * m_same_finger2[finger] * inv_m_input_length; + if (height > 150) { + height = 150; + } + var tip = parseFloat( + 100 * m_same_finger2[finger] * inv_m_input_length, + ).toFixed(2); + var red = + Math.floor(6000 * m_same_finger2[finger] * inv_m_input_length) + 128; + var green = 128; + if (red < 16) { + red = 16; + } + if (red > 255) { + red = 255; + } + var hex_red = red.toString(16); + var hex_bg = green.toString(16); + stats + .append("rect") + .attr("x", x + finger * 20) + .attr("y", y + 155 - height) + .attr("width", 15) + .attr("height", height) + .attr("fill", "#" + hex_red + hex_bg + hex_bg) + .attr("stroke", "#453033") + .attr("stroke-width", 1) + .attr("onmouseover", "showTooltip(evt,'" + tip + "%')") + .attr("onmouseout", "hideTooltip()"); + + stats + .append("text") + .attr("x", x + finger * 20 + 7) + .attr("y", y + 166) + .attr("fill", "#dfe2eb") + .attr("font-size", 10) + .attr("font-family", "Sans,Arial") + .attr("text-anchor", "middle") + .text(finger); + } + } else { + var keyValueArray = Object.entries(m_same_finger3); + keyValueArray.sort((a, b) => b[1] - a[1]); + m_same_finger3 = Object.fromEntries(keyValueArray); + + for (const bigram in m_same_finger3) { + sum += m_same_finger3[bigram] * inv_m_input_length; + } + stats + .append("text") + .attr("x", x + 40) + .attr("y", y - 16) + .attr("font-size", 16) + .attr("font-family", "Sans,Arial") + .attr("fill", "#dfe2eb") + .attr("text-anchor", "left") + .text("2u Same Finger Bigrams " + parseFloat(100 * sum).toFixed(2) + "%"); + // stats.append("text").attr("x",x+40).attr("y",y+200).attr("font-size",16).attr("font-family","Sans,Arial").attr("fill","#dfe2eb").attr("text-anchor","left").text("Input Length "+m_input_length); + + var i = 0; + var t = scroll_amount; + for (const bigram in m_same_finger3) { + if (t > 0) { + t -= 1; + continue; + } + var width = 18000 * m_same_finger3[bigram] * inv_m_input_length; + if (width > 200) { + width = 200; + } + stats + .append("rect") + .attr("x", x + 40) + .attr("y", y + i * 15) + .attr("width", width) + .attr("height", 10) + .attr("fill", "#7777bb") + .attr("stroke", "#9898d6") + .attr("stroke-width", 1); + stats + .append("text") + .attr("x", x + 20) + .attr("y", y + i * 15 + 8) + .attr("fill", "#dfe2eb") + .attr("font-size", 10) + .attr("font-family", "Roboto Mono") + .attr("text-anchor", "right") + .text(bigram); + stats + .append("text") + .attr("x", x + 200) + .attr("y", y + i * 15 + 8) + .attr("fill", "#dfe2eb") + .attr("font-size", 10) + .attr("font-family", "Sans,Arial") + .attr("text-anchor", "left") + .text( + parseFloat( + "" + 100 * m_same_finger3[bigram] * inv_m_input_length, + ).toFixed(2) + "%", + ); + //\n" + i += 1; + if (i > 10) { + break; + } + } + } + /////////////////////////////////// S K I P F I N G E R B I G R A M S /////////////////////////////// + var x = 250; + var y = 180; + sum = 0; + var tmp; + if (skip_toggle) { + var keyValueArray = Object.entries(m_skip_bigram); + keyValueArray.sort((a, b) => b[1] - a[1]); + tmp = Object.fromEntries(keyValueArray); + for (const bigram in tmp) { + sum += tmp[bigram] * inv_m_input_length; + } + stats + .append("text") + .attr("x", x + 40) + .attr("y", y - 16) + .attr("font-size", 16) + .attr("font-family", "Sans,Arial") + .attr("fill", "#dfe2eb") + .attr("text-anchor", "left") + .text("Skip Bigrams " + parseFloat(100 * sum).toFixed(2) + "%"); + } else { + var keyValueArray = Object.entries(m_skip_bigram2); + keyValueArray.sort((a, b) => b[1] - a[1]); + tmp = Object.fromEntries(keyValueArray); + for (const bigram in tmp) { + sum += tmp[bigram] * inv_m_input_length; + } + stats + .append("text") + .attr("x", x + 40) + .attr("y", y - 16) + .attr("font-size", 16) + .attr("font-family", "Sans,Arial") + .attr("fill", "#dfe2eb") + .attr("text-anchor", "left") + .text("Skip Bigrams (2u) " + parseFloat(100 * sum).toFixed(2) + "%"); + } + + stats + .append("path") + .attr( + "d", + `M ${x + 15} ${y - 24} L ${x + 35} ${y - 24} L ${x + 25} ${y - 34} Z`, + ) + .attr("fill", "#777777") + .attr("stroke", "#989898") + .attr("stroke-width", 1) + .attr( + "onmouseover", + "showTooltip(evt,'Toggle between showing all skip bigrams and only those with a 2u step between 1 and 3')", + ) + .attr("onmouseout", "hideTooltip()") + .attr("onclick", "skipToggle()") + .on("mouseover", function () { + d3.select(this).attr("fill", "#bbbbbb"); + }) + .on("mouseout", function () { + d3.select(this).attr("fill", "#777777"); + }); + + stats + .append("path") + .attr( + "d", + `M ${x + 15} ${y - 20} L ${x + 35} ${y - 20} L ${x + 25} ${y - 10} Z`, + ) + .attr("fill", "#777777") + .attr("stroke", "#989898") + .attr("stroke-width", 1) + .attr( + "onmouseover", + "showTooltip(evt,'Toggle between showing all skip bigrams and only those with a 2u step between 1 and 3')", + ) + .attr("onmouseout", "hideTooltip()") + .attr("onclick", "skipToggle()") + .on("mouseover", function () { + d3.select(this).attr("fill", "#bbbbbb"); + }) + .on("mouseout", function () { + d3.select(this).attr("fill", "#777777"); + }); + var i = 0; + var t = scroll_amount; + for (const bigram in tmp) { + if (t > 0) { + t -= 1; + continue; + } + var height = 36000 * tmp[bigram] * inv_m_input_length; + if (height > 200) { + height = 200; + } + stats + .append("rect") + .attr("x", x + 40) + .attr("y", y + i * 15) + .attr("width", height) + .attr("height", 10) + .attr("fill", "#7777bb") + .attr("stroke", "#9898d6") + .attr("stroke-width", 1); + stats + .append("text") + .attr("x", x + 17) + .attr("y", y + i * 15 + 8) + .attr("fill", "#dfe2eb") + .attr("font-size", 10) + .attr("font-family", "Roboto Mono") + .attr("text-anchor", "right") + .text(bigram); + stats + .append("text") + .attr("x", x + 200) + .attr("y", y + i * 15 + 8) + .attr("fill", "#dfe2eb") + .attr("font-size", 10) + .attr("font-family", "Sans,Arial") + .attr("text-anchor", "left") + .text( + parseFloat("" + 100 * tmp[bigram] * inv_m_input_length).toFixed(2) + + "%", + ); + //\n" + i += 1; + if (i > 10) { + break; + } + } + //////////////////////////// L A T E R A L S T R E T C H B I G R A M S /////////////////////////////// + var x = 500; + var y = 180; + sum = 0; + if (lsb_toggle == 0) { + var keyValueArray = Object.entries(m_lat_stretch); + keyValueArray.sort((a, b) => b[1] - a[1]); + tmp = Object.fromEntries(keyValueArray); + for (const bigram in tmp) { + sum += tmp[bigram] * inv_m_input_length; + } + stats + .append("text") + .attr("x", x + 40) + .attr("y", y - 16) + .attr("font-size", 16) + .attr("font-family", "Sans,Arial") + .attr("fill", "#dfe2eb") + .attr("text-anchor", "left") + .text("Lat Stretch Bigrams " + parseFloat(100 * sum).toFixed(2) + "%"); + } else { + var keyValueArray = Object.entries(m_lat_stretch2); + keyValueArray.sort((a, b) => b[1] - a[1]); + tmp = Object.fromEntries(keyValueArray); + for (const bigram in tmp) { + sum += tmp[bigram] * inv_m_input_length; + } + stats + .append("text") + .attr("x", x + 40) + .attr("y", y - 16) + .attr("font-size", 16) + .attr("font-family", "Sans,Arial") + .attr("fill", "#dfe2eb") + .attr("text-anchor", "left") + .text("Ring LSBs " + parseFloat(100 * sum).toFixed(2) + "%"); + } + + stats + .append("path") + .attr( + "d", + `M ${x + 15} ${y - 24} L ${x + 35} ${y - 24} L ${x + 25} ${y - 34} Z`, + ) + .attr("fill", "#777777") + .attr("stroke", "#989898") + .attr("stroke-width", 1) + .attr( + "onmouseover", + "showTooltip(evt,'Toggle between showing lateral stretches from the middle finger to ring finger')", + ) + .attr("onmouseout", "hideTooltip()") + .attr("onclick", "lsbToggle()") + .on("mouseover", function () { + d3.select(this).attr("fill", "#bbbbbb"); + }) + .on("mouseout", function () { + d3.select(this).attr("fill", "#777777"); + }); + + stats + .append("path") + .attr( + "d", + `M ${x + 15} ${y - 20} L ${x + 35} ${y - 20} L ${x + 25} ${y - 10} Z`, + ) + .attr("fill", "#777777") + .attr("stroke", "#989898") + .attr("stroke-width", 1) + .attr( + "onmouseover", + "showTooltip(evt,'Toggle between showing lateral stretches from the middle finger to ring finger')", + ) + .attr("onmouseout", "hideTooltip()") + .attr("onclick", "lsbToggle()") + .on("mouseover", function () { + d3.select(this).attr("fill", "#bbbbbb"); + }) + .on("mouseout", function () { + d3.select(this).attr("fill", "#777777"); + }); + var i = 0; + var t = scroll_amount; + for (const bigram in tmp) { + if (t > 0) { + t -= 1; + continue; + } + var height = 10000 * tmp[bigram] * inv_m_input_length; + if (height > 200) { + height = 200; + } + stats + .append("rect") + .attr("x", x + 40) + .attr("y", y + i * 15) + .attr("width", height) + .attr("height", 10) + .attr("fill", "#7777bb") + .attr("stroke", "#9898d6") + .attr("stroke-width", 1); + stats + .append("text") + .attr("x", x + 20) + .attr("y", y + i * 15 + 8) + .attr("fill", "#dfe2eb") + .attr("font-size", 10) + .attr("font-family", "Roboto Mono") + .attr("text-anchor", "right") + .text(bigram); + stats + .append("text") + .attr("x", x + 200) + .attr("y", y + i * 15 + 8) + .attr("fill", "#dfe2eb") + .attr("font-size", 10) + .attr("font-family", "Sans,Arial") + .attr("text-anchor", "left") + .text( + parseFloat("" + 100 * tmp[bigram] * inv_m_input_length).toFixed(2) + + "%", + ); + //\n" + i += 1; + if (i > 10) { + break; + } + } + //////////////////////////// S C I S S O R S /////////////////////////////// + var x = 760; + var y = 180; + sum = 0; + + if (scissors_toggle == 1) { + var keyValueArray = Object.entries(m_pinky_scissors); + keyValueArray.sort((a, b) => b[1] - a[1]); + tmp = Object.fromEntries(keyValueArray); + for (const bigram in tmp) { + sum += tmp[bigram] * inv_m_input_length; + } + stats + .append("text") + .attr("x", x + 40) + .attr("y", y - 16) + .attr("font-size", 16) + .attr("font-family", "Sans,Arial") + .attr("fill", "#dfe2eb") + .attr("text-anchor", "left") + .text("Pinky/Ring Scissors " + parseFloat(100 * sum).toFixed(2) + "%"); + } else if (scissors_toggle == 0) { + var keyValueArray = Object.entries(m_scissors); + keyValueArray.sort((a, b) => b[1] - a[1]); + tmp = Object.fromEntries(keyValueArray); + for (const bigram in tmp) { + sum += tmp[bigram] * inv_m_input_length; + } + stats + .append("text") + .attr("x", x + 40) + .attr("y", y - 16) + .attr("font-size", 16) + .attr("font-family", "Sans,Arial") + .attr("fill", "#dfe2eb") + .attr("text-anchor", "left") + .text("Scissors " + parseFloat(100 * sum).toFixed(2) + "%"); + } else { + var keyValueArray = Object.entries(m_all_scissors); + keyValueArray.sort((a, b) => b[1] - a[1]); + tmp = Object.fromEntries(keyValueArray); + for (const bigram in tmp) { + sum += tmp[bigram] * inv_m_input_length; + } + stats + .append("text") + .attr("x", x + 40) + .attr("y", y - 16) + .attr("font-size", 16) + .attr("font-family", "Sans,Arial") + .attr("fill", "#dfe2eb") + .attr("text-anchor", "left") + .text("Wide Scissors " + parseFloat(100 * sum).toFixed(2) + "%"); + } + stats + .append("path") + .attr( + "d", + `M ${x + 15} ${y - 24} L ${x + 35} ${y - 24} L ${x + 25} ${y - 34} Z`, + ) + .attr("fill", "#777777") + .attr("stroke", "#989898") + .attr("stroke-width", 1) + .attr( + "onmouseover", + "showTooltip(evt,'Toggle between showing scissors on ring and pinky, and all 2u scissors')", + ) + .attr("onmouseout", "hideTooltip()") + .attr("onclick", "scissorsToggle(-1)") + .on("mouseover", function () { + d3.select(this).attr("fill", "#bbbbbb"); + }) + .on("mouseout", function () { + d3.select(this).attr("fill", "#777777"); + }); + + stats + .append("path") + .attr( + "d", + `M ${x + 15} ${y - 20} L ${x + 35} ${y - 20} L ${x + 25} ${y - 10} Z`, + ) + .attr("fill", "#777777") + .attr("stroke", "#989898") + .attr("stroke-width", 1) + .attr( + "onmouseover", + "showTooltip(evt,'Toggle between showing scissors on ring and pinky, and all 2u scissors')", + ) + .attr("onmouseout", "hideTooltip()") + .attr("onclick", "scissorsToggle(1)") + .on("mouseover", function () { + d3.select(this).attr("fill", "#bbbbbb"); + }) + .on("mouseout", function () { + d3.select(this).attr("fill", "#777777"); + }); + var i = 0; + var t = scroll_amount; + for (const bigram in tmp) { + if (t > 0) { + t -= 1; + continue; + } + var height = 36000 * tmp[bigram] * inv_m_input_length; + if (height > 180) { + height = 180; + } + stats + .append("rect") + .attr("x", x + 40) + .attr("y", y + i * 15) + .attr("width", height) + .attr("height", 10) + .attr("fill", "#7777bb") + .attr("stroke", "#9898d6") + .attr("stroke-width", 1); + stats + .append("text") + .attr("x", x + 20) + .attr("y", y + i * 15 + 8) + .attr("fill", "#dfe2eb") + .attr("font-size", 10) + .attr("font-family", "Roboto Mono") + .attr("text-anchor", "right") + .text(bigram); + stats + .append("text") + .attr("x", x + 190) + .attr("y", y + i * 15 + 8) + .attr("fill", "#dfe2eb") + .attr("font-size", 10) + .attr("font-family", "Sans,Arial") + .attr("text-anchor", "left") + .text( + parseFloat("" + 100 * tmp[bigram] * inv_m_input_length).toFixed(2) + + "%", + ); + //\n" + i += 1; + if (i > 10) { + break; + } + } + /////////////////////////////////// T R I G R A M S T A T S /////////////////////////////// + var x = 760; + var y = 390; + dx = 105; + sum = 0; + scale = 1; + var trigram_title = "Trigram Stats"; + + if (trigram_toggle == 0) { + var keyValueArray = Object.entries(m_trigram_count); + keyValueArray.sort((a, b) => b[1] - a[1]); + tmp = Object.fromEntries(keyValueArray); + for (const cat in tmp) { + sum += tmp[cat]; + } + trigram_title = "Trigram Stats"; + scale = 1; + dx = 105; + } else if (trigram_toggle == 1) { + var keyValueArray = Object.entries(m_trigram_count_alt); + keyValueArray.sort((a, b) => b[1] - a[1]); + tmp = Object.fromEntries(keyValueArray); + for (const cat in tmp) { + sum += tmp[cat]; + } + trigram_title = "Trigram Stats (alts)"; + scale = 3; + dx = 47; + } else if (trigram_toggle == 2) { + var keyValueArray = Object.entries(m_trigram_count_red); + keyValueArray.sort((a, b) => b[1] - a[1]); + tmp = Object.fromEntries(keyValueArray); + for (const cat in tmp) { + sum += tmp[cat]; + } + trigram_title = "Trigram Stats (redirects)"; + scale = 3; + dx = 47; + } else if (trigram_toggle == 3) { + var keyValueArray = Object.entries(m_trigram_count_roll_in); + keyValueArray.sort((a, b) => b[1] - a[1]); + tmp = Object.fromEntries(keyValueArray); + for (const cat in tmp) { + sum += tmp[cat]; + } + trigram_title = "Trigram Stats (roll in)"; + scale = 3; + dx = 47; + } else if (trigram_toggle == 4) { + var keyValueArray = Object.entries(m_trigram_count_roll_out); + keyValueArray.sort((a, b) => b[1] - a[1]); + tmp = Object.fromEntries(keyValueArray); + for (const cat in tmp) { + sum += tmp[cat]; + } + trigram_title = "Trigram Stats (roll out)"; + scale = 3; + dx = 47; + } + const trigram_desc = { + alt: "the hands used to type the trigram are either LRL or RLR", + "alt sfs": + "trigram is typed LRL or RLR but finger1 and finger3 are the same and type a different character", + "bigram roll in": + "two adjacent characters in the trigram are typed with the same hand and the first is outside the second", + "bigram roll out": + "two adjacent characters in the trigram are typed with the same hand and the first is inside the second", + "weak redirect": + "a redirect but none of the fingers used are the index finger", + redirect: + "the three characters of the trigram are typed with the same hand and the direction changes", + "roll out": + "the three characters of the trigram are typed with the same hand and go from the inside to the outside", + "roll in": + "the three characters of the trigram are typed with the same hand and go from the outside to the inside", + other: + "all other trigrams that don\\'t fit into any of the other categories", + // "bigram same row":"two adjacent characters in the trigram are typed on the same row", + // "trigram same row":"the three characters in the trigram are typed on the same row", + // "double jump":"trigram is typed top, bottom, top or bottom, top, bottom", + }; + // for(var tri in m_redirects){ + // if (m_redirects[tri] > 40){ + // console.log(tri + " " + m_redirects[tri]); + // // trigram_desc["redirect"] = trigram_desc["redirect"].concat(" "+tri); + // } + // } + stats + .append("path") + .attr( + "d", + `M ${x + 15} ${y - 20} L ${x + 35} ${y - 20} L ${x + 25} ${y - 10} Z`, + ) + .attr("fill", "#777777") + .attr("stroke", "#989898") + .attr("stroke-width", 1) + .attr( + "onmouseover", + "showTooltip(evt,'Change pages to see different trigram stats')", + ) + .attr("onmouseout", "hideTooltip()") + .attr("onclick", "trigramToggle(-1)") + .on("mouseover", function () { + d3.select(this).attr("fill", "#bbbbbb"); + }) + .on("mouseout", function () { + d3.select(this).attr("fill", "#777777"); + }); + + stats + .append("path") + .attr( + "d", + `M ${x + 15} ${y - 24} L ${x + 35} ${y - 24} L ${x + 25} ${y - 34} Z`, + ) + .attr("fill", "#777777") + .attr("stroke", "#989898") + .attr("stroke-width", 1) + .attr( + "onmouseover", + "showTooltip(evt,'Change pages to see different trigram stats')", + ) + .attr("onmouseout", "hideTooltip()") + .attr("onclick", "trigramToggle(1)") + .on("mouseover", function () { + d3.select(this).attr("fill", "#bbbbbb"); + }) + .on("mouseout", function () { + d3.select(this).attr("fill", "#777777"); + }); + + stats + .append("text") + .attr("x", x + 40) + .attr("y", y - 16) + .attr("font-size", 16) + .attr("font-family", "Sans,Arial") + .attr("fill", "#dfe2eb") + .attr("text-anchor", "left") + .text(trigram_title); + + var i = 0; + var t = trigram_scroll_amount; + inv_sum = 1.0 / sum; + for (const cat in tmp) { + if (t > 0) { + t -= 1; + continue; + } + var tmp_cat_inv_sum = tmp[cat] * inv_sum; + var width = scale * 200 * tmp_cat_inv_sum; + if (width > 200) { + width = 200; + } + stats + .append("rect") + .attr("x", x + dx) + .attr("y", y + i * 15) + .attr("width", width) + .attr("height", 10) + .attr("fill", "#7777bb") + .attr("stroke", "#9898d6") + .attr("stroke-width", 1) + .attr("onmouseover", "showTooltip(evt,'" + trigram_desc[cat] + "')") + .attr("onmouseout", "hideTooltip()"); + stats + .append("text") + .attr("x", x + 20) + .attr("y", y + i * 15 + 8) + .attr("fill", "#dfe2eb") + .attr("font-size", 9) + .attr("font-family", "Roboto Mono") + .attr("text-anchor", "right") + .text(cat); + stats + .append("text") + .attr("x", x + 190) + .attr("y", y + i * 15 + 8) + .attr("fill", "#dfe2eb") + .attr("font-size", 10) + .attr("font-family", "Sans,Arial") + .attr("text-anchor", "left") + .text(parseFloat("" + 100 * tmp_cat_inv_sum).toFixed(2) + "%"); + //\n" + i += 1; + if (i > 10) { + break; + } + } + + /////////////////////////////////// S A M E H A N D S T R I N G S /////////////////////////////// + var x = 250; + var y = 390; + sum = 0; + + var keyValueArray = Object.entries(samehandstrings); + keyValueArray.sort((a, b) => b[1] * b[0].length - a[1] * a[0].length); + samehandstrings = Object.fromEntries(keyValueArray); + + scale = 30191.79 * inv_m_input_length; + // console.log("input length: "+m_input_length) + // console.log("scale : "+scale) + stats + .append("text") + .attr("x", x + 20) + .attr("y", y - 16) + .attr("font-size", 16) + .attr("font-family", "Sans,Arial") + .attr("fill", "#dfe2eb") + .attr("text-anchor", "left") + .text("Same Hand Strings"); + var i = 0; + t = sh_scroll_amount; + for (const word in samehandstrings) { + if (t > 0) { + t -= 1; + continue; + } + var count = samehandstrings[word]; + // console.log(word + " " + count) + word_len = word.length; + var word_len_count = word_len * count; + var width = scale * word_len_count; + if (width > 100) { + width = 100; + } + stats + .append("rect") + .attr("x", x + 70) + .attr("y", y + i * 15) + .attr("width", width) + .attr("height", 10) + .attr("fill", "#7777bb") + .attr("stroke", "#9898d6") + .attr("stroke-width", 1); + stats + .append("text") + .attr("x", x + 20) + .attr("y", y + i * 15 + 8) + .attr("fill", "#dfe2eb") + .attr("font-size", 10) + .attr("font-family", "Roboto Mono") + .attr("text-anchor", "right") + .text(word); + stats + .append("text") + .attr("x", x + 135) + .attr("y", y + i * 15 + 8) + .attr("fill", "#dfe2eb") + .attr("font-size", 10) + .attr("font-family", "Sans,Arial") + .attr("text-anchor", "left") + .text(parseFloat("" + word_len_count).toFixed(0)); // + i += 1; + if (i > 10) { + break; + } + } + + /////////////////////////////////// S A M E H A N D C O U N T S /////////////////////////////// + var x = 415; + var y = 390; + sum = 0; + + // var keyValueArray = Object.entries(samehandcount); + // keyValueArray.sort((a, b) => b - a); + // samehandcount = Object.fromEntries(keyValueArray); + scale = 140.89502 * inv_m_input_length; + // console.log("input length: "+m_input_length) + // console.log("scale : "+scale) + stats + .append("text") + .attr("x", x + 20) + .attr("y", y - 16) + .attr("font-size", 16) + .attr("font-family", "Sans,Arial") + .attr("fill", "#dfe2eb") + .attr("text-anchor", "left") + .text("Same Hand Count"); + var i = 0; + for (const len in samehandcount) { + var count = samehandcount[len]; + var width = scale * count; + if (width > 100) { + width = 100; + } + stats + .append("rect") + .attr("x", x + 40) + .attr("y", y + i * 15) + .attr("width", width) + .attr("height", 10) + .attr("fill", "#7777bb") + .attr("stroke", "#9898d6") + .attr("stroke-width", 1); + stats + .append("text") + .attr("x", x + 20) + .attr("y", y + i * 15 + 8) + .attr("fill", "#dfe2eb") + .attr("font-size", 10) + .attr("font-family", "Roboto Mono") + .attr("text-anchor", "right") + .text(len); + stats + .append("text") + .attr("x", x + 135) + .attr("y", y + i * 15 + 8) + .attr("fill", "#dfe2eb") + .attr("font-size", 10) + .attr("font-family", "Sans,Arial") + .attr("text-anchor", "left") + .text((scale * 7.14285714285714285714285 * count).toFixed(1)); + // stats.append("text").attr("x", x + 135).attr("y", y + i * 15 + 8).attr("fill", "#dfe2eb").attr("font-size", 10).attr("font-family", "Sans,Arial").attr("text-anchor", "left").text(count); + i += 1; + if (i > 10) { + break; + } + } + + /////////////////////////////////// H A R D W O R D S /////////////////////////////// + var x = 580; + var y = 390; + sum = 0; + var keyValueArray = Object.entries(word_effort); + keyValueArray.sort((a, b) => b[1] / b[0].length - a[1] / a[0].length); + word_effort = Object.fromEntries(keyValueArray); + stats + .append("text") + .attr("x", x + 40) + .attr("y", y - 16) + .attr("font-size", 16) + .attr("font-family", "Sans,Arial") + .attr("fill", "#dfe2eb") + .attr("text-anchor", "left") + .text("Hard Words "); + var i = 0; + t = hw_scroll_amount; + for (const word in word_effort) { + word_len = word.length; + if (word_len > 3 && words[word] > 4) { + if (t > 0) { + t -= 1; + continue; + } + var height = (100 * word_effort[word]) / word_len; + stats + .append("rect") + .attr("x", x + 80) + .attr("y", y + i * 15) + .attr("width", height) + .attr("height", 10) + .attr("fill", "#7777bb") + .attr("stroke", "#9898d6") + .attr("stroke-width", 1); + stats + .append("text") + .attr("x", x + 20) + .attr("y", y + i * 15 + 8) + .attr("fill", "#dfe2eb") + .attr("font-size", 10) + .attr("font-family", "Roboto Mono") + .attr("text-anchor", "right") + .text(word); + stats + .append("text") + .attr("x", x + 165) + .attr("y", y + i * 15 + 8) + .attr("fill", "#dfe2eb") + .attr("font-size", 10) + .attr("font-family", "Sans,Arial") + .attr("text-anchor", "left") + .text(parseFloat("" + word_effort[word]).toFixed(2)); + i += 1; + if (i > 10) { + break; + } + } + } + /////////////////////////////////// E A S Y W O R D S /////////////////////////////// + // var x = 610; + // var y = 390; + // sum = 0; + // var keyValueArray = Object.entries(word_effort); + // keyValueArray.sort((a, b) => a[1] - b[1]); + // word_effort = Object.fromEntries(keyValueArray); + // stats.append("text").attr("x", x + 40).attr("y", y - 16).attr("font-size", 16).attr("font-family", "Sans,Arial").attr("fill", "#dfe2eb").attr("text-anchor", "left").text("Easy Words ") + // var i = 0 + // for (var word in word_effort) { + // var height = 10*word_effort[word]; + // if (word.length > 3){ + // stats.append("rect").attr("x", x + 80).attr("y", y + i * 15).attr("width", height).attr("height", 10) + // .attr("fill", "#7777bb").attr("stroke", "#9898d6").attr("stroke-width", 1) + // stats.append("text").attr("x", x + 20).attr("y", y + i * 15 + 8).attr("fill", "#dfe2eb").attr("font-size", 10).attr("font-family", "Sans,Arial").attr("text-anchor", "right").text(word); + // stats.append("text").attr("x", x + 125).attr("y", y + i * 15 + 8).attr("fill", "#dfe2eb").attr("font-size", 10).attr("font-family", "Sans,Arial").attr("text-anchor", "left").text(parseFloat("" + (word_effort[word])).toFixed(2)); + // i += 1; + // if (i > 10) { break; } + // } + // } + + /////////////////////////////////// F I N G E R P A I R S /////////////////////////////// + var x = 10; + var y = 370; + var box_x = 26; + var box_y = 20; + var per = 0; + var finger1 = i; + var finger2 = j; + var sum = 0; + stats + .append("text") + .attr("x", 0) + .attr("y", 0) + .attr("font-size", 10) + .attr("font-family", "Sans,Arial") + .attr("fill", "#dfe2eb") + .attr("text-anchor", "middle") + .attr("transform", `translate(${x + 2},${y + 100}) rotate(-90)`) + .text("First Finger"); + stats + .append("text") + .attr("x", x + 130) + .attr("y", y) + .attr("font-size", 10) + .attr("font-family", "Sans,Arial") + .attr("fill", "#dfe2eb") + .attr("text-anchor", "middle") + .text("Second Finger"); + for (var i = 0; i <= 8; i++) { + sum = 0; + for (var j = 1; j <= 8; j++) { + finger1 = i; + finger2 = j; + if (i > 4) { + finger1 += 2; + } + if (j > 4) { + finger2 += 2; + } + if (m_finger_pairs[finger1]) { + if (m_finger_pairs[finger1][finger2]) { + sum += m_finger_pairs[finger1][finger2]; + } + } + } + for (var j = 0; j <= 8; j++) { + finger1 = i; + finger2 = j; + if (i > 4) { + finger1 += 2; + } + if (j > 4) { + finger2 += 2; + } + if (i == 0 && j == 0) { + } else if (i == 0 && j > 0) { + stats + .append("text") + .attr("x", x + box_x * j + 14) + .attr("y", y + box_y * i + 14) + .attr("font-size", 10) + .attr("font-family", "Sans,Arial") + .attr("fill", "#dfe2eb") + .attr("text-anchor", "middle") + .text(finger2); + } else if (i > 0 && j == 0) { + stats + .append("text") + .attr("x", x + box_x * j + 14) + .attr("y", y + box_y * i + 14) + .attr("font-size", 10) + .attr("font-family", "Sans,Arial") + .attr("fill", "#dfe2eb") + .attr("text-anchor", "middle") + .text(finger1); + } else { + if (m_finger_pairs[finger1]) { + if (m_finger_pairs[finger1][finger2]) { + if (sum > 0) { + per = parseFloat( + (100 * m_finger_pairs[finger1][finger2]) / sum, + ).toFixed(0); + } else { + per = -1; + } + red = Math.floor(128 + 3 * per); + if (red > 255) { + red = 255; + } + hex_red = red.toString(16); + + stats + .append("rect") + .attr("x", x + box_x * j) + .attr("y", y + box_y * i) + .attr("width", box_x) + .attr("height", box_y) + .attr("fill", "#" + hex_red + hex_bg + hex_bg) + .attr("stroke", "black") + .attr("stroke-width", "0.5"); + stats + .append("text") + .attr("x", x + box_x * j + 14) + .attr("y", y + box_y * i + 14) + .attr("font-size", 10) + .attr("font-family", "Sans,Arial") + .attr("fill", "black") + .attr("text-anchor", "middle") + .text(per + "%"); + } + } + } + } + } } - function makeDraggable(svg) { - svg.addEventListener('mousedown', startDrag, false); - svg.addEventListener('mousemove', drag, false); - svg.addEventListener('mouseup', endDrag, false); - svg.addEventListener('mouseleave', endDrag); - - svg.addEventListener('touchstart', startDrag); - svg.addEventListener('touchmove', drag); - svg.addEventListener('touchend', endDrag); - svg.addEventListener('touchleave', endDrag); - svg.addEventListener('touchcancel', endDrag); - - function getMousePosition(evt) { - var CTM = svg.getScreenCTM(); - if (evt.touches) { evt = evt.touches[0]; } - return { - x: (evt.clientX - CTM.e) / CTM.a, - y: (evt.clientY - CTM.f) / CTM.d - }; - } - - var selectedElement, offset, offset2, sibling; - var starti, dropi, startx, starty; - - function startDrag(evt) { - if (evt.target.classList.contains('draggable')) { - selectedElement = evt.target; - if (selectedElement.classList.contains('legend')){ - selectedElement = selectedElement.previousElementSibling; - sibling = evt.target; - } else { - sibling = selectedElement.nextElementSibling; // dude this is super useful! - } - if (selectedElement) { - // move to the end so they appear on top while dragging - svg.insertBefore(selectedElement, svg.lastChild); - svg.insertBefore(sibling, svg.lastChild); - - x = selectedElement.getAttributeNS(null, "x"); - y = selectedElement.getAttributeNS(null, "y"); - startx = x; - starty = y; - // scan through rcdata to find out which key are we closest to - closestdist = 9999; - starti = -1; - var keyname = "" - for (let i = 0; i < rcdata_len; i++) { - d = dist(x, y, rcdata[i][5], rcdata[i][4]); - if (d < closestdist) { - closestdist = d; - starti = i; - keyname = rcdata[i][0]; - } - } - // console.log("keyname = "+keyname); - if (keyname == "mod" || keyname == "back" || keyname == "tab" || keyname == "enter"){ - selectedElement = null; - return; - } - offset = getMousePosition(evt); - offset2 = getMousePosition(evt); - offset.x -= parseFloat(selectedElement.getAttributeNS(null, "x")); - offset.y -= parseFloat(selectedElement.getAttributeNS(null, "y")); - offset2.x -= parseFloat(sibling.getAttributeNS(null, "x")); - offset2.y -= parseFloat(sibling.getAttributeNS(null, "y")); - } - } - } - - function drag(evt) { - if (selectedElement) { - if (sibling) { - evt.preventDefault(); - var coord = getMousePosition(evt); - selectedElement.setAttributeNS(null, "x", coord.x - offset.x); - selectedElement.setAttributeNS(null, "y", coord.y - offset.y); - sibling.setAttributeNS(null, "x", coord.x - offset2.x); - sibling.setAttributeNS(null, "y", coord.y - offset2.y); - } - } - } - - function endDrag(evt) { - if (selectedElement) { - x = selectedElement.getAttributeNS(null, "x"); - y = selectedElement.getAttributeNS(null, "y"); - // console.log("drop at "+x+" "+y); - // scan through rcdata to find out which key are we closest to - closestdist = 9999; - var keyname = "" - for (let i = 0; i < rcdata_len; i++) { - d = dist(x, y, rcdata[i][5], rcdata[i][4]); - keyname = rcdata[i][0]; - if (d < closestdist) { - if (keyname == "mod" || keyname == "back" || keyname == "tab" || keyname == "enter") { - } else { - closestdist = d; - dropi = i; - } - } - } - if (dropi == starti) { - selectedElement.setAttributeNS(null, "x", startx); - selectedElement.setAttributeNS(null, "y", starty); - sibling.setAttributeNS(null, "x", parseInt(startx)+15); - sibling.setAttributeNS(null, "y", parseInt(starty)+19); - selectedElement = false; - sibling = false; - return; - } - if (rcdata[starti][0] == "space") { - if (rcdata[dropi][1] < 3) { - selectedElement.setAttributeNS(null, "x", startx); - selectedElement.setAttributeNS(null, "y", starty); - sibling.setAttributeNS(null, "x", parseInt(startx)+15); - sibling.setAttributeNS(null, "y", parseInt(starty)+19); - selectedElement = false; - sibling = false; - return; - } - } - if (rcdata[dropi][0] == "space") { - if (rcdata[starti][1] < 3) { - selectedElement.setAttributeNS(null, "x", startx); - selectedElement.setAttributeNS(null, "y", starty); - sibling.setAttributeNS(null, "x", parseInt(startx)+15); - sibling.setAttributeNS(null, "y", parseInt(starty)+19); - selectedElement = false; - sibling = false; - return; - } - } - if (closestdist > 0.8){ - selectedElement.setAttributeNS(null, "x", startx); - selectedElement.setAttributeNS(null, "y", starty); - sibling.setAttributeNS(null, "x", parseInt(startx)+15); - sibling.setAttributeNS(null, "y", parseInt(starty)+19); - selectedElement = false; - sibling = false; - return; - } - selectedElement = false; - sibling = false; - - // indices = [1,2,4,5,6] - indices = [0, 3, 7] - for (let i = 0; i < indices.length; i++){ - var k = indices[i]; - tmp = rcdata[starti][k]; - rcdata[starti][k] = rcdata[dropi][k]; - rcdata[dropi][k] = tmp; - } - if (rcdata[33][0] == "space" && rcdata[33][1] == 3 && rcdata[33][2] == 4){ - thumb = "r" - } - if (rcdata[39][0] == "space" && rcdata[39][1] == 3 && rcdata[39][2] == 7){ - thumb = "l" - } - - var queryParams = new URLSearchParams(window.location.search); - queryParams.set("layout", exportLayout()); - queryParams.set("mode",mode) - queryParams.set("lan",lang) - queryParams.set("thumb",thumb) - history.replaceState(null, null, "?"+queryParams.toString()); - - d3.select(svg).selectAll("*").remove(); - needs_update = true; - measureDictionary(); - measureWords(); - generateLayout(); - generatePlots(); - } - } + svg.addEventListener("mousedown", startDrag, false); + svg.addEventListener("mousemove", drag, false); + svg.addEventListener("mouseup", endDrag, false); + svg.addEventListener("mouseleave", endDrag); + + svg.addEventListener("touchstart", startDrag); + svg.addEventListener("touchmove", drag); + svg.addEventListener("touchend", endDrag); + svg.addEventListener("touchleave", endDrag); + svg.addEventListener("touchcancel", endDrag); + + function getMousePosition(evt) { + var CTM = svg.getScreenCTM(); + if (evt.touches) { + evt = evt.touches[0]; + } + return { + x: (evt.clientX - CTM.e) / CTM.a, + y: (evt.clientY - CTM.f) / CTM.d, + }; + } + + var selectedElement, offset, offset2, sibling; + var starti, dropi, startx, starty; + + function startDrag(evt) { + if (evt.target.classList.contains("draggable")) { + selectedElement = evt.target; + if (selectedElement.classList.contains("legend")) { + selectedElement = selectedElement.previousElementSibling; + sibling = evt.target; + } else { + sibling = selectedElement.nextElementSibling; // dude this is super useful! + } + if (selectedElement) { + // move to the end so they appear on top while dragging + svg.insertBefore(selectedElement, svg.lastChild); + svg.insertBefore(sibling, svg.lastChild); + + x = selectedElement.getAttributeNS(null, "x"); + y = selectedElement.getAttributeNS(null, "y"); + startx = x; + starty = y; + // scan through rcdata to find out which key are we closest to + closestdist = 9999; + starti = -1; + var keyname = ""; + for (let i = 0; i < rcdata_len; i++) { + d = dist(x, y, rcdata[i][5], rcdata[i][4]); + if (d < closestdist) { + closestdist = d; + starti = i; + keyname = rcdata[i][0]; + } + } + // console.log("keyname = "+keyname); + if ( + keyname == "mod" || + keyname == "back" || + keyname == "tab" || + keyname == "enter" + ) { + selectedElement = null; + return; + } + offset = getMousePosition(evt); + offset2 = getMousePosition(evt); + offset.x -= parseFloat(selectedElement.getAttributeNS(null, "x")); + offset.y -= parseFloat(selectedElement.getAttributeNS(null, "y")); + offset2.x -= parseFloat(sibling.getAttributeNS(null, "x")); + offset2.y -= parseFloat(sibling.getAttributeNS(null, "y")); + } + } + } + + function drag(evt) { + if (selectedElement) { + if (sibling) { + evt.preventDefault(); + var coord = getMousePosition(evt); + selectedElement.setAttributeNS(null, "x", coord.x - offset.x); + selectedElement.setAttributeNS(null, "y", coord.y - offset.y); + sibling.setAttributeNS(null, "x", coord.x - offset2.x); + sibling.setAttributeNS(null, "y", coord.y - offset2.y); + } + } + } + + function endDrag(evt) { + if (selectedElement) { + x = selectedElement.getAttributeNS(null, "x"); + y = selectedElement.getAttributeNS(null, "y"); + // console.log("drop at "+x+" "+y); + // scan through rcdata to find out which key are we closest to + closestdist = 9999; + var keyname = ""; + for (let i = 0; i < rcdata_len; i++) { + d = dist(x, y, rcdata[i][5], rcdata[i][4]); + keyname = rcdata[i][0]; + if (d < closestdist) { + if ( + keyname == "mod" || + keyname == "back" || + keyname == "tab" || + keyname == "enter" + ) { + } else { + closestdist = d; + dropi = i; + } + } + } + if (dropi == starti) { + selectedElement.setAttributeNS(null, "x", startx); + selectedElement.setAttributeNS(null, "y", starty); + sibling.setAttributeNS(null, "x", parseInt(startx) + 15); + sibling.setAttributeNS(null, "y", parseInt(starty) + 19); + selectedElement = false; + sibling = false; + return; + } + if (rcdata[starti][0] == "space") { + if (rcdata[dropi][1] < 3) { + selectedElement.setAttributeNS(null, "x", startx); + selectedElement.setAttributeNS(null, "y", starty); + sibling.setAttributeNS(null, "x", parseInt(startx) + 15); + sibling.setAttributeNS(null, "y", parseInt(starty) + 19); + selectedElement = false; + sibling = false; + return; + } + } + if (rcdata[dropi][0] == "space") { + if (rcdata[starti][1] < 3) { + selectedElement.setAttributeNS(null, "x", startx); + selectedElement.setAttributeNS(null, "y", starty); + sibling.setAttributeNS(null, "x", parseInt(startx) + 15); + sibling.setAttributeNS(null, "y", parseInt(starty) + 19); + selectedElement = false; + sibling = false; + return; + } + } + if (closestdist > 0.8) { + selectedElement.setAttributeNS(null, "x", startx); + selectedElement.setAttributeNS(null, "y", starty); + sibling.setAttributeNS(null, "x", parseInt(startx) + 15); + sibling.setAttributeNS(null, "y", parseInt(starty) + 19); + selectedElement = false; + sibling = false; + return; + } + selectedElement = false; + sibling = false; + + // indices = [1,2,4,5,6] + indices = [0, 3, 7]; + for (let i = 0; i < indices.length; i++) { + var k = indices[i]; + tmp = rcdata[starti][k]; + rcdata[starti][k] = rcdata[dropi][k]; + rcdata[dropi][k] = tmp; + } + if ( + rcdata[33][0] == "space" && + rcdata[33][1] == 3 && + rcdata[33][2] == 4 + ) { + thumb = "r"; + } + if ( + rcdata[39][0] == "space" && + rcdata[39][1] == 3 && + rcdata[39][2] == 7 + ) { + thumb = "l"; + } + + var queryParams = new URLSearchParams(window.location.search); + queryParams.set("layout", exportLayout()); + queryParams.set("mode", mode); + queryParams.set("lan", lang); + queryParams.set("thumb", thumb); + history.replaceState(null, null, "?" + queryParams.toString()); + + d3.select(svg).selectAll("*").remove(); + needs_update = true; + measureDictionary(); + measureWords(); + generateLayout(); + generatePlots(); + } + } } if (url_layout) { - importLayout(url_layout) + importLayout(url_layout); } -loadAllData() +loadAllData(); if (params.lan) { - lang = params.lan; - if (lang != "english"){ - selectLanguage(lang); - } -} \ No newline at end of file + lang = params.lan; + if (lang != "english") { + selectLanguage(lang); + } +} From efb8d873b608ea0ce2ce9ac3fee1686e2b00310e Mon Sep 17 00:00:00 2001 From: gaetan Date: Thu, 23 Apr 2026 11:01:43 +0200 Subject: [PATCH 02/17] Apply safe Biome suggestions, including duplicate else if --- keyboard_svg.js | 325 +++++++++++++++++++++++------------------------- 1 file changed, 154 insertions(+), 171 deletions(-) diff --git a/keyboard_svg.js b/keyboard_svg.js index ca8be36..cb01f55 100644 --- a/keyboard_svg.js +++ b/keyboard_svg.js @@ -164,7 +164,7 @@ function selectLanguage(lan, event) { .then((response) => response.json()) .then((data) => { if (event?.ctrlKey) { - console.log("adding " + lan + " to words"); + console.log(`adding ${lan} to words`); for (const word in data) { if (words[word]) { words[word] += data[word]; @@ -312,7 +312,7 @@ var effort = [ function openPopup() { for (let row = 0; row < nb_row; row++) { for (let col = 0; col < nb_columns; col++) { - const name = "textInput-" + row + "-" + col; + const name = `textInput-${row}-${col}`; document.getElementById(name).value = effort[row][col]; } } @@ -338,13 +338,13 @@ function strCount(str, char) { function closeImportPopup() { var importString = document.getElementById("importText").value; importString = importString.replace(/\s+/g, ""); - if (importString.length == 0) { + if (importString.length === 0) { document.getElementById("importPopup").style.display = "none"; return; } - if (importString.length == 30) { + if (importString.length === 30) { // probably cmini - if (strCount(importString, "-") == 0 && strCount(importString, "'") == 0) { + if (strCount(importString, "-") === 0 && strCount(importString, "'") === 0) { importString = importString.slice(0, 10) + "-" + @@ -353,8 +353,7 @@ function closeImportPopup() { importString.slice(20) + "\\^"; } else if ( - strCount(importString, "-") == 0 && - strCount(importString, ";") == 0 + strCount(importString, "-") === 0 && strCount(importString, ";") === 0 ) { importString = importString.slice(0, 10) + @@ -364,8 +363,7 @@ function closeImportPopup() { importString.slice(20) + "\\^"; } else if ( - strCount(importString, "'") == 0 && - strCount(importString, ";") == 0 + strCount(importString, "'") === 0 && strCount(importString, ";") === 0 ) { importString = importString.slice(0, 10) + @@ -375,8 +373,7 @@ function closeImportPopup() { importString.slice(20) + "\\^"; } else if ( - strCount(importString, "'") == 0 && - strCount(importString, "/") == 0 + strCount(importString, "'") === 0 && strCount(importString, "/") === 0 ) { importString = importString.slice(0, 10) + @@ -386,8 +383,7 @@ function closeImportPopup() { importString.slice(20) + "\\^"; } else if ( - strCount(importString, ";") == 0 && - strCount(importString, "/") == 0 + strCount(importString, ";") === 0 && strCount(importString, "/") === 0 ) { importString = importString.slice(0, 10) + @@ -397,19 +393,7 @@ function closeImportPopup() { importString.slice(20) + "\\^"; } else if ( - strCount(importString, ";") == 0 && - strCount(importString, "'") == 0 - ) { - importString = - importString.slice(0, 10) + - ";" + - importString.slice(10, 20) + - "'" + - importString.slice(20) + - "\\^"; - } else if ( - strCount(importString, "/") == 0 && - strCount(importString, "-") == 0 + strCount(importString, "/") === 0 && strCount(importString, "-") === 0 ) { importString = importString.slice(0, 10) + @@ -454,7 +438,7 @@ function closeImportPopup() { document.getElementById("importMessage").innerText = message; return; } else { - if ((mode == "iso" || mode == "ansi") && importString.length >= 33) { + if ((mode === "iso" || mode === "ansi") && importString.length >= 33) { document.getElementById("importMessage").innerText = "You can't have layouts with thumb letters on ISO/ANSI"; } else if (importString.length <= 35) { @@ -464,7 +448,7 @@ function closeImportPopup() { queryParams.set("layout", exportLayout()); queryParams.set("mode", mode); queryParams.set("lan", lang); - history.replaceState(null, null, "?" + queryParams.toString()); + history.replaceState(null, null, `?${queryParams.toString()}`); generateCoords(); measureDictionary(); measureWords(); @@ -488,7 +472,7 @@ function closeCorpusPopup() { var massive_string = document.getElementById("corpusText").value; massive_string = massive_string.toLowerCase().replace(/\s+/g, " "); words = {}; - if (massive_string.length == 0) { + if (massive_string.length === 0) { document.getElementById("corpusPopup").style.display = "none"; return; } @@ -589,7 +573,7 @@ function pasteEffortGridFromClipboard() { .then((text) => { // console.log("Clipboard content:", text); var numbersArray = text.split(",").map(Number); - if (numbersArray.length != 36) { + if (numbersArray.length !== 36) { return; } @@ -677,18 +661,18 @@ function hideTooltip() { function setMode() { if ( - dataloaded == false || - dictionaryloaded == false || - effortloaded == false + dataloaded === false || + dictionaryloaded === false || + effortloaded === false ) { return; } console.log("setMode to " + mode); - if (mode == "ergo") { + if (mode === "ergo") { setErgo(); - } else if (mode == "ansi") { + } else if (mode === "ansi") { setAnsi(); - } else if (mode == "iso") { + } else if (mode === "iso") { setIso(); } generateCoords(); @@ -706,9 +690,9 @@ function activateErgo() { function setErgo() { if ( - dataloaded == false || - dictionaryloaded == false || - effortloaded == false + dataloaded === false || + dictionaryloaded === false || + effortloaded === false ) { return; } @@ -752,19 +736,19 @@ function activateIso(anglemod) { function setIso(anglemod) { if ( - dataloaded == false || - dictionaryloaded == false || - effortloaded == false + dataloaded === false || + dictionaryloaded === false || + effortloaded === false ) { return; } hasshift = false; for (let i = 0; i < 34; i++) { - if (rcdata[i][0] == "shift" || rcdata[i][0] == "^") { + if (rcdata[i][0] === "shift" || rcdata[i][0] === "^") { hasshift = true; } } - if (hasshift == true) { + if (hasshift === true) { rcdata[32][1] = 2; rcdata[32][2] = 0; rcdata[32][6] = 1; @@ -792,7 +776,7 @@ function setIso(anglemod) { ]; } mode = "iso"; - var queryParams = new URLSearchParams(window.location.search); + const queryParams = new URLSearchParams(window.location.search); queryParams.set("layout", exportLayout()); queryParams.set("mode", mode); queryParams.set("lan", lang); @@ -863,19 +847,19 @@ function setAnsi() { } function importLayout(layout) { - if (layout.length == 35) { + if (layout.length === 35) { const decodedString = decodeURIComponent(layout); console.log("importing: " + decodedString); layout = decodedString; // change shift to = for (let i = 0; i < 34; i++) { - if (rcdata[i][0] == "^") { + if (rcdata[i][0] === "^") { rcdata[i][0] = "*"; } } // change ctrl to * for (let i = 0; i < 37; i++) { - if (rcdata[i][0] == "$") { + if (rcdata[i][0] === "$") { rcdata[i][0] = "="; console.log("setting " + i + " to *"); } @@ -884,7 +868,7 @@ function importLayout(layout) { for (let i = 0; i < 34; i++) { // qwertyuiop-asdfghjkl;'zxcvbnm,./\^ - 34 for (let j = 0; j < 34; j++) { - if (layout.charAt(i) == rcdata[j][0]) { + if (layout.charAt(i) === rcdata[j][0]) { // console.log("swap "+layout.charAt(i)+" at " + i + " with position " + j) // swap indices = [0, 3, 7]; // letter, freq, keyname @@ -901,12 +885,12 @@ function importLayout(layout) { let swap1 = 0; let swap2 = 0; for (let i = 0; i < 36; i++) { - if (rcdata[i][7] == 35) { + if (rcdata[i][7] === 35) { swap1 = i; } } for (let i = 0; i < 36; i++) { - if (rcdata[i][0] == layout.charAt(34)) { + if (rcdata[i][0] === layout.charAt(34)) { swap2 = i; } } @@ -924,7 +908,7 @@ function importLayout(layout) { for (let i = 0; i < 34; i++) { // qwertyuiop-asdfghjkl;'zxcvbnm,./\^ - 34 for (let j = 0; j < 34; j++) { - if (layout.charAt(i) == rcdata[j][0]) { + if (layout.charAt(i) === rcdata[j][0]) { // console.log("swap "+layout.charAt(i)+" at " + i + " with position " + j) // swap indices = [0, 3, 7]; // letter, freq, keyname @@ -938,8 +922,8 @@ function importLayout(layout) { } } for (let i = 0; i < 34; i++) { - if (rcdata[i][0] == "^") { - if (rcdata[i][1] == 3 && rcdata[i][2] == 4) { + if (rcdata[i][0] === "^") { + if (rcdata[i][1] === 3 && rcdata[i][2] === 4) { // cool } else { rcdata[i][0] = "="; @@ -947,7 +931,7 @@ function importLayout(layout) { } } } - if (thumb == "r") { + if (thumb === "r") { indices = [0, 3, 7]; // letter, freq, keyname for (let id = 0; id < indices.length; id++) { const k = indices[id]; @@ -1007,7 +991,7 @@ function getX(name, row, col) { } else { if (name === "space") { off = 0; - } else if (name == "rshift") { + } else if (name === "rshift") { off = w * 0.25; } else { off = w * 1.25; @@ -1029,7 +1013,7 @@ function getX(name, row, col) { off = w * 0.75; } } else if (row >= 2) { - if (col == -1) { + if (col === -1) { return dx; } else { if (name === "space") { @@ -1040,7 +1024,7 @@ function getX(name, row, col) { } } return dx + off + col * w; - } else if (mode == "ergo") { + } else if (mode === "ergo") { if (col > 5) { dx = dx + 40; } @@ -1073,7 +1057,7 @@ function getRow(letter) { function getChar(row, col) { for (let i = 0; i < rcdata_len; i++) { const key = rcdata[i]; - if (key[1] == row && key[2] == col) { + if (key[1] === row && key[2] === col) { return key[0]; } } @@ -1108,15 +1092,15 @@ function generateCoords() { function generateLayout() { if ( - dataloaded == false || - dictionaryloaded == false || - effortloaded == false + dataloaded === false || + dictionaryloaded === false || + effortloaded === false ) { return; } console.log("generateLayout"); svg.selectAll("*").remove(); - if (mode == "iso" || mode == "ansi") { + if (mode === "iso" || mode === "ansi") { outlinewidth = 572; } else { outlinewidth = 510; @@ -1135,7 +1119,7 @@ function generateLayout() { for (let i = 0; i < rcdata_len; i++) { dtx = 0; letter = rcdata[i][0]; - if (letter == "^") { + if (letter === "^") { letter = "shift"; } x = rcdata[i][5]; @@ -1153,13 +1137,13 @@ function generateLayout() { hex_bg = green.toString(16); fontsize = 16; - if (letter == "$") { + if (letter === "$") { letter = "ctrl"; } if (letter.length > 1) { fontsize = 10; } - if (letter.length > 4 && mode == "ergo") { + if (letter.length > 4 && mode === "ergo") { fontsize = 9; } @@ -1175,7 +1159,7 @@ function generateLayout() { .attr("stroke", "black") .attr("stroke-width", "1") .attr("class", "draggable"); - if (letter.length > 1 && mode != "ergo") { + if (letter.length > 1 && mode !== "ergo") { svg .append("text") .attr("x", x + 5) @@ -1198,8 +1182,8 @@ function generateLayout() { } } // - if (m_total_word_effort == 0) { - // console.log("m_total_word_effort == 0") + if (m_total_word_effort === 0) { + // console.log("m_total_word_effort === 0") measureDictionary(); measureWords(); } @@ -1404,9 +1388,9 @@ var samehandcount = {}; function measureDictionary() { if ( - dataloaded == false || - dictionaryloaded == false || - effortloaded == false + dataloaded === false || + dictionaryloaded === false || + effortloaded === false ) { return; } @@ -1443,7 +1427,7 @@ function measureDictionary() { if (bigram_effort[col1][row1]) { if (bigram_effort[col1][row1][col2]) { if (bigram_effort[col1][row1][col2][row2]) { - var e = bigram_effort[col1][row1][col2][row2]; + const e = bigram_effort[col1][row1][col2][row2]; total += e; } } @@ -1460,7 +1444,7 @@ function measureDictionary() { if (bigram_effort[col1][row1]) { if (bigram_effort[col1][row1][col2]) { if (bigram_effort[col1][row1][col2][row2]) { - var e = bigram_effort[col1][row1][col2][row2]; + const e = bigram_effort[col1][row1][col2][row2]; total += e; } } @@ -1478,7 +1462,7 @@ function measureDictionary() { if (bigram_effort[col1][row1]) { if (bigram_effort[col1][row1][col2]) { if (bigram_effort[col1][row1][col2][row2]) { - var e = bigram_effort[col1][row1][col2][row2]; + const e = bigram_effort[col1][row1][col2][row2]; total += 0.2 * e; } } @@ -1495,15 +1479,14 @@ function measureDictionary() { if (bigram_effort[col1][row1]) { if (bigram_effort[col1][row1][col2]) { if (bigram_effort[col1][row1][col2][row2]) { - var e = bigram_effort[col1][row1][col2][row2]; + const e = bigram_effort[col1][row1][col2][row2]; total += 0.2 * e; } } } } - if (isNaN(total)) { - console.log(word + " gives NaN for effort"); - } + if (total.isNan) console.log(word + " gives NaN for effort"); + word_effort[word] = 0.1 * total; } } @@ -1521,7 +1504,7 @@ function getDictionaryFromWords() { function getIndexOfKey(name) { var x = -1; for (let i = 0; i < 34; i++) { - if (rcdata[i][7] == name) { + if (rcdata[i][7] === name) { x = i; } } @@ -1535,7 +1518,7 @@ function updateRcData(lan) { if (letters.length >= 32) { break; } - var wordLetters = word.split(""); // Split the word into individual letters + const wordLetters = word.split(""); // Split the word into individual letters for (let i = 0; i < wordLetters.length; i++) { if (letters.indexOf(wordLetters[i]) === -1) { letters.push(wordLetters[i]); // Add letter to the list if not already present @@ -1545,7 +1528,7 @@ function updateRcData(lan) { // my new idea for fixing this issue still didn't work // the problem is that the keys that I want to change when switching languages aren't in a consistent position in the grid, or at a consistent position in the array, // or have a consistent letter on them. Even the index I added to try to make them consistent didn't work because of the way the import process works - if (lan == "german") { + if (lan === "german") { // letters = ['q', 'w', 'e', 'r', 't', 'z', 'u', 'i', 'o', 'p', 'ü', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'ö', 'ä', 'y','x', 'c', 'v', 'b', 'n', 'm', ',', '.', '\'', 'ß'] if (getIndexOfKey(10) >= 0) { rcdata[getIndexOfKey(10)][0] = "ü"; @@ -1562,7 +1545,7 @@ function updateRcData(lan) { if (getIndexOfKey(32) >= 0) { rcdata[getIndexOfKey(32)][0] = "ß"; } - } else if (lan == "english") { + } else if (lan === "english") { // letters = ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '-', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/','\\'] if (getIndexOfKey(10) >= 0) { rcdata[getIndexOfKey(10)][0] = "-"; @@ -1579,7 +1562,7 @@ function updateRcData(lan) { if (getIndexOfKey(32) >= 0) { rcdata[getIndexOfKey(32)][0] = "\\"; } - } else if (lan == "dutch") { + } else if (lan === "dutch") { // letters = ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '-', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/','\\'] if (getIndexOfKey(10) >= 0) { rcdata[getIndexOfKey(10)][0] = "-"; @@ -1596,7 +1579,7 @@ function updateRcData(lan) { if (getIndexOfKey(32) >= 0) { rcdata[getIndexOfKey(32)][0] = "\\"; } - } else if (lan == "french") { + } else if (lan === "french") { // letters = ['a', 'z', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', 'é', 'q', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'è', '\'', 'w', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', 'ç', 'à'] if (getIndexOfKey(10) >= 0) { rcdata[getIndexOfKey(10)][0] = "é"; @@ -1613,7 +1596,7 @@ function updateRcData(lan) { if (getIndexOfKey(32) >= 0) { rcdata[getIndexOfKey(32)][0] = "à"; } - } else if (lan == "italian") { + } else if (lan === "italian") { // letters = ['a', 'z', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', 'é', 'q', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'è', '\'', 'w', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', 'ç', 'à'] if (getIndexOfKey(10) >= 0) { rcdata[getIndexOfKey(10)][0] = "è"; @@ -1630,7 +1613,7 @@ function updateRcData(lan) { if (getIndexOfKey(32) >= 0) { rcdata[getIndexOfKey(32)][0] = "ì"; } - } else if (lan == "swedish") { + } else if (lan === "swedish") { // letters = ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', 'å', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'ö', 'ä', 'z', 'x', 'c', 'v', 'b','n', 'm', '.', ',', '\'', '\\'] if (getIndexOfKey(10) >= 0) { rcdata[getIndexOfKey(10)][0] = "å"; @@ -1647,7 +1630,7 @@ function updateRcData(lan) { if (getIndexOfKey(32) >= 0) { rcdata[getIndexOfKey(32)][0] = "\\"; } - } else if (lan == "spanish") { + } else if (lan === "spanish") { // letters = ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '-', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'ñ', '\'', 'z','x', 'c', 'v', 'b', 'n', 'm',',', '.', '/', '\\'] if (getIndexOfKey(10) >= 0) { rcdata[getIndexOfKey(10)][0] = "-"; @@ -1664,7 +1647,7 @@ function updateRcData(lan) { if (getIndexOfKey(32) >= 0) { rcdata[getIndexOfKey(32)][0] = "\\"; } - } else if (lan == "portuguese") { + } else if (lan === "portuguese") { // letters = ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '-', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'ç', '\'', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/','\\'] if (getIndexOfKey(10) >= 0) { rcdata[getIndexOfKey(10)][0] = "-"; @@ -1681,7 +1664,7 @@ function updateRcData(lan) { if (getIndexOfKey(32) >= 0) { rcdata[getIndexOfKey(32)][0] = "\\"; } - } else if (lan == "norweigan") { + } else if (lan === "norweigan") { // letters = ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', 'å', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'ø', 'æ', 'z', 'x','c','v', 'b', 'm', 'n', '.', ',', '\'', '\\'] if (getIndexOfKey(10) >= 0) { rcdata[getIndexOfKey(10)][0] = "å"; @@ -1698,7 +1681,7 @@ function updateRcData(lan) { if (getIndexOfKey(32) >= 0) { rcdata[getIndexOfKey(32)][0] = "\\"; } - } else if (lan == "finnish") { + } else if (lan === "finnish") { // letters = ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', 'å', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'ö', 'ä', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '\'', '\\'] if (getIndexOfKey(10) >= 0) { rcdata[getIndexOfKey(10)][0] = "å"; @@ -1715,7 +1698,7 @@ function updateRcData(lan) { if (getIndexOfKey(32) >= 0) { rcdata[getIndexOfKey(32)][0] = "\\"; } - } else if (lan == "estonian") { + } else if (lan === "estonian") { if (getIndexOfKey(10) >= 0) { rcdata[getIndexOfKey(10)][0] = "ä"; } @@ -1731,7 +1714,7 @@ function updateRcData(lan) { if (getIndexOfKey(32) >= 0) { rcdata[getIndexOfKey(32)][0] = "ö"; } - } else if (lan == "hungarian") { + } else if (lan === "hungarian") { // letters = ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '-', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/','\\'] if (getIndexOfKey(10) >= 0) { rcdata[getIndexOfKey(10)][0] = "-"; @@ -1748,7 +1731,7 @@ function updateRcData(lan) { if (getIndexOfKey(32) >= 0) { rcdata[getIndexOfKey(32)][0] = "\\"; } - } else if (lan == "polish") { + } else if (lan === "polish") { if (getIndexOfKey(10) >= 0) { rcdata[getIndexOfKey(10)][0] = "-"; } @@ -1769,9 +1752,9 @@ function updateRcData(lan) { function measureWords() { if ( - dataloaded == false || - dictionaryloaded == false || - effortloaded == false + dataloaded === false || + dictionaryloaded === false || + effortloaded === false ) { return; } @@ -1877,12 +1860,12 @@ function measureWords() { m_column_usage[col] = 0; } if ( - (row == 0 && col == 1) || - (row == 2 && col == 1) || - (row == 0 && col == 10) || - (row == 2 && col == 10) || - (row == 0 && col == 11) || - (row == 1 && col == 11) + (row === 0 && col === 1) || + (row === 2 && col === 1) || + (row === 0 && col === 10) || + (row === 2 && col === 10) || + (row === 0 && col === 11) || + (row === 1 && col === 11) ) { m_pinky_off += count; } @@ -1902,7 +1885,7 @@ function measureWords() { m_effort += count * getEffort(row, col); - var finger = getFinger(row, col); + const finger = getFinger(row, col); if (!m_finger_usage[finger]) { m_finger_usage[finger] = 0; } @@ -1941,7 +1924,7 @@ function measureWords() { // bigram stuff if (i > 0 && prevcol >= 0) { bigram = prevchar + char; - if (finger == prevfinger && prevchar != char) { + if (finger === prevfinger && prevchar !== char) { if (!m_same_finger[bigram]) { m_same_finger[bigram] = 0; } @@ -1961,10 +1944,10 @@ function measureWords() { } // lsbs if ( - (prevcol == 3 && col == 5) || - (prevcol == 8 && col == 6) || - (prevcol == 5 && col == 3) || - (prevcol == 6 && col == 8) + (prevcol === 3 && col === 5) || + (prevcol === 8 && col === 6) || + (prevcol === 5 && col === 3) || + (prevcol === 6 && col === 8) ) { if (!m_lat_stretch[bigram]) { m_lat_stretch[bigram] = 0; @@ -1972,10 +1955,10 @@ function measureWords() { m_lat_stretch[bigram] += count; } if ( - (prevcol == 2 && col == 5) || - (prevcol == 9 && col == 6) || - (prevcol == 5 && col == 2) || - (prevcol == 6 && col == 9) + (prevcol === 2 && col === 5) || + (prevcol === 9 && col === 6) || + (prevcol === 5 && col === 2) || + (prevcol === 6 && col === 9) ) { if (!m_lat_stretch2[bigram]) { m_lat_stretch2[bigram] = 0; @@ -1984,10 +1967,10 @@ function measureWords() { } // scissors if ( - Math.abs(col - prevcol) == 1 && + Math.abs(col - prevcol) === 1 && Math.abs(row - prevrow) >= 2 && - ((finger <= 4 && prevfinger <= 4 && finger != prevfinger) || - (finger >= 7 && prevfinger >= 7 && finger != prevfinger)) + ((finger <= 4 && prevfinger <= 4 && finger !== prevfinger) || + (finger >= 7 && prevfinger >= 7 && finger !== prevfinger)) ) { if (!m_scissors[bigram]) { m_scissors[bigram] = 0; @@ -2007,9 +1990,9 @@ function measureWords() { } // pinky/ring scissors if ( - Math.abs(col - prevcol) == 1 && + Math.abs(col - prevcol) === 1 && Math.abs(row - prevrow) >= 1 && - (finger == 1 || finger == 10 || prevfinger == 1 || prevfinger == 10) + (finger === 1 || finger === 10 || prevfinger === 1 || prevfinger === 10) ) { if (!m_pinky_scissors[bigram]) { m_pinky_scissors[bigram] = 0; @@ -2017,7 +2000,7 @@ function measureWords() { m_pinky_scissors[bigram] += count; } // same hand strings - if (prevhand == hand) { + if (prevhand === hand) { samehand = samehand + char; } else { if (samehand.length >= 4) { @@ -2039,7 +2022,7 @@ function measureWords() { if (!m_finger_pairs[prevfinger][finger]) { m_finger_pairs[prevfinger][finger] = 0; } - if (char != prevchar) { + if (char !== prevchar) { m_finger_pairs[prevfinger][finger] += count; } } @@ -2047,7 +2030,7 @@ function measureWords() { if (i > 1 && prevcol >= 0) { skip = ppchar + "_" + char; trigram = ppchar + prevchar + char; - if (finger == ppfinger && ppchar != char) { + if (finger === ppfinger && ppchar !== char) { if (!m_skip_bigram[skip]) { m_skip_bigram[skip] = 0; } @@ -2071,15 +2054,15 @@ function measureWords() { } else if ( (ppfinger < prevfinger && finger < prevfinger && - finger != ppfinger) || - (ppfinger > prevfinger && finger > prevfinger && finger != ppfinger) + finger !== ppfinger) || + (ppfinger > prevfinger && finger > prevfinger && finger !== ppfinger) ) { cat = "redirect"; // if (!m_redirects[trigram]) { // m_redirects[trigram] = 0; // } // m_redirects[trigram] += count; - if (ppfinger == 4 || prevfinger == 4 || finger == 4) { + if (ppfinger === 4 || prevfinger === 4 || finger === 4) { } else { cat = "weak redirect"; } @@ -2094,15 +2077,15 @@ function measureWords() { } else if ( (ppfinger > prevfinger && finger > prevfinger && - finger != ppfinger) || - (ppfinger < prevfinger && finger < prevfinger && finger != ppfinger) + finger !== ppfinger) || + (ppfinger < prevfinger && finger < prevfinger && finger !== ppfinger) ) { cat = "redirect"; // if (!m_redirects[trigram]) { // m_redirects[trigram] = 0; // } // m_redirects[trigram] += count; - if (ppfinger == 7 || prevfinger == 7 || finger == 7) { + if (ppfinger === 7 || prevfinger === 7 || finger === 7) { } else { cat = "weak redirect"; } @@ -2113,7 +2096,7 @@ function measureWords() { (ppfinger >= 6 && prevfinger <= 5 && finger >= 6) ) { cat = "alt"; - if (ppfinger == finger && ppchar != char) { + if (ppfinger === finger && ppchar !== char) { cat = "alt sfs"; } // 1 2 3 @@ -2186,7 +2169,7 @@ function measureWords() { m_trigram_count[cat] = 0; } m_trigram_count[cat] += count; - if (cat == "alt") { + if (cat === "alt") { if (!m_trigram_count_alt[trigram]) { m_trigram_count_alt[trigram] = 0; } @@ -2195,7 +2178,7 @@ function measureWords() { // } // if (count > 10){ console.log(trigram + " "+ count);} } - if (cat == "redirect" || cat == "weak redirect") { + if (cat === "redirect" || cat === "weak redirect") { if (!m_trigram_count_red[trigram]) { m_trigram_count_red[trigram] = 0; } @@ -2203,7 +2186,7 @@ function measureWords() { m_trigram_count_red[trigram] += count; // } } - if (cat == "roll in" || cat == "bigram roll in") { + if (cat === "roll in" || cat === "bigram roll in") { if (!m_trigram_count_roll_in[trigram]) { m_trigram_count_roll_in[trigram] = 0; } @@ -2211,7 +2194,7 @@ function measureWords() { m_trigram_count_roll_in[trigram] += count; // } } - if (cat == "roll out" || cat == "bigram roll out") { + if (cat === "roll out" || cat === "bigram roll out") { if (!m_trigram_count_roll_out[trigram]) { m_trigram_count_roll_out[trigram] = 0; } @@ -2251,7 +2234,7 @@ function measureWords() { const hundred_inv_sum = 100.0 / sum; for (const letter in m_letter_freq) { for (let i = 0; i < rcdata_len; i++) { - if (rcdata[i][0] == letter) { + if (rcdata[i][0] === letter) { rcdata[i][3] = hundred_inv_sum * m_letter_freq[letter]; } } @@ -2261,9 +2244,9 @@ function measureWords() { function generatePlots() { if ( - dataloaded == false || - dictionaryloaded == false || - effortloaded == false + dataloaded === false || + dictionaryloaded === false || + effortloaded === false ) { return; } @@ -2597,8 +2580,8 @@ function generatePlots() { .on("mouseout", function () { d3.select(this).attr("fill", "#777777"); }); - if (sfb_toggle == 0) { - var keyValueArray = Object.entries(m_same_finger); + if (sfb_toggle === 0) { + const keyValueArray = Object.entries(m_same_finger); keyValueArray.sort((a, b) => b[1] - a[1]); m_same_finger = Object.fromEntries(keyValueArray); @@ -2616,14 +2599,14 @@ function generatePlots() { .text("Same Finger Bigrams " + parseFloat(100 * sum).toFixed(2) + "%"); // stats.append("text").attr("x",x+40).attr("y",y+200).attr("font-size",16).attr("font-family","Sans,Arial").attr("fill","#dfe2eb").attr("text-anchor","left").text("Input Length "+m_input_length); - var i = 0; - var t = scroll_amount; + let i = 0; + let t = scroll_amount; for (const bigram in m_same_finger) { if (t > 0) { t -= 1; continue; } - var width = 18000 * m_same_finger[bigram] * inv_m_input_length; + let width = 18000 * m_same_finger[bigram] * inv_m_input_length; if (width > 200) { width = 200; } @@ -2664,7 +2647,7 @@ function generatePlots() { break; } } - } else if (sfb_toggle == 1) { + } else if (sfb_toggle === 1) { for (const finger in m_same_finger2) { sum += m_same_finger2[finger] * inv_m_input_length; } @@ -2719,7 +2702,7 @@ function generatePlots() { .text(finger); } } else { - var keyValueArray = Object.entries(m_same_finger3); + const keyValueArray = Object.entries(m_same_finger3); keyValueArray.sort((a, b) => b[1] - a[1]); m_same_finger3 = Object.fromEntries(keyValueArray); @@ -2919,8 +2902,8 @@ function generatePlots() { var x = 500; var y = 180; sum = 0; - if (lsb_toggle == 0) { - var keyValueArray = Object.entries(m_lat_stretch); + if (lsb_toggle === 0) { + const keyValueArray = Object.entries(m_lat_stretch); keyValueArray.sort((a, b) => b[1] - a[1]); tmp = Object.fromEntries(keyValueArray); for (const bigram in tmp) { @@ -2936,7 +2919,7 @@ function generatePlots() { .attr("text-anchor", "left") .text("Lat Stretch Bigrams " + parseFloat(100 * sum).toFixed(2) + "%"); } else { - var keyValueArray = Object.entries(m_lat_stretch2); + const keyValueArray = Object.entries(m_lat_stretch2); keyValueArray.sort((a, b) => b[1] - a[1]); tmp = Object.fromEntries(keyValueArray); for (const bigram in tmp) { @@ -3048,8 +3031,8 @@ function generatePlots() { var y = 180; sum = 0; - if (scissors_toggle == 1) { - var keyValueArray = Object.entries(m_pinky_scissors); + if (scissors_toggle === 1) { + const keyValueArray = Object.entries(m_pinky_scissors); keyValueArray.sort((a, b) => b[1] - a[1]); tmp = Object.fromEntries(keyValueArray); for (const bigram in tmp) { @@ -3761,10 +3744,10 @@ function makeDraggable(svg) { } // console.log("keyname = "+keyname); if ( - keyname == "mod" || - keyname == "back" || - keyname == "tab" || - keyname == "enter" + keyname === "mod" || + keyname === "back" || + keyname === "tab" || + keyname === "enter" ) { selectedElement = null; return; @@ -3783,7 +3766,7 @@ function makeDraggable(svg) { if (selectedElement) { if (sibling) { evt.preventDefault(); - var coord = getMousePosition(evt); + const coord = getMousePosition(evt); selectedElement.setAttributeNS(null, "x", coord.x - offset.x); selectedElement.setAttributeNS(null, "y", coord.y - offset.y); sibling.setAttributeNS(null, "x", coord.x - offset2.x); @@ -3799,16 +3782,16 @@ function makeDraggable(svg) { // console.log("drop at "+x+" "+y); // scan through rcdata to find out which key are we closest to closestdist = 9999; - var keyname = ""; + let keyname = ""; for (let i = 0; i < rcdata_len; i++) { d = dist(x, y, rcdata[i][5], rcdata[i][4]); keyname = rcdata[i][0]; if (d < closestdist) { if ( - keyname == "mod" || - keyname == "back" || - keyname == "tab" || - keyname == "enter" + keyname === "mod" || + keyname === "back" || + keyname === "tab" || + keyname === "enter" ) { } else { closestdist = d; @@ -3816,7 +3799,7 @@ function makeDraggable(svg) { } } } - if (dropi == starti) { + if (dropi === starti) { selectedElement.setAttributeNS(null, "x", startx); selectedElement.setAttributeNS(null, "y", starty); sibling.setAttributeNS(null, "x", parseInt(startx) + 15); @@ -3825,7 +3808,7 @@ function makeDraggable(svg) { sibling = false; return; } - if (rcdata[starti][0] == "space") { + if (rcdata[starti][0] === "space") { if (rcdata[dropi][1] < 3) { selectedElement.setAttributeNS(null, "x", startx); selectedElement.setAttributeNS(null, "y", starty); @@ -3836,7 +3819,7 @@ function makeDraggable(svg) { return; } } - if (rcdata[dropi][0] == "space") { + if (rcdata[dropi][0] === "space") { if (rcdata[starti][1] < 3) { selectedElement.setAttributeNS(null, "x", startx); selectedElement.setAttributeNS(null, "y", starty); @@ -3862,32 +3845,32 @@ function makeDraggable(svg) { // indices = [1,2,4,5,6] indices = [0, 3, 7]; for (let i = 0; i < indices.length; i++) { - var k = indices[i]; + const k = indices[i]; tmp = rcdata[starti][k]; rcdata[starti][k] = rcdata[dropi][k]; rcdata[dropi][k] = tmp; } if ( - rcdata[33][0] == "space" && - rcdata[33][1] == 3 && - rcdata[33][2] == 4 + rcdata[33][0] === "space" && + rcdata[33][1] === 3 && + rcdata[33][2] === 4 ) { thumb = "r"; } if ( - rcdata[39][0] == "space" && - rcdata[39][1] == 3 && - rcdata[39][2] == 7 + rcdata[39][0] === "space" && + rcdata[39][1] === 3 && + rcdata[39][2] === 7 ) { thumb = "l"; } - var queryParams = new URLSearchParams(window.location.search); + const queryParams = new URLSearchParams(window.location.search); queryParams.set("layout", exportLayout()); queryParams.set("mode", mode); queryParams.set("lan", lang); queryParams.set("thumb", thumb); - history.replaceState(null, null, "?" + queryParams.toString()); + history.replaceState(null, null, `?${queryParams.toString()}`); d3.select(svg).selectAll("*").remove(); needs_update = true; @@ -3905,7 +3888,7 @@ if (url_layout) { loadAllData(); if (params.lan) { lang = params.lan; - if (lang != "english") { + if (lang !== "english") { selectLanguage(lang); } } From 3183a7844c140cde088ca32bfe77b4de5f859209 Mon Sep 17 00:00:00 2001 From: gaetan Date: Thu, 23 Apr 2026 11:32:27 +0200 Subject: [PATCH 03/17] Apply unsafe Biome info --- keyboard_svg.js | 200 ++++++++++++++++++++++++------------------------ 1 file changed, 100 insertions(+), 100 deletions(-) diff --git a/keyboard_svg.js b/keyboard_svg.js index cb01f55..3ce8d54 100644 --- a/keyboard_svg.js +++ b/keyboard_svg.js @@ -156,7 +156,7 @@ function selectLanguage(lan, event) { lang = lan; var queryParams = new URLSearchParams(window.location.search); queryParams.set("lan", lang); - history.replaceState(null, null, "?" + queryParams.toString()); + history.replaceState(null, null, `?${queryParams.toString()}`); var word_list = `words-${lan}.json`; console.log(`============ ${lan.toUpperCase()} ============`); @@ -173,7 +173,7 @@ function selectLanguage(lan, event) { } } document.getElementById("langDropDown").innerHTML += - "+" + lan.charAt(0).toUpperCase() + lan.substr(1).toLowerCase(); + `+${lan.charAt(0).toUpperCase()}${lan.substr(1).toLowerCase()}`; } else { words = data; // Assign data to the global variable document.getElementById("langDropDown").innerHTML = @@ -428,11 +428,11 @@ function closeImportPopup() { var message = ""; if (missing.length > 0) { message = - message + "These letters are missing: " + missing.join(" ") + "\n"; + `${message}These letters are duplicated: ${duplicates.join(" ")}\n`; } if (duplicates.length > 0) { message = - message + "These letters are duplicated: " + duplicates.join(" ") + "\n"; + `${message}These letters are duplicated: ${duplicates.join(" ")}\n`; } if (message.length > 0) { document.getElementById("importMessage").innerText = message; @@ -459,7 +459,7 @@ function closeImportPopup() { document.getElementById("importMessage").innerText = "Input string contains too many characters"; console.log( - "input string is length " + importString.length + " " + importString, + `input string is length ${importString.length} ${importString}`, ); return; } @@ -527,7 +527,7 @@ function closeCorpusPopup() { function closePopup() { for (let row = 0; row < nb_row; row++) { for (let col = 0; col < nb_columns; col++) { - const name = "textInput-" + row + "-" + col; + const name = `textInput-${row}-${col}`; effort[row][col] = document.getElementById(name).value; } } @@ -541,7 +541,7 @@ function copyEffortGridToClipboard() { values = []; for (let row = 0; row < 3; row++) { for (let col = 0; col < 12; col++) { - const name = "textInput-" + row + "-" + col; + const name = `textInput-${row}-${col}`; values.push(document.getElementById(name).value); } } @@ -579,7 +579,7 @@ function pasteEffortGridFromClipboard() { for (let row = 0; row < 3; row++) { for (let col = 0; col < 12; col++) { - const name = "textInput-" + row + "-" + col; + const name = `textInput-${row}-${col}`; document.getElementById(name).value = numbersArray[row * 12 + col]; } } @@ -650,8 +650,8 @@ function showTooltip(evt, text) { const tooltip = document.getElementById("tooltip"); tooltip.innerHTML = text; tooltip.style.display = "block"; - tooltip.style.left = evt.pageX + 10 + "px"; - tooltip.style.top = evt.pageY + 10 + "px"; + tooltip.style.left = `${evt.pageX + 10}px`; + tooltip.style.top = `${evt.pageY + 10}px`; } function hideTooltip() { @@ -667,7 +667,7 @@ function setMode() { ) { return; } - console.log("setMode to " + mode); + console.log(`setMode to ${mode}`); if (mode === "ergo") { setErgo(); } else if (mode === "ansi") { @@ -721,7 +721,7 @@ function setErgo() { queryParams.set("mode", mode); queryParams.set("lan", lang); queryParams.set("thumb", thumb); - history.replaceState(null, null, "?" + queryParams.toString()); + history.replaceState(null, null, `?${queryParams.toString()}`); } function activateIso(anglemod) { @@ -780,7 +780,7 @@ function setIso(anglemod) { queryParams.set("layout", exportLayout()); queryParams.set("mode", mode); queryParams.set("lan", lang); - history.replaceState(null, null, "?" + queryParams.toString()); + history.replaceState(null, null, `?${queryParams.toString()}`); } else { console.log("You can't have layouts with thumb letters on ISO/ANSI"); } @@ -840,7 +840,7 @@ function setAnsi() { queryParams.set("layout", exportLayout()); queryParams.set("mode", mode); queryParams.set("lan", lang); - history.replaceState(null, null, "?" + queryParams.toString()); + history.replaceState(null, null, `?${queryParams.toString()}`); } else { console.log("You can't have layouts with thumb letters on ISO/ANSI"); } @@ -849,7 +849,7 @@ function setAnsi() { function importLayout(layout) { if (layout.length === 35) { const decodedString = decodeURIComponent(layout); - console.log("importing: " + decodedString); + console.log(`importing: ${decodedString}`); layout = decodedString; // change shift to = for (let i = 0; i < 34; i++) { @@ -861,7 +861,7 @@ function importLayout(layout) { for (let i = 0; i < 37; i++) { if (rcdata[i][0] === "$") { rcdata[i][0] = "="; - console.log("setting " + i + " to *"); + console.log(`setting ${i} to *`); } } // @@ -903,7 +903,7 @@ function importLayout(layout) { } } else { const decodedString = decodeURIComponent(layout); - console.log("importing: " + decodedString); + console.log(`importing: ${decodedString}`); layout = decodedString; for (let i = 0; i < 34; i++) { // qwertyuiop-asdfghjkl;'zxcvbnm,./\^ - 34 @@ -945,7 +945,7 @@ function importLayout(layout) { queryParams.set("mode", mode); queryParams.set("lan", lang); queryParams.set("thumb", thumb); - history.replaceState(null, null, "?" + queryParams.toString()); + history.replaceState(null, null, `?${queryParams.toString()}`); } function exportLayout() { @@ -1155,7 +1155,7 @@ function generateLayout() { .attr("height", w - gap) .attr("rx", 4) .attr("ry", 4) - .attr("fill", "#" + hex_red + hex_bg + hex_bg) + .attr("fill", `#${hex_red}${hex_bg}${hex_bg}`) .attr("stroke", "black") .attr("stroke-width", "1") .attr("class", "draggable"); @@ -1195,7 +1195,7 @@ function generateLayout() { .attr("font-family", "Sans,Arial") .attr("fill", "#dfe2eb") .attr("text-anchor", "left") - .text("Total Word Effort " + (m_total_word_effort / 100.0).toFixed(1)); + .text(`Total Word Effort ${(0.01 * m_total_word_effort).toFixed(1)}`); // effort text svg .append("text") @@ -1205,7 +1205,7 @@ function generateLayout() { .attr("font-family", "Sans,Arial") .attr("fill", "#dfe2eb") .attr("text-anchor", "left") - .text("Effort " + (577 * m_effort * inv_m_input_length).toFixed(2)); + .text(`Effort ${(577 * m_effort * inv_m_input_length).toFixed(2)}`); // edit button svg .append("rect") @@ -1485,7 +1485,7 @@ function measureDictionary() { } } } - if (total.isNan) console.log(word + " gives NaN for effort"); + if (total.isNan) console.log(`${word} gives NaN for effort`); word_effort[word] = 0.1 * total; } @@ -2028,7 +2028,7 @@ function measureWords() { } // trigram stuff if (i > 1 && prevcol >= 0) { - skip = ppchar + "_" + char; + skip = `${ppchar}_${char}`; trigram = ppchar + prevchar + char; if (finger === ppfinger && ppchar !== char) { if (!m_skip_bigram[skip]) { @@ -2270,20 +2270,20 @@ function generatePlots() { } const inv_sum_col_usage = 1.0 / sum_col_usage; for (const col in m_column_usage) { - var height = 300 * m_column_usage[col] * inv_sum_col_usage; - var tip = parseFloat(100 * m_column_usage[col] * inv_sum_col_usage).toFixed( + const height = 300 * m_column_usage[col] * inv_sum_col_usage; + const tip = parseFloat(100 * m_column_usage[col] * inv_sum_col_usage).toFixed( 2, ); - var red = Math.floor(275 * m_column_usage[col] * inv_sum_col_usage) + 128; - var green = 128; + let red = Math.floor(275 * m_column_usage[col] * inv_sum_col_usage) + 128; + const green = 128; if (red < 16) { red = 16; } if (red > 255) { red = 255; } - var hex_red = red.toString(16); - var hex_bg = green.toString(16); + const hex_red = red.toString(16); + const hex_bg = green.toString(16); stats .append("rect") @@ -2291,10 +2291,10 @@ function generatePlots() { .attr("y", 100 - height) .attr("width", 15) .attr("height", height) - .attr("fill", "#" + hex_red + hex_bg + hex_bg) + .attr("fill", `#${hex_red}${hex_bg}${hex_bg}`) .attr("stroke", "#453033") .attr("stroke-width", 1) - .attr("onmouseover", "showTooltip(evt,'" + tip + "%')") + .attr("onmouseover", `showTooltip(evt,'${tip}%')`) .attr("onmouseout", "hideTooltip()"); stats .append("text") @@ -2345,10 +2345,10 @@ function generatePlots() { .attr("y", y + 40 + row * 20) .attr("width", height) .attr("height", 14) - .attr("fill", "#" + hex_red + hex_bg + hex_bg) + .attr("fill", `#${hex_red}${hex_bg}${hex_bg}`) .attr("stroke", "#453033") .attr("stroke-width", 1) - .attr("onmouseover", "showTooltip(evt,'" + tip + "%')") + .attr("onmouseover", `showTooltip(evt,'${tip}%')`) .attr("onmouseout", "hideTooltip()"); stats .append("text") @@ -2358,7 +2358,7 @@ function generatePlots() { .attr("font-size", 10) .attr("font-family", "Sans,Arial") .attr("text-anchor", "middle") - .text(parseInt(row) + 1); + .text(parseInt(row) + 1); // lint/correctness/useParseIntRadix: Missing radix //\n" } /////////////////////////////////////// F I N G E R U S A G E ////////////////////////////////////// @@ -2387,29 +2387,29 @@ function generatePlots() { } var inv_sum = 1.0 / sum; for (const finger in m_finger_usage) { - var norm_finger_usage = m_finger_usage[finger] * inv_sum; - var height = 300 * norm_finger_usage; - var tip = parseFloat(100 * norm_finger_usage).toFixed(2); - var red = Math.floor(275 * norm_finger_usage) + 128; - var green = 128; + const norm_finger_usage = m_finger_usage[finger] * inv_sum; + const height = 300 * norm_finger_usage; + const tip = parseFloat(100 * norm_finger_usage).toFixed(2); + let red = Math.floor(275 * norm_finger_usage) + 128; + const green = 128; if (red < 16) { red = 16; } if (red > 255) { red = 255; } - var hex_red = red.toString(16); - var hex_bg = green.toString(16); + const hex_red = red.toString(16); + const hex_bg = green.toString(16); stats .append("rect") .attr("x", x + finger * 20) .attr("y", 100 - height) .attr("width", 15) .attr("height", height) - .attr("fill", "#" + hex_red + hex_bg + hex_bg) + .attr("fill", `#${hex_red}${hex_bg}${hex_bg}`) .attr("stroke", "#453033") .attr("stroke-width", 1) - .attr("onmouseover", "showTooltip(evt,'" + tip + "%')") + .attr("onmouseover", `showTooltip(evt,'${tip}%')`) .attr("onmouseout", "hideTooltip()"); stats .append("text") @@ -2429,7 +2429,7 @@ function generatePlots() { .attr("font-size", 11) .attr("font-family", "Sans,Arial") .attr("text-anchor", "middle") - .text(parseFloat(100 * left * inv_sum).toFixed(2) + "%"); + .text(`${parseFloat(100 * left * inv_sum).toFixed(2)}%`); stats .append("text") .attr("x", x + 177) @@ -2438,7 +2438,7 @@ function generatePlots() { .attr("font-size", 11) .attr("font-family", "Sans,Arial") .attr("text-anchor", "middle") - .text(parseFloat(100 * right * inv_sum).toFixed(2) + "%"); + .text(`${parseFloat(100 * right * inv_sum).toFixed(2)}%`); /////////////////////////////////////// F I N G E R D I S T A N C E ////////////////////////////////// var x = 250; var y = 0; @@ -2468,29 +2468,29 @@ function generatePlots() { .text("Finger Distance"); for (const finger in m_finger_distance) { if (m_finger_distance[finger] > 0) { - var norm_finger_distance = m_finger_distance[finger] * inv_max; - var height = 75 * norm_finger_distance; - var tip = parseFloat(100 * norm_finger_distance).toFixed(2); - var red = Math.floor(128 * norm_finger_distance) + 128; - var green = 128; + const norm_finger_distance = m_finger_distance[finger] * inv_max; + const height = 75 * norm_finger_distance; + const tip = parseFloat(100 * norm_finger_distance).toFixed(2); + let red = Math.floor(128 * norm_finger_distance) + 128; + const green = 128; if (red < 16) { red = 16; } if (red > 255) { red = 255; } - var hex_red = red.toString(16); - var hex_bg = green.toString(16); + const hex_red = red.toString(16); + const hex_bg = green.toString(16); stats .append("rect") .attr("x", x + finger * 20) .attr("y", 100 - height) .attr("width", 15) .attr("height", height) - .attr("fill", "#" + hex_red + hex_bg + hex_bg) + .attr("fill", `#${hex_red}${hex_bg}${hex_bg}`) .attr("stroke", "#453033") .attr("stroke-width", 1) - .attr("onmouseover", "showTooltip(evt,'" + tip + "')") + .attr("onmouseover", `showTooltip(evt,'${tip}')`) .attr("onmouseout", "hideTooltip()"); stats .append("text") @@ -2512,7 +2512,7 @@ function generatePlots() { .attr("font-size", 11) .attr("font-family", "Sans,Arial") .attr("text-anchor", "middle") - .text(parseFloat(100 * left * inv_sum).toFixed(2) + "%"); + .text(`${parseFloat(100 * left * inv_sum).toFixed(2)}%`); stats .append("text") .attr("x", x + 177) @@ -2521,7 +2521,7 @@ function generatePlots() { .attr("font-size", 11) .attr("font-family", "Sans,Arial") .attr("text-anchor", "middle") - .text(parseFloat(100 * right * inv_sum).toFixed(2) + "%"); + .text(`${parseFloat(100 * right * inv_sum).toFixed(2)}%`); stats .append("text") .attr("x", x + 117) @@ -2596,7 +2596,7 @@ function generatePlots() { .attr("font-family", "Sans,Arial") .attr("fill", "#dfe2eb") .attr("text-anchor", "left") - .text("Same Finger Bigrams " + parseFloat(100 * sum).toFixed(2) + "%"); + .text(`Same Finger Bigrams ${parseFloat(100 * sum).toFixed(2)}%`); // stats.append("text").attr("x",x+40).attr("y",y+200).attr("font-size",16).attr("font-family","Sans,Arial").attr("fill","#dfe2eb").attr("text-anchor","left").text("Input Length "+m_input_length); let i = 0; @@ -2637,9 +2637,9 @@ function generatePlots() { .attr("font-family", "Sans,Arial") .attr("text-anchor", "left") .text( - parseFloat( - "" + 100 * m_same_finger[bigram] * inv_m_input_length, - ).toFixed(2) + "%", + `${parseFloat( + `${100 * m_same_finger[bigram] * inv_m_input_length}`, + ).toFixed(2)}%`, ); //\n" i += 1; @@ -2659,7 +2659,7 @@ function generatePlots() { .attr("font-family", "Sans,Arial") .attr("fill", "#dfe2eb") .attr("text-anchor", "left") - .text("Same Finger Bigrams " + parseFloat(100 * sum).toFixed(2) + "%"); + .text(`Same Finger Bigrams ${parseFloat(100 * sum).toFixed(2)}%`); for (const finger in m_same_finger2) { var height = 30000 * m_same_finger2[finger] * inv_m_input_length; if (height > 150) { @@ -2685,10 +2685,10 @@ function generatePlots() { .attr("y", y + 155 - height) .attr("width", 15) .attr("height", height) - .attr("fill", "#" + hex_red + hex_bg + hex_bg) + .attr("fill", `#${hex_red}${hex_bg}${hex_bg}`) .attr("stroke", "#453033") .attr("stroke-width", 1) - .attr("onmouseover", "showTooltip(evt,'" + tip + "%')") + .attr("onmouseover", `showTooltip(evt,'${tip}%')`) .attr("onmouseout", "hideTooltip()"); stats @@ -2717,7 +2717,7 @@ function generatePlots() { .attr("font-family", "Sans,Arial") .attr("fill", "#dfe2eb") .attr("text-anchor", "left") - .text("2u Same Finger Bigrams " + parseFloat(100 * sum).toFixed(2) + "%"); + .text(`2u Same Finger Bigrams ${parseFloat(100 * sum).toFixed(2)}%`); // stats.append("text").attr("x",x+40).attr("y",y+200).attr("font-size",16).attr("font-family","Sans,Arial").attr("fill","#dfe2eb").attr("text-anchor","left").text("Input Length "+m_input_length); var i = 0; @@ -2758,9 +2758,9 @@ function generatePlots() { .attr("font-family", "Sans,Arial") .attr("text-anchor", "left") .text( - parseFloat( - "" + 100 * m_same_finger3[bigram] * inv_m_input_length, - ).toFixed(2) + "%", + `${parseFloat( + `${100 * m_same_finger3[bigram] * inv_m_input_length}`, + ).toFixed(2)}%`, ); //\n" i += 1; @@ -2805,7 +2805,7 @@ function generatePlots() { .attr("font-family", "Sans,Arial") .attr("fill", "#dfe2eb") .attr("text-anchor", "left") - .text("Skip Bigrams (2u) " + parseFloat(100 * sum).toFixed(2) + "%"); + .text(`Skip Bigrams (2u) ${parseFloat(100 * sum).toFixed(2)}%`); } stats @@ -2889,7 +2889,7 @@ function generatePlots() { .attr("font-family", "Sans,Arial") .attr("text-anchor", "left") .text( - parseFloat("" + 100 * tmp[bigram] * inv_m_input_length).toFixed(2) + + parseFloat(`${100 * tmp[bigram] * inv_m_input_length}`).toFixed(2) + "%", ); //\n" @@ -2917,7 +2917,7 @@ function generatePlots() { .attr("font-family", "Sans,Arial") .attr("fill", "#dfe2eb") .attr("text-anchor", "left") - .text("Lat Stretch Bigrams " + parseFloat(100 * sum).toFixed(2) + "%"); + .text(`Lat Stretch Bigrams ${parseFloat(100 * sum).toFixed(2)}%`); } else { const keyValueArray = Object.entries(m_lat_stretch2); keyValueArray.sort((a, b) => b[1] - a[1]); @@ -2933,7 +2933,7 @@ function generatePlots() { .attr("font-family", "Sans,Arial") .attr("fill", "#dfe2eb") .attr("text-anchor", "left") - .text("Ring LSBs " + parseFloat(100 * sum).toFixed(2) + "%"); + .text(`Ring LSBs ${parseFloat(100 * sum).toFixed(2)}%`); } stats @@ -3017,7 +3017,7 @@ function generatePlots() { .attr("font-family", "Sans,Arial") .attr("text-anchor", "left") .text( - parseFloat("" + 100 * tmp[bigram] * inv_m_input_length).toFixed(2) + + parseFloat(`${100 * tmp[bigram] * inv_m_input_length}`).toFixed(2) + "%", ); //\n" @@ -3046,9 +3046,9 @@ function generatePlots() { .attr("font-family", "Sans,Arial") .attr("fill", "#dfe2eb") .attr("text-anchor", "left") - .text("Pinky/Ring Scissors " + parseFloat(100 * sum).toFixed(2) + "%"); - } else if (scissors_toggle == 0) { - var keyValueArray = Object.entries(m_scissors); + .text(`Pinky/Ring Scissors ${parseFloat(100 * sum).toFixed(2)}%`); + } else if (scissors_toggle === 0) { + const keyValueArray = Object.entries(m_scissors); keyValueArray.sort((a, b) => b[1] - a[1]); tmp = Object.fromEntries(keyValueArray); for (const bigram in tmp) { @@ -3062,7 +3062,7 @@ function generatePlots() { .attr("font-family", "Sans,Arial") .attr("fill", "#dfe2eb") .attr("text-anchor", "left") - .text("Scissors " + parseFloat(100 * sum).toFixed(2) + "%"); + .text(`Scissors ${parseFloat(100 * sum).toFixed(2)}%`); } else { var keyValueArray = Object.entries(m_all_scissors); keyValueArray.sort((a, b) => b[1] - a[1]); @@ -3078,7 +3078,7 @@ function generatePlots() { .attr("font-family", "Sans,Arial") .attr("fill", "#dfe2eb") .attr("text-anchor", "left") - .text("Wide Scissors " + parseFloat(100 * sum).toFixed(2) + "%"); + .text(`Wide Scissors ${parseFloat(100 * sum).toFixed(2)}%`); } stats .append("path") @@ -3161,7 +3161,7 @@ function generatePlots() { .attr("font-family", "Sans,Arial") .attr("text-anchor", "left") .text( - parseFloat("" + 100 * tmp[bigram] * inv_m_input_length).toFixed(2) + + parseFloat(`${100 * tmp[bigram] * inv_m_input_length}`).toFixed(2) + "%", ); //\n" @@ -3178,7 +3178,7 @@ function generatePlots() { scale = 1; var trigram_title = "Trigram Stats"; - if (trigram_toggle == 0) { + if (trigram_toggle === 0) { var keyValueArray = Object.entries(m_trigram_count); keyValueArray.sort((a, b) => b[1] - a[1]); tmp = Object.fromEntries(keyValueArray); @@ -3188,7 +3188,7 @@ function generatePlots() { trigram_title = "Trigram Stats"; scale = 1; dx = 105; - } else if (trigram_toggle == 1) { + } else if (trigram_toggle === 1) { var keyValueArray = Object.entries(m_trigram_count_alt); keyValueArray.sort((a, b) => b[1] - a[1]); tmp = Object.fromEntries(keyValueArray); @@ -3198,7 +3198,7 @@ function generatePlots() { trigram_title = "Trigram Stats (alts)"; scale = 3; dx = 47; - } else if (trigram_toggle == 2) { + } else if (trigram_toggle === 2) { var keyValueArray = Object.entries(m_trigram_count_red); keyValueArray.sort((a, b) => b[1] - a[1]); tmp = Object.fromEntries(keyValueArray); @@ -3208,7 +3208,7 @@ function generatePlots() { trigram_title = "Trigram Stats (redirects)"; scale = 3; dx = 47; - } else if (trigram_toggle == 3) { + } else if (trigram_toggle === 3) { var keyValueArray = Object.entries(m_trigram_count_roll_in); keyValueArray.sort((a, b) => b[1] - a[1]); tmp = Object.fromEntries(keyValueArray); @@ -3218,7 +3218,7 @@ function generatePlots() { trigram_title = "Trigram Stats (roll in)"; scale = 3; dx = 47; - } else if (trigram_toggle == 4) { + } else if (trigram_toggle === 4) { var keyValueArray = Object.entries(m_trigram_count_roll_out); keyValueArray.sort((a, b) => b[1] - a[1]); tmp = Object.fromEntries(keyValueArray); @@ -3333,7 +3333,7 @@ function generatePlots() { .attr("fill", "#7777bb") .attr("stroke", "#9898d6") .attr("stroke-width", 1) - .attr("onmouseover", "showTooltip(evt,'" + trigram_desc[cat] + "')") + .attr("onmouseover", `showTooltip(evt,'${trigram_desc[cat]}')`) .attr("onmouseout", "hideTooltip()"); stats .append("text") @@ -3352,7 +3352,7 @@ function generatePlots() { .attr("font-size", 10) .attr("font-family", "Sans,Arial") .attr("text-anchor", "left") - .text(parseFloat("" + 100 * tmp_cat_inv_sum).toFixed(2) + "%"); + .text(`${parseFloat("" + 100 * tmp_cat_inv_sum).toFixed(2)}%`); //\n" i += 1; if (i > 10) { @@ -3422,7 +3422,7 @@ function generatePlots() { .attr("font-size", 10) .attr("font-family", "Sans,Arial") .attr("text-anchor", "left") - .text(parseFloat("" + word_len_count).toFixed(0)); // + .text(parseFloat(`${word_len_count}`).toFixed(0)); // i += 1; if (i > 10) { break; @@ -3542,7 +3542,7 @@ function generatePlots() { .attr("font-size", 10) .attr("font-family", "Sans,Arial") .attr("text-anchor", "left") - .text(parseFloat("" + word_effort[word]).toFixed(2)); + .text(parseFloat(`${word_effort[word]}`).toFixed(2)); i += 1; if (i > 10) { break; @@ -3624,8 +3624,8 @@ function generatePlots() { if (j > 4) { finger2 += 2; } - if (i == 0 && j == 0) { - } else if (i == 0 && j > 0) { + if (i === 0 && j === 0) { + } else if (i === 0 && j > 0) { stats .append("text") .attr("x", x + box_x * j + 14) @@ -3635,7 +3635,7 @@ function generatePlots() { .attr("fill", "#dfe2eb") .attr("text-anchor", "middle") .text(finger2); - } else if (i > 0 && j == 0) { + } else if (i > 0 && j === 0) { stats .append("text") .attr("x", x + box_x * j + 14) @@ -3667,7 +3667,7 @@ function generatePlots() { .attr("y", y + box_y * i) .attr("width", box_x) .attr("height", box_y) - .attr("fill", "#" + hex_red + hex_bg + hex_bg) + .attr("fill", `#${hex_red}${hex_bg}${hex_bg}`) .attr("stroke", "black") .attr("stroke-width", "0.5"); stats @@ -3678,7 +3678,7 @@ function generatePlots() { .attr("font-family", "Sans,Arial") .attr("fill", "black") .attr("text-anchor", "middle") - .text(per + "%"); + .text(`${per}%`); } } } @@ -3802,8 +3802,8 @@ function makeDraggable(svg) { if (dropi === starti) { selectedElement.setAttributeNS(null, "x", startx); selectedElement.setAttributeNS(null, "y", starty); - sibling.setAttributeNS(null, "x", parseInt(startx) + 15); - sibling.setAttributeNS(null, "y", parseInt(starty) + 19); + sibling.setAttributeNS(null, "x", parseInt(startx, 10) + 15); + sibling.setAttributeNS(null, "y", parseInt(starty, 10) + 19); selectedElement = false; sibling = false; return; @@ -3812,8 +3812,8 @@ function makeDraggable(svg) { if (rcdata[dropi][1] < 3) { selectedElement.setAttributeNS(null, "x", startx); selectedElement.setAttributeNS(null, "y", starty); - sibling.setAttributeNS(null, "x", parseInt(startx) + 15); - sibling.setAttributeNS(null, "y", parseInt(starty) + 19); + sibling.setAttributeNS(null, "x", parseInt(startx, 10) + 15); + sibling.setAttributeNS(null, "y", parseInt(starty, 10) + 19); selectedElement = false; sibling = false; return; @@ -3823,8 +3823,8 @@ function makeDraggable(svg) { if (rcdata[starti][1] < 3) { selectedElement.setAttributeNS(null, "x", startx); selectedElement.setAttributeNS(null, "y", starty); - sibling.setAttributeNS(null, "x", parseInt(startx) + 15); - sibling.setAttributeNS(null, "y", parseInt(starty) + 19); + sibling.setAttributeNS(null, "x", parseInt(startx, 10) + 15); + sibling.setAttributeNS(null, "y", parseInt(starty, 10) + 19); selectedElement = false; sibling = false; return; @@ -3833,8 +3833,8 @@ function makeDraggable(svg) { if (closestdist > 0.8) { selectedElement.setAttributeNS(null, "x", startx); selectedElement.setAttributeNS(null, "y", starty); - sibling.setAttributeNS(null, "x", parseInt(startx) + 15); - sibling.setAttributeNS(null, "y", parseInt(starty) + 19); + sibling.setAttributeNS(null, "x", parseInt(startx, 10) + 15); + sibling.setAttributeNS(null, "y", parseInt(starty, 10) + 19); selectedElement = false; sibling = false; return; From 9ce3798c4c814379c8fe75dd49ec46a73226ed89 Mon Sep 17 00:00:00 2001 From: gaetan Date: Thu, 23 Apr 2026 11:42:44 +0200 Subject: [PATCH 04/17] Fix trivial scope warnings (var let const) --- keyboard_svg.js | 75 +++++++++++++++++++++++++------------------------ 1 file changed, 38 insertions(+), 37 deletions(-) diff --git a/keyboard_svg.js b/keyboard_svg.js index 3ce8d54..c07b738 100644 --- a/keyboard_svg.js +++ b/keyboard_svg.js @@ -2326,18 +2326,18 @@ function generatePlots() { } const inv_sum_row_usage = 1.0 / sum_row_usage; for (const row in m_row_usage) { - var height = 200 * m_row_usage[row] * inv_sum_row_usage; - var tip = parseFloat(100 * m_row_usage[row] * inv_sum_row_usage).toFixed(2); - var red = Math.floor(190 * m_row_usage[row] * inv_sum_row_usage) + 128; - var green = 128; + const height = 200 * m_row_usage[row] * inv_sum_row_usage; + const tip = parseFloat(100 * m_row_usage[row] * inv_sum_row_usage).toFixed(2); + let red = Math.floor(190 * m_row_usage[row] * inv_sum_row_usage) + 128; + const green = 128; if (red < 16) { red = 16; } if (red > 255) { red = 255; } - var hex_red = red.toString(16); - var hex_bg = green.toString(16); + const hex_red = red.toString(16); + const hex_bg = green.toString(16); stats .append("rect") @@ -2358,7 +2358,7 @@ function generatePlots() { .attr("font-size", 10) .attr("font-family", "Sans,Arial") .attr("text-anchor", "middle") - .text(parseInt(row) + 1); // lint/correctness/useParseIntRadix: Missing radix + .text(parseInt(row, 10) + 1); //\n" } /////////////////////////////////////// F I N G E R U S A G E ////////////////////////////////////// @@ -2661,24 +2661,24 @@ function generatePlots() { .attr("text-anchor", "left") .text(`Same Finger Bigrams ${parseFloat(100 * sum).toFixed(2)}%`); for (const finger in m_same_finger2) { - var height = 30000 * m_same_finger2[finger] * inv_m_input_length; + let height = 30000 * m_same_finger2[finger] * inv_m_input_length; if (height > 150) { height = 150; } - var tip = parseFloat( + const tip = parseFloat( 100 * m_same_finger2[finger] * inv_m_input_length, ).toFixed(2); - var red = + let red = Math.floor(6000 * m_same_finger2[finger] * inv_m_input_length) + 128; - var green = 128; + const green = 128; if (red < 16) { red = 16; } if (red > 255) { red = 255; } - var hex_red = red.toString(16); - var hex_bg = green.toString(16); + const hex_red = red.toString(16); + const hex_bg = green.toString(16); stats .append("rect") .attr("x", x + finger * 20) @@ -2721,13 +2721,13 @@ function generatePlots() { // stats.append("text").attr("x",x+40).attr("y",y+200).attr("font-size",16).attr("font-family","Sans,Arial").attr("fill","#dfe2eb").attr("text-anchor","left").text("Input Length "+m_input_length); var i = 0; - var t = scroll_amount; + let t = scroll_amount; for (const bigram in m_same_finger3) { if (t > 0) { t -= 1; continue; } - var width = 18000 * m_same_finger3[bigram] * inv_m_input_length; + let width = 18000 * m_same_finger3[bigram] * inv_m_input_length; if (width > 200) { width = 200; } @@ -2775,7 +2775,7 @@ function generatePlots() { sum = 0; var tmp; if (skip_toggle) { - var keyValueArray = Object.entries(m_skip_bigram); + const keyValueArray = Object.entries(m_skip_bigram); keyValueArray.sort((a, b) => b[1] - a[1]); tmp = Object.fromEntries(keyValueArray); for (const bigram in tmp) { @@ -2789,9 +2789,9 @@ function generatePlots() { .attr("font-family", "Sans,Arial") .attr("fill", "#dfe2eb") .attr("text-anchor", "left") - .text("Skip Bigrams " + parseFloat(100 * sum).toFixed(2) + "%"); + .text(`Skip Bigrams ${parseFloat(100 * sum).toFixed(2)}%`); } else { - var keyValueArray = Object.entries(m_skip_bigram2); + const keyValueArray = Object.entries(m_skip_bigram2); keyValueArray.sort((a, b) => b[1] - a[1]); tmp = Object.fromEntries(keyValueArray); for (const bigram in tmp) { @@ -2858,7 +2858,7 @@ function generatePlots() { t -= 1; continue; } - var height = 36000 * tmp[bigram] * inv_m_input_length; + let height = 36000 * tmp[bigram] * inv_m_input_length; if (height > 200) { height = 200; } @@ -2986,7 +2986,7 @@ function generatePlots() { t -= 1; continue; } - var height = 10000 * tmp[bigram] * inv_m_input_length; + let height = 10000 * tmp[bigram] * inv_m_input_length; if (height > 200) { height = 200; } @@ -3064,7 +3064,7 @@ function generatePlots() { .attr("text-anchor", "left") .text(`Scissors ${parseFloat(100 * sum).toFixed(2)}%`); } else { - var keyValueArray = Object.entries(m_all_scissors); + const keyValueArray = Object.entries(m_all_scissors); keyValueArray.sort((a, b) => b[1] - a[1]); tmp = Object.fromEntries(keyValueArray); for (const bigram in tmp) { @@ -3130,7 +3130,7 @@ function generatePlots() { t -= 1; continue; } - var height = 36000 * tmp[bigram] * inv_m_input_length; + let height = 36000 * tmp[bigram] * inv_m_input_length; if (height > 180) { height = 180; } @@ -3170,7 +3170,8 @@ function generatePlots() { break; } } - /////////////////////////////////// T R I G R A M S T A T S /////////////////////////////// + + /////////////////////////////////// T R I G R A M S T A T S /////////////////////////////// var x = 760; var y = 390; dx = 105; @@ -3179,7 +3180,7 @@ function generatePlots() { var trigram_title = "Trigram Stats"; if (trigram_toggle === 0) { - var keyValueArray = Object.entries(m_trigram_count); + const keyValueArray = Object.entries(m_trigram_count); keyValueArray.sort((a, b) => b[1] - a[1]); tmp = Object.fromEntries(keyValueArray); for (const cat in tmp) { @@ -3189,7 +3190,7 @@ function generatePlots() { scale = 1; dx = 105; } else if (trigram_toggle === 1) { - var keyValueArray = Object.entries(m_trigram_count_alt); + const keyValueArray = Object.entries(m_trigram_count_alt); keyValueArray.sort((a, b) => b[1] - a[1]); tmp = Object.fromEntries(keyValueArray); for (const cat in tmp) { @@ -3199,7 +3200,7 @@ function generatePlots() { scale = 3; dx = 47; } else if (trigram_toggle === 2) { - var keyValueArray = Object.entries(m_trigram_count_red); + const keyValueArray = Object.entries(m_trigram_count_red); keyValueArray.sort((a, b) => b[1] - a[1]); tmp = Object.fromEntries(keyValueArray); for (const cat in tmp) { @@ -3209,7 +3210,7 @@ function generatePlots() { scale = 3; dx = 47; } else if (trigram_toggle === 3) { - var keyValueArray = Object.entries(m_trigram_count_roll_in); + const keyValueArray = Object.entries(m_trigram_count_roll_in); keyValueArray.sort((a, b) => b[1] - a[1]); tmp = Object.fromEntries(keyValueArray); for (const cat in tmp) { @@ -3219,7 +3220,7 @@ function generatePlots() { scale = 3; dx = 47; } else if (trigram_toggle === 4) { - var keyValueArray = Object.entries(m_trigram_count_roll_out); + const keyValueArray = Object.entries(m_trigram_count_roll_out); keyValueArray.sort((a, b) => b[1] - a[1]); tmp = Object.fromEntries(keyValueArray); for (const cat in tmp) { @@ -3319,8 +3320,8 @@ function generatePlots() { t -= 1; continue; } - var tmp_cat_inv_sum = tmp[cat] * inv_sum; - var width = scale * 200 * tmp_cat_inv_sum; + const tmp_cat_inv_sum = tmp[cat] * inv_sum; + let width = scale * 200 * tmp_cat_inv_sum; if (width > 200) { width = 200; } @@ -3352,7 +3353,7 @@ function generatePlots() { .attr("font-size", 10) .attr("font-family", "Sans,Arial") .attr("text-anchor", "left") - .text(`${parseFloat("" + 100 * tmp_cat_inv_sum).toFixed(2)}%`); + .text(`${parseFloat(`${100 * tmp_cat_inv_sum}`).toFixed(2)}%`); //\n" i += 1; if (i > 10) { @@ -3388,11 +3389,11 @@ function generatePlots() { t -= 1; continue; } - var count = samehandstrings[word]; + const count = samehandstrings[word]; // console.log(word + " " + count) word_len = word.length; - var word_len_count = word_len * count; - var width = scale * word_len_count; + const word_len_count = word_len * count; + let width = scale * word_len_count; if (width > 100) { width = 100; } @@ -3451,8 +3452,8 @@ function generatePlots() { .text("Same Hand Count"); var i = 0; for (const len in samehandcount) { - var count = samehandcount[len]; - var width = scale * count; + const count = samehandcount[len]; + let width = scale * count; if (width > 100) { width = 100; } @@ -3515,7 +3516,7 @@ function generatePlots() { t -= 1; continue; } - var height = (100 * word_effort[word]) / word_len; + const height = (100 * word_effort[word]) / word_len; stats .append("rect") .attr("x", x + 80) From 186fc2dc782b0424318210394e312183960f35d6 Mon Sep 17 00:00:00 2001 From: gaetan Date: Thu, 23 Apr 2026 11:52:17 +0200 Subject: [PATCH 05/17] Use let for local x, y and don't redefine --- keyboard_svg.js | 63 ++++++++++++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 30 deletions(-) diff --git a/keyboard_svg.js b/keyboard_svg.js index c07b738..ac90dcf 100644 --- a/keyboard_svg.js +++ b/keyboard_svg.js @@ -2253,8 +2253,8 @@ function generatePlots() { console.log("generatePlots"); stats.selectAll("*").remove(); /////////////////////////////////////// C O L U M N U S A G E //////////////////////////////////////////// - var x = 500; - var y = 0; + let x = 500; + let y = 0; stats .append("text") .attr("x", x + 40) @@ -2264,7 +2264,8 @@ function generatePlots() { .attr("fill", "#dfe2eb") .attr("text-anchor", "left") .text("Column Usage"); - var sum_col_usage = 0; + + let sum_col_usage = 0; for (const col in m_column_usage) { sum_col_usage += m_column_usage[col]; } @@ -2309,8 +2310,8 @@ function generatePlots() { } /////////////////////////////////////// R O W U S A G E //////////////////////////////////////////// - var x = 770; - var y = 0; + x = 770; + y = 0; stats .append("text") .attr("x", x + 40) @@ -2320,11 +2321,13 @@ function generatePlots() { .attr("fill", "#dfe2eb") .attr("text-anchor", "left") .text("Row Usage"); - var sum_row_usage = 0; + + var sum_row_usage = 0; for (const row in m_row_usage) { sum_row_usage += m_row_usage[row]; } const inv_sum_row_usage = 1.0 / sum_row_usage; + for (const row in m_row_usage) { const height = 200 * m_row_usage[row] * inv_sum_row_usage; const tip = parseFloat(100 * m_row_usage[row] * inv_sum_row_usage).toFixed(2); @@ -2362,8 +2365,8 @@ function generatePlots() { //\n" } /////////////////////////////////////// F I N G E R U S A G E ////////////////////////////////////// - var x = 0; - var y = 0; + x = 0; + y = 0; stats .append("text") .attr("x", x + 40) @@ -2440,8 +2443,8 @@ function generatePlots() { .attr("text-anchor", "middle") .text(`${parseFloat(100 * right * inv_sum).toFixed(2)}%`); /////////////////////////////////////// F I N G E R D I S T A N C E ////////////////////////////////// - var x = 250; - var y = 0; + x = 250; + y = 0; var max = m_input_length / 5.110882176; // this might be shadowing 'max' above sum = 0; left = 0; @@ -2533,8 +2536,8 @@ function generatePlots() { .text(parseFloat(100 * sum * inv_max).toFixed(1)); // (100*sum/max).toFixed(1) /////////////////////////////////// S A M E F I N G E R B I G R A M S /////////////////////////////// - var x = 0; - var y = 180; + x = 0; + y = 180; sum = 0; // toggle button stats @@ -2720,7 +2723,7 @@ function generatePlots() { .text(`2u Same Finger Bigrams ${parseFloat(100 * sum).toFixed(2)}%`); // stats.append("text").attr("x",x+40).attr("y",y+200).attr("font-size",16).attr("font-family","Sans,Arial").attr("fill","#dfe2eb").attr("text-anchor","left").text("Input Length "+m_input_length); - var i = 0; + let i = 0; let t = scroll_amount; for (const bigram in m_same_finger3) { if (t > 0) { @@ -2770,8 +2773,8 @@ function generatePlots() { } } /////////////////////////////////// S K I P F I N G E R B I G R A M S /////////////////////////////// - var x = 250; - var y = 180; + x = 250; + y = 180; sum = 0; var tmp; if (skip_toggle) { @@ -2899,8 +2902,8 @@ function generatePlots() { } } //////////////////////////// L A T E R A L S T R E T C H B I G R A M S /////////////////////////////// - var x = 500; - var y = 180; + x = 500; + y = 180; sum = 0; if (lsb_toggle === 0) { const keyValueArray = Object.entries(m_lat_stretch); @@ -3027,8 +3030,8 @@ function generatePlots() { } } //////////////////////////// S C I S S O R S /////////////////////////////// - var x = 760; - var y = 180; + x = 760; + y = 180; sum = 0; if (scissors_toggle === 1) { @@ -3172,8 +3175,8 @@ function generatePlots() { } /////////////////////////////////// T R I G R A M S T A T S /////////////////////////////// - var x = 760; - var y = 390; + x = 760; + y = 390; dx = 105; sum = 0; scale = 1; @@ -3362,8 +3365,8 @@ function generatePlots() { } /////////////////////////////////// S A M E H A N D S T R I N G S /////////////////////////////// - var x = 250; - var y = 390; + x = 250; + y = 390; sum = 0; var keyValueArray = Object.entries(samehandstrings); @@ -3431,8 +3434,8 @@ function generatePlots() { } /////////////////////////////////// S A M E H A N D C O U N T S /////////////////////////////// - var x = 415; - var y = 390; + x = 415; + y = 390; sum = 0; // var keyValueArray = Object.entries(samehandcount); @@ -3483,7 +3486,7 @@ function generatePlots() { .attr("font-size", 10) .attr("font-family", "Sans,Arial") .attr("text-anchor", "left") - .text((scale * 7.14285714285714285714285 * count).toFixed(1)); + .text((scale * 7.142857142857143 * count).toFixed(1)); // was 7.14285714285714285714285, lint/correctness/noPrecisionLoss // stats.append("text").attr("x", x + 135).attr("y", y + i * 15 + 8).attr("fill", "#dfe2eb").attr("font-size", 10).attr("font-family", "Sans,Arial").attr("text-anchor", "left").text(count); i += 1; if (i > 10) { @@ -3492,8 +3495,8 @@ function generatePlots() { } /////////////////////////////////// H A R D W O R D S /////////////////////////////// - var x = 580; - var y = 390; + x = 580; + y = 390; sum = 0; var keyValueArray = Object.entries(word_effort); keyValueArray.sort((a, b) => b[1] / b[0].length - a[1] / a[0].length); @@ -3572,8 +3575,8 @@ function generatePlots() { // } /////////////////////////////////// F I N G E R P A I R S /////////////////////////////// - var x = 10; - var y = 370; + x = 10; + y = 370; var box_x = 26; var box_y = 20; var per = 0; From 57c31826f67b2dc630c56ec6e6660d16224886d8 Mon Sep 17 00:00:00 2001 From: gaetan Date: Thu, 23 Apr 2026 12:10:37 +0200 Subject: [PATCH 06/17] Format comments for easier browsing, use block comments, add author where comment is a sentence --- keyboard_svg.js | 208 +++++++++++++++++++++++++++--------------------- 1 file changed, 117 insertions(+), 91 deletions(-) diff --git a/keyboard_svg.js b/keyboard_svg.js index ac90dcf..c657a65 100644 --- a/keyboard_svg.js +++ b/keyboard_svg.js @@ -38,7 +38,6 @@ var needs_update = true; function scroll(event) { event.preventDefault(); - // const svgRect = el.getBoundingClientRect(); const mouseX = event.clientX - svgRect.left; const mouseY = event.clientY - svgRect.top; @@ -98,19 +97,20 @@ function fetchData() { fetch(word_list_url) .then((response) => response.json()) .then((data) => { - words = data; // Assign data to the global variable + words = data; // (cyanophage) Assign data to the global variable console.log("fetchData"); dataloaded = true; needs_update = true; }) .catch((error) => console.error("Error loading JSON file:", error)); } + function fetchDictionary() { fetch(dictionary_url) .then((response) => response.json()) .then((data) => { if (data.dictionary) { - dictionary = data.dictionary; // Assign data to the global variable + dictionary = data.dictionary; // (cyanophage) Assign data to the global variable } else { console.log("something went wrong with loading the dictionary"); } @@ -131,7 +131,7 @@ async function loadAllData() { fetch(effort_url).then((response) => response.json()), ]); - // Assign the data to the global variables + // (cyanophage) Assign the data to the global variables words = wordsData; dictionary = dictionaryData.dictionary || []; bigram_effort = effortData; @@ -175,7 +175,7 @@ function selectLanguage(lan, event) { document.getElementById("langDropDown").innerHTML += `+${lan.charAt(0).toUpperCase()}${lan.substr(1).toLowerCase()}`; } else { - words = data; // Assign data to the global variable + words = data; // (cyanophage) Assign data to the global variable document.getElementById("langDropDown").innerHTML = lan.charAt(0).toUpperCase() + lan.substr(1).toLowerCase(); } @@ -247,7 +247,7 @@ var rcdata = [ ["back", 3, 6, 0, 0, 0, 1, 38], ["space", 3, 7, 0, 0, 0, 1, 39], ]; -const rcdata_len = rcdata.length; // Compute once +const rcdata_len = rcdata.length; var effort = [ [ @@ -343,8 +343,11 @@ function closeImportPopup() { return; } if (importString.length === 30) { - // probably cmini - if (strCount(importString, "-") === 0 && strCount(importString, "'") === 0) { + // (cyanophage) probably cmini + if ( + strCount(importString, "-") === 0 && + strCount(importString, "'") === 0 + ) { importString = importString.slice(0, 10) + "-" + @@ -353,7 +356,8 @@ function closeImportPopup() { importString.slice(20) + "\\^"; } else if ( - strCount(importString, "-") === 0 && strCount(importString, ";") === 0 + strCount(importString, "-") === 0 && + strCount(importString, ";") === 0 ) { importString = importString.slice(0, 10) + @@ -363,7 +367,8 @@ function closeImportPopup() { importString.slice(20) + "\\^"; } else if ( - strCount(importString, "'") === 0 && strCount(importString, ";") === 0 + strCount(importString, "'") === 0 && + strCount(importString, ";") === 0 ) { importString = importString.slice(0, 10) + @@ -373,7 +378,8 @@ function closeImportPopup() { importString.slice(20) + "\\^"; } else if ( - strCount(importString, "'") === 0 && strCount(importString, "/") === 0 + strCount(importString, "'") === 0 && + strCount(importString, "/") === 0 ) { importString = importString.slice(0, 10) + @@ -383,7 +389,8 @@ function closeImportPopup() { importString.slice(20) + "\\^"; } else if ( - strCount(importString, ";") === 0 && strCount(importString, "/") === 0 + strCount(importString, ";") === 0 && + strCount(importString, "/") === 0 ) { importString = importString.slice(0, 10) + @@ -393,7 +400,8 @@ function closeImportPopup() { importString.slice(20) + "\\^"; } else if ( - strCount(importString, "/") === 0 && strCount(importString, "-") === 0 + strCount(importString, "/") === 0 && + strCount(importString, "-") === 0 ) { importString = importString.slice(0, 10) + @@ -413,7 +421,7 @@ function closeImportPopup() { } } const letters = importString.toUpperCase().match(/[A-Z.,/\-';]/g) || []; - // Count occurrences of each letter + // (cyanophage) Count occurrences of each letter const letterCount = {}; letters.forEach((letter) => { letterCount[letter] = (letterCount[letter] || 0) + 1; @@ -427,12 +435,10 @@ function closeImportPopup() { ); var message = ""; if (missing.length > 0) { - message = - `${message}These letters are duplicated: ${duplicates.join(" ")}\n`; + message = `${message}These letters are duplicated: ${duplicates.join(" ")}\n`; } if (duplicates.length > 0) { - message = - `${message}These letters are duplicated: ${duplicates.join(" ")}\n`; + message = `${message}These letters are duplicated: ${duplicates.join(" ")}\n`; } if (message.length > 0) { document.getElementById("importMessage").innerText = message; @@ -484,7 +490,7 @@ function closeCorpusPopup() { list = massive_string.split(" "); var regex = /\d/; list.forEach((element) => { - // i don't know what to do with these at the moment. just replacing them for now + // (cyanophage) i don't know what to do with these at the moment. just replacing them for now element = element.replace("ä", "a"); element = element.replace("å", "a"); element = element.replace("á", "a"); @@ -567,7 +573,7 @@ function pasteEffortGridFromClipboard() { console.error("Clipboard API not supported"); return; } - // Retrieve clipboard content + // (cyanophage) Retrieve clipboard content navigator.clipboard .readText() .then((text) => { @@ -763,7 +769,7 @@ function setIso(anglemod) { rcdata[39] = ["space", 3, 3, 0, 0, 0, 6.5, 39]; if (anglemod) { fingerAssignment = [ - // angle mod + // (cyanophage) angle mod [1, 1, 2, 3, 4, 4, 7, 7, 8, 9, 10, 10, 10], [1, 1, 2, 3, 4, 4, 7, 7, 8, 9, 10, 10, 10], [1, 2, 3, 4, 4, 4, 7, 7, 8, 9, 10, 10, 10], @@ -851,12 +857,14 @@ function importLayout(layout) { const decodedString = decodeURIComponent(layout); console.log(`importing: ${decodedString}`); layout = decodedString; + // change shift to = for (let i = 0; i < 34; i++) { if (rcdata[i][0] === "^") { rcdata[i][0] = "*"; } } + // change ctrl to * for (let i = 0; i < 37; i++) { if (rcdata[i][0] === "$") { @@ -864,7 +872,7 @@ function importLayout(layout) { console.log(`setting ${i} to *`); } } - // + for (let i = 0; i < 34; i++) { // qwertyuiop-asdfghjkl;'zxcvbnm,./\^ - 34 for (let j = 0; j < 34; j++) { @@ -924,7 +932,7 @@ function importLayout(layout) { for (let i = 0; i < 34; i++) { if (rcdata[i][0] === "^") { if (rcdata[i][1] === 3 && rcdata[i][2] === 4) { - // cool + // (cyanophage) cool } else { rcdata[i][0] = "="; } @@ -1079,7 +1087,7 @@ function getFinger(row, col) { function dist(x1, y1, x2, y2) { dx = x1 - x2; dy = y1 - y2; - return inv_w * Math.sqrt(dx * dx + dy * dy); // pow is slow + return inv_w * Math.sqrt(dx * dx + dy * dy); // (narglab) pow is slow } function generateCoords() { @@ -1181,7 +1189,7 @@ function generateLayout() { .text(letter); } } - // + if (m_total_word_effort === 0) { // console.log("m_total_word_effort === 0") measureDictionary(); @@ -1196,6 +1204,7 @@ function generateLayout() { .attr("fill", "#dfe2eb") .attr("text-anchor", "left") .text(`Total Word Effort ${(0.01 * m_total_word_effort).toFixed(1)}`); + // effort text svg .append("text") @@ -1206,6 +1215,7 @@ function generateLayout() { .attr("fill", "#dfe2eb") .attr("text-anchor", "left") .text(`Effort ${(577 * m_effort * inv_m_input_length).toFixed(2)}`); + // edit button svg .append("rect") @@ -1248,6 +1258,7 @@ function generateLayout() { .attr("onclick", "activateErgo()") .attr("onmouseover", "showTooltip(evt,'Switch layout to Ergo')") .attr("onmouseout", "hideTooltip()"); + svg .append("text") .attr("x", 640 + 23) @@ -1258,6 +1269,7 @@ function generateLayout() { .attr("text-anchor", "middle") .attr("pointer-events", "none") .text("Ergo"); + // iso button svg .append("rect") @@ -1344,7 +1356,7 @@ var m_column_usage = {}; var m_finger_usage = {}; var m_finger_distance = {}; var m_finger_pairs = {}; -var m_same_finger = {}; // per bigram +var m_same_finger = {}; // per bigram var m_same_finger2 = {}; // per finger var m_same_finger3 = {}; // per bigram 2u var m_skip_bigram = {}; @@ -1413,7 +1425,7 @@ function measureDictionary() { count += 1; total = 0.0; word = dictionary[wordi]; - word_len = word.length; // Compute once + word_len = word.length; char1 = word.charAt(0); samehand = `${char1}`; for (let i = 1; i < word_len; i++) { @@ -1486,7 +1498,7 @@ function measureDictionary() { } } if (total.isNan) console.log(`${word} gives NaN for effort`); - + word_effort[word] = 0.1 * total; } } @@ -1502,33 +1514,35 @@ function getDictionaryFromWords() { } function getIndexOfKey(name) { - var x = -1; + let x_key = -1; for (let i = 0; i < 34; i++) { if (rcdata[i][7] === name) { - x = i; + x_key = i; } } - return x; + return x_key; } function updateRcData(lan) { - // what are the 33 letters ? + // (cyanophage) what are the 33 letters ? var letters = []; for (const word in words) { if (letters.length >= 32) { break; } - const wordLetters = word.split(""); // Split the word into individual letters + const wordLetters = word.split(""); // (cyanophage) Split the word into individual letters for (let i = 0; i < wordLetters.length; i++) { if (letters.indexOf(wordLetters[i]) === -1) { - letters.push(wordLetters[i]); // Add letter to the list if not already present + letters.push(wordLetters[i]); // (cyanophage) Add letter to the list if not already present } } } - // my new idea for fixing this issue still didn't work - // the problem is that the keys that I want to change when switching languages aren't in a consistent position in the grid, or at a consistent position in the array, - // or have a consistent letter on them. Even the index I added to try to make them consistent didn't work because of the way the import process works - if (lan === "german") { + /* (cyanophage) + * my new idea for fixing this issue still didn't work + * the problem is that the keys that I want to change when switching languages aren't in a consistent position in the grid, or at a consistent position in the array, + * or have a consistent letter on them. Even the index I added to try to make them consistent didn't work because of the way the import process works + */ + if (lan === "german") { // letters = ['q', 'w', 'e', 'r', 't', 'z', 'u', 'i', 'o', 'p', 'ü', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'ö', 'ä', 'y','x', 'c', 'v', 'b', 'n', 'm', ',', '.', '\'', 'ß'] if (getIndexOfKey(10) >= 0) { rcdata[getIndexOfKey(10)][0] = "ü"; @@ -1822,7 +1836,7 @@ function measureWords() { [1, 10], ]; const count = words[word]; - word_len = word.length; // Compute once + word_len = word.length; m_input_length += count * (word_len + 1); if (word_effort[word]) { @@ -1855,7 +1869,7 @@ function measureWords() { } if (col < 0) { continue; - } // this is the part that just skips numbers and other characters + } // (cyanophage) this is the part that just skips numbers and other characters if (!m_column_usage[col]) { m_column_usage[col] = 0; } @@ -1992,7 +2006,10 @@ function measureWords() { if ( Math.abs(col - prevcol) === 1 && Math.abs(row - prevrow) >= 1 && - (finger === 1 || finger === 10 || prevfinger === 1 || prevfinger === 10) + (finger === 1 || + finger === 10 || + prevfinger === 1 || + prevfinger === 10) ) { if (!m_pinky_scissors[bigram]) { m_pinky_scissors[bigram] = 0; @@ -2055,7 +2072,9 @@ function measureWords() { (ppfinger < prevfinger && finger < prevfinger && finger !== ppfinger) || - (ppfinger > prevfinger && finger > prevfinger && finger !== ppfinger) + (ppfinger > prevfinger && + finger > prevfinger && + finger !== ppfinger) ) { cat = "redirect"; // if (!m_redirects[trigram]) { @@ -2078,7 +2097,9 @@ function measureWords() { (ppfinger > prevfinger && finger > prevfinger && finger !== ppfinger) || - (ppfinger < prevfinger && finger < prevfinger && finger !== ppfinger) + (ppfinger < prevfinger && + finger < prevfinger && + finger !== ppfinger) ) { cat = "redirect"; // if (!m_redirects[trigram]) { @@ -2252,7 +2273,8 @@ function generatePlots() { } console.log("generatePlots"); stats.selectAll("*").remove(); - /////////////////////////////////////// C O L U M N U S A G E //////////////////////////////////////////// + + // ================================ C O L U M N U S A G E ================================ let x = 500; let y = 0; stats @@ -2272,9 +2294,9 @@ function generatePlots() { const inv_sum_col_usage = 1.0 / sum_col_usage; for (const col in m_column_usage) { const height = 300 * m_column_usage[col] * inv_sum_col_usage; - const tip = parseFloat(100 * m_column_usage[col] * inv_sum_col_usage).toFixed( - 2, - ); + const tip = parseFloat( + 100 * m_column_usage[col] * inv_sum_col_usage, + ).toFixed(2); let red = Math.floor(275 * m_column_usage[col] * inv_sum_col_usage) + 128; const green = 128; if (red < 16) { @@ -2309,7 +2331,7 @@ function generatePlots() { //\n" } - /////////////////////////////////////// R O W U S A G E //////////////////////////////////////////// + // ================================ R O W U S A G E ================================ x = 770; y = 0; stats @@ -2321,8 +2343,8 @@ function generatePlots() { .attr("fill", "#dfe2eb") .attr("text-anchor", "left") .text("Row Usage"); - - var sum_row_usage = 0; + + var sum_row_usage = 0; for (const row in m_row_usage) { sum_row_usage += m_row_usage[row]; } @@ -2330,7 +2352,9 @@ function generatePlots() { for (const row in m_row_usage) { const height = 200 * m_row_usage[row] * inv_sum_row_usage; - const tip = parseFloat(100 * m_row_usage[row] * inv_sum_row_usage).toFixed(2); + const tip = parseFloat(100 * m_row_usage[row] * inv_sum_row_usage).toFixed( + 2, + ); let red = Math.floor(190 * m_row_usage[row] * inv_sum_row_usage) + 128; const green = 128; if (red < 16) { @@ -2364,7 +2388,7 @@ function generatePlots() { .text(parseInt(row, 10) + 1); //\n" } - /////////////////////////////////////// F I N G E R U S A G E ////////////////////////////////////// + // ================================ F I N G E R U S A G E ================================ x = 0; y = 0; stats @@ -2442,10 +2466,10 @@ function generatePlots() { .attr("font-family", "Sans,Arial") .attr("text-anchor", "middle") .text(`${parseFloat(100 * right * inv_sum).toFixed(2)}%`); - /////////////////////////////////////// F I N G E R D I S T A N C E ////////////////////////////////// + // ================================ F I N G E R D I S T A N C E ================================ x = 250; y = 0; - var max = m_input_length / 5.110882176; // this might be shadowing 'max' above + var max = m_input_length / 5.110882176; // (narglab) this might be shadowing 'max' above sum = 0; left = 0; right = 0; @@ -2535,7 +2559,7 @@ function generatePlots() { .attr("text-anchor", "middle") .text(parseFloat(100 * sum * inv_max).toFixed(1)); // (100*sum/max).toFixed(1) - /////////////////////////////////// S A M E F I N G E R B I G R A M S /////////////////////////////// + // ================================ S A M E F I N G E R B I G R A M S ================================ x = 0; y = 180; sum = 0; @@ -2772,7 +2796,7 @@ function generatePlots() { } } } - /////////////////////////////////// S K I P F I N G E R B I G R A M S /////////////////////////////// + // ================================ S K I P F I N G E R B I G R A M S ================================ x = 250; y = 180; sum = 0; @@ -2901,7 +2925,7 @@ function generatePlots() { break; } } - //////////////////////////// L A T E R A L S T R E T C H B I G R A M S /////////////////////////////// + // ================================ L A T E R A L S T R E T C H B I G R A M S ================================ x = 500; y = 180; sum = 0; @@ -3029,7 +3053,7 @@ function generatePlots() { break; } } - //////////////////////////// S C I S S O R S /////////////////////////////// + // ================================ S C I S S O R S ================================ x = 760; y = 180; sum = 0; @@ -3173,8 +3197,8 @@ function generatePlots() { break; } } - - /////////////////////////////////// T R I G R A M S T A T S /////////////////////////////// + + // ================================ T R I G R A M S T A T S ================================ x = 760; y = 390; dx = 105; @@ -3364,7 +3388,7 @@ function generatePlots() { } } - /////////////////////////////////// S A M E H A N D S T R I N G S /////////////////////////////// + // ================================ S A M E H A N D S T R I N G S ================================ x = 250; y = 390; sum = 0; @@ -3426,14 +3450,14 @@ function generatePlots() { .attr("font-size", 10) .attr("font-family", "Sans,Arial") .attr("text-anchor", "left") - .text(parseFloat(`${word_len_count}`).toFixed(0)); // + .text(parseFloat(`${word_len_count}`).toFixed(0)); i += 1; if (i > 10) { break; } } - /////////////////////////////////// S A M E H A N D C O U N T S /////////////////////////////// + // ================================ S A M E H A N D C O U N T S ================================ x = 415; y = 390; sum = 0; @@ -3486,7 +3510,7 @@ function generatePlots() { .attr("font-size", 10) .attr("font-family", "Sans,Arial") .attr("text-anchor", "left") - .text((scale * 7.142857142857143 * count).toFixed(1)); // was 7.14285714285714285714285, lint/correctness/noPrecisionLoss + .text((scale * 7.142857142857143 * count).toFixed(1)); // (narglab) was 7.14285714285714285714285, lint/correctness/noPrecisionLoss // stats.append("text").attr("x", x + 135).attr("y", y + i * 15 + 8).attr("fill", "#dfe2eb").attr("font-size", 10).attr("font-family", "Sans,Arial").attr("text-anchor", "left").text(count); i += 1; if (i > 10) { @@ -3494,7 +3518,7 @@ function generatePlots() { } } - /////////////////////////////////// H A R D W O R D S /////////////////////////////// + // ================================ H A R D W O R D S ================================ x = 580; y = 390; sum = 0; @@ -3553,28 +3577,30 @@ function generatePlots() { } } } - /////////////////////////////////// E A S Y W O R D S /////////////////////////////// - // var x = 610; - // var y = 390; - // sum = 0; - // var keyValueArray = Object.entries(word_effort); - // keyValueArray.sort((a, b) => a[1] - b[1]); - // word_effort = Object.fromEntries(keyValueArray); - // stats.append("text").attr("x", x + 40).attr("y", y - 16).attr("font-size", 16).attr("font-family", "Sans,Arial").attr("fill", "#dfe2eb").attr("text-anchor", "left").text("Easy Words ") - // var i = 0 - // for (var word in word_effort) { - // var height = 10*word_effort[word]; - // if (word.length > 3){ - // stats.append("rect").attr("x", x + 80).attr("y", y + i * 15).attr("width", height).attr("height", 10) - // .attr("fill", "#7777bb").attr("stroke", "#9898d6").attr("stroke-width", 1) - // stats.append("text").attr("x", x + 20).attr("y", y + i * 15 + 8).attr("fill", "#dfe2eb").attr("font-size", 10).attr("font-family", "Sans,Arial").attr("text-anchor", "right").text(word); - // stats.append("text").attr("x", x + 125).attr("y", y + i * 15 + 8).attr("fill", "#dfe2eb").attr("font-size", 10).attr("font-family", "Sans,Arial").attr("text-anchor", "left").text(parseFloat("" + (word_effort[word])).toFixed(2)); - // i += 1; - // if (i > 10) { break; } - // } - // } - - /////////////////////////////////// F I N G E R P A I R S /////////////////////////////// + // ================================ E A S Y W O R D S ================================ + /* + var x = 610; + var y = 390; + sum = 0; + var keyValueArray = Object.entries(word_effort); + keyValueArray.sort((a, b) => a[1] - b[1]); + word_effort = Object.fromEntries(keyValueArray); + stats.append("text").attr("x", x + 40).attr("y", y - 16).attr("font-size", 16).attr("font-family", "Sans,Arial").attr("fill", "#dfe2eb").attr("text-anchor", "left").text("Easy Words ") + var i = 0 + for (var word in word_effort) { + var height = 10*word_effort[word]; + if (word.length > 3){ + stats.append("rect").attr("x", x + 80).attr("y", y + i * 15).attr("width", height).attr("height", 10) + .attr("fill", "#7777bb").attr("stroke", "#9898d6").attr("stroke-width", 1) + stats.append("text").attr("x", x + 20).attr("y", y + i * 15 + 8).attr("fill", "#dfe2eb").attr("font-size", 10).attr("font-family", "Sans,Arial").attr("text-anchor", "right").text(word); + stats.append("text").attr("x", x + 125).attr("y", y + i * 15 + 8).attr("fill", "#dfe2eb").attr("font-size", 10).attr("font-family", "Sans,Arial").attr("text-anchor", "left").text(parseFloat("" + (word_effort[word])).toFixed(2)); + i += 1; + if (i > 10) { break; } + } + } + */ + + // ================================ F I N G E R P A I R S ================================ x = 10; y = 370; var box_x = 26; @@ -3723,10 +3749,10 @@ function makeDraggable(svg) { selectedElement = selectedElement.previousElementSibling; sibling = evt.target; } else { - sibling = selectedElement.nextElementSibling; // dude this is super useful! + sibling = selectedElement.nextElementSibling; // (cyanophage) dude this is super useful! } if (selectedElement) { - // move to the end so they appear on top while dragging + // (cyanophage) move to the end so they appear on top while dragging svg.insertBefore(selectedElement, svg.lastChild); svg.insertBefore(sibling, svg.lastChild); @@ -3734,7 +3760,7 @@ function makeDraggable(svg) { y = selectedElement.getAttributeNS(null, "y"); startx = x; starty = y; - // scan through rcdata to find out which key are we closest to + // (cyanophage) scan through rcdata to find out which key are we closest to closestdist = 9999; starti = -1; var keyname = ""; @@ -3784,7 +3810,7 @@ function makeDraggable(svg) { x = selectedElement.getAttributeNS(null, "x"); y = selectedElement.getAttributeNS(null, "y"); // console.log("drop at "+x+" "+y); - // scan through rcdata to find out which key are we closest to + // (cyanophage) scan through rcdata to find out which key are we closest to closestdist = 9999; let keyname = ""; for (let i = 0; i < rcdata_len; i++) { From 10d0a43a8e7e2e769e2fa16a8a20723e6154fb5e Mon Sep 17 00:00:00 2001 From: gaetan Date: Thu, 23 Apr 2026 14:17:40 +0200 Subject: [PATCH 07/17] Use const y_ with names, e.g. y_hard_words, to avoid confusion with global y --- keyboard_svg.js | 382 ++++++++++++++++++++++++++---------------------- 1 file changed, 211 insertions(+), 171 deletions(-) diff --git a/keyboard_svg.js b/keyboard_svg.js index c657a65..d2cdb65 100644 --- a/keyboard_svg.js +++ b/keyboard_svg.js @@ -872,7 +872,7 @@ function importLayout(layout) { console.log(`setting ${i} to *`); } } - + for (let i = 0; i < 34; i++) { // qwertyuiop-asdfghjkl;'zxcvbnm,./\^ - 34 for (let j = 0; j < 34; j++) { @@ -1039,6 +1039,7 @@ function getX(name, row, col) { return dx + col * w; } } + function getY(name, row, col) { return 10 + row * w; } @@ -1113,6 +1114,7 @@ function generateLayout() { } else { outlinewidth = 510; } + svg .append("rect") .attr("x", 45) @@ -1124,14 +1126,17 @@ function generateLayout() { .attr("fill-opactiy", "0.0") .attr("rx", 8) .attr("ry", 8); + for (let i = 0; i < rcdata_len; i++) { dtx = 0; letter = rcdata[i][0]; if (letter === "^") { letter = "shift"; } + x = rcdata[i][5]; y = rcdata[i][4]; + per = rcdata[i][3]; keywidth = rcdata[i][6]; red = Math.floor(127 * per * inv_default_max) + 128; @@ -1167,6 +1172,7 @@ function generateLayout() { .attr("stroke", "black") .attr("stroke-width", "1") .attr("class", "draggable"); + if (letter.length > 1 && mode !== "ergo") { svg .append("text") @@ -1189,7 +1195,7 @@ function generateLayout() { .text(letter); } } - + if (m_total_word_effort === 0) { // console.log("m_total_word_effort === 0") measureDictionary(); @@ -1356,12 +1362,12 @@ var m_column_usage = {}; var m_finger_usage = {}; var m_finger_distance = {}; var m_finger_pairs = {}; -var m_same_finger = {}; // per bigram +var m_same_finger = {}; // per bigram var m_same_finger2 = {}; // per finger var m_same_finger3 = {}; // per bigram 2u var m_skip_bigram = {}; var m_skip_bigram2 = {}; -var m_redirects = {}; +// var m_redirects = {}; var m_scissors = {}; var m_all_scissors = {}; var m_pinky_scissors = {}; @@ -1374,7 +1380,7 @@ var m_trigram_count_alt = {}; var m_trigram_count_red = {}; var m_trigram_count_roll_in = {}; var m_trigram_count_roll_out = {}; -var m_pinky_off = 0; +// var m_pinky_off = 0; var m_input_length = 0; var inv_m_input_length = 1; var m_effort = 0; @@ -1538,11 +1544,11 @@ function updateRcData(lan) { } } /* (cyanophage) - * my new idea for fixing this issue still didn't work - * the problem is that the keys that I want to change when switching languages aren't in a consistent position in the grid, or at a consistent position in the array, - * or have a consistent letter on them. Even the index I added to try to make them consistent didn't work because of the way the import process works - */ - if (lan === "german") { + * my new idea for fixing this issue still didn't work + * the problem is that the keys that I want to change when switching languages aren't in a consistent position in the grid, or at a consistent position in the array, + * or have a consistent letter on them. Even the index I added to try to make them consistent didn't work because of the way the import process works + */ + if (lan === "german") { // letters = ['q', 'w', 'e', 'r', 't', 'z', 'u', 'i', 'o', 'p', 'ü', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'ö', 'ä', 'y','x', 'c', 'v', 'b', 'n', 'm', ',', '.', '\'', 'ß'] if (getIndexOfKey(10) >= 0) { rcdata[getIndexOfKey(10)][0] = "ü"; @@ -1817,10 +1823,10 @@ function measureWords() { var m_effort_per_letter = {}; var m_effort_per_word = {}; var word_count = 0; + for (const word in words) { - if (word_count > 40000) { - break; - } + if (word_count > 40000) break; + word_count += 1; finger_pos = [ [0, 0], @@ -1835,6 +1841,7 @@ function measureWords() { [1, 9], [1, 10], ]; + const count = words[word]; word_len = word.length; m_input_length += count * (word_len + 1); @@ -1846,6 +1853,7 @@ function measureWords() { char = word.charAt(0); samehand = char; + for (let i = 0; i < word_len; i++) { char = word.charAt(i); if (i > 0) { @@ -2233,6 +2241,7 @@ function measureWords() { prevchar = char; prevfinger = finger; } + if (samehand.length >= 4) { if (!samehandstrings[samehand]) { samehandstrings[samehand] = 0; @@ -2244,19 +2253,22 @@ function measureWords() { } samehandcount[samehand.length] += count; } + inv_m_input_length = 1.0 / m_input_length; var scale = 1006393 * inv_m_input_length; m_total_word_effort *= scale; // console.log("word count "+word_count) - var sum = 0; + + let sum_freqs = 0; for (const letter in m_letter_freq) { - sum += m_letter_freq[letter]; + sum_freqs += m_letter_freq[letter]; } - const hundred_inv_sum = 100.0 / sum; + + const hundred_inv_sum_freqs = 100.0 / sum_freqs; for (const letter in m_letter_freq) { for (let i = 0; i < rcdata_len; i++) { if (rcdata[i][0] === letter) { - rcdata[i][3] = hundred_inv_sum * m_letter_freq[letter]; + rcdata[i][3] = hundred_inv_sum_freqs * m_letter_freq[letter]; } } } @@ -2276,7 +2288,7 @@ function generatePlots() { // ================================ C O L U M N U S A G E ================================ let x = 500; - let y = 0; + // let y_column_usage = 0; stats .append("text") .attr("x", x + 40) @@ -2292,6 +2304,7 @@ function generatePlots() { sum_col_usage += m_column_usage[col]; } const inv_sum_col_usage = 1.0 / sum_col_usage; + for (const col in m_column_usage) { const height = 300 * m_column_usage[col] * inv_sum_col_usage; const tip = parseFloat( @@ -2333,7 +2346,7 @@ function generatePlots() { // ================================ R O W U S A G E ================================ x = 770; - y = 0; + const y_row_usage = 0; stats .append("text") .attr("x", x + 40) @@ -2344,7 +2357,7 @@ function generatePlots() { .attr("text-anchor", "left") .text("Row Usage"); - var sum_row_usage = 0; + let sum_row_usage = 0; for (const row in m_row_usage) { sum_row_usage += m_row_usage[row]; } @@ -2369,7 +2382,7 @@ function generatePlots() { stats .append("rect") .attr("x", x + 19) - .attr("y", y + 40 + row * 20) + .attr("y", y_row_usage + 40 + row * 20) .attr("width", height) .attr("height", 14) .attr("fill", `#${hex_red}${hex_bg}${hex_bg}`) @@ -2380,7 +2393,7 @@ function generatePlots() { stats .append("text") .attr("x", x + 9) - .attr("y", y + 51 + row * 20) + .attr("y", y_row_usage + 51 + row * 20) .attr("fill", "#dfe2eb") .attr("font-size", 10) .attr("font-family", "Sans,Arial") @@ -2388,9 +2401,10 @@ function generatePlots() { .text(parseInt(row, 10) + 1); //\n" } + // ================================ F I N G E R U S A G E ================================ x = 0; - y = 0; + // let y_finger_usage = 0; stats .append("text") .attr("x", x + 40) @@ -2400,11 +2414,13 @@ function generatePlots() { .attr("fill", "#dfe2eb") .attr("text-anchor", "left") .text("Finger Usage"); - var sum = 0; + + let sum_finger_usage = 0; var left = 0; var right = 0; + for (const finger in m_finger_usage) { - sum += m_finger_usage[finger]; + sum_finger_usage += m_finger_usage[finger]; if (finger <= 4) { left += m_finger_usage[finger]; } @@ -2412,9 +2428,10 @@ function generatePlots() { right += m_finger_usage[finger]; } } - var inv_sum = 1.0 / sum; + const inv_sum_finger_usage = 1.0 / sum_finger_usage; + for (const finger in m_finger_usage) { - const norm_finger_usage = m_finger_usage[finger] * inv_sum; + const norm_finger_usage = m_finger_usage[finger] * inv_sum_finger_usage; const height = 300 * norm_finger_usage; const tip = parseFloat(100 * norm_finger_usage).toFixed(2); let red = Math.floor(275 * norm_finger_usage) + 128; @@ -2456,7 +2473,7 @@ function generatePlots() { .attr("font-size", 11) .attr("font-family", "Sans,Arial") .attr("text-anchor", "middle") - .text(`${parseFloat(100 * left * inv_sum).toFixed(2)}%`); + .text(`${parseFloat(100 * left * inv_sum_finger_usage).toFixed(2)}%`); stats .append("text") .attr("x", x + 177) @@ -2465,16 +2482,17 @@ function generatePlots() { .attr("font-size", 11) .attr("font-family", "Sans,Arial") .attr("text-anchor", "middle") - .text(`${parseFloat(100 * right * inv_sum).toFixed(2)}%`); + .text(`${parseFloat(100 * right * inv_sum_finger_usage).toFixed(2)}%`); + // ================================ F I N G E R D I S T A N C E ================================ x = 250; - y = 0; + // const y_finger_distance = 0; var max = m_input_length / 5.110882176; // (narglab) this might be shadowing 'max' above - sum = 0; + let sum_finger_distance = 0; left = 0; right = 0; for (const finger in m_finger_distance) { - sum += m_finger_distance[finger]; + sum_finger_distance += m_finger_distance[finger]; if (finger <= 4) { left += m_finger_distance[finger]; } @@ -2483,7 +2501,7 @@ function generatePlots() { } } var inv_max = 1.0 / max; - inv_sum = 1.0 / sum; + const inv_sum_finger_distance = 1.0 / sum_finger_distance; stats .append("text") .attr("x", x + 40) @@ -2539,7 +2557,7 @@ function generatePlots() { .attr("font-size", 11) .attr("font-family", "Sans,Arial") .attr("text-anchor", "middle") - .text(`${parseFloat(100 * left * inv_sum).toFixed(2)}%`); + .text(`${parseFloat(100 * left * inv_sum_finger_distance).toFixed(2)}%`); stats .append("text") .attr("x", x + 177) @@ -2548,7 +2566,7 @@ function generatePlots() { .attr("font-size", 11) .attr("font-family", "Sans,Arial") .attr("text-anchor", "middle") - .text(`${parseFloat(100 * right * inv_sum).toFixed(2)}%`); + .text(`${parseFloat(100 * right * inv_sum_finger_distance).toFixed(2)}%`); stats .append("text") .attr("x", x + 117) @@ -2557,18 +2575,18 @@ function generatePlots() { .attr("font-size", 11) .attr("font-family", "Sans,Arial") .attr("text-anchor", "middle") - .text(parseFloat(100 * sum * inv_max).toFixed(1)); - // (100*sum/max).toFixed(1) + .text(parseFloat(100 * sum_finger_distance * inv_max).toFixed(1)); + // ================================ S A M E F I N G E R B I G R A M S ================================ x = 0; - y = 180; - sum = 0; + const y_same_fb = 180; + let sum_sfb = 0; // toggle button stats .append("path") .attr( "d", - `M ${x + 15} ${y - 24} L ${x + 35} ${y - 24} L ${x + 25} ${y - 34} Z`, + `M ${x + 15} ${y_same_fb - 24} L ${x + 35} ${y_same_fb - 24} L ${x + 25} ${y_same_fb - 34} Z`, ) .attr("fill", "#777777") .attr("stroke", "#989898") @@ -2590,7 +2608,7 @@ function generatePlots() { .append("path") .attr( "d", - `M ${x + 15} ${y - 20} L ${x + 35} ${y - 20} L ${x + 25} ${y - 10} Z`, + `M ${x + 15} ${y_same_fb - 20} L ${x + 35} ${y_same_fb - 20} L ${x + 25} ${y_same_fb - 10} Z`, ) .attr("fill", "#777777") .attr("stroke", "#989898") @@ -2613,24 +2631,26 @@ function generatePlots() { m_same_finger = Object.fromEntries(keyValueArray); for (const bigram in m_same_finger) { - sum += m_same_finger[bigram] * inv_m_input_length; + sum_sfb += m_same_finger[bigram] * inv_m_input_length; } + stats .append("text") .attr("x", x + 40) - .attr("y", y - 16) + .attr("y", y_same_fb - 16) .attr("font-size", 16) .attr("font-family", "Sans,Arial") .attr("fill", "#dfe2eb") .attr("text-anchor", "left") - .text(`Same Finger Bigrams ${parseFloat(100 * sum).toFixed(2)}%`); + .text(`Same Finger Bigrams ${parseFloat(100 * sum_sfb).toFixed(2)}%`); // stats.append("text").attr("x",x+40).attr("y",y+200).attr("font-size",16).attr("font-family","Sans,Arial").attr("fill","#dfe2eb").attr("text-anchor","left").text("Input Length "+m_input_length); - let i = 0; - let t = scroll_amount; + let plot_i = 0; + let plot_t = scroll_amount; + for (const bigram in m_same_finger) { - if (t > 0) { - t -= 1; + if (plot_t > 0) { + plot_t -= 1; continue; } let width = 18000 * m_same_finger[bigram] * inv_m_input_length; @@ -2640,7 +2660,7 @@ function generatePlots() { stats .append("rect") .attr("x", x + 40) - .attr("y", y + i * 15) + .attr("y", y_same_fb + plot_i * 15) .attr("width", width) .attr("height", 10) .attr("fill", "#7777bb") @@ -2649,7 +2669,7 @@ function generatePlots() { stats .append("text") .attr("x", x + 20) - .attr("y", y + i * 15 + 8) + .attr("y", y_same_fb + plot_i * 15 + 8) .attr("fill", "#dfe2eb") .attr("font-size", 10) .attr("font-family", "Roboto Mono") @@ -2658,7 +2678,7 @@ function generatePlots() { stats .append("text") .attr("x", x + 200) - .attr("y", y + i * 15 + 8) + .attr("y", y_same_fb + plot_i * 15 + 8) .attr("fill", "#dfe2eb") .attr("font-size", 10) .attr("font-family", "Sans,Arial") @@ -2669,24 +2689,25 @@ function generatePlots() { ).toFixed(2)}%`, ); //\n" - i += 1; - if (i > 10) { + plot_i += 1; + if (plot_i > 10) { break; } } } else if (sfb_toggle === 1) { for (const finger in m_same_finger2) { - sum += m_same_finger2[finger] * inv_m_input_length; + sum_sfb += m_same_finger2[finger] * inv_m_input_length; } stats .append("text") .attr("x", x + 40) - .attr("y", y - 16) + .attr("y", y_same_fb - 16) .attr("font-size", 16) .attr("font-family", "Sans,Arial") .attr("fill", "#dfe2eb") .attr("text-anchor", "left") - .text(`Same Finger Bigrams ${parseFloat(100 * sum).toFixed(2)}%`); + .text(`Same Finger Bigrams ${parseFloat(100 * sum_sfb).toFixed(2)}%`); + for (const finger in m_same_finger2) { let height = 30000 * m_same_finger2[finger] * inv_m_input_length; if (height > 150) { @@ -2709,7 +2730,7 @@ function generatePlots() { stats .append("rect") .attr("x", x + finger * 20) - .attr("y", y + 155 - height) + .attr("y", y_same_fb + 155 - height) .attr("width", 15) .attr("height", height) .attr("fill", `#${hex_red}${hex_bg}${hex_bg}`) @@ -2721,7 +2742,7 @@ function generatePlots() { stats .append("text") .attr("x", x + finger * 20 + 7) - .attr("y", y + 166) + .attr("y", y_same_fb + 166) .attr("fill", "#dfe2eb") .attr("font-size", 10) .attr("font-family", "Sans,Arial") @@ -2734,24 +2755,24 @@ function generatePlots() { m_same_finger3 = Object.fromEntries(keyValueArray); for (const bigram in m_same_finger3) { - sum += m_same_finger3[bigram] * inv_m_input_length; + sum_sfb += m_same_finger3[bigram] * inv_m_input_length; } stats .append("text") .attr("x", x + 40) - .attr("y", y - 16) + .attr("y", y_same_fb - 16) .attr("font-size", 16) .attr("font-family", "Sans,Arial") .attr("fill", "#dfe2eb") .attr("text-anchor", "left") - .text(`2u Same Finger Bigrams ${parseFloat(100 * sum).toFixed(2)}%`); + .text(`2u Same Finger Bigrams ${parseFloat(100 * sum_sfb).toFixed(2)}%`); // stats.append("text").attr("x",x+40).attr("y",y+200).attr("font-size",16).attr("font-family","Sans,Arial").attr("fill","#dfe2eb").attr("text-anchor","left").text("Input Length "+m_input_length); - let i = 0; - let t = scroll_amount; + plot_i = 0; + plot_t = scroll_amount; for (const bigram in m_same_finger3) { - if (t > 0) { - t -= 1; + if (plot_t > 0) { + plot_t -= 1; continue; } let width = 18000 * m_same_finger3[bigram] * inv_m_input_length; @@ -2761,7 +2782,7 @@ function generatePlots() { stats .append("rect") .attr("x", x + 40) - .attr("y", y + i * 15) + .attr("y", y_same_fb + plot_i * 15) .attr("width", width) .attr("height", 10) .attr("fill", "#7777bb") @@ -2770,7 +2791,7 @@ function generatePlots() { stats .append("text") .attr("x", x + 20) - .attr("y", y + i * 15 + 8) + .attr("y", y_same_fb + plot_i * 15 + 8) .attr("fill", "#dfe2eb") .attr("font-size", 10) .attr("font-family", "Roboto Mono") @@ -2779,7 +2800,7 @@ function generatePlots() { stats .append("text") .attr("x", x + 200) - .attr("y", y + i * 15 + 8) + .attr("y", y_same_fb + plot_i * 15 + 8) .attr("fill", "#dfe2eb") .attr("font-size", 10) .attr("font-family", "Sans,Arial") @@ -2790,56 +2811,56 @@ function generatePlots() { ).toFixed(2)}%`, ); //\n" - i += 1; - if (i > 10) { + plot_i += 1; + if (plot_i > 10) { break; } } } // ================================ S K I P F I N G E R B I G R A M S ================================ x = 250; - y = 180; - sum = 0; + const y_skip_fb = 180; + let sum_skip_fb = 0; var tmp; if (skip_toggle) { const keyValueArray = Object.entries(m_skip_bigram); keyValueArray.sort((a, b) => b[1] - a[1]); tmp = Object.fromEntries(keyValueArray); for (const bigram in tmp) { - sum += tmp[bigram] * inv_m_input_length; + sum_skip_fb += tmp[bigram] * inv_m_input_length; } stats .append("text") .attr("x", x + 40) - .attr("y", y - 16) + .attr("y", y_skip_fb - 16) .attr("font-size", 16) .attr("font-family", "Sans,Arial") .attr("fill", "#dfe2eb") .attr("text-anchor", "left") - .text(`Skip Bigrams ${parseFloat(100 * sum).toFixed(2)}%`); + .text(`Skip Bigrams ${parseFloat(100 * sum_skip_fb).toFixed(2)}%`); } else { const keyValueArray = Object.entries(m_skip_bigram2); keyValueArray.sort((a, b) => b[1] - a[1]); tmp = Object.fromEntries(keyValueArray); for (const bigram in tmp) { - sum += tmp[bigram] * inv_m_input_length; + sum_skip_fb += tmp[bigram] * inv_m_input_length; } stats .append("text") .attr("x", x + 40) - .attr("y", y - 16) + .attr("y", y_skip_fb - 16) .attr("font-size", 16) .attr("font-family", "Sans,Arial") .attr("fill", "#dfe2eb") .attr("text-anchor", "left") - .text(`Skip Bigrams (2u) ${parseFloat(100 * sum).toFixed(2)}%`); + .text(`Skip Bigrams (2u) ${parseFloat(100 * sum_skip_fb).toFixed(2)}%`); } stats .append("path") .attr( "d", - `M ${x + 15} ${y - 24} L ${x + 35} ${y - 24} L ${x + 25} ${y - 34} Z`, + `M ${x + 15} ${y_skip_fb - 24} L ${x + 35} ${y_skip_fb - 24} L ${x + 25} ${y_skip_fb - 34} Z`, ) .attr("fill", "#777777") .attr("stroke", "#989898") @@ -2861,7 +2882,7 @@ function generatePlots() { .append("path") .attr( "d", - `M ${x + 15} ${y - 20} L ${x + 35} ${y - 20} L ${x + 25} ${y - 10} Z`, + `M ${x + 15} ${y_skip_fb - 20} L ${x + 35} ${y_skip_fb - 20} L ${x + 25} ${y_skip_fb - 10} Z`, ) .attr("fill", "#777777") .attr("stroke", "#989898") @@ -2878,11 +2899,12 @@ function generatePlots() { .on("mouseout", function () { d3.select(this).attr("fill", "#777777"); }); - var i = 0; - var t = scroll_amount; + + plot_i = 0; + plot_t = scroll_amount; for (const bigram in tmp) { - if (t > 0) { - t -= 1; + if (plot_t > 0) { + plot_t -= 1; continue; } let height = 36000 * tmp[bigram] * inv_m_input_length; @@ -2892,7 +2914,7 @@ function generatePlots() { stats .append("rect") .attr("x", x + 40) - .attr("y", y + i * 15) + .attr("y", y_skip_fb + plot_i * 15) .attr("width", height) .attr("height", 10) .attr("fill", "#7777bb") @@ -2901,7 +2923,7 @@ function generatePlots() { stats .append("text") .attr("x", x + 17) - .attr("y", y + i * 15 + 8) + .attr("y", y_skip_fb + plot_i * 15 + 8) .attr("fill", "#dfe2eb") .attr("font-size", 10) .attr("font-family", "Roboto Mono") @@ -2910,7 +2932,7 @@ function generatePlots() { stats .append("text") .attr("x", x + 200) - .attr("y", y + i * 15 + 8) + .attr("y", y_skip_fb + plot_i * 15 + 8) .attr("fill", "#dfe2eb") .attr("font-size", 10) .attr("font-family", "Sans,Arial") @@ -2920,14 +2942,15 @@ function generatePlots() { "%", ); //\n" - i += 1; - if (i > 10) { + plot_i += 1; + if (plot_i > 10) { break; } } + // ================================ L A T E R A L S T R E T C H B I G R A M S ================================ x = 500; - y = 180; + const y_lat_sb = 180; sum = 0; if (lsb_toggle === 0) { const keyValueArray = Object.entries(m_lat_stretch); @@ -2939,7 +2962,7 @@ function generatePlots() { stats .append("text") .attr("x", x + 40) - .attr("y", y - 16) + .attr("y", y_lat_sb - 16) .attr("font-size", 16) .attr("font-family", "Sans,Arial") .attr("fill", "#dfe2eb") @@ -2955,7 +2978,7 @@ function generatePlots() { stats .append("text") .attr("x", x + 40) - .attr("y", y - 16) + .attr("y", y_lat_sb - 16) .attr("font-size", 16) .attr("font-family", "Sans,Arial") .attr("fill", "#dfe2eb") @@ -2967,7 +2990,7 @@ function generatePlots() { .append("path") .attr( "d", - `M ${x + 15} ${y - 24} L ${x + 35} ${y - 24} L ${x + 25} ${y - 34} Z`, + `M ${x + 15} ${y_lat_sb - 24} L ${x + 35} ${y_lat_sb - 24} L ${x + 25} ${y_lat_sb - 34} Z`, ) .attr("fill", "#777777") .attr("stroke", "#989898") @@ -2989,7 +3012,7 @@ function generatePlots() { .append("path") .attr( "d", - `M ${x + 15} ${y - 20} L ${x + 35} ${y - 20} L ${x + 25} ${y - 10} Z`, + `M ${x + 15} ${y_lat_sb - 20} L ${x + 35} ${y_lat_sb - 20} L ${x + 25} ${y_lat_sb - 10} Z`, ) .attr("fill", "#777777") .attr("stroke", "#989898") @@ -3006,11 +3029,12 @@ function generatePlots() { .on("mouseout", function () { d3.select(this).attr("fill", "#777777"); }); - var i = 0; - var t = scroll_amount; + + plot_i = 0; + t = scroll_amount; for (const bigram in tmp) { - if (t > 0) { - t -= 1; + if (plot_t > 0) { + plot_t -= 1; continue; } let height = 10000 * tmp[bigram] * inv_m_input_length; @@ -3020,7 +3044,7 @@ function generatePlots() { stats .append("rect") .attr("x", x + 40) - .attr("y", y + i * 15) + .attr("y", y_lat_sb + plot_i * 15) .attr("width", height) .attr("height", 10) .attr("fill", "#7777bb") @@ -3029,7 +3053,7 @@ function generatePlots() { stats .append("text") .attr("x", x + 20) - .attr("y", y + i * 15 + 8) + .attr("y", y_lat_sb + plot_i * 15 + 8) .attr("fill", "#dfe2eb") .attr("font-size", 10) .attr("font-family", "Roboto Mono") @@ -3038,7 +3062,7 @@ function generatePlots() { stats .append("text") .attr("x", x + 200) - .attr("y", y + i * 15 + 8) + .attr("y", y_lat_sb + plot_i * 15 + 8) .attr("fill", "#dfe2eb") .attr("font-size", 10) .attr("font-family", "Sans,Arial") @@ -3048,14 +3072,15 @@ function generatePlots() { "%", ); //\n" - i += 1; - if (i > 10) { + plot_i += 1; + if (plot_i > 10) { break; } } + // ================================ S C I S S O R S ================================ x = 760; - y = 180; + const y_scissors = 180; sum = 0; if (scissors_toggle === 1) { @@ -3068,7 +3093,7 @@ function generatePlots() { stats .append("text") .attr("x", x + 40) - .attr("y", y - 16) + .attr("y", y_scissors - 16) .attr("font-size", 16) .attr("font-family", "Sans,Arial") .attr("fill", "#dfe2eb") @@ -3084,7 +3109,7 @@ function generatePlots() { stats .append("text") .attr("x", x + 40) - .attr("y", y - 16) + .attr("y", y_scissors - 16) .attr("font-size", 16) .attr("font-family", "Sans,Arial") .attr("fill", "#dfe2eb") @@ -3100,7 +3125,7 @@ function generatePlots() { stats .append("text") .attr("x", x + 40) - .attr("y", y - 16) + .attr("y", y_scissors - 16) .attr("font-size", 16) .attr("font-family", "Sans,Arial") .attr("fill", "#dfe2eb") @@ -3111,7 +3136,7 @@ function generatePlots() { .append("path") .attr( "d", - `M ${x + 15} ${y - 24} L ${x + 35} ${y - 24} L ${x + 25} ${y - 34} Z`, + `M ${x + 15} ${y_scissors - 24} L ${x + 35} ${y_scissors - 24} L ${x + 25} ${y_scissors - 34} Z`, ) .attr("fill", "#777777") .attr("stroke", "#989898") @@ -3133,7 +3158,7 @@ function generatePlots() { .append("path") .attr( "d", - `M ${x + 15} ${y - 20} L ${x + 35} ${y - 20} L ${x + 25} ${y - 10} Z`, + `M ${x + 15} ${y_scissors - 20} L ${x + 35} ${y_scissors - 20} L ${x + 25} ${y_scissors - 10} Z`, ) .attr("fill", "#777777") .attr("stroke", "#989898") @@ -3150,8 +3175,9 @@ function generatePlots() { .on("mouseout", function () { d3.select(this).attr("fill", "#777777"); }); - var i = 0; - var t = scroll_amount; + + plot_i = 0; + plot_t = scroll_amount; for (const bigram in tmp) { if (t > 0) { t -= 1; @@ -3164,7 +3190,7 @@ function generatePlots() { stats .append("rect") .attr("x", x + 40) - .attr("y", y + i * 15) + .attr("y", y_scissors + plot_i * 15) .attr("width", height) .attr("height", 10) .attr("fill", "#7777bb") @@ -3173,7 +3199,7 @@ function generatePlots() { stats .append("text") .attr("x", x + 20) - .attr("y", y + i * 15 + 8) + .attr("y", y_scissors + plot_i * 15 + 8) .attr("fill", "#dfe2eb") .attr("font-size", 10) .attr("font-family", "Roboto Mono") @@ -3182,7 +3208,7 @@ function generatePlots() { stats .append("text") .attr("x", x + 190) - .attr("y", y + i * 15 + 8) + .attr("y", y_scissors + plot_i * 15 + 8) .attr("fill", "#dfe2eb") .attr("font-size", 10) .attr("font-family", "Sans,Arial") @@ -3192,15 +3218,15 @@ function generatePlots() { "%", ); //\n" - i += 1; - if (i > 10) { + plot_i += 1; + if (plot_i > 10) { break; } } // ================================ T R I G R A M S T A T S ================================ x = 760; - y = 390; + const y_trigram = 390; dx = 105; sum = 0; scale = 1; @@ -3289,7 +3315,7 @@ function generatePlots() { .append("path") .attr( "d", - `M ${x + 15} ${y - 20} L ${x + 35} ${y - 20} L ${x + 25} ${y - 10} Z`, + `M ${x + 15} ${y_trigram - 20} L ${x + 35} ${y_trigram - 20} L ${x + 25} ${y_trigram - 10} Z`, ) .attr("fill", "#777777") .attr("stroke", "#989898") @@ -3311,7 +3337,7 @@ function generatePlots() { .append("path") .attr( "d", - `M ${x + 15} ${y - 24} L ${x + 35} ${y - 24} L ${x + 25} ${y - 34} Z`, + `M ${x + 15} ${y_trigram - 24} L ${x + 35} ${y_trigram - 24} L ${x + 25} ${y_trigram - 34} Z`, ) .attr("fill", "#777777") .attr("stroke", "#989898") @@ -3332,16 +3358,17 @@ function generatePlots() { stats .append("text") .attr("x", x + 40) - .attr("y", y - 16) + .attr("y", y_trigram - 16) .attr("font-size", 16) .attr("font-family", "Sans,Arial") .attr("fill", "#dfe2eb") .attr("text-anchor", "left") .text(trigram_title); - var i = 0; - var t = trigram_scroll_amount; + plot_i = 0; + plot_t = trigram_scroll_amount; inv_sum = 1.0 / sum; + for (const cat in tmp) { if (t > 0) { t -= 1; @@ -3355,7 +3382,7 @@ function generatePlots() { stats .append("rect") .attr("x", x + dx) - .attr("y", y + i * 15) + .attr("y", y_trigram + plot_i * 15) .attr("width", width) .attr("height", 10) .attr("fill", "#7777bb") @@ -3366,7 +3393,7 @@ function generatePlots() { stats .append("text") .attr("x", x + 20) - .attr("y", y + i * 15 + 8) + .attr("y", y_trigram + plot_i * 15 + 8) .attr("fill", "#dfe2eb") .attr("font-size", 9) .attr("font-family", "Roboto Mono") @@ -3375,22 +3402,22 @@ function generatePlots() { stats .append("text") .attr("x", x + 190) - .attr("y", y + i * 15 + 8) + .attr("y", y_trigram + plot_i * 15 + 8) .attr("fill", "#dfe2eb") .attr("font-size", 10) .attr("font-family", "Sans,Arial") .attr("text-anchor", "left") .text(`${parseFloat(`${100 * tmp_cat_inv_sum}`).toFixed(2)}%`); //\n" - i += 1; - if (i > 10) { + plot_i += 1; + if (plot_i > 10) { break; } } // ================================ S A M E H A N D S T R I N G S ================================ x = 250; - y = 390; + const y_same_hand_strings = 390; sum = 0; var keyValueArray = Object.entries(samehandstrings); @@ -3403,17 +3430,18 @@ function generatePlots() { stats .append("text") .attr("x", x + 20) - .attr("y", y - 16) + .attr("y", y_same_hand_strings - 16) .attr("font-size", 16) .attr("font-family", "Sans,Arial") .attr("fill", "#dfe2eb") .attr("text-anchor", "left") .text("Same Hand Strings"); - var i = 0; - t = sh_scroll_amount; + + plot_i = 0; + plot_t = sh_scroll_amount; for (const word in samehandstrings) { - if (t > 0) { - t -= 1; + if (plot_t > 0) { + plot_t -= 1; continue; } const count = samehandstrings[word]; @@ -3427,7 +3455,7 @@ function generatePlots() { stats .append("rect") .attr("x", x + 70) - .attr("y", y + i * 15) + .attr("y", y_same_hand_strings + plot_i * 15) .attr("width", width) .attr("height", 10) .attr("fill", "#7777bb") @@ -3436,7 +3464,7 @@ function generatePlots() { stats .append("text") .attr("x", x + 20) - .attr("y", y + i * 15 + 8) + .attr("y", y_same_hand_strings + plot_i * 15 + 8) .attr("fill", "#dfe2eb") .attr("font-size", 10) .attr("font-family", "Roboto Mono") @@ -3445,21 +3473,21 @@ function generatePlots() { stats .append("text") .attr("x", x + 135) - .attr("y", y + i * 15 + 8) + .attr("y", y_same_hand_strings + plot_i * 15 + 8) .attr("fill", "#dfe2eb") .attr("font-size", 10) .attr("font-family", "Sans,Arial") .attr("text-anchor", "left") .text(parseFloat(`${word_len_count}`).toFixed(0)); - i += 1; - if (i > 10) { + plot_i += 1; + if (plot_i > 10) { break; } } // ================================ S A M E H A N D C O U N T S ================================ x = 415; - y = 390; + const y_same_hand_counts = 390; sum = 0; // var keyValueArray = Object.entries(samehandcount); @@ -3471,13 +3499,13 @@ function generatePlots() { stats .append("text") .attr("x", x + 20) - .attr("y", y - 16) + .attr("y", y_same_hand_counts - 16) .attr("font-size", 16) .attr("font-family", "Sans,Arial") .attr("fill", "#dfe2eb") .attr("text-anchor", "left") .text("Same Hand Count"); - var i = 0; + plot_i = 0; for (const len in samehandcount) { const count = samehandcount[len]; let width = scale * count; @@ -3487,7 +3515,7 @@ function generatePlots() { stats .append("rect") .attr("x", x + 40) - .attr("y", y + i * 15) + .attr("y", y_same_hand_counts + plot_i * 15) .attr("width", width) .attr("height", 10) .attr("fill", "#7777bb") @@ -3496,7 +3524,7 @@ function generatePlots() { stats .append("text") .attr("x", x + 20) - .attr("y", y + i * 15 + 8) + .attr("y", y_same_hand_counts + plot_i * 15 + 8) .attr("fill", "#dfe2eb") .attr("font-size", 10) .attr("font-family", "Roboto Mono") @@ -3505,37 +3533,40 @@ function generatePlots() { stats .append("text") .attr("x", x + 135) - .attr("y", y + i * 15 + 8) + .attr("y", y_same_hand_counts + plot_i * 15 + 8) .attr("fill", "#dfe2eb") .attr("font-size", 10) .attr("font-family", "Sans,Arial") .attr("text-anchor", "left") .text((scale * 7.142857142857143 * count).toFixed(1)); // (narglab) was 7.14285714285714285714285, lint/correctness/noPrecisionLoss // stats.append("text").attr("x", x + 135).attr("y", y + i * 15 + 8).attr("fill", "#dfe2eb").attr("font-size", 10).attr("font-family", "Sans,Arial").attr("text-anchor", "left").text(count); - i += 1; - if (i > 10) { + plot_i += 1; + if (plot_i > 10) { break; } } // ================================ H A R D W O R D S ================================ x = 580; - y = 390; + const y_hard_words = 390; sum = 0; + var keyValueArray = Object.entries(word_effort); keyValueArray.sort((a, b) => b[1] / b[0].length - a[1] / a[0].length); word_effort = Object.fromEntries(keyValueArray); stats .append("text") .attr("x", x + 40) - .attr("y", y - 16) + .attr("y", y_hard_words - 16) .attr("font-size", 16) .attr("font-family", "Sans,Arial") .attr("fill", "#dfe2eb") .attr("text-anchor", "left") .text("Hard Words "); - var i = 0; - t = hw_scroll_amount; + + plot_i = 0; + plot_t = hw_scroll_amount; + for (const word in word_effort) { word_len = word.length; if (word_len > 3 && words[word] > 4) { @@ -3547,7 +3578,7 @@ function generatePlots() { stats .append("rect") .attr("x", x + 80) - .attr("y", y + i * 15) + .attr("y", y_hard_words + plot_i * 15) .attr("width", height) .attr("height", 10) .attr("fill", "#7777bb") @@ -3556,7 +3587,7 @@ function generatePlots() { stats .append("text") .attr("x", x + 20) - .attr("y", y + i * 15 + 8) + .attr("y", y_hard_words + plot_i * 15 + 8) .attr("fill", "#dfe2eb") .attr("font-size", 10) .attr("font-family", "Roboto Mono") @@ -3565,20 +3596,21 @@ function generatePlots() { stats .append("text") .attr("x", x + 165) - .attr("y", y + i * 15 + 8) + .attr("y", y_hard_words + plot_i * 15 + 8) .attr("fill", "#dfe2eb") .attr("font-size", 10) .attr("font-family", "Sans,Arial") .attr("text-anchor", "left") .text(parseFloat(`${word_effort[word]}`).toFixed(2)); - i += 1; - if (i > 10) { + plot_i += 1; + if (plot_i > 10) { break; } } } + // ================================ E A S Y W O R D S ================================ - /* + /* var x = 610; var y = 390; sum = 0; @@ -3602,13 +3634,15 @@ function generatePlots() { // ================================ F I N G E R P A I R S ================================ x = 10; - y = 370; + const y_finger_pairs = 370; var box_x = 26; var box_y = 20; var per = 0; - var finger1 = i; - var finger2 = j; - var sum = 0; + + let finger1 = plot_i; + let finger2 = j; + + let sum_finger_pairs = 0; stats .append("text") .attr("x", 0) @@ -3617,19 +3651,25 @@ function generatePlots() { .attr("font-family", "Sans,Arial") .attr("fill", "#dfe2eb") .attr("text-anchor", "middle") - .attr("transform", `translate(${x + 2},${y + 100}) rotate(-90)`) + .attr( + "transform", + `translate(${x + 2},${y_finger_pairs + 100}) rotate(-90)`, + ) .text("First Finger"); stats .append("text") .attr("x", x + 130) - .attr("y", y) + .attr("y", y_finger_pairs) .attr("font-size", 10) .attr("font-family", "Sans,Arial") .attr("fill", "#dfe2eb") .attr("text-anchor", "middle") .text("Second Finger"); - for (var i = 0; i <= 8; i++) { - sum = 0; + + plot_i = 0; + + for (let i = 0; i <= 8; i++) { + sum_finger_pairs = 0; for (var j = 1; j <= 8; j++) { finger1 = i; finger2 = j; @@ -3641,7 +3681,7 @@ function generatePlots() { } if (m_finger_pairs[finger1]) { if (m_finger_pairs[finger1][finger2]) { - sum += m_finger_pairs[finger1][finger2]; + sum_finger_pairs += m_finger_pairs[finger1][finger2]; } } } @@ -3659,7 +3699,7 @@ function generatePlots() { stats .append("text") .attr("x", x + box_x * j + 14) - .attr("y", y + box_y * i + 14) + .attr("y", y_finger_pairs + box_y * i + 14) .attr("font-size", 10) .attr("font-family", "Sans,Arial") .attr("fill", "#dfe2eb") @@ -3669,7 +3709,7 @@ function generatePlots() { stats .append("text") .attr("x", x + box_x * j + 14) - .attr("y", y + box_y * i + 14) + .attr("y", y_finger_pairs + box_y * i + 14) .attr("font-size", 10) .attr("font-family", "Sans,Arial") .attr("fill", "#dfe2eb") @@ -3678,9 +3718,9 @@ function generatePlots() { } else { if (m_finger_pairs[finger1]) { if (m_finger_pairs[finger1][finger2]) { - if (sum > 0) { + if (sum_finger_pairs > 0) { per = parseFloat( - (100 * m_finger_pairs[finger1][finger2]) / sum, + (100 * m_finger_pairs[finger1][finger2]) / sum_finger_pairs, ).toFixed(0); } else { per = -1; @@ -3694,7 +3734,7 @@ function generatePlots() { stats .append("rect") .attr("x", x + box_x * j) - .attr("y", y + box_y * i) + .attr("y", y_finger_pairs + box_y * i) .attr("width", box_x) .attr("height", box_y) .attr("fill", `#${hex_red}${hex_bg}${hex_bg}`) @@ -3703,7 +3743,7 @@ function generatePlots() { stats .append("text") .attr("x", x + box_x * j + 14) - .attr("y", y + box_y * i + 14) + .attr("y", y_finger_pairs + box_y * i + 14) .attr("font-size", 10) .attr("font-family", "Sans,Arial") .attr("fill", "black") From a8d7c3e7a0cd1a2a551caaebbe44393acf933fe0 Mon Sep 17 00:00:00 2001 From: gaetan Date: Thu, 23 Apr 2026 14:22:50 +0200 Subject: [PATCH 08/17] Remove unused parameters from getY() --- keyboard_svg.js | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/keyboard_svg.js b/keyboard_svg.js index d2cdb65..4ff3d15 100644 --- a/keyboard_svg.js +++ b/keyboard_svg.js @@ -1040,7 +1040,7 @@ function getX(name, row, col) { } } -function getY(name, row, col) { +function getY(row) { return 10 + row * w; } @@ -1094,7 +1094,7 @@ function dist(x1, y1, x2, y2) { function generateCoords() { console.log("generateCoords"); for (let i = 0; i < rcdata_len; i++) { - rcdata[i][4] = getY(rcdata[i][0], rcdata[i][1], rcdata[i][2]); // Y + rcdata[i][4] = getY(rcdata[i][1]); // Y rcdata[i][5] = getX(rcdata[i][0], rcdata[i][1], rcdata[i][2]); // X } } @@ -1918,16 +1918,14 @@ function measureWords() { } // d = dist(col, row, finger_pos[finger][1], finger_pos[finger][0]); x1 = getX(char, row, col); - y1 = getY(char, row, col); + y1 = getY(row); x2 = getX( getChar(finger_pos[finger][0], finger_pos[finger][1]), finger_pos[finger][0], finger_pos[finger][1], ); y2 = getY( - getChar(finger_pos[finger][0], finger_pos[finger][1]), finger_pos[finger][0], - finger_pos[finger][1], ); d = dist(x1, y1, x2, y2); if (!m_finger_distance[finger]) { @@ -3667,10 +3665,11 @@ function generatePlots() { .text("Second Finger"); plot_i = 0; + var j = 1; for (let i = 0; i <= 8; i++) { sum_finger_pairs = 0; - for (var j = 1; j <= 8; j++) { + for (j = 1; j <= 8; j++) { finger1 = i; finger2 = j; if (i > 4) { @@ -3685,7 +3684,7 @@ function generatePlots() { } } } - for (var j = 0; j <= 8; j++) { + for (j = 0; j <= 8; j++) { finger1 = i; finger2 = j; if (i > 4) { @@ -3803,7 +3802,7 @@ function makeDraggable(svg) { // (cyanophage) scan through rcdata to find out which key are we closest to closestdist = 9999; starti = -1; - var keyname = ""; + let keyname = ""; for (let i = 0; i < rcdata_len; i++) { d = dist(x, y, rcdata[i][5], rcdata[i][4]); if (d < closestdist) { From 68e264e6184809107247ac31703e37d4bea73606 Mon Sep 17 00:00:00 2001 From: gaetan Date: Thu, 23 Apr 2026 14:28:28 +0200 Subject: [PATCH 09/17] Rename key-value arrays and make them const --- keyboard_svg.js | 98 ++++++++++++++++++++++++------------------------- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/keyboard_svg.js b/keyboard_svg.js index 4ff3d15..6ab0cb7 100644 --- a/keyboard_svg.js +++ b/keyboard_svg.js @@ -1925,7 +1925,7 @@ function measureWords() { finger_pos[finger][1], ); y2 = getY( - finger_pos[finger][0], + finger_pos[finger][0] ); d = dist(x1, y1, x2, y2); if (!m_finger_distance[finger]) { @@ -2624,9 +2624,9 @@ function generatePlots() { d3.select(this).attr("fill", "#777777"); }); if (sfb_toggle === 0) { - const keyValueArray = Object.entries(m_same_finger); - keyValueArray.sort((a, b) => b[1] - a[1]); - m_same_finger = Object.fromEntries(keyValueArray); + const keyValueArray_same_finger = Object.entries(m_same_finger); + keyValueArray_same_finger.sort((a, b) => b[1] - a[1]); + m_same_finger = Object.fromEntries(keyValueArray_same_finger); for (const bigram in m_same_finger) { sum_sfb += m_same_finger[bigram] * inv_m_input_length; @@ -2748,9 +2748,9 @@ function generatePlots() { .text(finger); } } else { - const keyValueArray = Object.entries(m_same_finger3); - keyValueArray.sort((a, b) => b[1] - a[1]); - m_same_finger3 = Object.fromEntries(keyValueArray); + const keyValueArray_same_finger3 = Object.entries(m_same_finger3); + keyValueArray_same_finger3.sort((a, b) => b[1] - a[1]); + m_same_finger3 = Object.fromEntries(keyValueArray_same_finger3); for (const bigram in m_same_finger3) { sum_sfb += m_same_finger3[bigram] * inv_m_input_length; @@ -2821,9 +2821,9 @@ function generatePlots() { let sum_skip_fb = 0; var tmp; if (skip_toggle) { - const keyValueArray = Object.entries(m_skip_bigram); - keyValueArray.sort((a, b) => b[1] - a[1]); - tmp = Object.fromEntries(keyValueArray); + const keyValueArray_skip_bigram = Object.entries(m_skip_bigram); + keyValueArray_skip_bigram.sort((a, b) => b[1] - a[1]); + tmp = Object.fromEntries(keyValueArray_skip_bigram); for (const bigram in tmp) { sum_skip_fb += tmp[bigram] * inv_m_input_length; } @@ -2837,9 +2837,9 @@ function generatePlots() { .attr("text-anchor", "left") .text(`Skip Bigrams ${parseFloat(100 * sum_skip_fb).toFixed(2)}%`); } else { - const keyValueArray = Object.entries(m_skip_bigram2); - keyValueArray.sort((a, b) => b[1] - a[1]); - tmp = Object.fromEntries(keyValueArray); + const keyValueArray_skip_bigram2 = Object.entries(m_skip_bigram2); + keyValueArray_skip_bigram2.sort((a, b) => b[1] - a[1]); + tmp = Object.fromEntries(keyValueArray_skip_bigram2); for (const bigram in tmp) { sum_skip_fb += tmp[bigram] * inv_m_input_length; } @@ -2951,9 +2951,9 @@ function generatePlots() { const y_lat_sb = 180; sum = 0; if (lsb_toggle === 0) { - const keyValueArray = Object.entries(m_lat_stretch); - keyValueArray.sort((a, b) => b[1] - a[1]); - tmp = Object.fromEntries(keyValueArray); + const keyValueArray_lat_stretch = Object.entries(m_lat_stretch); + keyValueArray_lat_stretch.sort((a, b) => b[1] - a[1]); + tmp = Object.fromEntries(keyValueArray_lat_stretch); for (const bigram in tmp) { sum += tmp[bigram] * inv_m_input_length; } @@ -2967,9 +2967,9 @@ function generatePlots() { .attr("text-anchor", "left") .text(`Lat Stretch Bigrams ${parseFloat(100 * sum).toFixed(2)}%`); } else { - const keyValueArray = Object.entries(m_lat_stretch2); - keyValueArray.sort((a, b) => b[1] - a[1]); - tmp = Object.fromEntries(keyValueArray); + const keyValueArray_lat_stretch2 = Object.entries(m_lat_stretch2); + keyValueArray_lat_stretch2.sort((a, b) => b[1] - a[1]); + tmp = Object.fromEntries(keyValueArray_lat_stretch2); for (const bigram in tmp) { sum += tmp[bigram] * inv_m_input_length; } @@ -3082,9 +3082,9 @@ function generatePlots() { sum = 0; if (scissors_toggle === 1) { - const keyValueArray = Object.entries(m_pinky_scissors); - keyValueArray.sort((a, b) => b[1] - a[1]); - tmp = Object.fromEntries(keyValueArray); + const keyValueArray_pinky_scissors = Object.entries(m_pinky_scissors); + keyValueArray_pinky_scissors.sort((a, b) => b[1] - a[1]); + tmp = Object.fromEntries(keyValueArray_pinky_scissors); for (const bigram in tmp) { sum += tmp[bigram] * inv_m_input_length; } @@ -3098,9 +3098,9 @@ function generatePlots() { .attr("text-anchor", "left") .text(`Pinky/Ring Scissors ${parseFloat(100 * sum).toFixed(2)}%`); } else if (scissors_toggle === 0) { - const keyValueArray = Object.entries(m_scissors); - keyValueArray.sort((a, b) => b[1] - a[1]); - tmp = Object.fromEntries(keyValueArray); + const keyValueArray_scissors = Object.entries(m_scissors); + keyValueArray_scissors.sort((a, b) => b[1] - a[1]); + tmp = Object.fromEntries(keyValueArray_scissors); for (const bigram in tmp) { sum += tmp[bigram] * inv_m_input_length; } @@ -3114,9 +3114,9 @@ function generatePlots() { .attr("text-anchor", "left") .text(`Scissors ${parseFloat(100 * sum).toFixed(2)}%`); } else { - const keyValueArray = Object.entries(m_all_scissors); - keyValueArray.sort((a, b) => b[1] - a[1]); - tmp = Object.fromEntries(keyValueArray); + const keyValueArray_all_scissors = Object.entries(m_all_scissors); + keyValueArray_all_scissors.sort((a, b) => b[1] - a[1]); + tmp = Object.fromEntries(keyValueArray_all_scissors); for (const bigram in tmp) { sum += tmp[bigram] * inv_m_input_length; } @@ -3231,9 +3231,9 @@ function generatePlots() { var trigram_title = "Trigram Stats"; if (trigram_toggle === 0) { - const keyValueArray = Object.entries(m_trigram_count); - keyValueArray.sort((a, b) => b[1] - a[1]); - tmp = Object.fromEntries(keyValueArray); + const keyValueArray_trigram_count = Object.entries(m_trigram_count); + keyValueArray_trigram_count.sort((a, b) => b[1] - a[1]); + tmp = Object.fromEntries(keyValueArray_trigram_count); for (const cat in tmp) { sum += tmp[cat]; } @@ -3241,9 +3241,9 @@ function generatePlots() { scale = 1; dx = 105; } else if (trigram_toggle === 1) { - const keyValueArray = Object.entries(m_trigram_count_alt); - keyValueArray.sort((a, b) => b[1] - a[1]); - tmp = Object.fromEntries(keyValueArray); + const keyValueArray_trigram_count_alt = Object.entries(m_trigram_count_alt); + keyValueArray_trigram_count_alt.sort((a, b) => b[1] - a[1]); + tmp = Object.fromEntries(keyValueArray_trigram_count_alt); for (const cat in tmp) { sum += tmp[cat]; } @@ -3251,9 +3251,9 @@ function generatePlots() { scale = 3; dx = 47; } else if (trigram_toggle === 2) { - const keyValueArray = Object.entries(m_trigram_count_red); - keyValueArray.sort((a, b) => b[1] - a[1]); - tmp = Object.fromEntries(keyValueArray); + const keyValueArray_trigram_count_red = Object.entries(m_trigram_count_red); + keyValueArray_trigram_count_red.sort((a, b) => b[1] - a[1]); + tmp = Object.fromEntries(keyValueArray_trigram_count_red); for (const cat in tmp) { sum += tmp[cat]; } @@ -3261,9 +3261,9 @@ function generatePlots() { scale = 3; dx = 47; } else if (trigram_toggle === 3) { - const keyValueArray = Object.entries(m_trigram_count_roll_in); - keyValueArray.sort((a, b) => b[1] - a[1]); - tmp = Object.fromEntries(keyValueArray); + const keyValueArray_trigram_count_roll_in = Object.entries(m_trigram_count_roll_in); + keyValueArray_trigram_count_roll_in.sort((a, b) => b[1] - a[1]); + tmp = Object.fromEntries(keyValueArray_trigram_count_roll_in); for (const cat in tmp) { sum += tmp[cat]; } @@ -3271,9 +3271,9 @@ function generatePlots() { scale = 3; dx = 47; } else if (trigram_toggle === 4) { - const keyValueArray = Object.entries(m_trigram_count_roll_out); - keyValueArray.sort((a, b) => b[1] - a[1]); - tmp = Object.fromEntries(keyValueArray); + const keyValueArray_trigram_count_roll_out = Object.entries(m_trigram_count_roll_out); + keyValueArray_trigram_count_roll_out.sort((a, b) => b[1] - a[1]); + tmp = Object.fromEntries(keyValueArray_trigram_count_roll_out); for (const cat in tmp) { sum += tmp[cat]; } @@ -3418,9 +3418,9 @@ function generatePlots() { const y_same_hand_strings = 390; sum = 0; - var keyValueArray = Object.entries(samehandstrings); - keyValueArray.sort((a, b) => b[1] * b[0].length - a[1] * a[0].length); - samehandstrings = Object.fromEntries(keyValueArray); + const keyValueArray_same_hand_strings = Object.entries(samehandstrings); + keyValueArray_same_hand_strings.sort((a, b) => b[1] * b[0].length - a[1] * a[0].length); + samehandstrings = Object.fromEntries(keyValueArray_same_hand_strings); scale = 30191.79 * inv_m_input_length; // console.log("input length: "+m_input_length) @@ -3549,9 +3549,9 @@ function generatePlots() { const y_hard_words = 390; sum = 0; - var keyValueArray = Object.entries(word_effort); - keyValueArray.sort((a, b) => b[1] / b[0].length - a[1] / a[0].length); - word_effort = Object.fromEntries(keyValueArray); + const keyValueArray_hard_words = Object.entries(word_effort); + keyValueArray_hard_words.sort((a, b) => b[1] / b[0].length - a[1] / a[0].length); + word_effort = Object.fromEntries(keyValueArray_hard_words); stats .append("text") .attr("x", x + 40) From fede4a0671b37fa4934f482a2f9b97b9432adb01 Mon Sep 17 00:00:00 2001 From: gaetan Date: Thu, 23 Apr 2026 14:33:22 +0200 Subject: [PATCH 10/17] Declare j before use --- keyboard_svg.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/keyboard_svg.js b/keyboard_svg.js index 6ab0cb7..bc69158 100644 --- a/keyboard_svg.js +++ b/keyboard_svg.js @@ -3637,6 +3637,8 @@ function generatePlots() { var box_y = 20; var per = 0; + var j = 1; + let finger1 = plot_i; let finger2 = j; @@ -3665,7 +3667,6 @@ function generatePlots() { .text("Second Finger"); plot_i = 0; - var j = 1; for (let i = 0; i <= 8; i++) { sum_finger_pairs = 0; From a790bfe13e97f798bde952f10c10f02d88a3ace0 Mon Sep 17 00:00:00 2001 From: gaetan Date: Thu, 23 Apr 2026 15:33:32 +0200 Subject: [PATCH 11/17] Use triple equals for comparisons --- optimiser.js | 78 ++++++++++++++++++++++++++-------------------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/optimiser.js b/optimiser.js index 32696dd..f497dac 100644 --- a/optimiser.js +++ b/optimiser.js @@ -112,7 +112,7 @@ function getCharacters() { char = wordt.charAt(i); if (!letter_freq[char]) { letter_freq[char] = { count: 0, enabled: 1 } - if (char == ' ') { letter_freq[char].enabled = 0 } + if (char === ' ') { letter_freq[char].enabled = 0 } } letter_freq[char].count += count; if (i > 0) { @@ -167,7 +167,7 @@ function getY(row, col) { } function getKey(row, col) { for (let i = 0; i < rcdata.length; i++) { - if(rcdata[i].row == row && rcdata[i].col == col) { + if(rcdata[i].row === row && rcdata[i].col === col) { return i } } @@ -216,12 +216,12 @@ const dragHandler = d3.drag() if (closestdist < 12){ if (dropi >= 0){ for (let i = 0; i < rcdata.length; i++) { - if (startkey == "␣") { - if (rcdata[i].char == " ") { + if (startkey === "␣") { + if (rcdata[i].char === " ") { rcdata[i].char = "" } } else { - if (rcdata[i].char == startkey) { + if (rcdata[i].char === startkey) { rcdata[i].char = "" } } @@ -625,19 +625,19 @@ function generateGraphs2() { } function setMode(thing){ - if (thing == 'SFB'){ + if (thing === 'SFB'){ mode = 'sfb'; mult = 100; - } else if (thing == 'Effort') { + } else if (thing === 'Effort') { mode = 'effort'; mult = 1; - } else if (thing == "Scissors") { + } else if (thing === "Scissors") { mode = 'scissors'; mult = 100; - } else if (thing == "LSB") { + } else if (thing === "LSB") { mode = 'lat_str'; mult = 100; - } else if (thing == "SFS") { + } else if (thing === "SFS") { mode = 'sfs'; mult = 100; } @@ -723,7 +723,7 @@ function generateLayout() { .attr("stroke", d => d.enabled === 1 ? "#00dd00" : "#dd0000"); mergedGroups.select("text") - .text(d => d.char == " " ? "␣" : d.char); + .text(d => d.char === " " ? "␣" : d.char); } function sortLetterFreq(){ @@ -786,9 +786,9 @@ function generateCharacters() { mergedGroups.attr("transform", d => `translate(${d.x}, ${d.y})`); - mergedGroups.select("rect").attr("stroke", d => letter_freq[d.letter].enabled == 1 ? "#00ff00" : "#ff0000"); + mergedGroups.select("rect").attr("stroke", d => letter_freq[d.letter].enabled === 1 ? "#00ff00" : "#ff0000"); - mergedGroups.select("text").text(d => d.letter == " " ? "␣" : d.letter); // Use a special character for space + mergedGroups.select("text").text(d => d.letter === " " ? "␣" : d.letter); // Use a special character for space } function countCharsKeys() { @@ -796,12 +796,12 @@ function countCharsKeys() { var char_count = 0; for (let i = 0; i < rcdata.length; i++) { on = rcdata[i].enabled; - if (on == 1) { + if (on === 1) { key_count += 1; } } for (var m in letter_freq) { - if (letter_freq[m].enabled == 1) { + if (letter_freq[m].enabled === 1) { char_count += 1; } } @@ -938,7 +938,7 @@ function addStatLine(x, y, data) { function getEffort(row, col) { for (let i = 0; i < rcdata.length; i++) { - if (rcdata[i].row == row && rcdata[i].col == col) { + if (rcdata[i].row === row && rcdata[i].col === col) { return rcdata[i].effort } } @@ -946,7 +946,7 @@ function getEffort(row, col) { } function setEffort(row, col,value) { for (let i = 0; i < rcdata.length; i++) { - if (rcdata[i].row == row && rcdata[i].col == col) { + if (rcdata[i].row === row && rcdata[i].col === col) { rcdata[i].effort = value } } @@ -968,7 +968,7 @@ function loadEffortValuesFromCookie(cookieName, data) { for(let i=0;i < ca.length;i++) { let c = ca[i]; while (c.charAt(0)==' ') c = c.substring(1,c.length); - if (c.indexOf(nameEQ) == 0) { + if (c.indexOf(nameEQ) === 0) { const effortValuesString = c.substring(nameEQ.length,c.length); if (effortValuesString) { const effortValues = JSON.parse(effortValuesString); @@ -1018,7 +1018,7 @@ function openCorpusPopup() { function closeCorpusPopup() { var massive_string = document.getElementById('corpusText').value; massive_string = massive_string.toLowerCase().replace(/\s+/g, ' '); - if (massive_string.length == 0) { + if (massive_string.length === 0) { document.getElementById('corpusPopup').style.display = 'none'; return; } @@ -1083,7 +1083,7 @@ function pasteEffortGridFromClipboard() { .then(text => { // console.log("Clipboard content:", text); var numbersArray = text.split(",").map(Number); - if (numbersArray.length != 36) { + if (numbersArray.length !== 36) { return } @@ -1133,12 +1133,12 @@ function dist(x1, y1, x2, y2) { function toggleKeyOnOff(d) { console.log("toggleKeyOnOff "+d); - if (d.enabled == 1){ + if (d.enabled === 1){ d.enabled = 0 } else { d.enabled = 1; for (var m in letter_freq) { - if (m == d.char) { + if (m === d.char) { letter_freq[m].enabled = 1; } } @@ -1153,8 +1153,8 @@ function toggleKeyOnOff(d) { function toggleCharOnOff(char) { for (var m in letter_freq) { - if (m == char) { - if (letter_freq[m].enabled == 0) { + if (m === char) { + if (letter_freq[m].enabled === 0) { letter_freq[m].enabled = 1; } else { letter_freq[m].enabled = 0; @@ -1181,7 +1181,7 @@ function hideTooltip() { function shuffle(array) { // https://stackoverflow.com/questions/2450954/how-to-randomize-shuffle-a-javascript-array let currentIndex = array.length; - while (currentIndex != 0) { + while (currentIndex !== 0) { let randomIndex = Math.floor(Math.random() * currentIndex); currentIndex--; var tmp = array[currentIndex]; @@ -1196,7 +1196,7 @@ function shuffleData(data, reps) { var tmp_keys = _.cloneDeep(data) var editable_keys = []; for (let i = 0; i < tmp_keys.length; i++) { - if (tmp_keys[i].enabled == 1) { + if (tmp_keys[i].enabled === 1) { editable_keys.push(i); } } @@ -1204,7 +1204,7 @@ function shuffleData(data, reps) { // pick a random key var key1 = editable_keys[Math.floor(Math.random()*editable_keys.length)]; var key2 = editable_keys[Math.floor(Math.random()*editable_keys.length)]; - while(key1 == key2) { + while(key1 === key2) { key2 = editable_keys[Math.floor(Math.random()*editable_keys.length)]; } tmp = tmp_keys[key1].char @@ -1217,8 +1217,8 @@ function shuffleData(data, reps) { function create_uid(rcdata) { var arr = []; for (let i = 0; i < rcdata.length; i++) { - if (rcdata[i].enabled == 1) { - if (rcdata[i].char == " ") { + if (rcdata[i].enabled === 1) { + if (rcdata[i].char === " ") { arr.push("␣"); } else { arr.push(rcdata[i].char); @@ -1233,7 +1233,7 @@ function start() { console.log("construct list of chars"); var list_of_chars = []; for (var m in letter_freq) { - if (letter_freq[m].enabled == 1) { + if (letter_freq[m].enabled === 1) { list_of_chars.push(m); } } @@ -1241,9 +1241,9 @@ function start() { // check the letters fixed on the keyboard are off in the character list for (var m in letter_freq) { - if (letter_freq[m].enabled == 1) { + if (letter_freq[m].enabled === 1) { for (let i = 0; i < rcdata.length; i++) { - if (rcdata[i].char == m) { + if (rcdata[i].char === m) { error = true } } @@ -1252,7 +1252,7 @@ function start() { if (error) { return; } for (let i = 0; i < rcdata.length; i++) { - if (rcdata[i].enabled == 1) { + if (rcdata[i].enabled === 1) { rcdata[i].char = list_of_chars.pop(); } } @@ -1262,7 +1262,7 @@ function start() { function clearLetters() { for (let i = 0; i < rcdata.length; i++) { - if (rcdata[i].char != "" && rcdata[i].enabled == 1) { + if (rcdata[i].char !== "" && rcdata[i].enabled === 1) { rcdata[i].char = "" } } @@ -1317,7 +1317,7 @@ function calculateScore(value, weight, min, denom, perc) { } function run() { - if (error == true) {console.log("sort errors first");return;} + if (error === true) {console.log("sort errors first");return;} runs += 1; best_score = 1000000; var messages_sent = 0; @@ -1327,10 +1327,10 @@ function run() { if (window.Worker) { const myWorker = new Worker("worker.js"); - if (setup == false) { + if (setup === false) { start(); for (let i = 0; i < rcdata.length; i++) { - if (rcdata[i].enabled == 1) { + if (rcdata[i].enabled === 1) { editable_keys.push(i); } } @@ -1387,7 +1387,7 @@ function run() { for(let r = 0; r <= 2; r++ ) { var p = getKey(r, c) var q = getKey(r, d) - if (rcdata[p].enabled == 1 && rcdata[q].enabled == 1) { + if (rcdata[p].enabled === 1 && rcdata[q].enabled === 1) { tmp = tmp_keys[p].char tmp_keys[p].char = tmp_keys[q].char tmp_keys[q].char = tmp @@ -1447,7 +1447,7 @@ function run() { } messages_received += 1; // console.log("sent = "+messages_sent+" received = "+messages_received); - if (messages_received == messages_sent) { + if (messages_received === messages_sent) { console.log(iter + " best result: "+best_score); update_progress(); if (found_new_result) { From 19de160e83d1e17d203f70c1cee5c0748f4e0e3b Mon Sep 17 00:00:00 2001 From: gaetan Date: Thu, 23 Apr 2026 16:08:44 +0200 Subject: [PATCH 12/17] Use string templates --- optimiser.js | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/optimiser.js b/optimiser.js index f497dac..07fe4df 100644 --- a/optimiser.js +++ b/optimiser.js @@ -106,7 +106,7 @@ function getCharacters() { var count = 0; var wordt; for (var word in words) { - wordt = " "+word+" " + wordt = `" ${word} "` count = words[word]; for (let i = 0; i < wordt.length; i++) { char = wordt.charAt(i); @@ -136,7 +136,7 @@ function getCharacters() { for(var tmp in bigram_freq) { bigram_count += 1 } - console.log("there are "+bigram_count+ " bigrams") + console.log(`"there are ${bigram_count} bigrams"`) for(var tmp in trigram_freq) { if (trigram_freq[tmp] <= 30) { @@ -147,10 +147,10 @@ function getCharacters() { for(var tmp in trigram_freq) { trigram_count += 1 } - console.log("there are "+trigram_count+ " trigrams") + console.log(`"there are ${trigram_count} trigrams"`) letter_freq[" "].count = letter_freq[" "].count / 2; - console.log("input_length: "+input_length); + console.log(`"input_length: ${input_length}`); sortLetterFreq(); } @@ -232,7 +232,7 @@ const dragHandler = d3.drag() generateLayout(); generateCharacters(); } else { - console.log("can't drop here "+dropi) + console.log(`"can't drop here ${dropi}"`) } } else { // console.log("closest end",closestdist) @@ -642,7 +642,7 @@ function setMode(thing){ mult = 100; } yLabel = thing - console.log("setting mode to "+mode); + console.log(`"setting mode to ${mode}"`); generateGraphs2(); } @@ -810,11 +810,11 @@ function countCharsKeys() { var diff = 0 if (key_count > char_count) { diff = key_count - char_count - error_text = "Too many keys ("+diff+"); Select more characters or deselect some keys"; + error_text = `"Too many keys (${diff}); Select more characters or deselect some keys"`; error = true; } else if(char_count > key_count) { diff = char_count - key_count - error_text = "Too many chars ("+diff+"); Select fewer characters or select some more keys"; + error_text = `"Too many chars (${diff}); Select fewer characters or select some more keys"`; error = true; } } @@ -955,7 +955,7 @@ function setEffort(row, col,value) { function openEffortPopup() { for (var row = 0; row < 3; row++) { for (var col = 0; col < 12; col++) { - var name = "textInput-" + row + "-" + col + var name = `"textInput-${row}-${col}` document.getElementById(name).value = getEffort(row,col) } } @@ -967,7 +967,7 @@ function loadEffortValuesFromCookie(cookieName, data) { const ca = document.cookie.split(';'); for(let i=0;i < ca.length;i++) { let c = ca[i]; - while (c.charAt(0)==' ') c = c.substring(1,c.length); + while (c.charAt(0) === ' ') c = c.substring(1,c.length); if (c.indexOf(nameEQ) === 0) { const effortValuesString = c.substring(nameEQ.length,c.length); if (effortValuesString) { @@ -1003,7 +1003,7 @@ function saveEffortValuesToCookie(cookieName, data, daysToExpire) { function closeEffortPopup() { for (var row = 0; row < 3; row++) { for (var col = 0; col < 12; col++) { - var name = "textInput-" + row + "-" + col + var name = `"textInput-${row}-${col}"` setEffort(row, col, document.getElementById(name).value); } } @@ -1052,7 +1052,7 @@ function copyEffortGridToClipboard() { values = [] for (var row = 0; row < 3; row++) { for (var col = 0; col < 12; col++) { - var name = "textInput-" + row + "-" + col + var name = `"textInput-${row}-${col}` values.push(document.getElementById(name).value); } } @@ -1089,7 +1089,7 @@ function pasteEffortGridFromClipboard() { for (var row = 0; row < 3; row++) { for (var col = 0; col < 12; col++) { - var name = "textInput-" + row + "-" + col + var name = `"textInput-${row}-${col}` document.getElementById(name).value = numbersArray[row * 12 + col] } } @@ -1101,13 +1101,13 @@ function pasteEffortGridFromClipboard() { function selectLanguage(lan, event) { - var word_list = 'words-'+lan+'.json'; - console.log("============ "+lan.toUpperCase()+" ============") + var word_list = `'words-${lan}.json'`; + console.log(`"============ ${lan.toUpperCase()} ============"`) fetch(word_list) .then(response => response.json()) .then(data => { if (event.ctrlKey){ - console.log("adding "+lan+" to words") + console.log(`"adding ${lan} to words"`) for (var word in data) { if (words[word]){ words[word] += data[word] @@ -1132,7 +1132,7 @@ function dist(x1, y1, x2, y2) { } function toggleKeyOnOff(d) { - console.log("toggleKeyOnOff "+d); + console.log(`"toggleKeyOnOff ${d}`); if (d.enabled === 1){ d.enabled = 0 } else { From 6302769ea30d9618672c3040d0f305967ffc71cc Mon Sep 17 00:00:00 2001 From: gaetan Date: Thu, 23 Apr 2026 16:19:03 +0200 Subject: [PATCH 13/17] Fix declaration scopes (var, let, const) --- optimiser.js | 91 ++++++++++++++++++++++++++-------------------------- 1 file changed, 46 insertions(+), 45 deletions(-) diff --git a/optimiser.js b/optimiser.js index 07fe4df..237dd93 100644 --- a/optimiser.js +++ b/optimiser.js @@ -133,7 +133,7 @@ function getCharacters() { input_length += (word.length + 1) * count; } var bigram_count = 0 - for(var tmp in bigram_freq) { + for(const _tmp in bigram_freq) { bigram_count += 1 } console.log(`"there are ${bigram_count} bigrams"`) @@ -144,7 +144,7 @@ function getCharacters() { } } var trigram_count = 0 - for(var tmp in trigram_freq) { + for(const _tmp in trigram_freq) { trigram_count += 1 } console.log(`"there are ${trigram_count} trigrams"`) @@ -183,8 +183,8 @@ const dragHandler = d3.drag() // console.log("start:",event.x,event.y); closestdist = 9999; startkey = "$" - for(var i = 0; i < letter_position.length; i++) { - var d2 = dist(event.x, event.y, letter_position[i].x+15, letter_position[i].y+15); // distance to centre of key + for(let i = 0; i < letter_position.length; i++) { + const d2 = dist(event.x, event.y, letter_position[i].x+15, letter_position[i].y+15); // distance to centre of key if (d2 < closestdist) { closestdist = d2; startkey = letter_position[i].letter @@ -393,7 +393,7 @@ function generateGraphs() { max_score = best_results[i].score; } } - if (max_score==0){ + if (max_score === 0){ max_score = 10; } // Remove and redraw y-axis ticks when scale changes @@ -421,11 +421,11 @@ function generateGraphs() { .text("Score"); for (let i = 0; i <= tickCount; i++) { - var tickValue = (i * tickInterval).toString() + let tickValue = (i * tickInterval).toString() if (max_score < 1000 && tickValue.length > 3){ tickValue = tickValue.substring(0,3) } - var yPos = yBase - i*tickInterval*scale; + const yPos = yBase - i*tickInterval*scale; // Tick mark svg.append("line") @@ -538,7 +538,7 @@ function generateGraphs2() { max_score = percentage; } } - if (max_score==0){ + if (max_score === 0){ max_score = 1; } // Remove and redraw y-axis ticks when scale changes @@ -566,11 +566,11 @@ function generateGraphs2() { .text(yLabel); for (let i = 0; i <= tickCount; i++) { - var tickValue = (i * tickInterval).toString() + let tickValue = (i * tickInterval).toString() if (max_score < 1000 && tickValue.length > 3){ tickValue = tickValue.substring(0,3) } - var yPos = yBase - i*tickInterval*scale; + const yPos = yBase - i*tickInterval*scale; // Tick mark svg.append("line") @@ -652,7 +652,7 @@ function generateModeButtons() { var buttons = ["SFB","Effort","Scissors","LSB","SFS"] if (svg.select(".mode-button").empty()) { - for(var i = 0; i < buttons.length; i++){ + for(let i = 0; i < buttons.length; i++){ svg.append("rect") // x axis .attr("class", "mode-button") .attr("x", xLeft+(i*100)) @@ -953,9 +953,9 @@ function setEffort(row, col,value) { } function openEffortPopup() { - for (var row = 0; row < 3; row++) { - for (var col = 0; col < 12; col++) { - var name = `"textInput-${row}-${col}` + for (let row = 0; row < 3; row++) { + for (let col = 0; col < 12; col++) { + const name = `"textInput-${row}-${col}` document.getElementById(name).value = getEffort(row,col) } } @@ -1001,9 +1001,9 @@ function saveEffortValuesToCookie(cookieName, data, daysToExpire) { } function closeEffortPopup() { - for (var row = 0; row < 3; row++) { - for (var col = 0; col < 12; col++) { - var name = `"textInput-${row}-${col}"` + for (let row = 0; row < 3; row++) { + for (let col = 0; col < 12; col++) { + const name = `"textInput-${row}-${col}"` setEffort(row, col, document.getElementById(name).value); } } @@ -1050,13 +1050,13 @@ function closeCorpusPopup() { function copyEffortGridToClipboard() { values = [] - for (var row = 0; row < 3; row++) { - for (var col = 0; col < 12; col++) { - var name = `"textInput-${row}-${col}` + for (let row = 0; row < 3; row++) { + for (let col = 0; col < 12; col++) { + const name = `"textInput-${row}-${col}` values.push(document.getElementById(name).value); } } - var str = values.join(","); + const str = values.join(","); if (!navigator.clipboard) { console.error("Clipboard API not supported"); @@ -1087,9 +1087,9 @@ function pasteEffortGridFromClipboard() { return } - for (var row = 0; row < 3; row++) { - for (var col = 0; col < 12; col++) { - var name = `"textInput-${row}-${col}` + for (let row = 0; row < 3; row++) { + for (let col = 0; col < 12; col++) { + const name = `"textInput-${row}-${col}` document.getElementById(name).value = numbersArray[row * 12 + col] } } @@ -1167,7 +1167,7 @@ function toggleCharOnOff(char) { } function showTooltip(evt, text) { - let tooltip = document.getElementById("tooltip"); + const tooltip = document.getElementById("tooltip"); tooltip.innerHTML = text; tooltip.style.display = "block"; tooltip.style.left = evt.pageX + 10 + 'px'; @@ -1175,16 +1175,16 @@ function showTooltip(evt, text) { } function hideTooltip() { - var tooltip = document.getElementById("tooltip"); + const tooltip = document.getElementById("tooltip"); tooltip.style.display = "none"; } function shuffle(array) { // https://stackoverflow.com/questions/2450954/how-to-randomize-shuffle-a-javascript-array let currentIndex = array.length; while (currentIndex !== 0) { - let randomIndex = Math.floor(Math.random() * currentIndex); + const randomIndex = Math.floor(Math.random() * currentIndex); currentIndex--; - var tmp = array[currentIndex]; + const tmp = array[currentIndex]; array[currentIndex] = array[randomIndex]; array[randomIndex] = tmp; } @@ -1202,8 +1202,8 @@ function shuffleData(data, reps) { } for (let i = 0; i < reps; i++) { // pick a random key - var key1 = editable_keys[Math.floor(Math.random()*editable_keys.length)]; - var key2 = editable_keys[Math.floor(Math.random()*editable_keys.length)]; + const key1 = editable_keys[Math.floor(Math.random()*editable_keys.length)]; + let key2 = editable_keys[Math.floor(Math.random()*editable_keys.length)]; while(key1 === key2) { key2 = editable_keys[Math.floor(Math.random()*editable_keys.length)]; } @@ -1240,7 +1240,7 @@ function start() { list_of_chars = shuffle(list_of_chars); // check the letters fixed on the keyboard are off in the character list - for (var m in letter_freq) { + for (const m in letter_freq) { if (letter_freq[m].enabled === 1) { for (let i = 0; i < rcdata.length; i++) { if (rcdata[i].char === m) { @@ -1283,8 +1283,8 @@ var editable_keys; function update_progress() { svg.selectAll(".progress").remove(); if (running) { - var x = 1060; - for(var r = 0; r < 360; r += 60){ + const x = 1060; + for(let r = 0; r < 360; r += 60){ svg.append("rect") .attr("class", "progress") .attr("x", x).attr("y", 562) @@ -1299,12 +1299,13 @@ function update_progress() { } function calculateScore(value, weight, min, denom, perc) { - if (perc==true) { + let score = -1; + if (perc === true) { value = (100*value)/denom - var score = (value - min) * weight + score = (value - min) * weight } else { value = value/denom - var score = (value - min) * weight + score = (value - min) * weight } if (isNaN(score)) { console.log("score is NaN. ",value,weight,min,denom,perc) @@ -1358,14 +1359,14 @@ function run() { for (let i = 0; i < editable_keys.length; i++) { for (let j = 0; j < editable_keys.length; j++) { if (j > i) { - var tmp_keys = _.cloneDeep(rcdata) + const tmp_keys = _.cloneDeep(rcdata) // swap keys - var p = editable_keys[i] - var q = editable_keys[j] + const p = editable_keys[i] + const q = editable_keys[j] tmp = tmp_keys[p].char tmp_keys[p].char = tmp_keys[q].char tmp_keys[q].char = tmp - var uid = create_uid(tmp_keys) + const uid = create_uid(tmp_keys) if (uid_set.has(uid)) { } else { messages_sent += 1; @@ -1383,10 +1384,10 @@ function run() { for (let c = 1; c <= 10; c++) { for (let d = 1; d <= 10; d++) { if (d > c) { - var tmp_keys = _.cloneDeep(rcdata) + const tmp_keys = _.cloneDeep(rcdata) for(let r = 0; r <= 2; r++ ) { - var p = getKey(r, c) - var q = getKey(r, d) + const p = getKey(r, c) + const q = getKey(r, d) if (rcdata[p].enabled === 1 && rcdata[q].enabled === 1) { tmp = tmp_keys[p].char tmp_keys[p].char = tmp_keys[q].char @@ -1394,7 +1395,7 @@ function run() { } } - var uid = create_uid(tmp_keys) + const uid = create_uid(tmp_keys) if (uid_set.has(uid)) { } else { messages_sent += 1; @@ -1463,7 +1464,7 @@ function run() { } } rcdata = best_config - var uid = create_uid(rcdata) + const uid = create_uid(rcdata) uid_set.add(uid) best_results.push({config: best_config, score: best_score, result: best_result, iter: iter}) results = []; From 7bb29c2f36fdfef2fa36c8d3628c53efc914d622 Mon Sep 17 00:00:00 2001 From: gaetan Date: Thu, 23 Apr 2026 16:29:08 +0200 Subject: [PATCH 14/17] Fix minor warnings --- optimiser.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/optimiser.js b/optimiser.js index 237dd93..d9ffcbd 100644 --- a/optimiser.js +++ b/optimiser.js @@ -308,7 +308,7 @@ function generateButtons() { d3.select(this).property("value", "1"); times = 1; } else { - times = parseInt(value); + times = parseInt(value, 10); } generateGraphs(); generateGraphs2(); @@ -844,7 +844,7 @@ function generateStats() { y = 30 var weight_x = 136 var min_x = 196 - var score_x = 255 + let score_x = 255 // headers infoPanel.append("text").attr("x", x+weight_x).attr("y", y).attr("fill", "#aaaaaa") @@ -856,7 +856,7 @@ function generateStats() { // sfb - var score_x = 255; + score_x = 255; y += 35 addStatLine(x,y,sfb_data) y += 35 @@ -1128,7 +1128,9 @@ function selectLanguage(lan, event) { } function dist(x1, y1, x2, y2) { - return Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2)); + dx = x1 - x2; + dy = y1 - y2; + return Math.sqrt(dx*dx + dy*dy); } function toggleKeyOnOff(d) { @@ -1307,7 +1309,7 @@ function calculateScore(value, weight, min, denom, perc) { value = value/denom score = (value - min) * weight } - if (isNaN(score)) { + if (score.isNaN) { console.log("score is NaN. ",value,weight,min,denom,perc) return 0 } From af48cba8364700bb692ed82ed125aa00bd9b5b6d Mon Sep 17 00:00:00 2001 From: gaetan Date: Thu, 23 Apr 2026 16:33:23 +0200 Subject: [PATCH 15/17] Turn function expressions to arrow functions --- optimiser.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/optimiser.js b/optimiser.js index d9ffcbd..4b8a2ae 100644 --- a/optimiser.js +++ b/optimiser.js @@ -692,7 +692,7 @@ function generateLayout() { const keyGroupsEnter = keyGroups.enter() .append("g") .attr("class", "key-group") - .on("click", function(event, d) { + .on("click", (event, d) => { toggleKeyOnOff(d); }); @@ -758,7 +758,7 @@ function generateCharacters() { .attr("class", "letter-group") // The drag handler and click listener are applied only once on creation. .call(dragHandler) - .on("click", function(event, d) { + .on("click", (event, d) => { // This function would be defined elsewhere in your code toggleCharOnOff(d.letter); }); @@ -1413,7 +1413,7 @@ function run() { } // Listen for results coming back from the worker - myWorker.onmessage = function(e) { + myWorker.onmessage = (e) => { const { result, config } = e.data; uid = create_uid(config) var score = 0; @@ -1523,7 +1523,7 @@ function run() { } }; - myWorker.onerror = function(error) { + myWorker.onerror = (error) => { console.error('Main: There was an error with the worker.', error); }; } else { From 64a7473f5fe60cb15fe70d75e3c4fe2adab6ee89 Mon Sep 17 00:00:00 2001 From: gaetan Date: Thu, 23 Apr 2026 16:45:52 +0200 Subject: [PATCH 16/17] Precompute denominators --- optimiser.js | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/optimiser.js b/optimiser.js index 4b8a2ae..2739266 100644 --- a/optimiser.js +++ b/optimiser.js @@ -1302,11 +1302,12 @@ function update_progress() { function calculateScore(value, weight, min, denom, perc) { let score = -1; + const inv_denom = 1.0 / denom; if (perc === true) { - value = (100*value)/denom + value = (100*value) * inv_denom score = (value - min) * weight } else { - value = value/denom + value = value * inv_denom score = (value - min) * weight } if (score.isNaN) { @@ -1471,15 +1472,16 @@ function run() { best_results.push({config: best_config, score: best_score, result: best_result, iter: iter}) results = []; - sfb_data.metric = ((100*best_result.sfb) / input_length).toFixed(2) + "%" - effort_data.metric = (best_result.effort / input_length).toFixed(2) - psfb_data.metric = (100*best_result.psfb / input_length).toFixed(2) + "%" - rsfb_data.metric = (100*best_result.rsfb / input_length).toFixed(2) + "%" - scissors_data.metric = (100*best_result.scissors / input_length).toFixed(2) + "%" - prscissors_data.metric = (100*best_result.prscissors / input_length).toFixed(2) + "%" - wscissors_data.metric = (100*best_result.wide_scissors / input_length).toFixed(2) + "%" - latstr_data.metric = (100*best_result.lat_str / input_length).toFixed(2) + "%" - sfs_data.metric = (100*best_result.sfs / input_length).toFixed(2) + "%" + const inv_input_lenght = 1.0 / input_length; + sfb_data.metric = ((100*best_result.sfb) * inv_input_lenght).toFixed(2) + "%" + effort_data.metric = (best_result.effort * inv_input_lenght).toFixed(2) + psfb_data.metric = (100*best_result.psfb * inv_input_lenght).toFixed(2) + "%" + rsfb_data.metric = (100*best_result.rsfb * inv_input_lenght).toFixed(2) + "%" + scissors_data.metric = (100*best_result.scissors * inv_input_lenght).toFixed(2) + "%" + prscissors_data.metric = (100*best_result.prscissors * inv_input_lenght).toFixed(2) + "%" + wscissors_data.metric = (100*best_result.wide_scissors * inv_input_lenght).toFixed(2) + "%" + latstr_data.metric = (100*best_result.lat_str * inv_input_lenght).toFixed(2) + "%" + sfs_data.metric = (100*best_result.sfs * inv_input_lenght).toFixed(2) + "%" vowels_data.metric = (best_result.vowels) hbalance_data.metric = (best_result.hand_balance).toFixed(2) From e10c24406b3d89a935329b54c6abc6ba17591792 Mon Sep 17 00:00:00 2001 From: gaetan Date: Thu, 23 Apr 2026 16:49:02 +0200 Subject: [PATCH 17/17] Run formatter --- optimiser.js | 3181 +++++++++++++++++++++++++++++--------------------- 1 file changed, 1818 insertions(+), 1363 deletions(-) diff --git a/optimiser.js b/optimiser.js index 2739266..6fd63ba 100644 --- a/optimiser.js +++ b/optimiser.js @@ -1,7 +1,11 @@ - var swidth = 1200; var sheight = 700; -var svg = d3.select("#svglayout").append("svg").attr("xmlns","http://www.w3.org/2000/svg").attr("width", swidth).attr("height", sheight); +var svg = d3 + .select("#svglayout") + .append("svg") + .attr("xmlns", "http://www.w3.org/2000/svg") + .attr("width", swidth) + .attr("height", sheight); svg.append("g").attr("id", "info-panel"); @@ -21,76 +25,153 @@ var error_text = ""; var m_score = 0; -var sfb_data = {label: "SFB:", metric: 0, score: 0, weight: 4, min: 0.3, desc: "Single finger bigrams"} -var effort_data = {label: "Effort:", metric: 0, score: 0, weight: 4, min: 0, desc: "Effort based on defined matrix"} -var psfb_data = {label: "pSFB:", metric: 0, score: 0, weight: 0.7, min: 0, desc: "Additional penalty for SFBs on the pinky"} -var rsfb_data = {label: "rSFB:", metric: 0, score: 0, weight: 0.3, min: 0, desc: "Additional penalty for SFBs on the ring finger"} -var scissors_data = {label: "Scissors:", metric: 0, score: 0, weight: 0.8, min: 0, desc: "Two letters on the same hand, two rows between them, on adjacent fingers"} -var prscissors_data = {label: "PRScissor:", metric: 0, score: 0, weight: 0.8, min: 0.2, desc: "Two letters typed with the ring and pinky with at least one row between them"} -var wscissors_data = {label: "WScissors:", metric: 0, score: 0, weight: 0.5, min: 0.05, desc: "Two letters on the same hand, two rows between them, more than one column between them" } -var latstr_data = {label: "LSB:", metric: 0, score: 0, weight: 0.5, min: 0.12, desc: "Lateral stretch bigrams"} -var sfs_data = {label: "SFS:", metric: 0, score: 0, weight: 0.2, min: 0, desc: "Single finger skipgrams (1u)"} -var vowels_data = {label: "Vowels:", metric: 0, score: 0, weight: 3, min: 0, desc: "Should vowels be on the same side"} -var hbalance_data = {label: "Hand Bal:", metric: 0, score: 0, weight: 0.7, min: 1, desc: "Hand balance, how much different from 50/50 usage" } +var sfb_data = { + label: "SFB:", + metric: 0, + score: 0, + weight: 4, + min: 0.3, + desc: "Single finger bigrams", +}; +var effort_data = { + label: "Effort:", + metric: 0, + score: 0, + weight: 4, + min: 0, + desc: "Effort based on defined matrix", +}; +var psfb_data = { + label: "pSFB:", + metric: 0, + score: 0, + weight: 0.7, + min: 0, + desc: "Additional penalty for SFBs on the pinky", +}; +var rsfb_data = { + label: "rSFB:", + metric: 0, + score: 0, + weight: 0.3, + min: 0, + desc: "Additional penalty for SFBs on the ring finger", +}; +var scissors_data = { + label: "Scissors:", + metric: 0, + score: 0, + weight: 0.8, + min: 0, + desc: "Two letters on the same hand, two rows between them, on adjacent fingers", +}; +var prscissors_data = { + label: "PRScissor:", + metric: 0, + score: 0, + weight: 0.8, + min: 0.2, + desc: "Two letters typed with the ring and pinky with at least one row between them", +}; +var wscissors_data = { + label: "WScissors:", + metric: 0, + score: 0, + weight: 0.5, + min: 0.05, + desc: "Two letters on the same hand, two rows between them, more than one column between them", +}; +var latstr_data = { + label: "LSB:", + metric: 0, + score: 0, + weight: 0.5, + min: 0.12, + desc: "Lateral stretch bigrams", +}; +var sfs_data = { + label: "SFS:", + metric: 0, + score: 0, + weight: 0.2, + min: 0, + desc: "Single finger skipgrams (1u)", +}; +var vowels_data = { + label: "Vowels:", + metric: 0, + score: 0, + weight: 3, + min: 0, + desc: "Should vowels be on the same side", +}; +var hbalance_data = { + label: "Hand Bal:", + metric: 0, + score: 0, + weight: 0.7, + min: 1, + desc: "Hand balance, how much different from 50/50 usage", +}; var rcdata = [ - {char:"", row:0, col:0, enabled:0, finger:1, x:0, y:1, effort:7}, - {char:"", row:0, col:1, enabled:1, finger:1, x:0, y:1, effort:3}, - {char:"", row:0, col:2, enabled:1, finger:2, x:0, y:1, effort:2}, - {char:"", row:0, col:3, enabled:1, finger:3, x:0, y:1, effort:1}, - {char:"", row:0, col:4, enabled:1, finger:4, x:0, y:1, effort:1}, - {char:"", row:0, col:5, enabled:1, finger:4, x:0, y:1, effort:2}, - {char:"", row:0, col:6, enabled:1, finger:7, x:0, y:1, effort:2}, - {char:"", row:0, col:7, enabled:1, finger:7, x:0, y:1, effort:1}, - {char:"", row:0, col:8, enabled:1, finger:8, x:0, y:1, effort:1}, - {char:"", row:0, col:9, enabled:1, finger:9, x:0, y:1, effort:2}, - {char:"", row:0, col:10, enabled:1, finger:10, x:0, y:1, effort:3}, - {char:"", row:0, col:11, enabled:0, finger:10, x:0, y:1, effort:7}, - {char:"", row:1, col:0, enabled:0, finger:1, x:0, y:1, effort:6}, - {char:"", row:1, col:1, enabled:1, finger:1, x:0, y:1, effort:2}, - {char:"", row:1, col:2, enabled:1, finger:2, x:0, y:1, effort:0}, - {char:"", row:1, col:3, enabled:1, finger:3, x:0, y:1, effort:0}, - {char:"", row:1, col:4, enabled:1, finger:4, x:0, y:1, effort:0}, - {char:"", row:1, col:5, enabled:1, finger:4, x:0, y:1, effort:1}, - {char:"", row:1, col:6, enabled:1, finger:7, x:0, y:1, effort:1}, - {char:"", row:1, col:7, enabled:1, finger:7, x:0, y:1, effort:0}, - {char:"", row:1, col:8, enabled:1, finger:8, x:0, y:1, effort:0}, - {char:"", row:1, col:9, enabled:1, finger:9, x:0, y:1, effort:0}, - {char:"", row:1, col:10, enabled:1, finger:10, x:0, y:1, effort:2}, - {char:"", row:1, col:11, enabled:0, finger:10, x:0, y:1, effort:6}, - {char:"", row:2, col:0, enabled:0, finger:1, x:0, y:1, effort:7}, - {char:"", row:2, col:1, enabled:1, finger:1, x:0, y:1, effort:6}, - {char:"", row:2, col:2, enabled:1, finger:2, x:0, y:1, effort:2.1}, - {char:"", row:2, col:3, enabled:1, finger:3, x:0, y:1, effort:1.1}, - {char:"", row:2, col:4, enabled:1, finger:4, x:0, y:1, effort:1.1}, - {char:"", row:2, col:5, enabled:1, finger:4, x:0, y:1, effort:3.1}, - {char:"", row:2, col:6, enabled:1, finger:7, x:0, y:1, effort:3.1}, - {char:"", row:2, col:7, enabled:1, finger:7, x:0, y:1, effort:1.1}, - {char:"", row:2, col:8, enabled:1, finger:8, x:0, y:1, effort:1.1}, - {char:"", row:2, col:9, enabled:1, finger:9, x:0, y:1, effort:2.1}, - {char:"", row:2, col:10, enabled:1, finger:10, x:0, y:1, effort:6}, - {char:"", row:2, col:11, enabled:0, finger:10, x:0, y:1, effort:7}, - {char:"", row:3, col:5, enabled:0, finger:5, x:0, y:1, effort:0}, - {char:" ", row:3, col:6, enabled:0, finger:6, x:0, y:1, effort:0} -] + { char: "", row: 0, col: 0, enabled: 0, finger: 1, x: 0, y: 1, effort: 7 }, + { char: "", row: 0, col: 1, enabled: 1, finger: 1, x: 0, y: 1, effort: 3 }, + { char: "", row: 0, col: 2, enabled: 1, finger: 2, x: 0, y: 1, effort: 2 }, + { char: "", row: 0, col: 3, enabled: 1, finger: 3, x: 0, y: 1, effort: 1 }, + { char: "", row: 0, col: 4, enabled: 1, finger: 4, x: 0, y: 1, effort: 1 }, + { char: "", row: 0, col: 5, enabled: 1, finger: 4, x: 0, y: 1, effort: 2 }, + { char: "", row: 0, col: 6, enabled: 1, finger: 7, x: 0, y: 1, effort: 2 }, + { char: "", row: 0, col: 7, enabled: 1, finger: 7, x: 0, y: 1, effort: 1 }, + { char: "", row: 0, col: 8, enabled: 1, finger: 8, x: 0, y: 1, effort: 1 }, + { char: "", row: 0, col: 9, enabled: 1, finger: 9, x: 0, y: 1, effort: 2 }, + { char: "", row: 0, col: 10, enabled: 1, finger: 10, x: 0, y: 1, effort: 3 }, + { char: "", row: 0, col: 11, enabled: 0, finger: 10, x: 0, y: 1, effort: 7 }, + { char: "", row: 1, col: 0, enabled: 0, finger: 1, x: 0, y: 1, effort: 6 }, + { char: "", row: 1, col: 1, enabled: 1, finger: 1, x: 0, y: 1, effort: 2 }, + { char: "", row: 1, col: 2, enabled: 1, finger: 2, x: 0, y: 1, effort: 0 }, + { char: "", row: 1, col: 3, enabled: 1, finger: 3, x: 0, y: 1, effort: 0 }, + { char: "", row: 1, col: 4, enabled: 1, finger: 4, x: 0, y: 1, effort: 0 }, + { char: "", row: 1, col: 5, enabled: 1, finger: 4, x: 0, y: 1, effort: 1 }, + { char: "", row: 1, col: 6, enabled: 1, finger: 7, x: 0, y: 1, effort: 1 }, + { char: "", row: 1, col: 7, enabled: 1, finger: 7, x: 0, y: 1, effort: 0 }, + { char: "", row: 1, col: 8, enabled: 1, finger: 8, x: 0, y: 1, effort: 0 }, + { char: "", row: 1, col: 9, enabled: 1, finger: 9, x: 0, y: 1, effort: 0 }, + { char: "", row: 1, col: 10, enabled: 1, finger: 10, x: 0, y: 1, effort: 2 }, + { char: "", row: 1, col: 11, enabled: 0, finger: 10, x: 0, y: 1, effort: 6 }, + { char: "", row: 2, col: 0, enabled: 0, finger: 1, x: 0, y: 1, effort: 7 }, + { char: "", row: 2, col: 1, enabled: 1, finger: 1, x: 0, y: 1, effort: 6 }, + { char: "", row: 2, col: 2, enabled: 1, finger: 2, x: 0, y: 1, effort: 2.1 }, + { char: "", row: 2, col: 3, enabled: 1, finger: 3, x: 0, y: 1, effort: 1.1 }, + { char: "", row: 2, col: 4, enabled: 1, finger: 4, x: 0, y: 1, effort: 1.1 }, + { char: "", row: 2, col: 5, enabled: 1, finger: 4, x: 0, y: 1, effort: 3.1 }, + { char: "", row: 2, col: 6, enabled: 1, finger: 7, x: 0, y: 1, effort: 3.1 }, + { char: "", row: 2, col: 7, enabled: 1, finger: 7, x: 0, y: 1, effort: 1.1 }, + { char: "", row: 2, col: 8, enabled: 1, finger: 8, x: 0, y: 1, effort: 1.1 }, + { char: "", row: 2, col: 9, enabled: 1, finger: 9, x: 0, y: 1, effort: 2.1 }, + { char: "", row: 2, col: 10, enabled: 1, finger: 10, x: 0, y: 1, effort: 6 }, + { char: "", row: 2, col: 11, enabled: 0, finger: 10, x: 0, y: 1, effort: 7 }, + { char: "", row: 3, col: 5, enabled: 0, finger: 5, x: 0, y: 1, effort: 0 }, + { char: " ", row: 3, col: 6, enabled: 0, finger: 6, x: 0, y: 1, effort: 0 }, +]; rcdata = loadEffortValuesFromCookie("rcdataEffort", rcdata); var letter_position = []; -const word_list_url = 'words-english.json'; +const word_list_url = "words-english.json"; async function loadAllData() { - try { - const [wordsData] = await Promise.all([ - fetch(word_list_url).then(response => response.json()), - ]); - - words = wordsData; - getCharacters(); - generateSVG(); - } catch (error) { - console.error('Error loading data:', error); - } + try { + const [wordsData] = await Promise.all([ + fetch(word_list_url).then((response) => response.json()), + ]); + + words = wordsData; + getCharacters(); + generateSVG(); + } catch (error) { + console.error("Error loading data:", error); + } } var letter_freq = {}; @@ -98,1183 +179,1407 @@ var bigram_freq = {}; var trigram_freq = {}; var input_length = 0; function getCharacters() { - letter_freq = {}; - bigram_freq = {}; - trigram_freq = {}; - input_length = 0; - letter_position = []; - var count = 0; - var wordt; - for (var word in words) { - wordt = `" ${word} "` - count = words[word]; - for (let i = 0; i < wordt.length; i++) { - char = wordt.charAt(i); - if (!letter_freq[char]) { - letter_freq[char] = { count: 0, enabled: 1 } - if (char === ' ') { letter_freq[char].enabled = 0 } - } - letter_freq[char].count += count; - if (i > 0) { - bigram = wordt.charAt(i-1) + wordt.charAt(i); - if (!bigram_freq[bigram]) { - bigram_freq[bigram] = 0 - } - bigram_freq[bigram] += count; - } - if (i > 1) { - trigram = wordt.charAt(i-2) + wordt.charAt(i-1) + wordt.charAt(i); - if (!trigram_freq[trigram]) { - trigram_freq[trigram] = 0 - } - trigram_freq[trigram] += count; - } - } - input_length += (word.length + 1) * count; - } - var bigram_count = 0 - for(const _tmp in bigram_freq) { - bigram_count += 1 - } - console.log(`"there are ${bigram_count} bigrams"`) - - for(var tmp in trigram_freq) { - if (trigram_freq[tmp] <= 30) { - Reflect.deleteProperty(trigram_freq, tmp) - } - } - var trigram_count = 0 - for(const _tmp in trigram_freq) { - trigram_count += 1 - } - console.log(`"there are ${trigram_count} trigrams"`) - - letter_freq[" "].count = letter_freq[" "].count / 2; - console.log(`"input_length: ${input_length}`); - - sortLetterFreq(); + letter_freq = {}; + bigram_freq = {}; + trigram_freq = {}; + input_length = 0; + letter_position = []; + var count = 0; + var wordt; + for (var word in words) { + wordt = `" ${word} "`; + count = words[word]; + for (let i = 0; i < wordt.length; i++) { + char = wordt.charAt(i); + if (!letter_freq[char]) { + letter_freq[char] = { count: 0, enabled: 1 }; + if (char === " ") { + letter_freq[char].enabled = 0; + } + } + letter_freq[char].count += count; + if (i > 0) { + bigram = wordt.charAt(i - 1) + wordt.charAt(i); + if (!bigram_freq[bigram]) { + bigram_freq[bigram] = 0; + } + bigram_freq[bigram] += count; + } + if (i > 1) { + trigram = wordt.charAt(i - 2) + wordt.charAt(i - 1) + wordt.charAt(i); + if (!trigram_freq[trigram]) { + trigram_freq[trigram] = 0; + } + trigram_freq[trigram] += count; + } + } + input_length += (word.length + 1) * count; + } + var bigram_count = 0; + for (const _tmp in bigram_freq) { + bigram_count += 1; + } + console.log(`"there are ${bigram_count} bigrams"`); + + for (var tmp in trigram_freq) { + if (trigram_freq[tmp] <= 30) { + Reflect.deleteProperty(trigram_freq, tmp); + } + } + var trigram_count = 0; + for (const _tmp in trigram_freq) { + trigram_count += 1; + } + console.log(`"there are ${trigram_count} trigrams"`); + + letter_freq[" "].count = letter_freq[" "].count / 2; + console.log(`"input_length: ${input_length}`); + + sortLetterFreq(); } function getX(row, col) { - dx = 370; - if (col > 5) { - dx = dx + 40; - } - return dx + col * w + dx = 370; + if (col > 5) { + dx = dx + 40; + } + return dx + col * w; } function getY(row, col) { - return 10 + row * w + return 10 + row * w; } function getKey(row, col) { - for (let i = 0; i < rcdata.length; i++) { - if(rcdata[i].row === row && rcdata[i].col === col) { - return i - } - } - return 0 + for (let i = 0; i < rcdata.length; i++) { + if (rcdata[i].row === row && rcdata[i].col === col) { + return i; + } + } + return 0; } -var col = "" +var col = ""; var selectedElement, offsetx, offsety, sibling; var startkey, dropi, startx, starty, d; -const dragHandler = d3.drag() -.on("start", function(event, d) { - // console.log("start:",event.x,event.y); - closestdist = 9999; - startkey = "$" - for(let i = 0; i < letter_position.length; i++) { - const d2 = dist(event.x, event.y, letter_position[i].x+15, letter_position[i].y+15); // distance to centre of key - if (d2 < closestdist) { - closestdist = d2; - startkey = letter_position[i].letter - startx = letter_position[i].x; - starty = letter_position[i].y; - offsetx = event.x - startx - offsety = event.y - starty - } - } - if (closestdist < 12){ - d3.select(this).raise(); - } -}) -.on("drag", function(event, d) { - d3.select(this).attr("transform", `translate(${event.x-offsetx}, ${event.y-offsety})`); -}) -.on("end", function(event, ele) { - dropi = -1; - closestdist = 9999; - for (let i = 0; i < rcdata.length; i++) { - d = dist(event.x-offsetx, event.y-offsety, rcdata[i].x, rcdata[i].y); - if (d < closestdist) { - closestdist = d; - dropi = i; - } - } - - d3.select(this).attr("transform", `translate(${startx}, ${starty})`); - if (closestdist < 12){ - if (dropi >= 0){ - for (let i = 0; i < rcdata.length; i++) { - if (startkey === "␣") { - if (rcdata[i].char === " ") { - rcdata[i].char = "" - } - } else { - if (rcdata[i].char === startkey) { - rcdata[i].char = "" - } - } - } - rcdata[dropi].char = startkey - rcdata[dropi].enabled = 0 - letter_freq[startkey].enabled = 0 - generateLayout(); - generateCharacters(); - } else { - console.log(`"can't drop here ${dropi}"`) - } - } else { - // console.log("closest end",closestdist) - } -}); - -function generateSVG(){ - generateButtons(); - generateLayout(); - generateCharacters(); - generateGraphs(); - generateGraphs2(); - generateModeButtons(); - countCharsKeys(); - generateStats(); +const dragHandler = d3 + .drag() + .on("start", function (event, d) { + // console.log("start:",event.x,event.y); + closestdist = 9999; + startkey = "$"; + for (let i = 0; i < letter_position.length; i++) { + const d2 = dist( + event.x, + event.y, + letter_position[i].x + 15, + letter_position[i].y + 15, + ); // distance to centre of key + if (d2 < closestdist) { + closestdist = d2; + startkey = letter_position[i].letter; + startx = letter_position[i].x; + starty = letter_position[i].y; + offsetx = event.x - startx; + offsety = event.y - starty; + } + } + if (closestdist < 12) { + d3.select(this).raise(); + } + }) + .on("drag", function (event, d) { + d3.select(this).attr( + "transform", + `translate(${event.x - offsetx}, ${event.y - offsety})`, + ); + }) + .on("end", function (event, ele) { + dropi = -1; + closestdist = 9999; + for (let i = 0; i < rcdata.length; i++) { + d = dist(event.x - offsetx, event.y - offsety, rcdata[i].x, rcdata[i].y); + if (d < closestdist) { + closestdist = d; + dropi = i; + } + } + + d3.select(this).attr("transform", `translate(${startx}, ${starty})`); + if (closestdist < 12) { + if (dropi >= 0) { + for (let i = 0; i < rcdata.length; i++) { + if (startkey === "␣") { + if (rcdata[i].char === " ") { + rcdata[i].char = ""; + } + } else { + if (rcdata[i].char === startkey) { + rcdata[i].char = ""; + } + } + } + rcdata[dropi].char = startkey; + rcdata[dropi].enabled = 0; + letter_freq[startkey].enabled = 0; + generateLayout(); + generateCharacters(); + } else { + console.log(`"can't drop here ${dropi}"`); + } + } else { + // console.log("closest end",closestdist) + } + }); + +function generateSVG() { + generateButtons(); + generateLayout(); + generateCharacters(); + generateGraphs(); + generateGraphs2(); + generateModeButtons(); + countCharsKeys(); + generateStats(); } function clicked_run() { - results = []; // cleaned out after each run - best_results = []; // preserved over multiple runs - runs = 0; - iter = 0; - console.log("times",times) - uid_set = new Set(); - best_score = 1000000; - bestest_score = 1000000; - time_to_shuffle = false; - editable_keys = []; - setup = false; - running = true; - run(); + results = []; // cleaned out after each run + best_results = []; // preserved over multiple runs + runs = 0; + iter = 0; + console.log("times", times); + uid_set = new Set(); + best_score = 1000000; + bestest_score = 1000000; + time_to_shuffle = false; + editable_keys = []; + setup = false; + running = true; + run(); } function generateButtons() { - // border - // svg.append("rect").attr("x", 1).attr("y", 1).attr("width", swidth-2).attr("height", sheight-2) - // .attr("stroke", "#777777").attr("fill","#1b1c1f").attr("fill-opacity", "0").attr("rx", 8).attr("ry", 8) - - x = 1100 - y = 550 - // Clear button - svg.append("rect").attr("x", x).attr("y", y-30).attr("width", 80).attr("height", 26).attr("rx", 1).attr("ry", 1) - .attr("stroke", "#111111").attr("fill", "#aaaaaa").attr("fill-opacity", "1.0").attr("onclick", "clearLetters()"); - svg.append("text").attr("x", x + 40).attr("y", y-30+19).attr("font-size", 16).attr("text-anchor", "middle") - .attr("onclick", "clearLetters()").text("CLEAR"); - - // Run button - svg.append("rect").attr("x", x).attr("y", y).attr("width", 80).attr("height", 26) - .attr("stroke", "#111111").attr("fill", "#aaaaaa").attr("fill-opacity", "1.0").attr("rx", 1).attr("ry", 1) - .attr("onclick", "clicked_run()"); - - svg.append("text").attr("x", x + 40).attr("y", y+19).attr("font-size", 16).attr("text-anchor", "middle") - .attr("onclick", "clicked_run()") - .text("RUN"); - - // key weight edit button - svg.append("rect").attr("x", x).attr("y", y-90).attr("width", 80).attr("height", 25) - .attr("stroke", "#777777").attr("fill", "#aaaaaa").attr("fill-opacity", "1.0").attr("onclick", "openEffortPopup()") - svg.append("text").attr("x", x+40).attr("y", y-90+18).attr("font-size", 16).attr("text-anchor", "middle") - .attr("onclick", "openEffortPopup()").text("Edit Effort"); - - svg.append("text").attr("x", x-40).attr("y", y-60+19).attr("font-size", 16).attr("text-anchor", "middle").attr("fill", "#aaaaaa") - .text("Iterations:"); - const timesField = svg.append("foreignObject").attr("x", x).attr("y", y - 60) - .attr("width", 80).attr("height", 26).append("xhtml:input") - .attr("type", "number").attr("step", "0.01").style("width", "100%").style("height", "100%").style("border", "1px solid #ccc") - .style("background", "#555").style("padding", "3px").style("font-size", "16px").style("text-align", "center"); - - timesField.property("value", times); - timesField.on("input", function() { - const value = d3.select(this).property("value"); - if (value === "") { - d3.select(this).property("value", "1"); - times = 1; - } else { - times = parseInt(value, 10); - } - generateGraphs(); - generateGraphs2(); - }); - - // keyboard layout bounding box - svg.append("rect").attr("x", 360).attr("y", 0).attr("width", 508).attr("height", 168) - .attr("stroke", "#777777").attr("fill", "#1b1c1f").attr("fill-opacity", "0.0").attr("rx", 8).attr("ry", 8) + // border + // svg.append("rect").attr("x", 1).attr("y", 1).attr("width", swidth-2).attr("height", sheight-2) + // .attr("stroke", "#777777").attr("fill","#1b1c1f").attr("fill-opacity", "0").attr("rx", 8).attr("ry", 8) + + x = 1100; + y = 550; + // Clear button + svg + .append("rect") + .attr("x", x) + .attr("y", y - 30) + .attr("width", 80) + .attr("height", 26) + .attr("rx", 1) + .attr("ry", 1) + .attr("stroke", "#111111") + .attr("fill", "#aaaaaa") + .attr("fill-opacity", "1.0") + .attr("onclick", "clearLetters()"); + svg + .append("text") + .attr("x", x + 40) + .attr("y", y - 30 + 19) + .attr("font-size", 16) + .attr("text-anchor", "middle") + .attr("onclick", "clearLetters()") + .text("CLEAR"); + + // Run button + svg + .append("rect") + .attr("x", x) + .attr("y", y) + .attr("width", 80) + .attr("height", 26) + .attr("stroke", "#111111") + .attr("fill", "#aaaaaa") + .attr("fill-opacity", "1.0") + .attr("rx", 1) + .attr("ry", 1) + .attr("onclick", "clicked_run()"); + + svg + .append("text") + .attr("x", x + 40) + .attr("y", y + 19) + .attr("font-size", 16) + .attr("text-anchor", "middle") + .attr("onclick", "clicked_run()") + .text("RUN"); + + // key weight edit button + svg + .append("rect") + .attr("x", x) + .attr("y", y - 90) + .attr("width", 80) + .attr("height", 25) + .attr("stroke", "#777777") + .attr("fill", "#aaaaaa") + .attr("fill-opacity", "1.0") + .attr("onclick", "openEffortPopup()"); + svg + .append("text") + .attr("x", x + 40) + .attr("y", y - 90 + 18) + .attr("font-size", 16) + .attr("text-anchor", "middle") + .attr("onclick", "openEffortPopup()") + .text("Edit Effort"); + + svg + .append("text") + .attr("x", x - 40) + .attr("y", y - 60 + 19) + .attr("font-size", 16) + .attr("text-anchor", "middle") + .attr("fill", "#aaaaaa") + .text("Iterations:"); + const timesField = svg + .append("foreignObject") + .attr("x", x) + .attr("y", y - 60) + .attr("width", 80) + .attr("height", 26) + .append("xhtml:input") + .attr("type", "number") + .attr("step", "0.01") + .style("width", "100%") + .style("height", "100%") + .style("border", "1px solid #ccc") + .style("background", "#555") + .style("padding", "3px") + .style("font-size", "16px") + .style("text-align", "center"); + + timesField.property("value", times); + timesField.on("input", function () { + const value = d3.select(this).property("value"); + if (value === "") { + d3.select(this).property("value", "1"); + times = 1; + } else { + times = parseInt(value, 10); + } + generateGraphs(); + generateGraphs2(); + }); + + // keyboard layout bounding box + svg + .append("rect") + .attr("x", 360) + .attr("y", 0) + .attr("width", 508) + .attr("height", 168) + .attr("stroke", "#777777") + .attr("fill", "#1b1c1f") + .attr("fill-opacity", "0.0") + .attr("rx", 8) + .attr("ry", 8); } function handleCircleHover(data, element) { - rcdata = data.config; + rcdata = data.config; - d3.select(element) - .attr("r", 5) - .attr("fill", "#ff6600") - // redraw the layout - generateLayout(); + d3.select(element).attr("r", 5).attr("fill", "#ff6600"); + // redraw the layout + generateLayout(); } function handleCircleLeave(data, element) { - // Reset the circle - d3.select(element) - .attr("r", 3) - .attr("fill", "#999999"); + // Reset the circle + d3.select(element).attr("r", 3).attr("fill", "#999999"); - svg.selectAll(".tooltip").remove(); + svg.selectAll(".tooltip").remove(); } function generateGraphs() { - console.log("generateGraphs") - var yBase = 390; - var xLeft = 380; - // Draw axes once (only if they don't exist) - if (svg.select(".x-axis").empty()) { - svg.append("line") // x axis - .attr("class", "x-axis") - .attr("x1", xLeft) - .attr("y1", yBase) - .attr("x2", 900) - .attr("y2", yBase) - .style('stroke-width', 2) - .style("stroke", "#999999"); - } - - if (svg.select(".y-axis").empty()) { - svg.append("line") // y axis - .attr("class", "y-axis") - .attr("x1", xLeft) - .attr("y1", yBase-150) - .attr("x2", xLeft) - .attr("y2", yBase) - .style('stroke-width', 2) - .style("stroke", "#999999"); - } - svg.selectAll(".x-label").remove(); - // Draw x-axis labels once - var xstep = (900-xLeft)/times - var k = 1; - while ((900-xLeft)/(times/k) < 20 && k < 10){ - k += 1 - } - for (let i = k; i <= times; i += k) { - svg.append("text") - .attr("class", "x-label") - .attr("x", xLeft + (i-0.5) * xstep) - .attr("y", yBase+18) - .attr("font-size", 14) - .attr("text-anchor", "middle") - .attr("fill", "#999999") - .text(i); - } - - // Calculate scale - var min_score = 100000; - var max_score = 0; - for (let i = 0; i < best_results.length; i++) { - if (best_results[i].score < min_score) { - min_score = best_results[i].score; - } - if (best_results[i].score > max_score) { - max_score = best_results[i].score; - } - } - if (max_score === 0){ - max_score = 10; - } - // Remove and redraw y-axis ticks when scale changes - svg.selectAll(".y-tick").remove(); - - var validIntervals = [100,50,20,10,5,2,1,0.5,0.2,0.1] - var it=0; - while (max_score/validIntervals[it] < 5 && it < 9){ - it+=1; - } - var tickInterval = validIntervals[it]; - var maxTick = tickInterval * Math.ceil(max_score/tickInterval) - var tickCount = Math.ceil(max_score/tickInterval) - var scale = 150 / maxTick; - // console.log("graph",max_score, tickCount, tickInterval, scale); - - svg.append("text") - .attr("class", "y-tick") - .attr("x", xLeft-20) - .attr("y", yBase-75) - .attr("transform","rotate(-90, "+(xLeft-40)+","+(yBase-75)+")") - .attr("font-size", 14) - .attr("text-anchor", "end") - .attr("fill", "#999999") - .text("Score"); - - for (let i = 0; i <= tickCount; i++) { - let tickValue = (i * tickInterval).toString() - if (max_score < 1000 && tickValue.length > 3){ - tickValue = tickValue.substring(0,3) - } - const yPos = yBase - i*tickInterval*scale; - - // Tick mark - svg.append("line") - .attr("class", "y-tick") - .attr("x1", xLeft-5) - .attr("y1", yPos) - .attr("x2", xLeft+1) - .attr("y2", yPos) - .style('stroke-width', 2) - .style("stroke", "#999999"); - - // Tick label - svg.append("text") - .attr("class", "y-tick") - .attr("x", xLeft-10) - .attr("y", yPos + 5) - .attr("font-size", 14) - .attr("text-anchor", "end") - .attr("fill", "#999999") - .text(tickValue); - } - - // Use D3 data binding with enter/exit pattern - var circles = svg.selectAll(".data-point") - .data(best_results, d => d.iter); // Use iter as key for object constancy - - // Remove old circles (if needed) - circles.exit().remove(); - - // Add new circles - circles.enter() - .append("circle") - .attr("class", "data-point") - .attr("cx", d => xLeft + (d.iter + 0.5) * xstep) - .attr("cy", d => yBase - d.score * scale) - .attr("r", 3) - .attr("fill", "#999999") - .attr("stroke", "#ffffff") - .attr("onmouseover", d => "showTooltip(evt,'"+(d.score).toFixed(2)+"')").attr("onmouseout", "hideTooltip()") - .on("mouseover", function(event, d) { - handleCircleHover(d, this); - }) - .on("mouseout", function(event, d) { - handleCircleLeave(d, this); - }); - - // Update existing circles (in case positions need to change based on scale) - circles - .attr("cx", d => xLeft + (d.iter + 0.5) * xstep) - .attr("cy", d => yBase - d.score * scale); + console.log("generateGraphs"); + var yBase = 390; + var xLeft = 380; + // Draw axes once (only if they don't exist) + if (svg.select(".x-axis").empty()) { + svg + .append("line") // x axis + .attr("class", "x-axis") + .attr("x1", xLeft) + .attr("y1", yBase) + .attr("x2", 900) + .attr("y2", yBase) + .style("stroke-width", 2) + .style("stroke", "#999999"); + } + + if (svg.select(".y-axis").empty()) { + svg + .append("line") // y axis + .attr("class", "y-axis") + .attr("x1", xLeft) + .attr("y1", yBase - 150) + .attr("x2", xLeft) + .attr("y2", yBase) + .style("stroke-width", 2) + .style("stroke", "#999999"); + } + svg.selectAll(".x-label").remove(); + // Draw x-axis labels once + var xstep = (900 - xLeft) / times; + var k = 1; + while ((900 - xLeft) / (times / k) < 20 && k < 10) { + k += 1; + } + for (let i = k; i <= times; i += k) { + svg + .append("text") + .attr("class", "x-label") + .attr("x", xLeft + (i - 0.5) * xstep) + .attr("y", yBase + 18) + .attr("font-size", 14) + .attr("text-anchor", "middle") + .attr("fill", "#999999") + .text(i); + } + + // Calculate scale + var min_score = 100000; + var max_score = 0; + for (let i = 0; i < best_results.length; i++) { + if (best_results[i].score < min_score) { + min_score = best_results[i].score; + } + if (best_results[i].score > max_score) { + max_score = best_results[i].score; + } + } + if (max_score === 0) { + max_score = 10; + } + // Remove and redraw y-axis ticks when scale changes + svg.selectAll(".y-tick").remove(); + + var validIntervals = [100, 50, 20, 10, 5, 2, 1, 0.5, 0.2, 0.1]; + var it = 0; + while (max_score / validIntervals[it] < 5 && it < 9) { + it += 1; + } + var tickInterval = validIntervals[it]; + var maxTick = tickInterval * Math.ceil(max_score / tickInterval); + var tickCount = Math.ceil(max_score / tickInterval); + var scale = 150 / maxTick; + // console.log("graph",max_score, tickCount, tickInterval, scale); + + svg + .append("text") + .attr("class", "y-tick") + .attr("x", xLeft - 20) + .attr("y", yBase - 75) + .attr("transform", "rotate(-90, " + (xLeft - 40) + "," + (yBase - 75) + ")") + .attr("font-size", 14) + .attr("text-anchor", "end") + .attr("fill", "#999999") + .text("Score"); + + for (let i = 0; i <= tickCount; i++) { + let tickValue = (i * tickInterval).toString(); + if (max_score < 1000 && tickValue.length > 3) { + tickValue = tickValue.substring(0, 3); + } + const yPos = yBase - i * tickInterval * scale; + + // Tick mark + svg + .append("line") + .attr("class", "y-tick") + .attr("x1", xLeft - 5) + .attr("y1", yPos) + .attr("x2", xLeft + 1) + .attr("y2", yPos) + .style("stroke-width", 2) + .style("stroke", "#999999"); + + // Tick label + svg + .append("text") + .attr("class", "y-tick") + .attr("x", xLeft - 10) + .attr("y", yPos + 5) + .attr("font-size", 14) + .attr("text-anchor", "end") + .attr("fill", "#999999") + .text(tickValue); + } + + // Use D3 data binding with enter/exit pattern + var circles = svg.selectAll(".data-point").data(best_results, (d) => d.iter); // Use iter as key for object constancy + + // Remove old circles (if needed) + circles.exit().remove(); + + // Add new circles + circles + .enter() + .append("circle") + .attr("class", "data-point") + .attr("cx", (d) => xLeft + (d.iter + 0.5) * xstep) + .attr("cy", (d) => yBase - d.score * scale) + .attr("r", 3) + .attr("fill", "#999999") + .attr("stroke", "#ffffff") + .attr("onmouseover", (d) => "showTooltip(evt,'" + d.score.toFixed(2) + "')") + .attr("onmouseout", "hideTooltip()") + .on("mouseover", function (event, d) { + handleCircleHover(d, this); + }) + .on("mouseout", function (event, d) { + handleCircleLeave(d, this); + }); + + // Update existing circles (in case positions need to change based on scale) + circles + .attr("cx", (d) => xLeft + (d.iter + 0.5) * xstep) + .attr("cy", (d) => yBase - d.score * scale); } -var mode = 'sfb'; +var mode = "sfb"; var mult = 100; var yLabel = "SFB"; function generateGraphs2() { - console.log("generateGraphs2") - var yBase = 590; - var xLeft = 380; - // Draw axes once (only if they don't exist) - if (svg.select(".x-axis2").empty()) { - svg.append("line") // x axis - .attr("class", "x-axis2") - .attr("x1", xLeft) - .attr("y1", yBase) - .attr("x2", 900) - .attr("y2", yBase) - .style('stroke-width', 2) - .style("stroke", "#999999"); - } - - if (svg.select(".y-axis2").empty()) { - svg.append("line") // y axis - .attr("class", "y-axis2") - .attr("x1", xLeft) - .attr("y1", yBase-150) - .attr("x2", xLeft) - .attr("y2", yBase) - .style('stroke-width', 2) - .style("stroke", "#999999"); - } - svg.selectAll(".x-label2").remove(); - // Draw x-axis labels once - var xstep = (900-xLeft)/times - var k = 1; - while ((900-xLeft)/(times/k) < 20 && k < 10){ - k += 1 - } - for (let i = k; i <= times; i += k) { - svg.append("text") - .attr("class", "x-label2") - .attr("x", xLeft + (i-0.5) * xstep) - .attr("y", yBase+18) - .attr("font-size", 14) - .attr("text-anchor", "middle") - .attr("fill", "#999999") - .text(i); - } - - // Calculate scale - var min_score = 100000; - var max_score = 0; - var percentage = 0; - for (let i = 0; i < best_results.length; i++) { - percentage = mult*best_results[i].result[mode]/input_length; - if (percentage < min_score) { - min_score = percentage; - } - if (percentage > max_score) { - max_score = percentage; - } - } - if (max_score === 0){ - max_score = 1; - } - // Remove and redraw y-axis ticks when scale changes - svg.selectAll(".y-tick2").remove(); - - var validIntervals = [100,50,20,10,5,2,1,0.5,0.2,0.1] - var it=0; - while (max_score/validIntervals[it] < 5 && it < 9){ - it+=1; - } - var tickInterval = validIntervals[it]; - var maxTick = tickInterval * Math.ceil(max_score/tickInterval) - var tickCount = Math.ceil(max_score/tickInterval) - var scale = 150 / maxTick; - // console.log("graph2",max_score, tickCount, tickInterval, scale); - - svg.append("text") - .attr("class", "y-tick2") - .attr("x", xLeft-20) - .attr("y", yBase-75) - .attr("transform","rotate(-90, "+(xLeft-40)+","+(yBase-75)+")") - .attr("font-size", 14) - .attr("text-anchor", "end") - .attr("fill", "#999999") - .text(yLabel); - - for (let i = 0; i <= tickCount; i++) { - let tickValue = (i * tickInterval).toString() - if (max_score < 1000 && tickValue.length > 3){ - tickValue = tickValue.substring(0,3) - } - const yPos = yBase - i*tickInterval*scale; - - // Tick mark - svg.append("line") - .attr("class", "y-tick2") - .attr("x1", xLeft-5) - .attr("y1", yPos) - .attr("x2", xLeft+1) - .attr("y2", yPos) - .style('stroke-width', 2) - .style("stroke", "#999999"); - - // Tick label - svg.append("text") - .attr("class", "y-tick2") - .attr("x", xLeft-10) - .attr("y", yPos + 5) - .attr("font-size", 14) - .attr("text-anchor", "end") - .attr("fill", "#999999") - .text(tickValue); - } - - // Use D3 data binding with enter/exit pattern - var circles = svg.selectAll(".data-point2") - .data(best_results, d => d.iter); // Use iter as key for object constancy - - // Remove old circles (if needed) - circles.exit().remove(); - - // Add new circles - circles.enter() - .append("circle") - .attr("class", "data-point2") - .attr("cx", d => xLeft + (d.iter + 0.5) * xstep) - .attr("cy", d => yBase - (mult*d.result[mode]/input_length) * scale) - .attr("r", 3) - .attr("fill", "#999999") - .attr("stroke", "#ffffff") - .attr("onmouseover", d => "showTooltip(evt,'"+(mult*d.result[mode]/input_length).toFixed(2)+"')").attr("onmouseout", "hideTooltip()") - .on("mouseover", function(event, d) { - handleCircleHover(d, this); - }) - .on("mouseout", function(event, d) { - handleCircleLeave(d, this); - }); - - // Update existing circles (in case positions need to change based on scale) - circles - .attr("cx", d => xLeft + (d.iter + 0.5) * xstep) - .attr("cy", d => yBase - (mult*d.result[mode]/input_length) * scale) - .attr("onmouseover", d => "showTooltip(evt,'"+(mult*d.result[mode]/input_length).toFixed(2)+"')").attr("onmouseout", "hideTooltip()"); + console.log("generateGraphs2"); + var yBase = 590; + var xLeft = 380; + // Draw axes once (only if they don't exist) + if (svg.select(".x-axis2").empty()) { + svg + .append("line") // x axis + .attr("class", "x-axis2") + .attr("x1", xLeft) + .attr("y1", yBase) + .attr("x2", 900) + .attr("y2", yBase) + .style("stroke-width", 2) + .style("stroke", "#999999"); + } + + if (svg.select(".y-axis2").empty()) { + svg + .append("line") // y axis + .attr("class", "y-axis2") + .attr("x1", xLeft) + .attr("y1", yBase - 150) + .attr("x2", xLeft) + .attr("y2", yBase) + .style("stroke-width", 2) + .style("stroke", "#999999"); + } + svg.selectAll(".x-label2").remove(); + // Draw x-axis labels once + var xstep = (900 - xLeft) / times; + var k = 1; + while ((900 - xLeft) / (times / k) < 20 && k < 10) { + k += 1; + } + for (let i = k; i <= times; i += k) { + svg + .append("text") + .attr("class", "x-label2") + .attr("x", xLeft + (i - 0.5) * xstep) + .attr("y", yBase + 18) + .attr("font-size", 14) + .attr("text-anchor", "middle") + .attr("fill", "#999999") + .text(i); + } + + // Calculate scale + var min_score = 100000; + var max_score = 0; + var percentage = 0; + for (let i = 0; i < best_results.length; i++) { + percentage = (mult * best_results[i].result[mode]) / input_length; + if (percentage < min_score) { + min_score = percentage; + } + if (percentage > max_score) { + max_score = percentage; + } + } + if (max_score === 0) { + max_score = 1; + } + // Remove and redraw y-axis ticks when scale changes + svg.selectAll(".y-tick2").remove(); + + var validIntervals = [100, 50, 20, 10, 5, 2, 1, 0.5, 0.2, 0.1]; + var it = 0; + while (max_score / validIntervals[it] < 5 && it < 9) { + it += 1; + } + var tickInterval = validIntervals[it]; + var maxTick = tickInterval * Math.ceil(max_score / tickInterval); + var tickCount = Math.ceil(max_score / tickInterval); + var scale = 150 / maxTick; + // console.log("graph2",max_score, tickCount, tickInterval, scale); + + svg + .append("text") + .attr("class", "y-tick2") + .attr("x", xLeft - 20) + .attr("y", yBase - 75) + .attr("transform", "rotate(-90, " + (xLeft - 40) + "," + (yBase - 75) + ")") + .attr("font-size", 14) + .attr("text-anchor", "end") + .attr("fill", "#999999") + .text(yLabel); + + for (let i = 0; i <= tickCount; i++) { + let tickValue = (i * tickInterval).toString(); + if (max_score < 1000 && tickValue.length > 3) { + tickValue = tickValue.substring(0, 3); + } + const yPos = yBase - i * tickInterval * scale; + + // Tick mark + svg + .append("line") + .attr("class", "y-tick2") + .attr("x1", xLeft - 5) + .attr("y1", yPos) + .attr("x2", xLeft + 1) + .attr("y2", yPos) + .style("stroke-width", 2) + .style("stroke", "#999999"); + + // Tick label + svg + .append("text") + .attr("class", "y-tick2") + .attr("x", xLeft - 10) + .attr("y", yPos + 5) + .attr("font-size", 14) + .attr("text-anchor", "end") + .attr("fill", "#999999") + .text(tickValue); + } + + // Use D3 data binding with enter/exit pattern + var circles = svg.selectAll(".data-point2").data(best_results, (d) => d.iter); // Use iter as key for object constancy + + // Remove old circles (if needed) + circles.exit().remove(); + + // Add new circles + circles + .enter() + .append("circle") + .attr("class", "data-point2") + .attr("cx", (d) => xLeft + (d.iter + 0.5) * xstep) + .attr("cy", (d) => yBase - ((mult * d.result[mode]) / input_length) * scale) + .attr("r", 3) + .attr("fill", "#999999") + .attr("stroke", "#ffffff") + .attr( + "onmouseover", + (d) => + "showTooltip(evt,'" + + ((mult * d.result[mode]) / input_length).toFixed(2) + + "')", + ) + .attr("onmouseout", "hideTooltip()") + .on("mouseover", function (event, d) { + handleCircleHover(d, this); + }) + .on("mouseout", function (event, d) { + handleCircleLeave(d, this); + }); + + // Update existing circles (in case positions need to change based on scale) + circles + .attr("cx", (d) => xLeft + (d.iter + 0.5) * xstep) + .attr("cy", (d) => yBase - ((mult * d.result[mode]) / input_length) * scale) + .attr( + "onmouseover", + (d) => + "showTooltip(evt,'" + + ((mult * d.result[mode]) / input_length).toFixed(2) + + "')", + ) + .attr("onmouseout", "hideTooltip()"); } -function setMode(thing){ - if (thing === 'SFB'){ - mode = 'sfb'; - mult = 100; - } else if (thing === 'Effort') { - mode = 'effort'; - mult = 1; - } else if (thing === "Scissors") { - mode = 'scissors'; - mult = 100; - } else if (thing === "LSB") { - mode = 'lat_str'; - mult = 100; - } else if (thing === "SFS") { - mode = 'sfs'; - mult = 100; - } - yLabel = thing - console.log(`"setting mode to ${mode}"`); - generateGraphs2(); +function setMode(thing) { + if (thing === "SFB") { + mode = "sfb"; + mult = 100; + } else if (thing === "Effort") { + mode = "effort"; + mult = 1; + } else if (thing === "Scissors") { + mode = "scissors"; + mult = 100; + } else if (thing === "LSB") { + mode = "lat_str"; + mult = 100; + } else if (thing === "SFS") { + mode = "sfs"; + mult = 100; + } + yLabel = thing; + console.log(`"setting mode to ${mode}"`); + generateGraphs2(); } function generateModeButtons() { - var yBase = 640; - var xLeft = 380; - var buttons = ["SFB","Effort","Scissors","LSB","SFS"] - if (svg.select(".mode-button").empty()) { - - for(let i = 0; i < buttons.length; i++){ - svg.append("rect") // x axis - .attr("class", "mode-button") - .attr("x", xLeft+(i*100)) - .attr("y", yBase) - .attr("width", 90) - .attr("height", 30) - .attr("stroke", "#333333") - .attr("fill", "#222222") - .attr("onclick", "setMode('"+buttons[i]+"')") - svg.append("text") - .attr("x", xLeft+(i*100)+45) - .attr("y", yBase+16) - .attr("fill", "#999") - .attr("font-size", 16) - .attr("font-family", "Roboto Mono, monospace") - .attr("text-anchor", "middle") - .attr("dominant-baseline", "middle") - .style("pointer-events", "none") - .text(buttons[i]) - } - } + var yBase = 640; + var xLeft = 380; + var buttons = ["SFB", "Effort", "Scissors", "LSB", "SFS"]; + if (svg.select(".mode-button").empty()) { + for (let i = 0; i < buttons.length; i++) { + svg + .append("rect") // x axis + .attr("class", "mode-button") + .attr("x", xLeft + i * 100) + .attr("y", yBase) + .attr("width", 90) + .attr("height", 30) + .attr("stroke", "#333333") + .attr("fill", "#222222") + .attr("onclick", "setMode('" + buttons[i] + "')"); + svg + .append("text") + .attr("x", xLeft + i * 100 + 45) + .attr("y", yBase + 16) + .attr("fill", "#999") + .attr("font-size", 16) + .attr("font-family", "Roboto Mono, monospace") + .attr("text-anchor", "middle") + .attr("dominant-baseline", "middle") + .style("pointer-events", "none") + .text(buttons[i]); + } + } } function generateLayout() { - for (let i = 0; i < rcdata.length; i++) { - x = getX(rcdata[i].row,rcdata[i].col); - y = getY(rcdata[i].row,rcdata[i].col); - rcdata[i].x = x; - rcdata[i].y = y; - // console.log(i, rcdata[i].x, rcdata[i].y) - } - const keyGroups = svg.selectAll("g.key-group") - .data(rcdata, d => `${d.row}-${d.col}`) - - keyGroups.exit().remove(); - - const keyGroupsEnter = keyGroups.enter() - .append("g") - .attr("class", "key-group") - .on("click", (event, d) => { - toggleKeyOnOff(d); - }); - - // Append the rectangle to each new group - keyGroupsEnter.append("rect") - .attr("width", 30) - .attr("height", 30) - .attr("rx", 6) - .attr("ry", 6) - .attr("fill", "#aaaaaa") - - // Append the text to each new group - keyGroupsEnter.append("text") - .attr("x", 15) - .attr("y", 15) - .attr("font-size", 16) - .attr("font-family", "Roboto Mono, monospace") - .attr("text-anchor", "middle") - .attr("dominant-baseline", "middle") - .style("pointer-events", "none"); // Prevents text from capturing mouse events from the group - - const mergedGroups = keyGroupsEnter.merge(keyGroups); - - mergedGroups.attr("transform", d => `translate(${d.x}, ${d.y})`); - - mergedGroups.select("rect") - .attr("stroke-width", "1") - .attr("stroke", d => d.enabled === 1 ? "#00dd00" : "#dd0000"); - - mergedGroups.select("text") - .text(d => d.char === " " ? "␣" : d.char); + for (let i = 0; i < rcdata.length; i++) { + x = getX(rcdata[i].row, rcdata[i].col); + y = getY(rcdata[i].row, rcdata[i].col); + rcdata[i].x = x; + rcdata[i].y = y; + // console.log(i, rcdata[i].x, rcdata[i].y) + } + const keyGroups = svg + .selectAll("g.key-group") + .data(rcdata, (d) => `${d.row}-${d.col}`); + + keyGroups.exit().remove(); + + const keyGroupsEnter = keyGroups + .enter() + .append("g") + .attr("class", "key-group") + .on("click", (event, d) => { + toggleKeyOnOff(d); + }); + + // Append the rectangle to each new group + keyGroupsEnter + .append("rect") + .attr("width", 30) + .attr("height", 30) + .attr("rx", 6) + .attr("ry", 6) + .attr("fill", "#aaaaaa"); + + // Append the text to each new group + keyGroupsEnter + .append("text") + .attr("x", 15) + .attr("y", 15) + .attr("font-size", 16) + .attr("font-family", "Roboto Mono, monospace") + .attr("text-anchor", "middle") + .attr("dominant-baseline", "middle") + .style("pointer-events", "none"); // Prevents text from capturing mouse events from the group + + const mergedGroups = keyGroupsEnter.merge(keyGroups); + + mergedGroups.attr("transform", (d) => `translate(${d.x}, ${d.y})`); + + mergedGroups + .select("rect") + .attr("stroke-width", "1") + .attr("stroke", (d) => (d.enabled === 1 ? "#00dd00" : "#dd0000")); + + mergedGroups.select("text").text((d) => (d.char === " " ? "␣" : d.char)); } -function sortLetterFreq(){ - // sort letters highest to lowest. ETAOINSHRDLU etc - var keyValueArray = Object.entries(letter_freq); - keyValueArray.sort((a, b) => b[1].count - a[1].count); - var tmp = Object.fromEntries(keyValueArray); - letter_position = [] - var ix = 920; - x = ix; - y = 20; - for (var letter in tmp) { - letter_position.push({letter: letter, count: letter_freq[letter].count, enabled: letter_freq[letter].enabled, x: x, y: y}); - x += 38; - if (x >= ix+(7*38)) { - x = ix; - y += 38; - } - } - +function sortLetterFreq() { + // sort letters highest to lowest. ETAOINSHRDLU etc + var keyValueArray = Object.entries(letter_freq); + keyValueArray.sort((a, b) => b[1].count - a[1].count); + var tmp = Object.fromEntries(keyValueArray); + letter_position = []; + var ix = 920; + x = ix; + y = 20; + for (var letter in tmp) { + letter_position.push({ + letter: letter, + count: letter_freq[letter].count, + enabled: letter_freq[letter].enabled, + x: x, + y: y, + }); + x += 38; + if (x >= ix + 7 * 38) { + x = ix; + y += 38; + } + } } function generateCharacters() { - console.log("generateCharacters"); - - const letterGroups = svg.selectAll("g.letter-group").data(letter_position, d => d.letter); - - letterGroups.exit().remove(); - - const letterGroupsEnter = letterGroups.enter() - .append("g") - .attr("class", "letter-group") - // The drag handler and click listener are applied only once on creation. - .call(dragHandler) - .on("click", (event, d) => { - // This function would be defined elsewhere in your code - toggleCharOnOff(d.letter); - }); - - // Append the rectangle to the new groups - letterGroupsEnter.append("rect") - .attr("width", 30) - .attr("height", 30) - .attr("rx", 4) - .attr("ry", 4) - .attr("fill", "#aaaaaa") - .attr("stroke-width", "1"); - - // Append the text to the new groups - letterGroupsEnter.append("text") - .attr("x", 15) // Center horizontally - .attr("y", 15) // Center vertically - .attr("font-size", 16) - .attr("font-family", "Roboto Mono, monospace") - .attr("text-anchor", "middle") - .attr("dominant-baseline", "middle") - .style("pointer-events", "none"); // Ensures clicks are registered by the group - - const mergedGroups = letterGroupsEnter.merge(letterGroups); - - mergedGroups.attr("transform", d => `translate(${d.x}, ${d.y})`); - - mergedGroups.select("rect").attr("stroke", d => letter_freq[d.letter].enabled === 1 ? "#00ff00" : "#ff0000"); - - mergedGroups.select("text").text(d => d.letter === " " ? "␣" : d.letter); // Use a special character for space + console.log("generateCharacters"); + + const letterGroups = svg + .selectAll("g.letter-group") + .data(letter_position, (d) => d.letter); + + letterGroups.exit().remove(); + + const letterGroupsEnter = letterGroups + .enter() + .append("g") + .attr("class", "letter-group") + // The drag handler and click listener are applied only once on creation. + .call(dragHandler) + .on("click", (event, d) => { + // This function would be defined elsewhere in your code + toggleCharOnOff(d.letter); + }); + + // Append the rectangle to the new groups + letterGroupsEnter + .append("rect") + .attr("width", 30) + .attr("height", 30) + .attr("rx", 4) + .attr("ry", 4) + .attr("fill", "#aaaaaa") + .attr("stroke-width", "1"); + + // Append the text to the new groups + letterGroupsEnter + .append("text") + .attr("x", 15) // Center horizontally + .attr("y", 15) // Center vertically + .attr("font-size", 16) + .attr("font-family", "Roboto Mono, monospace") + .attr("text-anchor", "middle") + .attr("dominant-baseline", "middle") + .style("pointer-events", "none"); // Ensures clicks are registered by the group + + const mergedGroups = letterGroupsEnter.merge(letterGroups); + + mergedGroups.attr("transform", (d) => `translate(${d.x}, ${d.y})`); + + mergedGroups + .select("rect") + .attr("stroke", (d) => + letter_freq[d.letter].enabled === 1 ? "#00ff00" : "#ff0000", + ); + + mergedGroups.select("text").text((d) => (d.letter === " " ? "␣" : d.letter)); // Use a special character for space } function countCharsKeys() { - var key_count = 0; - var char_count = 0; - for (let i = 0; i < rcdata.length; i++) { - on = rcdata[i].enabled; - if (on === 1) { - key_count += 1; - } - } - for (var m in letter_freq) { - if (letter_freq[m].enabled === 1) { - char_count += 1; - } - } - error_text = ""; - error = false; - var diff = 0 - if (key_count > char_count) { - diff = key_count - char_count - error_text = `"Too many keys (${diff}); Select more characters or deselect some keys"`; - error = true; - } else if(char_count > key_count) { - diff = char_count - key_count - error_text = `"Too many chars (${diff}); Select fewer characters or select some more keys"`; - error = true; - } + var key_count = 0; + var char_count = 0; + for (let i = 0; i < rcdata.length; i++) { + on = rcdata[i].enabled; + if (on === 1) { + key_count += 1; + } + } + for (var m in letter_freq) { + if (letter_freq[m].enabled === 1) { + char_count += 1; + } + } + error_text = ""; + error = false; + var diff = 0; + if (key_count > char_count) { + diff = key_count - char_count; + error_text = `"Too many keys (${diff}); Select more characters or deselect some keys"`; + error = true; + } else if (char_count > key_count) { + diff = char_count - key_count; + error_text = `"Too many chars (${diff}); Select fewer characters or select some more keys"`; + error = true; + } } function generateStats() { - console.log("generateStats") - const infoPanel = d3.select("#info-panel"); - - infoPanel.html(null); - - infoPanel.append("text").attr("x", 340).attr("y", 200).attr("fill", "#ffaaaa") - .attr("font-size", 13).attr("text-anchor", "left") - .attr("font-family", "Roboto Mono") - .text(error_text); - - // === RUN COUNTER === - x = 1050 - y = 568 - // infoPanel.append("text").attr("x", x).attr("y", y).attr("fill", "#aaaaaa") - // .attr("font-size", 20).attr("text-anchor", "left").text(runs); - if (iter >= 0) { - infoPanel.append("text").attr("x", x-55).attr("y", y).attr("fill", "#aaaaaa") - .attr("font-size", 20).attr("text-anchor", "left").text((100 * (iter+1) / times).toFixed(1) + "%"); - } - // === SCORES === - x = 20 - y = 30 - var weight_x = 136 - var min_x = 196 - let score_x = 255 - - // headers - infoPanel.append("text").attr("x", x+weight_x).attr("y", y).attr("fill", "#aaaaaa") - .attr("font-size", 14).attr("text-anchor", "left").text("Weights:"); - infoPanel.append("text").attr("x", x+min_x+10).attr("y", y).attr("fill", "#aaaaaa") - .attr("font-size", 14).attr("text-anchor", "left").text("Min:"); - infoPanel.append("text").attr("x", x+score_x).attr("y", y).attr("fill", "#aaaaaa") - .attr("font-size", 14).attr("text-anchor", "left").text("Scores:"); - - // sfb - - score_x = 255; - y += 35 - addStatLine(x,y,sfb_data) - y += 35 - addStatLine(x,y,effort_data) - y += 35 - addStatLine(x,y,psfb_data) - y += 35 - addStatLine(x,y,rsfb_data) - y += 35 - addStatLine(x,y,scissors_data) - y += 35 - addStatLine(x,y,prscissors_data) - y += 35 - addStatLine(x,y,wscissors_data) - y += 35 - addStatLine(x,y,latstr_data) - y += 35 - addStatLine(x,y,sfs_data) - y += 35 - addStatLine(x,y,vowels_data) - y += 35 - addStatLine(x,y,hbalance_data) - y += 35 - - infoPanel.append("text").attr("x", x).attr("y", y).attr("fill", "#aaaaaa").attr("font-family", "Roboto Mono") - .attr("font-size", 14).attr("text-anchor", "left").text("Score:"); - infoPanel.append("text").attr("x", x+score_x).attr("y", y).attr("fill", "#aaaaaa").attr("font-family", "Roboto Mono") - .attr("font-size", 14).attr("text-anchor", "left").text(m_score.toFixed(2)); - - infoPanel.raise(); + console.log("generateStats"); + const infoPanel = d3.select("#info-panel"); + + infoPanel.html(null); + + infoPanel + .append("text") + .attr("x", 340) + .attr("y", 200) + .attr("fill", "#ffaaaa") + .attr("font-size", 13) + .attr("text-anchor", "left") + .attr("font-family", "Roboto Mono") + .text(error_text); + + // === RUN COUNTER === + x = 1050; + y = 568; + // infoPanel.append("text").attr("x", x).attr("y", y).attr("fill", "#aaaaaa") + // .attr("font-size", 20).attr("text-anchor", "left").text(runs); + if (iter >= 0) { + infoPanel + .append("text") + .attr("x", x - 55) + .attr("y", y) + .attr("fill", "#aaaaaa") + .attr("font-size", 20) + .attr("text-anchor", "left") + .text(((100 * (iter + 1)) / times).toFixed(1) + "%"); + } + // === SCORES === + x = 20; + y = 30; + var weight_x = 136; + var min_x = 196; + let score_x = 255; + + // headers + infoPanel + .append("text") + .attr("x", x + weight_x) + .attr("y", y) + .attr("fill", "#aaaaaa") + .attr("font-size", 14) + .attr("text-anchor", "left") + .text("Weights:"); + infoPanel + .append("text") + .attr("x", x + min_x + 10) + .attr("y", y) + .attr("fill", "#aaaaaa") + .attr("font-size", 14) + .attr("text-anchor", "left") + .text("Min:"); + infoPanel + .append("text") + .attr("x", x + score_x) + .attr("y", y) + .attr("fill", "#aaaaaa") + .attr("font-size", 14) + .attr("text-anchor", "left") + .text("Scores:"); + + // sfb + + score_x = 255; + y += 35; + addStatLine(x, y, sfb_data); + y += 35; + addStatLine(x, y, effort_data); + y += 35; + addStatLine(x, y, psfb_data); + y += 35; + addStatLine(x, y, rsfb_data); + y += 35; + addStatLine(x, y, scissors_data); + y += 35; + addStatLine(x, y, prscissors_data); + y += 35; + addStatLine(x, y, wscissors_data); + y += 35; + addStatLine(x, y, latstr_data); + y += 35; + addStatLine(x, y, sfs_data); + y += 35; + addStatLine(x, y, vowels_data); + y += 35; + addStatLine(x, y, hbalance_data); + y += 35; + + infoPanel + .append("text") + .attr("x", x) + .attr("y", y) + .attr("fill", "#aaaaaa") + .attr("font-family", "Roboto Mono") + .attr("font-size", 14) + .attr("text-anchor", "left") + .text("Score:"); + infoPanel + .append("text") + .attr("x", x + score_x) + .attr("y", y) + .attr("fill", "#aaaaaa") + .attr("font-family", "Roboto Mono") + .attr("font-size", 14) + .attr("text-anchor", "left") + .text(m_score.toFixed(2)); + + infoPanel.raise(); } function addStatLine(x, y, data) { - const infoPanel = d3.select("#info-panel"); - var value_x = 86 - var weight_x = 136 - var min_x = 196 - var score_x = 255 - infoPanel.append("text").attr("x", x).attr("y", y).attr("fill", "#aaaaaa").attr("font-family", "Roboto Mono") - .attr("font-size", 14).attr("text-anchor", "left").text(data.label).attr("onmouseover", "showTooltip(evt,'"+data.desc+"')").attr("onmouseout", "hideTooltip()"); - infoPanel.append("text").attr("x", x+value_x).attr("y", y).attr("fill", "#aaaaaa").attr("font-family", "Roboto Mono") - .attr("font-size", 14).attr("text-anchor", "left").text(data.metric); - infoPanel.append("text").attr("x", x+score_x).attr("y", y).attr("fill", "#aaaaaa").attr("font-family", "Roboto Mono") - .attr("font-size", 14).attr("text-anchor", "left").text(data.score.toFixed(3)); - - const weight_field = infoPanel.append("foreignObject").attr("x", x + weight_x).attr("y", y - 20) - .attr("width", 50).attr("height", 25).append("xhtml:input") - .attr("type", "number").attr("step", "0.01").style("width", "100%").style("height", "100%").style("border", "1px solid #ccc") - .style("background", "#555").style("padding", "3px").style("font-size", "16px").style("text-align", "right"); - - weight_field.property("value", data.weight); - weight_field.on("input", function() { - const value = d3.select(this).property("value"); - if (value === "") { - d3.select(this).property("value", "0"); - data.weight = 0; - } else { - data.weight = parseFloat(value); - } - }); - - const min_field = infoPanel.append("foreignObject").attr("x", x + min_x).attr("y", y - 20) - .attr("width", 50).attr("height", 25).append("xhtml:input") - .attr("type", "number").style("width", "100%").style("height", "100%").style("border", "1px solid #ccc") - .style("background", "#555").style("padding", "3px").style("font-size", "16px").style("text-align", "right"); - - min_field.property("value", data.min); - min_field.on("input", function() { - const value = d3.select(this).property("value"); - if (value === "") { - d3.select(this).property("value", "0"); - data.min = 0; - } else { - data.min = parseFloat(value); - } - }); - + const infoPanel = d3.select("#info-panel"); + var value_x = 86; + var weight_x = 136; + var min_x = 196; + var score_x = 255; + infoPanel + .append("text") + .attr("x", x) + .attr("y", y) + .attr("fill", "#aaaaaa") + .attr("font-family", "Roboto Mono") + .attr("font-size", 14) + .attr("text-anchor", "left") + .text(data.label) + .attr("onmouseover", "showTooltip(evt,'" + data.desc + "')") + .attr("onmouseout", "hideTooltip()"); + infoPanel + .append("text") + .attr("x", x + value_x) + .attr("y", y) + .attr("fill", "#aaaaaa") + .attr("font-family", "Roboto Mono") + .attr("font-size", 14) + .attr("text-anchor", "left") + .text(data.metric); + infoPanel + .append("text") + .attr("x", x + score_x) + .attr("y", y) + .attr("fill", "#aaaaaa") + .attr("font-family", "Roboto Mono") + .attr("font-size", 14) + .attr("text-anchor", "left") + .text(data.score.toFixed(3)); + + const weight_field = infoPanel + .append("foreignObject") + .attr("x", x + weight_x) + .attr("y", y - 20) + .attr("width", 50) + .attr("height", 25) + .append("xhtml:input") + .attr("type", "number") + .attr("step", "0.01") + .style("width", "100%") + .style("height", "100%") + .style("border", "1px solid #ccc") + .style("background", "#555") + .style("padding", "3px") + .style("font-size", "16px") + .style("text-align", "right"); + + weight_field.property("value", data.weight); + weight_field.on("input", function () { + const value = d3.select(this).property("value"); + if (value === "") { + d3.select(this).property("value", "0"); + data.weight = 0; + } else { + data.weight = parseFloat(value); + } + }); + + const min_field = infoPanel + .append("foreignObject") + .attr("x", x + min_x) + .attr("y", y - 20) + .attr("width", 50) + .attr("height", 25) + .append("xhtml:input") + .attr("type", "number") + .style("width", "100%") + .style("height", "100%") + .style("border", "1px solid #ccc") + .style("background", "#555") + .style("padding", "3px") + .style("font-size", "16px") + .style("text-align", "right"); + + min_field.property("value", data.min); + min_field.on("input", function () { + const value = d3.select(this).property("value"); + if (value === "") { + d3.select(this).property("value", "0"); + data.min = 0; + } else { + data.min = parseFloat(value); + } + }); } function getEffort(row, col) { - for (let i = 0; i < rcdata.length; i++) { - if (rcdata[i].row === row && rcdata[i].col === col) { - return rcdata[i].effort - } - } - return 0 + for (let i = 0; i < rcdata.length; i++) { + if (rcdata[i].row === row && rcdata[i].col === col) { + return rcdata[i].effort; + } + } + return 0; } -function setEffort(row, col,value) { - for (let i = 0; i < rcdata.length; i++) { - if (rcdata[i].row === row && rcdata[i].col === col) { - rcdata[i].effort = value - } - } +function setEffort(row, col, value) { + for (let i = 0; i < rcdata.length; i++) { + if (rcdata[i].row === row && rcdata[i].col === col) { + rcdata[i].effort = value; + } + } } function openEffortPopup() { - for (let row = 0; row < 3; row++) { - for (let col = 0; col < 12; col++) { - const name = `"textInput-${row}-${col}` - document.getElementById(name).value = getEffort(row,col) - } - } - document.getElementById('popup').style.display = 'flex'; + for (let row = 0; row < 3; row++) { + for (let col = 0; col < 12; col++) { + const name = `"textInput-${row}-${col}`; + document.getElementById(name).value = getEffort(row, col); + } + } + document.getElementById("popup").style.display = "flex"; } function loadEffortValuesFromCookie(cookieName, data) { - const nameEQ = cookieName + "="; - const ca = document.cookie.split(';'); - for(let i=0;i < ca.length;i++) { - let c = ca[i]; - while (c.charAt(0) === ' ') c = c.substring(1,c.length); - if (c.indexOf(nameEQ) === 0) { - const effortValuesString = c.substring(nameEQ.length,c.length); - if (effortValuesString) { - const effortValues = JSON.parse(effortValuesString); - - // Update the rcdata array with the loaded effort values - if (Array.isArray(effortValues) && effortValues.length === data.length) { - return data.map((item, index) => { - item.effort = effortValues[index]; - return item; - }); - } - } - return data; // Return original data if cookie is empty or malformed - } - } - return data; // Return original data if cookie not found + const nameEQ = cookieName + "="; + const ca = document.cookie.split(";"); + for (let i = 0; i < ca.length; i++) { + let c = ca[i]; + while (c.charAt(0) === " ") c = c.substring(1, c.length); + if (c.indexOf(nameEQ) === 0) { + const effortValuesString = c.substring(nameEQ.length, c.length); + if (effortValuesString) { + const effortValues = JSON.parse(effortValuesString); + + // Update the rcdata array with the loaded effort values + if ( + Array.isArray(effortValues) && + effortValues.length === data.length + ) { + return data.map((item, index) => { + item.effort = effortValues[index]; + return item; + }); + } + } + return data; // Return original data if cookie is empty or malformed + } + } + return data; // Return original data if cookie not found } function saveEffortValuesToCookie(cookieName, data, daysToExpire) { - const effortValues = data.map(item => item.effort); - const effortValuesString = JSON.stringify(effortValues); - - let expires = ""; - if (daysToExpire) { - const date = new Date(); - date.setTime(date.getTime() + (daysToExpire * 24 * 60 * 60 * 1000)); - expires = "; expires=" + date.toUTCString(); - } - document.cookie = cookieName + "=" + (effortValuesString || "") + expires + "; path=/"; + const effortValues = data.map((item) => item.effort); + const effortValuesString = JSON.stringify(effortValues); + + let expires = ""; + if (daysToExpire) { + const date = new Date(); + date.setTime(date.getTime() + daysToExpire * 24 * 60 * 60 * 1000); + expires = "; expires=" + date.toUTCString(); + } + document.cookie = + cookieName + "=" + (effortValuesString || "") + expires + "; path=/"; } function closeEffortPopup() { - for (let row = 0; row < 3; row++) { - for (let col = 0; col < 12; col++) { - const name = `"textInput-${row}-${col}"` - setEffort(row, col, document.getElementById(name).value); - } - } - saveEffortValuesToCookie("rcdataEffort", rcdata, 28); - document.getElementById('popup').style.display = 'none'; + for (let row = 0; row < 3; row++) { + for (let col = 0; col < 12; col++) { + const name = `"textInput-${row}-${col}"`; + setEffort(row, col, document.getElementById(name).value); + } + } + saveEffortValuesToCookie("rcdataEffort", rcdata, 28); + document.getElementById("popup").style.display = "none"; } function openCorpusPopup() { - document.getElementById('corpusPopup').style.display = 'flex'; + document.getElementById("corpusPopup").style.display = "flex"; } function closeCorpusPopup() { - var massive_string = document.getElementById('corpusText').value; - massive_string = massive_string.toLowerCase().replace(/\s+/g, ' '); - if (massive_string.length === 0) { - document.getElementById('corpusPopup').style.display = 'none'; - return; - } - words = {}; - list = massive_string.split(" ") - var regex = /\d/; - list.forEach(element => { - if (regex.test(element)){ - // no numbers please - } else { - if (words[element]) { - words[element] += 1 - } else { - words[element] = 1 - } - } - }); - input_length = 0; - letter_freq = {}; - bigram_freq = {}; - trigram_freq = {}; - getCharacters(); - countCharsKeys(); - generateCharacters(); - generateStats(); - // hide popup - document.getElementById('corpusPopup').style.display = 'none'; + var massive_string = document.getElementById("corpusText").value; + massive_string = massive_string.toLowerCase().replace(/\s+/g, " "); + if (massive_string.length === 0) { + document.getElementById("corpusPopup").style.display = "none"; + return; + } + words = {}; + list = massive_string.split(" "); + var regex = /\d/; + list.forEach((element) => { + if (regex.test(element)) { + // no numbers please + } else { + if (words[element]) { + words[element] += 1; + } else { + words[element] = 1; + } + } + }); + input_length = 0; + letter_freq = {}; + bigram_freq = {}; + trigram_freq = {}; + getCharacters(); + countCharsKeys(); + generateCharacters(); + generateStats(); + // hide popup + document.getElementById("corpusPopup").style.display = "none"; } function copyEffortGridToClipboard() { - values = [] - for (let row = 0; row < 3; row++) { - for (let col = 0; col < 12; col++) { - const name = `"textInput-${row}-${col}` - values.push(document.getElementById(name).value); - } - } - const str = values.join(","); - - if (!navigator.clipboard) { - console.error("Clipboard API not supported"); - return; - } - - navigator.clipboard.writeText(str) - .then( - // console.log("copied!") - ) - .catch(err => { - console.error("Failed to copy to clipboard contents:", err); - }); - + values = []; + for (let row = 0; row < 3; row++) { + for (let col = 0; col < 12; col++) { + const name = `"textInput-${row}-${col}`; + values.push(document.getElementById(name).value); + } + } + const str = values.join(","); + + if (!navigator.clipboard) { + console.error("Clipboard API not supported"); + return; + } + + navigator.clipboard + .writeText(str) + .then( + // console.log("copied!") + ) + .catch((err) => { + console.error("Failed to copy to clipboard contents:", err); + }); } function pasteEffortGridFromClipboard() { - if (!navigator.clipboard) { - console.error("Clipboard API not supported"); - return; - } - // Retrieve clipboard content - navigator.clipboard.readText() - .then(text => { - // console.log("Clipboard content:", text); - var numbersArray = text.split(",").map(Number); - if (numbersArray.length !== 36) { - return - } - - for (let row = 0; row < 3; row++) { - for (let col = 0; col < 12; col++) { - const name = `"textInput-${row}-${col}` - document.getElementById(name).value = numbersArray[row * 12 + col] - } - } - }) - .catch(err => { - console.error("Failed to read clipboard contents:", err); - }); + if (!navigator.clipboard) { + console.error("Clipboard API not supported"); + return; + } + // Retrieve clipboard content + navigator.clipboard + .readText() + .then((text) => { + // console.log("Clipboard content:", text); + var numbersArray = text.split(",").map(Number); + if (numbersArray.length !== 36) { + return; + } + + for (let row = 0; row < 3; row++) { + for (let col = 0; col < 12; col++) { + const name = `"textInput-${row}-${col}`; + document.getElementById(name).value = numbersArray[row * 12 + col]; + } + } + }) + .catch((err) => { + console.error("Failed to read clipboard contents:", err); + }); } - function selectLanguage(lan, event) { - var word_list = `'words-${lan}.json'`; - console.log(`"============ ${lan.toUpperCase()} ============"`) - fetch(word_list) - .then(response => response.json()) - .then(data => { - if (event.ctrlKey){ - console.log(`"adding ${lan} to words"`) - for (var word in data) { - if (words[word]){ - words[word] += data[word] - } else { - words[word] = data[word] - } - } - document.getElementById("langDropDown").innerHTML += ("+"+lan.charAt(0).toUpperCase() + lan.substr(1).toLowerCase()); - } else { - words = data; // Assign data to the global variable - document.getElementById("langDropDown").innerHTML = lan.charAt(0).toUpperCase() + lan.substr(1).toLowerCase(); - } - console.log("fetchData"); - getCharacters() - generateCharacters() - }) - .catch(error => console.error('Error loading JSON file:', error)); + var word_list = `'words-${lan}.json'`; + console.log(`"============ ${lan.toUpperCase()} ============"`); + fetch(word_list) + .then((response) => response.json()) + .then((data) => { + if (event.ctrlKey) { + console.log(`"adding ${lan} to words"`); + for (var word in data) { + if (words[word]) { + words[word] += data[word]; + } else { + words[word] = data[word]; + } + } + document.getElementById("langDropDown").innerHTML += + "+" + lan.charAt(0).toUpperCase() + lan.substr(1).toLowerCase(); + } else { + words = data; // Assign data to the global variable + document.getElementById("langDropDown").innerHTML = + lan.charAt(0).toUpperCase() + lan.substr(1).toLowerCase(); + } + console.log("fetchData"); + getCharacters(); + generateCharacters(); + }) + .catch((error) => console.error("Error loading JSON file:", error)); } function dist(x1, y1, x2, y2) { - dx = x1 - x2; - dy = y1 - y2; - return Math.sqrt(dx*dx + dy*dy); + dx = x1 - x2; + dy = y1 - y2; + return Math.sqrt(dx * dx + dy * dy); } function toggleKeyOnOff(d) { - console.log(`"toggleKeyOnOff ${d}`); - if (d.enabled === 1){ - d.enabled = 0 - } else { - d.enabled = 1; - for (var m in letter_freq) { - if (m === d.char) { - letter_freq[m].enabled = 1; - } - } - d.char = ""; - } - - countCharsKeys(); - generateStats(); - generateLayout(); - generateCharacters(); + console.log(`"toggleKeyOnOff ${d}`); + if (d.enabled === 1) { + d.enabled = 0; + } else { + d.enabled = 1; + for (var m in letter_freq) { + if (m === d.char) { + letter_freq[m].enabled = 1; + } + } + d.char = ""; + } + + countCharsKeys(); + generateStats(); + generateLayout(); + generateCharacters(); } function toggleCharOnOff(char) { - for (var m in letter_freq) { - if (m === char) { - if (letter_freq[m].enabled === 0) { - letter_freq[m].enabled = 1; - } else { - letter_freq[m].enabled = 0; - } - } - } - generateCharacters(); - countCharsKeys(); - generateStats(); + for (var m in letter_freq) { + if (m === char) { + if (letter_freq[m].enabled === 0) { + letter_freq[m].enabled = 1; + } else { + letter_freq[m].enabled = 0; + } + } + } + generateCharacters(); + countCharsKeys(); + generateStats(); } function showTooltip(evt, text) { - const tooltip = document.getElementById("tooltip"); - tooltip.innerHTML = text; - tooltip.style.display = "block"; - tooltip.style.left = evt.pageX + 10 + 'px'; - tooltip.style.top = evt.pageY + 10 + 'px'; + const tooltip = document.getElementById("tooltip"); + tooltip.innerHTML = text; + tooltip.style.display = "block"; + tooltip.style.left = evt.pageX + 10 + "px"; + tooltip.style.top = evt.pageY + 10 + "px"; } function hideTooltip() { - const tooltip = document.getElementById("tooltip"); - tooltip.style.display = "none"; + const tooltip = document.getElementById("tooltip"); + tooltip.style.display = "none"; } -function shuffle(array) { // https://stackoverflow.com/questions/2450954/how-to-randomize-shuffle-a-javascript-array - let currentIndex = array.length; - while (currentIndex !== 0) { - const randomIndex = Math.floor(Math.random() * currentIndex); - currentIndex--; - const tmp = array[currentIndex]; - array[currentIndex] = array[randomIndex]; - array[randomIndex] = tmp; - } - return array +function shuffle(array) { + // https://stackoverflow.com/questions/2450954/how-to-randomize-shuffle-a-javascript-array + let currentIndex = array.length; + while (currentIndex !== 0) { + const randomIndex = Math.floor(Math.random() * currentIndex); + currentIndex--; + const tmp = array[currentIndex]; + array[currentIndex] = array[randomIndex]; + array[randomIndex] = tmp; + } + return array; } function shuffleData(data, reps) { - if (times<20){reps+=(20-times)} - var tmp_keys = _.cloneDeep(data) - var editable_keys = []; - for (let i = 0; i < tmp_keys.length; i++) { - if (tmp_keys[i].enabled === 1) { - editable_keys.push(i); - } - } - for (let i = 0; i < reps; i++) { - // pick a random key - const key1 = editable_keys[Math.floor(Math.random()*editable_keys.length)]; - let key2 = editable_keys[Math.floor(Math.random()*editable_keys.length)]; - while(key1 === key2) { - key2 = editable_keys[Math.floor(Math.random()*editable_keys.length)]; - } - tmp = tmp_keys[key1].char - tmp_keys[key1].char = tmp_keys[key2].char - tmp_keys[key2].char = tmp - } - return tmp_keys + if (times < 20) { + reps += 20 - times; + } + var tmp_keys = _.cloneDeep(data); + var editable_keys = []; + for (let i = 0; i < tmp_keys.length; i++) { + if (tmp_keys[i].enabled === 1) { + editable_keys.push(i); + } + } + for (let i = 0; i < reps; i++) { + // pick a random key + const key1 = + editable_keys[Math.floor(Math.random() * editable_keys.length)]; + let key2 = editable_keys[Math.floor(Math.random() * editable_keys.length)]; + while (key1 === key2) { + key2 = editable_keys[Math.floor(Math.random() * editable_keys.length)]; + } + tmp = tmp_keys[key1].char; + tmp_keys[key1].char = tmp_keys[key2].char; + tmp_keys[key2].char = tmp; + } + return tmp_keys; } function create_uid(rcdata) { - var arr = []; - for (let i = 0; i < rcdata.length; i++) { - if (rcdata[i].enabled === 1) { - if (rcdata[i].char === " ") { - arr.push("␣"); - } else { - arr.push(rcdata[i].char); - } - } - } - return arr.join("") + var arr = []; + for (let i = 0; i < rcdata.length; i++) { + if (rcdata[i].enabled === 1) { + if (rcdata[i].char === " ") { + arr.push("␣"); + } else { + arr.push(rcdata[i].char); + } + } + } + return arr.join(""); } var setup = false; function start() { - console.log("construct list of chars"); - var list_of_chars = []; - for (var m in letter_freq) { - if (letter_freq[m].enabled === 1) { - list_of_chars.push(m); - } - } - list_of_chars = shuffle(list_of_chars); - - // check the letters fixed on the keyboard are off in the character list - for (const m in letter_freq) { - if (letter_freq[m].enabled === 1) { - for (let i = 0; i < rcdata.length; i++) { - if (rcdata[i].char === m) { - error = true - } - } - } - } - if (error) { return; } - - for (let i = 0; i < rcdata.length; i++) { - if (rcdata[i].enabled === 1) { - rcdata[i].char = list_of_chars.pop(); - } - } - setup = true; - generateLayout(); + console.log("construct list of chars"); + var list_of_chars = []; + for (var m in letter_freq) { + if (letter_freq[m].enabled === 1) { + list_of_chars.push(m); + } + } + list_of_chars = shuffle(list_of_chars); + + // check the letters fixed on the keyboard are off in the character list + for (const m in letter_freq) { + if (letter_freq[m].enabled === 1) { + for (let i = 0; i < rcdata.length; i++) { + if (rcdata[i].char === m) { + error = true; + } + } + } + } + if (error) { + return; + } + + for (let i = 0; i < rcdata.length; i++) { + if (rcdata[i].enabled === 1) { + rcdata[i].char = list_of_chars.pop(); + } + } + setup = true; + generateLayout(); } function clearLetters() { - for (let i = 0; i < rcdata.length; i++) { - if (rcdata[i].char !== "" && rcdata[i].enabled === 1) { - rcdata[i].char = "" - } - } - best_results = []; - generateLayout(); - generateCharacters(); + for (let i = 0; i < rcdata.length; i++) { + if (rcdata[i].char !== "" && rcdata[i].enabled === 1) { + rcdata[i].char = ""; + } + } + best_results = []; + generateLayout(); + generateCharacters(); } var results; -var best_results=[]; +var best_results = []; var uid_set; var best_score; var best_result; @@ -1283,254 +1588,404 @@ var time_to_shuffle; var editable_keys; function update_progress() { - svg.selectAll(".progress").remove(); - if (running) { - const x = 1060; - for(let r = 0; r < 360; r += 60){ - svg.append("rect") - .attr("class", "progress") - .attr("x", x).attr("y", 562) - .attr("width", 10).attr("height", 2) - .attr("stroke", "#111111") - .attr("fill", "#aaaaaa") - .attr("transform","rotate("+(progress+r)+","+(x+15)+",563)") - } - progress += 21; - if (progress > 360) {progress -= 360;} - } + svg.selectAll(".progress").remove(); + if (running) { + const x = 1060; + for (let r = 0; r < 360; r += 60) { + svg + .append("rect") + .attr("class", "progress") + .attr("x", x) + .attr("y", 562) + .attr("width", 10) + .attr("height", 2) + .attr("stroke", "#111111") + .attr("fill", "#aaaaaa") + .attr( + "transform", + "rotate(" + (progress + r) + "," + (x + 15) + ",563)", + ); + } + progress += 21; + if (progress > 360) { + progress -= 360; + } + } } function calculateScore(value, weight, min, denom, perc) { - let score = -1; - const inv_denom = 1.0 / denom; - if (perc === true) { - value = (100*value) * inv_denom - score = (value - min) * weight - } else { - value = value * inv_denom - score = (value - min) * weight - } - if (score.isNaN) { - console.log("score is NaN. ",value,weight,min,denom,perc) - return 0 - } - if (score < 0) { - return 0 - } - return score + let score = -1; + const inv_denom = 1.0 / denom; + if (perc === true) { + value = 100 * value * inv_denom; + score = (value - min) * weight; + } else { + value = value * inv_denom; + score = (value - min) * weight; + } + if (score.isNaN) { + console.log("score is NaN. ", value, weight, min, denom, perc); + return 0; + } + if (score < 0) { + return 0; + } + return score; } function run() { - if (error === true) {console.log("sort errors first");return;} - runs += 1; - best_score = 1000000; - var messages_sent = 0; - var messages_received = 0; - var found_new_result = false; - var best_config - if (window.Worker) { - const myWorker = new Worker("worker.js"); - - if (setup === false) { - start(); - for (let i = 0; i < rcdata.length; i++) { - if (rcdata[i].enabled === 1) { - editable_keys.push(i); - } - } - } - - if (time_to_shuffle) { - rcdata = shuffleData(rcdata, times-iter); - iter += 1; - time_to_shuffle = false; - best_score = 1000000; - } else { - if (results.length > 0) { - for (let i = 0; i < results.length; i++) { - if (results[i].score < best_score) { - best_score = results[i].score - best_config = results[i].config - } - } - if (best_config) { - rcdata = best_config - } - } - } - - for (let i = 0; i < editable_keys.length; i++) { - for (let j = 0; j < editable_keys.length; j++) { - if (j > i) { - const tmp_keys = _.cloneDeep(rcdata) - // swap keys - const p = editable_keys[i] - const q = editable_keys[j] - tmp = tmp_keys[p].char - tmp_keys[p].char = tmp_keys[q].char - tmp_keys[q].char = tmp - const uid = create_uid(tmp_keys) - if (uid_set.has(uid)) { - } else { - messages_sent += 1; - myWorker.postMessage({ - letter_freq: letter_freq, - bigrams: bigram_freq, - trigrams: trigram_freq, - config: tmp_keys, - }); - } - } - } - } - // column swap - for (let c = 1; c <= 10; c++) { - for (let d = 1; d <= 10; d++) { - if (d > c) { - const tmp_keys = _.cloneDeep(rcdata) - for(let r = 0; r <= 2; r++ ) { - const p = getKey(r, c) - const q = getKey(r, d) - if (rcdata[p].enabled === 1 && rcdata[q].enabled === 1) { - tmp = tmp_keys[p].char - tmp_keys[p].char = tmp_keys[q].char - tmp_keys[q].char = tmp - } - } - - const uid = create_uid(tmp_keys) - if (uid_set.has(uid)) { - } else { - messages_sent += 1; - myWorker.postMessage({ - letter_freq: letter_freq, - bigrams: bigram_freq, - trigrams: trigram_freq, - config: tmp_keys, - }); - } - } - } - } - - // Listen for results coming back from the worker - myWorker.onmessage = (e) => { - const { result, config } = e.data; - uid = create_uid(config) - var score = 0; - - sfb_data.score = calculateScore(result.sfb, sfb_data.weight, sfb_data.min, input_length, true) - effort_data.score = calculateScore(result.effort, effort_data.weight, effort_data.min, input_length, false) - psfb_data.score = calculateScore(result.psfb, psfb_data.weight, psfb_data.min, input_length, true) - rsfb_data.score = calculateScore(result.rsfb, rsfb_data.weight, rsfb_data.min, input_length, true) - scissors_data.score = calculateScore(result.scissors, scissors_data.weight, scissors_data.min, input_length, true) - prscissors_data.score = calculateScore(result.prscissors, prscissors_data.weight, prscissors_data.min, input_length, true) - wscissors_data.score = calculateScore(result.wide_scissors, wscissors_data.weight, wscissors_data.min, input_length, true) - latstr_data.score = calculateScore(result.lat_str, latstr_data.weight, latstr_data.min, input_length, true) - sfs_data.score = calculateScore(result.sfs, sfs_data.weight, sfs_data.min, input_length, true) - vowels_data.score = (result.vowels - vowels_data.min) * vowels_data.weight - hbalance_data.score = (result.hand_balance - hbalance_data.min) * hbalance_data.weight - if (hbalance_data.score < 0) {hbalance_data.score = 0} - - score += sfb_data.score - score += effort_data.score - score += psfb_data.score - score += rsfb_data.score - score += scissors_data.score - score += prscissors_data.score - score += wscissors_data.score - score += latstr_data.score - score += sfs_data.score - score += vowels_data.score - score += hbalance_data.score - - results.push({score: score, config: config, result: result, iter: iter}) - if (score < best_score) { - best_score = score; - found_new_result = true; - } - messages_received += 1; - // console.log("sent = "+messages_sent+" received = "+messages_received); - if (messages_received === messages_sent) { - console.log(iter + " best result: "+best_score); - update_progress(); - if (found_new_result) { - run(); - } else { - time_to_shuffle = true; - best_score = 1000000; - for (let i = 0; i < results.length; i++) { - if (results[i].score < best_score) { - best_config = results[i].config - best_score = results[i].score - best_result = results[i].result - } - } - rcdata = best_config - const uid = create_uid(rcdata) - uid_set.add(uid) - best_results.push({config: best_config, score: best_score, result: best_result, iter: iter}) - results = []; - - const inv_input_lenght = 1.0 / input_length; - sfb_data.metric = ((100*best_result.sfb) * inv_input_lenght).toFixed(2) + "%" - effort_data.metric = (best_result.effort * inv_input_lenght).toFixed(2) - psfb_data.metric = (100*best_result.psfb * inv_input_lenght).toFixed(2) + "%" - rsfb_data.metric = (100*best_result.rsfb * inv_input_lenght).toFixed(2) + "%" - scissors_data.metric = (100*best_result.scissors * inv_input_lenght).toFixed(2) + "%" - prscissors_data.metric = (100*best_result.prscissors * inv_input_lenght).toFixed(2) + "%" - wscissors_data.metric = (100*best_result.wide_scissors * inv_input_lenght).toFixed(2) + "%" - latstr_data.metric = (100*best_result.lat_str * inv_input_lenght).toFixed(2) + "%" - sfs_data.metric = (100*best_result.sfs * inv_input_lenght).toFixed(2) + "%" - vowels_data.metric = (best_result.vowels) - hbalance_data.metric = (best_result.hand_balance).toFixed(2) - - sfb_data.score = calculateScore(best_result.sfb, sfb_data.weight, sfb_data.min, input_length, true) - effort_data.score = calculateScore(best_result.effort, effort_data.weight, effort_data.min, input_length, false) - psfb_data.score = calculateScore(best_result.psfb, psfb_data.weight, psfb_data.min, input_length, true) - rsfb_data.score = calculateScore(best_result.rsfb, rsfb_data.weight, rsfb_data.min, input_length, true) - scissors_data.score = calculateScore(best_result.scissors, scissors_data.weight, scissors_data.min, input_length, true) - prscissors_data.score = calculateScore(best_result.prscissors, prscissors_data.weight, prscissors_data.min, input_length, true) - wscissors_data.score = calculateScore(best_result.wide_scissors, wscissors_data.weight, wscissors_data.min, input_length, true) - latstr_data.score = calculateScore(best_result.lat_str, latstr_data.weight, latstr_data.min, input_length, true) - sfs_data.score = calculateScore(best_result.sfs, sfs_data.weight, sfs_data.min, input_length, true) - vowels_data.score = (best_result.vowels - vowels_data.min) * vowels_data.weight - hbalance_data.score = (best_result.hand_balance - hbalance_data.min) * hbalance_data.weight - if (hbalance_data.score < 0) {hbalance_data.score = 0} - - m_score = sfb_data.score + - effort_data.score + - psfb_data.score + - rsfb_data.score + - scissors_data.score + - prscissors_data.score + - wscissors_data.score + - latstr_data.score + - sfs_data.score + - vowels_data.score + - hbalance_data.score - - generateLayout(); - generateStats(); - generateGraphs(); - generateGraphs2(); - - if (iter+1 < times) { - // console.log("=== "+(times-iter)+" ===") - run(); - } else { - running = false; - } - } - } - }; - - myWorker.onerror = (error) => { - console.error('Main: There was an error with the worker.', error); - }; - } else { - console.log('Your browser does not support Web Workers.'); - } + if (error === true) { + console.log("sort errors first"); + return; + } + runs += 1; + best_score = 1000000; + var messages_sent = 0; + var messages_received = 0; + var found_new_result = false; + var best_config; + if (window.Worker) { + const myWorker = new Worker("worker.js"); + + if (setup === false) { + start(); + for (let i = 0; i < rcdata.length; i++) { + if (rcdata[i].enabled === 1) { + editable_keys.push(i); + } + } + } + + if (time_to_shuffle) { + rcdata = shuffleData(rcdata, times - iter); + iter += 1; + time_to_shuffle = false; + best_score = 1000000; + } else { + if (results.length > 0) { + for (let i = 0; i < results.length; i++) { + if (results[i].score < best_score) { + best_score = results[i].score; + best_config = results[i].config; + } + } + if (best_config) { + rcdata = best_config; + } + } + } + + for (let i = 0; i < editable_keys.length; i++) { + for (let j = 0; j < editable_keys.length; j++) { + if (j > i) { + const tmp_keys = _.cloneDeep(rcdata); + // swap keys + const p = editable_keys[i]; + const q = editable_keys[j]; + tmp = tmp_keys[p].char; + tmp_keys[p].char = tmp_keys[q].char; + tmp_keys[q].char = tmp; + const uid = create_uid(tmp_keys); + if (uid_set.has(uid)) { + } else { + messages_sent += 1; + myWorker.postMessage({ + letter_freq: letter_freq, + bigrams: bigram_freq, + trigrams: trigram_freq, + config: tmp_keys, + }); + } + } + } + } + // column swap + for (let c = 1; c <= 10; c++) { + for (let d = 1; d <= 10; d++) { + if (d > c) { + const tmp_keys = _.cloneDeep(rcdata); + for (let r = 0; r <= 2; r++) { + const p = getKey(r, c); + const q = getKey(r, d); + if (rcdata[p].enabled === 1 && rcdata[q].enabled === 1) { + tmp = tmp_keys[p].char; + tmp_keys[p].char = tmp_keys[q].char; + tmp_keys[q].char = tmp; + } + } + + const uid = create_uid(tmp_keys); + if (uid_set.has(uid)) { + } else { + messages_sent += 1; + myWorker.postMessage({ + letter_freq: letter_freq, + bigrams: bigram_freq, + trigrams: trigram_freq, + config: tmp_keys, + }); + } + } + } + } + + // Listen for results coming back from the worker + myWorker.onmessage = (e) => { + const { result, config } = e.data; + uid = create_uid(config); + var score = 0; + + sfb_data.score = calculateScore( + result.sfb, + sfb_data.weight, + sfb_data.min, + input_length, + true, + ); + effort_data.score = calculateScore( + result.effort, + effort_data.weight, + effort_data.min, + input_length, + false, + ); + psfb_data.score = calculateScore( + result.psfb, + psfb_data.weight, + psfb_data.min, + input_length, + true, + ); + rsfb_data.score = calculateScore( + result.rsfb, + rsfb_data.weight, + rsfb_data.min, + input_length, + true, + ); + scissors_data.score = calculateScore( + result.scissors, + scissors_data.weight, + scissors_data.min, + input_length, + true, + ); + prscissors_data.score = calculateScore( + result.prscissors, + prscissors_data.weight, + prscissors_data.min, + input_length, + true, + ); + wscissors_data.score = calculateScore( + result.wide_scissors, + wscissors_data.weight, + wscissors_data.min, + input_length, + true, + ); + latstr_data.score = calculateScore( + result.lat_str, + latstr_data.weight, + latstr_data.min, + input_length, + true, + ); + sfs_data.score = calculateScore( + result.sfs, + sfs_data.weight, + sfs_data.min, + input_length, + true, + ); + vowels_data.score = + (result.vowels - vowels_data.min) * vowels_data.weight; + hbalance_data.score = + (result.hand_balance - hbalance_data.min) * hbalance_data.weight; + if (hbalance_data.score < 0) { + hbalance_data.score = 0; + } + + score += sfb_data.score; + score += effort_data.score; + score += psfb_data.score; + score += rsfb_data.score; + score += scissors_data.score; + score += prscissors_data.score; + score += wscissors_data.score; + score += latstr_data.score; + score += sfs_data.score; + score += vowels_data.score; + score += hbalance_data.score; + + results.push({ + score: score, + config: config, + result: result, + iter: iter, + }); + if (score < best_score) { + best_score = score; + found_new_result = true; + } + messages_received += 1; + // console.log("sent = "+messages_sent+" received = "+messages_received); + if (messages_received === messages_sent) { + console.log(iter + " best result: " + best_score); + update_progress(); + if (found_new_result) { + run(); + } else { + time_to_shuffle = true; + best_score = 1000000; + for (let i = 0; i < results.length; i++) { + if (results[i].score < best_score) { + best_config = results[i].config; + best_score = results[i].score; + best_result = results[i].result; + } + } + rcdata = best_config; + const uid = create_uid(rcdata); + uid_set.add(uid); + best_results.push({ + config: best_config, + score: best_score, + result: best_result, + iter: iter, + }); + results = []; + + const inv_input_lenght = 1.0 / input_length; + sfb_data.metric = + (100 * best_result.sfb * inv_input_lenght).toFixed(2) + "%"; + effort_data.metric = (best_result.effort * inv_input_lenght).toFixed( + 2, + ); + psfb_data.metric = + (100 * best_result.psfb * inv_input_lenght).toFixed(2) + "%"; + rsfb_data.metric = + (100 * best_result.rsfb * inv_input_lenght).toFixed(2) + "%"; + scissors_data.metric = + (100 * best_result.scissors * inv_input_lenght).toFixed(2) + "%"; + prscissors_data.metric = + (100 * best_result.prscissors * inv_input_lenght).toFixed(2) + "%"; + wscissors_data.metric = + (100 * best_result.wide_scissors * inv_input_lenght).toFixed(2) + + "%"; + latstr_data.metric = + (100 * best_result.lat_str * inv_input_lenght).toFixed(2) + "%"; + sfs_data.metric = + (100 * best_result.sfs * inv_input_lenght).toFixed(2) + "%"; + vowels_data.metric = best_result.vowels; + hbalance_data.metric = best_result.hand_balance.toFixed(2); + + sfb_data.score = calculateScore( + best_result.sfb, + sfb_data.weight, + sfb_data.min, + input_length, + true, + ); + effort_data.score = calculateScore( + best_result.effort, + effort_data.weight, + effort_data.min, + input_length, + false, + ); + psfb_data.score = calculateScore( + best_result.psfb, + psfb_data.weight, + psfb_data.min, + input_length, + true, + ); + rsfb_data.score = calculateScore( + best_result.rsfb, + rsfb_data.weight, + rsfb_data.min, + input_length, + true, + ); + scissors_data.score = calculateScore( + best_result.scissors, + scissors_data.weight, + scissors_data.min, + input_length, + true, + ); + prscissors_data.score = calculateScore( + best_result.prscissors, + prscissors_data.weight, + prscissors_data.min, + input_length, + true, + ); + wscissors_data.score = calculateScore( + best_result.wide_scissors, + wscissors_data.weight, + wscissors_data.min, + input_length, + true, + ); + latstr_data.score = calculateScore( + best_result.lat_str, + latstr_data.weight, + latstr_data.min, + input_length, + true, + ); + sfs_data.score = calculateScore( + best_result.sfs, + sfs_data.weight, + sfs_data.min, + input_length, + true, + ); + vowels_data.score = + (best_result.vowels - vowels_data.min) * vowels_data.weight; + hbalance_data.score = + (best_result.hand_balance - hbalance_data.min) * + hbalance_data.weight; + if (hbalance_data.score < 0) { + hbalance_data.score = 0; + } + + m_score = + sfb_data.score + + effort_data.score + + psfb_data.score + + rsfb_data.score + + scissors_data.score + + prscissors_data.score + + wscissors_data.score + + latstr_data.score + + sfs_data.score + + vowels_data.score + + hbalance_data.score; + + generateLayout(); + generateStats(); + generateGraphs(); + generateGraphs2(); + + if (iter + 1 < times) { + // console.log("=== "+(times-iter)+" ===") + run(); + } else { + running = false; + } + } + } + }; + + myWorker.onerror = (error) => { + console.error("Main: There was an error with the worker.", error); + }; + } else { + console.log("Your browser does not support Web Workers."); + } } loadAllData();