Published
Edited
Mar 11, 2019
1 fork
1 star
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
{
console.clear(); svg.selectAll("*").remove();
// Initialize time and time step
let t = 0;
let dt = 0.005;
svg.append("text")
.attr("x", X(0.45))
.attr("y", -marg/4)
.attr("font-size", 20)
.attr("id", "curTime")
.text("t = " + t.toFixed(3));
// Initialize customer and server queues
let q = [];
let nextArrival = 0;
let customerID = 0;
mutable nCustLost = 0;
mutable nCustServ = 0;
let s =[];
for (let n=0;n<maxServers;n++) {
s.push([-1,-1,Infinity, Infinity, -1]);
}
// Start simulation
let curServers = -1;
while (true) {
t+=dt;
svg.selectAll("#curTime").text("t=" + t.toFixed(3));
// Redraw store if params changed
if (getNserv() != curServers) {
curServers = getNserv();
svg.selectAll("rect").remove();
// Draw box representing the store
let store = svg.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", width-2*marg)
.attr("height", height-2*marg)
.attr("stroke", "black")
.attr("stroke-width",5)
.attr("fill", "none");
// Draw server stations
for (let n=0;n<maxServers;n++) {
if (n<Nservers) {s[n][4] = 0;}
svg.append("rect")
.attr("x", X(0+stationWidth*n))
.attr("y", Y(stationHeight))
.attr("width", X(stationWidth))
.attr("height", (height-2*marg)*stationHeight)
.attr("stroke", "black")
.attr("stroke-width",3)
.attr("fill", stationStatus(n));
}
}
// Check for new customer arrivals
if (nextArrival <= t) {
let x = Math.random()*0.8+0.1;
let y = Math.random()*0.6+0.3;
let curT = t;
let waitTime = t+getWaitTime();
customerID+=1;
q.push([x,y,curT,waitTime,customerID]);
svg.append("circle")
.attr("cx", X(x))
.attr("cy", Y(y))
.attr("r", 10)
.attr("stroke", "transparent")
.attr("fill", colorize(getAnnoyance(curT,t,waitTime)))
.attr("id", 'c' + customerID);
nextArrival = nextArrival+getArrTime();
console.log("Next arrival time: " + nextArrival);
}
// Check customer wait times and update display
for (let n=0;n<q.length;n++) {
// Any customers who have been waiting too long will leave the store
if (q[n][3] < t) {
mutable nCustLost+=1;
svg.selectAll("[id=c" + q[n][4] + "]")
.transition()
.duration(200)
.attr("r", 50)
.style("fill", "red")
.transition()
.duration(100)
.attr("r", 1)
.style("fill", "transparent")
.remove();
q.splice(n,1);
n-=1;
}
// Otherwise update their color
else {
let a = q[n][2];
let b = q[n][3];
svg.selectAll("[id=c" + q[n][4] + "]")
.attr("fill", colorize(getAnnoyance(a,t,b)));
}
}
// Check if any customers are waiting
if (q.length > 0) {
let openStation = getOpenStation(s);
// Check if any service stations are open
if (openStation > -1) {
// Get the customer who has been waiting the longest and move to the service queue
let cust = q.shift();
// Determine when their service will be done
cust[3] = t+getServTime();
// Compute the position of the server window
cust[0] = 0.05+(openStation*stationWidth);
cust[1] = stationHeight/2;
// Add customer to service array
s[openStation] = cust;
// Animate the transition
svg.selectAll("[id=c" + cust[4] + "]")
.transition()
.duration(1000)
.attr("cx", X(cust[0]))
.attr("cy", Y(cust[1]))
.attr("r", 15)
.style("fill", "blue");
}
}
// Check for customers done getting service
for (let n=0;n<maxServers;n++) {
if (s[n][3] < t) {
mutable nCustServ+=1;
svg.selectAll("[id=c" + s[n][4] + "]")
.transition()
.duration(200)
.attr("r",50)
.style("fill", "green")
.transition("fill", "transparent")
.duration(200)
.remove();
s[n] = [-1,-1,Infinity,Infinity,0];
}
}
// Check if we closed any stations with customers inside!
// This makes them mad and they will leave immediately.
for (let n=Nservers;n<maxServers;n++) {
if (s[n][4] > 0) {
mutable nCustLost+=1;
svg.selectAll("[id=c" + s[n][4] + "]")
.transition()
.duration(200)
.attr("r", 50)
.style("fill", "red")
.transition()
.remove();
s[n] = [-1,-1,Infinity,Infinity,-1];
}
}

yield(svg.node().parentNode)
}
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more