{
const pos = {
A:[90,170], B:[220,80], C:[220,250],
D:[380,85], E:[380,250], F:[560,170]
};
const edges = [
["A","B",4],["A","C",2],["B","C",1],["B","D",5],
["C","D",8],["C","E",3],["D","E",2],["D","F",11],["E","F",7]
];
const steps = [
{ current:"A", finalised:["A"], dist:{A:0,B:4,C:2,D:"∞",E:"∞",F:"∞"}, tree:[] },
{ current:"C", finalised:["A","C"], dist:{A:0,B:3,C:2,D:10,E:5,F:"∞"}, tree:[["A","C"]] },
{ current:"B", finalised:["A","C","B"], dist:{A:0,B:3,C:2,D:8,E:5,F:"∞"}, tree:[["A","C"],["C","B"]] },
{ current:"E", finalised:["A","C","B","E"], dist:{A:0,B:3,C:2,D:8,E:5,F:12}, tree:[["A","C"],["C","B"],["C","E"]] },
{ current:"D", finalised:["A","C","B","E","D"], dist:{A:0,B:3,C:2,D:8,E:5,F:12}, tree:[["A","C"],["C","B"],["C","E"],["B","D"]] },
{ current:"F", finalised:["A","C","B","E","D","F"], dist:{A:0,B:3,C:2,D:8,E:5,F:12}, tree:[["A","C"],["C","B"],["C","E"],["B","D"],["E","F"]] }
];
function svgEl(tag) { return document.createElementNS("http://www.w3.org/2000/svg", tag); }
const container = document.createElement("div");
container.style.cssText = "max-width:760px; margin:1rem 0 1.25rem 0; font-family:inherit;";
const actions = document.createElement("div");
actions.style.cssText = "display:flex; gap:0.6rem; align-items:center; margin-bottom:0.7rem;";
const prevBtn = document.createElement("button"); prevBtn.textContent = "Previous";
const nextBtn = document.createElement("button"); nextBtn.textContent = "Next step";
const stage = document.createElement("strong");
actions.append(prevBtn, nextBtn, stage);
const readout = document.createElement("div");
readout.style.cssText = "display:flex; gap:1rem; flex-wrap:wrap; margin-bottom:0.6rem; color:#334155;";
const currentBox = document.createElement("span");
const pathBox = document.createElement("span");
readout.append(currentBox, pathBox);
const svg = svgEl("svg");
svg.setAttribute("viewBox", "0 0 640 340");
svg.style.width = "100%";
svg.style.height = "auto";
svg.style.border = "1px solid #e2e8f0";
svg.style.background = "#fff";
const caption = document.createElement("p");
caption.style.cssText = "margin:0.65rem 0 0 0; color:#475569;";
let idx = 0;
function redraw() {
const step = steps[idx];
stage.textContent = `Step ${idx + 1} of ${steps.length}`;
currentBox.textContent = `newly finalised vertex: ${step.current}`;
pathBox.textContent = `current shortest path to F: ${idx < 3 ? "not yet certified" : "A → C → E → F (12)"}`;
svg.replaceChildren();
edges.forEach(([u,v,w]) => {
const [x1,y1] = pos[u], [x2,y2] = pos[v];
const inTree = step.tree.some(([a,b]) => (a === u && b === v) || (a === v && b === u));
const line = svgEl("line");
line.setAttribute("x1", x1); line.setAttribute("y1", y1);
line.setAttribute("x2", x2); line.setAttribute("y2", y2);
line.setAttribute("stroke", inTree ? "#2563eb" : "#94a3b8");
line.setAttribute("stroke-width", inTree ? "5" : "2");
svg.appendChild(line);
const label = svgEl("text");
label.setAttribute("x", (x1 + x2) / 2);
label.setAttribute("y", (y1 + y2) / 2 - 6);
label.setAttribute("text-anchor", "middle");
label.setAttribute("font-size", "12");
label.setAttribute("fill", "#334155");
label.textContent = String(w);
svg.appendChild(label);
});
Object.entries(pos).forEach(([node,[x,y]]) => {
const finalised = step.finalised.includes(node);
const current = step.current === node;
const c = svgEl("circle");
c.setAttribute("cx", x); c.setAttribute("cy", y); c.setAttribute("r", 22);
c.setAttribute("fill", current ? "#f59e0b" : finalised ? "#1d4ed8" : "#e2e8f0");
c.setAttribute("stroke", "#0f172a");
c.setAttribute("stroke-width", "1.2");
svg.appendChild(c);
const t = svgEl("text");
t.setAttribute("x", x); t.setAttribute("y", y + 4);
t.setAttribute("text-anchor", "middle");
t.setAttribute("font-size", "14");
t.setAttribute("font-weight", "700");
t.setAttribute("fill", finalised || current ? "#fff" : "#0f172a");
t.textContent = node;
svg.appendChild(t);
const d = svgEl("text");
d.setAttribute("x", x); d.setAttribute("y", y + 38);
d.setAttribute("text-anchor", "middle");
d.setAttribute("font-size", "12");
d.setAttribute("fill", "#334155");
d.textContent = `dist ${step.dist[node]}`;
svg.appendChild(d);
});
caption.textContent = idx < steps.length - 1
? "Blue edges are already certified as part of the shortest-path tree. The amber vertex is the next one whose current distance is now known to be final."
: "By the end, every vertex is finalised and the blue edges form the shortest-path tree rooted at A.";
}
prevBtn.addEventListener("click", () => { idx = Math.max(0, idx - 1); redraw(); });
nextBtn.addEventListener("click", () => { idx = Math.min(steps.length - 1, idx + 1); redraw(); });
container.append(actions, readout, svg, caption);
redraw();
return container;
}