Add cents/frequency toggle for node labels

- Add toggle button and 'f' keyboard shortcut
- Calculate frequencies on-demand using fundamental * fraction
- Use direct style updates for reliable label refresh
This commit is contained in:
Michael Winter 2026-04-04 13:56:42 +02:00
parent e09fbbae45
commit 1a56c35276

View file

@ -283,6 +283,7 @@
<input type="number" id="fundamentalInput" value="110" style="width: 60px;"> <input type="number" id="fundamentalInput" value="110" style="width: 60px;">
<span style="margin-left: 15px;">Octave:</span> <span style="margin-left: 15px;">Octave:</span>
<input type="number" id="octaveInput" value="2" style="width: 40px;"> <input type="number" id="octaveInput" value="2" style="width: 40px;">
<button id="toggleUnitBtn" style="margin-left: 15px;">Show: Cents</button>
</div> </div>
<div class="controls"> <div class="controls">
@ -317,6 +318,53 @@
let hasPrev = false; let hasPrev = false;
let hasNext = false; let hasNext = false;
let allGraphsData = null; let allGraphsData = null;
let displayMode = 'cents';
// Parse fraction string like "3/2" or "1" into a number
function parseFraction(fracStr) {
if (!fracStr || fracStr === "1") return 1;
const parts = fracStr.split('/');
if (parts.length === 2) {
return parseInt(parts[0]) / parseInt(parts[1]);
}
return parseFloat(fracStr);
}
// Toggle between cents and frequency display
function toggleDisplayUnit() {
displayMode = displayMode === 'cents' ? 'frequency' : 'cents';
const btn = document.getElementById('toggleUnitBtn');
if (btn) {
btn.textContent = displayMode === 'cents' ? 'Show: Cents' : 'Show: Frequency';
}
if (!cy) return;
const fundamental = parseFloat(document.getElementById("fundamentalInput").value) || 110;
cy.nodes().forEach(node => {
const cents = node.data('cents');
const fraction = node.data('fraction');
if (displayMode === 'frequency' && fraction) {
const frac = parseFraction(fraction);
const freq = fundamental * frac;
node.data('displayLabel', Math.round(freq * 10) / 10);
} else {
node.data('displayLabel', cents);
}
node.style('label', node.data('displayLabel'));
});
}
// Set up toggle button listener after DOM loads
document.addEventListener('DOMContentLoaded', () => {
const toggleBtn = document.getElementById('toggleUnitBtn');
if (toggleBtn) {
toggleBtn.addEventListener('click', toggleDisplayUnit);
}
});
// Cytoscape instance // Cytoscape instance
let cy = null; let cy = null;
@ -343,7 +391,7 @@
'background-color': 'data(color)', 'background-color': 'data(color)',
'width': 32, 'width': 32,
'height': 32, 'height': 32,
'label': 'data(cents)', 'label': function(ele) { return ele.data('displayLabel'); },
'text-valign': 'center', 'text-valign': 'center',
'text-halign': 'center', 'text-halign': 'center',
'color': '#000000', 'color': '#000000',
@ -572,6 +620,8 @@
id: nodeId, id: nodeId,
localId: n.id, localId: n.id,
cents: n.cents, cents: n.cents,
displayLabel: n.cents,
fraction: n.fraction || "1",
chordIndex: chordIdx, chordIndex: chordIdx,
chordLabel: `c${chordIdx}`, chordLabel: `c${chordIdx}`,
color: voiceColors[n.id % voiceColors.length], color: voiceColors[n.id % voiceColors.length],
@ -724,6 +774,7 @@
nodes.push({ nodes.push({
id: i, id: i,
cents: Math.round(cents), cents: Math.round(cents),
displayLabel: Math.round(cents),
fraction: pitch.fraction || "1", fraction: pitch.fraction || "1",
hs_array: pitch.hs_array || [] hs_array: pitch.hs_array || []
}); });
@ -1020,6 +1071,8 @@
}).catch(err => { }).catch(err => {
console.log('Error sending kill:', err); console.log('Error sending kill:', err);
}); });
} else if (e.key === "f" || e.key === "F") {
toggleDisplayUnit();
} }
}); });