Queue Animations
queues
distributed systems
Published
January 17, 2026
Description:
- M/D/1 queue
- Queue Policy: FIFO, unbounded.
Code
Code
Code
{
const interval = setInterval(() => {
// Start serving if idle and queue not empty
if (!mutable serverBusy && mutable queue.length > 0) {
mutable serverItem = mutable queue[0];
mutable queue = mutable queue.slice(1);
mutable serverBusy = true;
mutable serviceTimer = Math.ceil(10 / serviceRate);
}
// Deterministic service: count down timer
if (mutable serverBusy) {
mutable serviceTimer = mutable serviceTimer - 1;
if (mutable serviceTimer <= 0) {
mutable serverBusy = false;
mutable serverItem = null;
}
}
}, 100);
invalidation.then(() => clearInterval(interval));
}Code
Code
{
const width = 600;
const height = 120;
const queueWidth = 340;
const baseItemSize = 20;
const gap = 2;
// Calculate item size: shrink if more than 15 items (cap at 80 for sizing)
const displayCount = Math.min(queue.length, 80);
const itemSize = displayCount <= 15
? baseItemSize
: Math.max(2, (queueWidth - gap * displayCount) / displayCount);
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height])
.attr("width", width)
.attr("height", height);
// Queue container
svg.append("rect")
.attr("x", 50)
.attr("y", 30)
.attr("width", 350)
.attr("height", 50)
.attr("fill", "#f0f0f0")
.attr("stroke", "#333")
.attr("stroke-width", 2);
svg.append("text")
.attr("x", 225)
.attr("y", 100)
.attr("text-anchor", "middle")
.attr("font-size", 12)
.text("Queue");
// Server container
svg.append("rect")
.attr("x", 450)
.attr("y", 30)
.attr("width", 50)
.attr("height", 50)
.attr("fill", serverBusy ? "#ffcccc" : "#ccffcc")
.attr("stroke", "#333")
.attr("stroke-width", 2);
svg.append("text")
.attr("x", 475)
.attr("y", 100)
.attr("text-anchor", "middle")
.attr("font-size", 12)
.text("Server");
// Arrow
svg.append("path")
.attr("d", "M 405 55 L 445 55")
.attr("stroke", "#333")
.attr("stroke-width", 2)
.attr("marker-end", "url(#arrow)");
svg.append("defs").append("marker")
.attr("id", "arrow")
.attr("viewBox", "0 0 10 10")
.attr("refX", 9)
.attr("refY", 5)
.attr("markerWidth", 6)
.attr("markerHeight", 6)
.attr("orient", "auto")
.append("path")
.attr("d", "M 0 0 L 10 5 L 0 10 z")
.attr("fill", "#333");
// Arrival arrow
svg.append("path")
.attr("d", "M 10 55 L 45 55")
.attr("stroke", "#333")
.attr("stroke-width", 2)
.attr("marker-end", "url(#arrow)");
// Queue items (cap visual at 80)
const visibleQueue = queue.slice(0, 80);
svg.selectAll(".queue-item")
.data(visibleQueue)
.join("rect")
.attr("class", "queue-item")
.attr("x", (d, i) => 55 + i * (itemSize + gap))
.attr("y", 55 - itemSize / 2)
.attr("width", itemSize)
.attr("height", itemSize)
.attr("fill", "#4a90d9")
.attr("rx", Math.max(1, itemSize / 6));
// Server item
if (serverBusy) {
svg.append("rect")
.attr("x", 465)
.attr("y", 45)
.attr("width", baseItemSize)
.attr("height", baseItemSize)
.attr("fill", "#d94a4a")
.attr("rx", 3);
}
return svg.node();
}