diff --git a/keyboard_svg.js b/keyboard_svg.js
index 6a23cfb..bc69158 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; // (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
- } 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; // (cyanophage) 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()),
+ ]);
+
+ // (cyanophage) 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; // (cyanophage) 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;
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 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
- ],
+ [
+ 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,801 +310,1064 @@ 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) {
+ // (cyanophage) 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 {
+ importString =
+ importString.slice(0, 10) +
+ "+" +
+ importString.slice(10, 20) +
+ "*" +
+ importString.slice(20) +
+ "\\^";
+ }
+ }
+ const letters = importString.toUpperCase().match(/[A-Z.,/\-';]/g) || [];
+ // (cyanophage) 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 duplicated: ${duplicates.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) => {
+ // (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");
+ 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;
+ }
+ // (cyanophage) 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 (effort[row]){
- if (effort[row][column]){
- return effort[row][column];
- }
- }
- return 0;
+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 = [
+ // (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],
+ ];
+ } 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";
+ 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 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) {
+ // (cyanophage) 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
+
+function getY(row) {
+ 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); // (narglab) 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][1]); // 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 ${(0.01 * m_total_word_effort).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 = {};
var m_skip_bigram2 = {};
-var m_redirects = {};
+// var m_redirects = {};
var m_scissors = {};
var m_all_scissors = {};
var m_pinky_scissors = {};
@@ -1092,1432 +1380,2585 @@ 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;
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;
+ 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]) {
+ const 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]) {
+ const 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]) {
+ const 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]) {
+ const e = bigram_effort[col1][row1][col2][row2];
+ total += 0.2 * e;
+ }
+ }
+ }
+ }
+ if (total.isNan) 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) {
+ let x_key = -1;
+ for (let i = 0; i < 34; i++) {
+ if (rcdata[i][7] === name) {
+ x_key = i;
+ }
+ }
+ return x_key;
}
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] = '\\' }
- }
+ // (cyanophage) what are the 33 letters ?
+ var letters = [];
+ for (const word in words) {
+ if (letters.length >= 32) {
+ break;
+ }
+ 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]); // (cyanophage) Add letter to the list if not already present
+ }
+ }
+ }
+ /* (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] = "ü";
+ }
+ 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;
+ 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;
+ } // (cyanophage) 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);
+
+ const 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(row);
+ x2 = getX(
+ getChar(finger_pos[finger][0], finger_pos[finger][1]),
+ finger_pos[finger][0],
+ finger_pos[finger][1],
+ );
+ y2 = getY(
+ finger_pos[finger][0]
+ );
+ 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)
+
+ let sum_freqs = 0;
+ for (const letter in m_letter_freq) {
+ sum_freqs += m_letter_freq[letter];
+ }
+
+ 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_freqs * 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 ================================
+ let x = 500;
+ // let y_column_usage = 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");
+
+ let 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) {
+ 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);
+ 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;
+ }
+ const hex_red = red.toString(16);
+ const 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 ================================
+ x = 770;
+ const y_row_usage = 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");
+
+ let 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,
+ );
+ 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;
+ }
+ const hex_red = red.toString(16);
+ const hex_bg = green.toString(16);
+
+ stats
+ .append("rect")
+ .attr("x", x + 19)
+ .attr("y", y_row_usage + 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_row_usage + 51 + row * 20)
+ .attr("fill", "#dfe2eb")
+ .attr("font-size", 10)
+ .attr("font-family", "Sans,Arial")
+ .attr("text-anchor", "middle")
+ .text(parseInt(row, 10) + 1);
+ //\n"
+ }
+
+ // ================================ F I N G E R U S A G E ================================
+ x = 0;
+ // let y_finger_usage = 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");
+
+ let sum_finger_usage = 0;
+ var left = 0;
+ var right = 0;
+
+ for (const finger in m_finger_usage) {
+ sum_finger_usage += m_finger_usage[finger];
+ if (finger <= 4) {
+ left += m_finger_usage[finger];
+ }
+ if (finger >= 7) {
+ right += m_finger_usage[finger];
+ }
+ }
+ 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_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;
+ const green = 128;
+ if (red < 16) {
+ red = 16;
+ }
+ if (red > 255) {
+ red = 255;
+ }
+ 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("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_finger_usage).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_finger_usage).toFixed(2)}%`);
+
+ // ================================ F I N G E R D I S T A N C E ================================
+ x = 250;
+ // const y_finger_distance = 0;
+ var max = m_input_length / 5.110882176; // (narglab) this might be shadowing 'max' above
+ let sum_finger_distance = 0;
+ left = 0;
+ right = 0;
+ for (const finger in m_finger_distance) {
+ sum_finger_distance += 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;
+ const inv_sum_finger_distance = 1.0 / sum_finger_distance;
+ 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) {
+ 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;
+ }
+ 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("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_finger_distance).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_finger_distance).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_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;
+ const y_same_fb = 180;
+ let sum_sfb = 0;
+ // toggle button
+ stats
+ .append("path")
+ .attr(
+ "d",
+ `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")
+ .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_same_fb - 20} L ${x + 35} ${y_same_fb - 20} L ${x + 25} ${y_same_fb - 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) {
+ 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;
+ }
+
+ stats
+ .append("text")
+ .attr("x", x + 40)
+ .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_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 plot_i = 0;
+ let plot_t = scroll_amount;
+
+ for (const bigram in m_same_finger) {
+ if (plot_t > 0) {
+ plot_t -= 1;
+ continue;
+ }
+ let 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_same_fb + plot_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_same_fb + plot_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_same_fb + plot_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"
+ plot_i += 1;
+ if (plot_i > 10) {
+ break;
+ }
+ }
+ } else if (sfb_toggle === 1) {
+ for (const finger in m_same_finger2) {
+ sum_sfb += m_same_finger2[finger] * inv_m_input_length;
+ }
+ stats
+ .append("text")
+ .attr("x", x + 40)
+ .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_sfb).toFixed(2)}%`);
+
+ for (const finger in m_same_finger2) {
+ let height = 30000 * m_same_finger2[finger] * inv_m_input_length;
+ if (height > 150) {
+ height = 150;
+ }
+ const tip = parseFloat(
+ 100 * m_same_finger2[finger] * inv_m_input_length,
+ ).toFixed(2);
+ let red =
+ Math.floor(6000 * m_same_finger2[finger] * inv_m_input_length) + 128;
+ const green = 128;
+ if (red < 16) {
+ red = 16;
+ }
+ if (red > 255) {
+ red = 255;
+ }
+ const hex_red = red.toString(16);
+ const hex_bg = green.toString(16);
+ stats
+ .append("rect")
+ .attr("x", x + finger * 20)
+ .attr("y", y_same_fb + 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_same_fb + 166)
+ .attr("fill", "#dfe2eb")
+ .attr("font-size", 10)
+ .attr("font-family", "Sans,Arial")
+ .attr("text-anchor", "middle")
+ .text(finger);
+ }
+ } else {
+ 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;
+ }
+ stats
+ .append("text")
+ .attr("x", x + 40)
+ .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_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);
+
+ plot_i = 0;
+ plot_t = scroll_amount;
+ for (const bigram in m_same_finger3) {
+ if (plot_t > 0) {
+ plot_t -= 1;
+ continue;
+ }
+ let 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_same_fb + plot_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_same_fb + plot_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_same_fb + plot_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"
+ 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;
+ const y_skip_fb = 180;
+ let sum_skip_fb = 0;
+ var tmp;
+ if (skip_toggle) {
+ 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;
+ }
+ stats
+ .append("text")
+ .attr("x", x + 40)
+ .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_skip_fb).toFixed(2)}%`);
+ } else {
+ 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;
+ }
+ stats
+ .append("text")
+ .attr("x", x + 40)
+ .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_skip_fb).toFixed(2)}%`);
+ }
+
+ stats
+ .append("path")
+ .attr(
+ "d",
+ `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")
+ .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_skip_fb - 20} L ${x + 35} ${y_skip_fb - 20} L ${x + 25} ${y_skip_fb - 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");
+ });
+
+ plot_i = 0;
+ plot_t = scroll_amount;
+ for (const bigram in tmp) {
+ if (plot_t > 0) {
+ plot_t -= 1;
+ continue;
+ }
+ let height = 36000 * tmp[bigram] * inv_m_input_length;
+ if (height > 200) {
+ height = 200;
+ }
+ stats
+ .append("rect")
+ .attr("x", x + 40)
+ .attr("y", y_skip_fb + plot_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_skip_fb + plot_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_skip_fb + plot_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"
+ 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;
+ const y_lat_sb = 180;
+ sum = 0;
+ if (lsb_toggle === 0) {
+ 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;
+ }
+ stats
+ .append("text")
+ .attr("x", x + 40)
+ .attr("y", y_lat_sb - 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 {
+ 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;
+ }
+ stats
+ .append("text")
+ .attr("x", x + 40)
+ .attr("y", y_lat_sb - 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_lat_sb - 24} L ${x + 35} ${y_lat_sb - 24} L ${x + 25} ${y_lat_sb - 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_lat_sb - 20} L ${x + 35} ${y_lat_sb - 20} L ${x + 25} ${y_lat_sb - 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");
+ });
+
+ plot_i = 0;
+ t = scroll_amount;
+ for (const bigram in tmp) {
+ if (plot_t > 0) {
+ plot_t -= 1;
+ continue;
+ }
+ let height = 10000 * tmp[bigram] * inv_m_input_length;
+ if (height > 200) {
+ height = 200;
+ }
+ stats
+ .append("rect")
+ .attr("x", x + 40)
+ .attr("y", y_lat_sb + plot_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_lat_sb + plot_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_lat_sb + plot_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"
+ plot_i += 1;
+ if (plot_i > 10) {
+ break;
+ }
+ }
+
+ // ================================ S C I S S O R S ================================
+ x = 760;
+ const y_scissors = 180;
+ sum = 0;
+
+ if (scissors_toggle === 1) {
+ 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;
+ }
+ stats
+ .append("text")
+ .attr("x", x + 40)
+ .attr("y", y_scissors - 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) {
+ 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;
+ }
+ stats
+ .append("text")
+ .attr("x", x + 40)
+ .attr("y", y_scissors - 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 {
+ 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;
+ }
+ stats
+ .append("text")
+ .attr("x", x + 40)
+ .attr("y", y_scissors - 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_scissors - 24} L ${x + 35} ${y_scissors - 24} L ${x + 25} ${y_scissors - 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_scissors - 20} L ${x + 35} ${y_scissors - 20} L ${x + 25} ${y_scissors - 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");
+ });
+
+ plot_i = 0;
+ plot_t = scroll_amount;
+ for (const bigram in tmp) {
+ if (t > 0) {
+ t -= 1;
+ continue;
+ }
+ let height = 36000 * tmp[bigram] * inv_m_input_length;
+ if (height > 180) {
+ height = 180;
+ }
+ stats
+ .append("rect")
+ .attr("x", x + 40)
+ .attr("y", y_scissors + plot_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_scissors + plot_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_scissors + plot_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"
+ plot_i += 1;
+ if (plot_i > 10) {
+ break;
+ }
+ }
+
+ // ================================ T R I G R A M S T A T S ================================
+ x = 760;
+ const y_trigram = 390;
+ dx = 105;
+ sum = 0;
+ scale = 1;
+ var trigram_title = "Trigram Stats";
+
+ if (trigram_toggle === 0) {
+ 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];
+ }
+ trigram_title = "Trigram Stats";
+ scale = 1;
+ dx = 105;
+ } else if (trigram_toggle === 1) {
+ 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];
+ }
+ trigram_title = "Trigram Stats (alts)";
+ scale = 3;
+ dx = 47;
+ } else if (trigram_toggle === 2) {
+ 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];
+ }
+ trigram_title = "Trigram Stats (redirects)";
+ scale = 3;
+ dx = 47;
+ } else if (trigram_toggle === 3) {
+ 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];
+ }
+ trigram_title = "Trigram Stats (roll in)";
+ scale = 3;
+ dx = 47;
+ } else if (trigram_toggle === 4) {
+ 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];
+ }
+ 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_trigram - 20} L ${x + 35} ${y_trigram - 20} L ${x + 25} ${y_trigram - 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_trigram - 24} L ${x + 35} ${y_trigram - 24} L ${x + 25} ${y_trigram - 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_trigram - 16)
+ .attr("font-size", 16)
+ .attr("font-family", "Sans,Arial")
+ .attr("fill", "#dfe2eb")
+ .attr("text-anchor", "left")
+ .text(trigram_title);
+
+ plot_i = 0;
+ plot_t = trigram_scroll_amount;
+ inv_sum = 1.0 / sum;
+
+ for (const cat in tmp) {
+ if (t > 0) {
+ t -= 1;
+ continue;
+ }
+ const tmp_cat_inv_sum = tmp[cat] * inv_sum;
+ let width = scale * 200 * tmp_cat_inv_sum;
+ if (width > 200) {
+ width = 200;
+ }
+ stats
+ .append("rect")
+ .attr("x", x + dx)
+ .attr("y", y_trigram + plot_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_trigram + plot_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_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"
+ 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;
+ const y_same_hand_strings = 390;
+ sum = 0;
+
+ 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)
+ // console.log("scale : "+scale)
+ stats
+ .append("text")
+ .attr("x", x + 20)
+ .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");
+
+ plot_i = 0;
+ plot_t = sh_scroll_amount;
+ for (const word in samehandstrings) {
+ if (plot_t > 0) {
+ plot_t -= 1;
+ continue;
+ }
+ const count = samehandstrings[word];
+ // console.log(word + " " + count)
+ word_len = word.length;
+ const word_len_count = word_len * count;
+ let width = scale * word_len_count;
+ if (width > 100) {
+ width = 100;
+ }
+ stats
+ .append("rect")
+ .attr("x", x + 70)
+ .attr("y", y_same_hand_strings + plot_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_same_hand_strings + plot_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_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));
+ plot_i += 1;
+ if (plot_i > 10) {
+ break;
+ }
+ }
+
+ // ================================ S A M E H A N D C O U N T S ================================
+ x = 415;
+ const y_same_hand_counts = 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_same_hand_counts - 16)
+ .attr("font-size", 16)
+ .attr("font-family", "Sans,Arial")
+ .attr("fill", "#dfe2eb")
+ .attr("text-anchor", "left")
+ .text("Same Hand Count");
+ plot_i = 0;
+ for (const len in samehandcount) {
+ const count = samehandcount[len];
+ let width = scale * count;
+ if (width > 100) {
+ width = 100;
+ }
+ stats
+ .append("rect")
+ .attr("x", x + 40)
+ .attr("y", y_same_hand_counts + plot_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_same_hand_counts + plot_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_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);
+ plot_i += 1;
+ if (plot_i > 10) {
+ break;
+ }
+ }
+
+ // ================================ H A R D W O R D S ================================
+ x = 580;
+ const y_hard_words = 390;
+ sum = 0;
+
+ 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)
+ .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 ");
+
+ 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) {
+ if (t > 0) {
+ t -= 1;
+ continue;
+ }
+ const height = (100 * word_effort[word]) / word_len;
+ stats
+ .append("rect")
+ .attr("x", x + 80)
+ .attr("y", y_hard_words + plot_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_hard_words + plot_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_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));
+ 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;
+ 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;
+ const y_finger_pairs = 370;
+ var box_x = 26;
+ var box_y = 20;
+ var per = 0;
+
+ var j = 1;
+
+ let finger1 = plot_i;
+ let finger2 = j;
+
+ let sum_finger_pairs = 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_finger_pairs + 100}) rotate(-90)`,
+ )
+ .text("First Finger");
+ stats
+ .append("text")
+ .attr("x", x + 130)
+ .attr("y", y_finger_pairs)
+ .attr("font-size", 10)
+ .attr("font-family", "Sans,Arial")
+ .attr("fill", "#dfe2eb")
+ .attr("text-anchor", "middle")
+ .text("Second Finger");
+
+ plot_i = 0;
+
+ for (let i = 0; i <= 8; i++) {
+ sum_finger_pairs = 0;
+ for (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_finger_pairs += m_finger_pairs[finger1][finger2];
+ }
+ }
+ }
+ for (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_finger_pairs + 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_finger_pairs + 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_finger_pairs > 0) {
+ per = parseFloat(
+ (100 * m_finger_pairs[finger1][finger2]) / sum_finger_pairs,
+ ).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_finger_pairs + 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_finger_pairs + 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; // (cyanophage) dude this is super useful!
+ }
+ if (selectedElement) {
+ // (cyanophage) 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;
+ // (cyanophage) scan through rcdata to find out which key are we closest to
+ closestdist = 9999;
+ starti = -1;
+ let 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();
+ 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);
+ 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);
+ // (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++) {
+ 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, 10) + 15);
+ sibling.setAttributeNS(null, "y", parseInt(starty, 10) + 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, 10) + 15);
+ sibling.setAttributeNS(null, "y", parseInt(starty, 10) + 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, 10) + 15);
+ sibling.setAttributeNS(null, "y", parseInt(starty, 10) + 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, 10) + 15);
+ sibling.setAttributeNS(null, "y", parseInt(starty, 10) + 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++) {
+ 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
+ ) {
+ thumb = "r";
+ }
+ if (
+ rcdata[39][0] === "space" &&
+ rcdata[39][1] === 3 &&
+ rcdata[39][2] === 7
+ ) {
+ thumb = "l";
+ }
+
+ 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()}`);
+
+ 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);
+ }
+}
diff --git a/optimiser.js b/optimiser.js
index 32696dd..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,1181 +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(var 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(var 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(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
- 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);
- }
- 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++) {
- var tickValue = (i * tickInterval).toString()
- if (max_score < 1000 && tickValue.length > 3){
- tickValue = tickValue.substring(0,3)
- }
- var 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++) {
- var tickValue = (i * tickInterval).toString()
- if (max_score < 1000 && tickValue.length > 3){
- tickValue = tickValue.substring(0,3)
- }
- var 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(var 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", function(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", function(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
- var 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
-
- var 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 (var row = 0; row < 3; row++) {
- for (var col = 0; col < 12; col++) {
- var 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 (var row = 0; row < 3; row++) {
- for (var col = 0; col < 12; col++) {
- var 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 (var row = 0; row < 3; row++) {
- for (var col = 0; col < 12; col++) {
- var 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);
+ }
+ }
+ 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 (var row = 0; row < 3; row++) {
- for (var col = 0; col < 12; col++) {
- var 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) {
- 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) {
- 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) {
- 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";
+ 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);
- currentIndex--;
- var 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
- 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) {
- 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 (var 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;
@@ -1281,251 +1588,404 @@ var time_to_shuffle;
var editable_keys;
function update_progress() {
- svg.selectAll(".progress").remove();
- if (running) {
- var x = 1060;
- for(var 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) {
- if (perc==true) {
- value = (100*value)/denom
- var score = (value - min) * weight
- } else {
- value = value/denom
- var score = (value - min) * weight
- }
- if (isNaN(score)) {
- 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) {
- var tmp_keys = _.cloneDeep(rcdata)
- // swap keys
- var p = editable_keys[i]
- var 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)
- 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) {
- var tmp_keys = _.cloneDeep(rcdata)
- 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) {
- tmp = tmp_keys[p].char
- tmp_keys[p].char = tmp_keys[q].char
- tmp_keys[q].char = tmp
- }
- }
-
- var 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 = function(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
- var uid = create_uid(rcdata)
- uid_set.add(uid)
- 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) + "%"
- 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 = function(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();