1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
|
import { chromaticScale } from "./scale.mjs";
const strings = {
string1: 'E',
string2: 'A',
string3: 'D',
string4: 'G',
string5: 'B',
string6: 'E'
};
function isAccidental(note) {
return note[1] === '#' || note[1] === 'b';
}
function alternateAccidental(note) {
const root = chromaticScale.indexOf(note[0]);
switch (note[1]) {
case '#':
return `${chromaticScale[root+2]}b`;
case 'b':
return `${chromaticScale[root-1]}#`;
default:
return note;
}
}
function fretToNote(stringName, fretName) {
console.debug('fretToNote', stringName, fretName);
const string = strings[stringName];
if (!string) {
return null;
}
if (!fretName?.startsWith('fret')) {
return string;
}
const root = chromaticScale.indexOf(string)
const fret = Number(fretName.substring(4));
console.debug('root', root, 'fret', fret);
return chromaticScale[root+fret];
}
function formChanged(form) {
console.log('form changed', form);
const formData = new FormData(form);
console.log('form', formData);
form.querySelectorAll('p').forEach(p => {
const val = formData.get(p.className)
console.debug('found sel', val, p.className, formData);
const note = fretToNote(p.className, val);
if (isAccidental(note)) {
p.innerText = `${note} / ${alternateAccidental(note)}`;
} else {
p.innerText = note;
}
});
}
function handleFormChanged(e) {
console.log('handle form changed', e);
formChanged(e.target.form);
}
let mousedownVal = undefined;
function mousedown(e) {
// at mousedown time, the form hasn't yet been changed. to support
// deselecting elements, we need to know what the previous
// selection was, so store it here.
//
// it'd be nice to be able to do this just in the click handler.
mousedownVal = e.target.checked;
}
function click(e) {
const elt = e.target;
// if this element was selected at mousedown time, deselect it
// now.
if (mousedownVal) {
elt.checked = false;
}
}
export default function Fretboard(form) {
console.debug('Fretboard()', form);
form.onchange = handleFormChanged;
form.querySelectorAll('input[type="radio"]').forEach(elt => {
elt.onmousedown = mousedown;
elt.onclick = click;
});
formChanged(form);
}
|