Compare commits
2 Commits
b6717cdc68
...
f1f9e3b34d
| Author | SHA1 | Date |
|---|---|---|
|
|
f1f9e3b34d | |
|
|
deff7369e5 |
|
|
@ -382,7 +382,10 @@ class FolkFlowRiver extends HTMLElement {
|
|||
private shadow: ShadowRoot;
|
||||
private nodes: FlowNode[] = [];
|
||||
private simulating = false;
|
||||
private looping = false;
|
||||
private simTimer: ReturnType<typeof setInterval> | null = null;
|
||||
private initialNodes: FlowNode[] | null = null;
|
||||
private steadyCount = 0;
|
||||
private dragging = false;
|
||||
private dragStartX = 0;
|
||||
private dragStartY = 0;
|
||||
|
|
@ -430,14 +433,51 @@ class FolkFlowRiver extends HTMLElement {
|
|||
|
||||
private startSimulation() {
|
||||
if (this.simTimer) return;
|
||||
// Snapshot initial state for loop reset
|
||||
if (!this.initialNodes) {
|
||||
this.initialNodes = this.nodes.map(n => ({ ...n, data: { ...n.data } }));
|
||||
}
|
||||
this.steadyCount = 0;
|
||||
this.simTimer = setInterval(() => {
|
||||
const prev = this.nodes;
|
||||
this.nodes = simulateTick(this.nodes, DEFAULT_CONFIG);
|
||||
|
||||
// Detect steady state: check if values stopped changing
|
||||
let changed = false;
|
||||
for (let i = 0; i < this.nodes.length; i++) {
|
||||
const a = prev[i].data as Record<string, unknown>;
|
||||
const b = this.nodes[i].data as Record<string, unknown>;
|
||||
if (a.currentValue !== b.currentValue || a.fundingReceived !== b.fundingReceived) {
|
||||
changed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!changed) this.steadyCount++;
|
||||
else this.steadyCount = 0;
|
||||
|
||||
this.render();
|
||||
|
||||
// If looping and steady for 3 ticks, reset after a brief pause
|
||||
if (this.looping && this.steadyCount >= 3 && this.initialNodes) {
|
||||
this.stopSimulation();
|
||||
setTimeout(() => {
|
||||
if (!this.looping) return;
|
||||
this.nodes = this.initialNodes!.map(n => ({ ...n, data: { ...n.data } }));
|
||||
this.render();
|
||||
setTimeout(() => {
|
||||
if (!this.looping) return;
|
||||
this.simulating = true;
|
||||
this.startSimulation();
|
||||
this.render();
|
||||
}, 500);
|
||||
}, 1500);
|
||||
}
|
||||
}, 500);
|
||||
}
|
||||
|
||||
private stopSimulation() {
|
||||
if (this.simTimer) { clearInterval(this.simTimer); this.simTimer = null; }
|
||||
this.simulating = false;
|
||||
}
|
||||
|
||||
private showAmountPopover(sourceId: string, anchorX: number, anchorY: number) {
|
||||
|
|
@ -535,6 +575,7 @@ class FolkFlowRiver extends HTMLElement {
|
|||
</svg>
|
||||
<div class="controls">
|
||||
<button class="${this.simulating ? "active" : ""}" data-action="toggle-sim">${this.simulating ? "Pause" : "Simulate"}</button>
|
||||
<button class="${this.looping ? "active" : ""}" data-action="toggle-loop" title="Loop simulation">🔁</button>
|
||||
</div>
|
||||
<div class="legend">
|
||||
<div class="legend-item"><div class="legend-dot" style="background:${COLORS.inflow}"></div> Inflow</div>
|
||||
|
|
@ -551,6 +592,19 @@ class FolkFlowRiver extends HTMLElement {
|
|||
this.render();
|
||||
});
|
||||
|
||||
// Event: toggle loop
|
||||
this.shadow.querySelector("[data-action=toggle-loop]")?.addEventListener("click", () => {
|
||||
this.looping = !this.looping;
|
||||
if (this.looping && !this.simulating) {
|
||||
// Auto-start simulation when enabling loop
|
||||
this.initialNodes = null; // fresh snapshot
|
||||
this.simulating = true;
|
||||
this.startSimulation();
|
||||
}
|
||||
if (!this.looping) this.initialNodes = null;
|
||||
this.render();
|
||||
});
|
||||
|
||||
// Event delegation for interactive elements + drag-to-pan
|
||||
const container = this.shadow.querySelector(".container") as HTMLElement;
|
||||
if (!container) return;
|
||||
|
|
|
|||
Loading…
Reference in New Issue