Move graph computation from server to client
This commit is contained in:
parent
79e1259f5b
commit
c6bb3a12ce
|
|
@ -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() {
|
async function loadAllGraphs() {
|
||||||
try {
|
try {
|
||||||
const response = await fetch("/api/all-graphs");
|
const response = await fetch("/api/chords");
|
||||||
if (!response.ok) throw new Error("API not available");
|
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;
|
totalSteps = allGraphsData.total - 1;
|
||||||
|
|
||||||
|
|
@ -597,10 +607,100 @@
|
||||||
updateUI();
|
updateUI();
|
||||||
|
|
||||||
} catch (e) {
|
} 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
|
// Update UI elements
|
||||||
function updateUI() {
|
function updateUI() {
|
||||||
hasPrev = currentIndex > 0;
|
hasPrev = currentIndex > 0;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue