diff --git a/webapp/path_navigator.html b/webapp/path_navigator.html
index 987988d..d4854a4 100644
--- a/webapp/path_navigator.html
+++ b/webapp/path_navigator.html
@@ -578,12 +578,22 @@
});
}
- // Load from Flask API - get ALL graphs at once
+ // Load from Flask API - get chords and compute graphs client-side
async function loadAllGraphs() {
try {
- const response = await fetch("/api/all-graphs");
+ const response = await fetch("/api/chords");
if (!response.ok) throw new Error("API not available");
- allGraphsData = await response.json();
+ const data = await response.json();
+
+ // Compute graphs from raw chord data client-side
+ const graphs = data.chords.map((chord, index) => {
+ return calculateGraph(chord, index);
+ });
+
+ allGraphsData = {
+ total: data.total,
+ graphs: graphs
+ };
totalSteps = allGraphsData.total - 1;
@@ -597,10 +607,100 @@
updateUI();
} catch (e) {
- console.log("Error loading graphs:", e);
+ console.log("Error loading chords:", e);
}
}
+ // Compute graph (nodes + edges) from raw chord data - client-side version
+ function calculateGraph(chord, index) {
+ if (!chord) return { nodes: [], edges: [] };
+
+ const nodes = [];
+ const dims = [2, 3, 5, 7];
+
+ // Calculate cents for each pitch
+ for (let i = 0; i < chord.length; i++) {
+ const pitch = chord[i];
+ const fraction = parseFraction(pitch.fraction || "1");
+ const cents = fraction > 0 ? 1200 * Math.log2(fraction) : 0;
+
+ nodes.push({
+ id: i,
+ cents: Math.round(cents),
+ fraction: pitch.fraction || "1",
+ hs_array: pitch.hs_array || []
+ });
+ }
+
+ // Find edges: differ by ±1 in exactly one dimension (ignoring dim 0)
+ const edges = [];
+ for (let i = 0; i < chord.length; i++) {
+ for (let j = i + 1; j < chord.length; j++) {
+ const hs1 = chord[i].hs_array || [];
+ const hs2 = chord[j].hs_array || [];
+
+ if (!hs1.length || !hs2.length) continue;
+
+ // Count differences in dims 1, 2, 3
+ let diffCount = 0;
+ let diffDim = -1;
+
+ for (let d = 1; d < hs1.length; d++) {
+ const diff = hs2[d] - hs1[d];
+ if (Math.abs(diff) === 1) {
+ diffCount++;
+ diffDim = d;
+ } else if (diff !== 0) {
+ break; // diff > 1 in this dimension
+ }
+ }
+
+ // Check if exactly one dimension differs
+ if (diffCount === 1 && diffDim > 0) {
+ // Calculate frequency ratio
+ const diffHs = [];
+ for (let d = 0; d < hs1.length; d++) {
+ diffHs.push(hs1[d] - hs2[d]);
+ }
+
+ let numerator = 1;
+ let denominator = 1;
+ for (let dIdx = 0; dIdx < dims.length; dIdx++) {
+ const exp = diffHs[dIdx];
+ if (exp > 0) {
+ numerator *= Math.pow(dims[dIdx], exp);
+ } else if (exp < 0) {
+ denominator *= Math.pow(dims[dIdx], -exp);
+ }
+ }
+
+ const ratio = denominator > 1 ? `${numerator}/${denominator}` : `${numerator}`;
+
+ edges.push({
+ source: i,
+ target: j,
+ ratio: ratio,
+ dim: diffDim
+ });
+ }
+ }
+ }
+
+ return { nodes, edges, index };
+ }
+
+ // Parse fraction string to number
+ function parseFraction(fracStr) {
+ if (typeof fracStr === 'number') return fracStr;
+ if (!fracStr) return 1;
+
+ if (fracStr.includes('/')) {
+ const [num, den] = fracStr.split('/').map(Number);
+ return num / den;
+ }
+ return Number(fracStr);
+ }
+
// Update UI elements
function updateUI() {
hasPrev = currentIndex > 0;