Today I made a few tweaks, but the main thing was adding an Entry component and a means of moving entities through the model. Remembering that the entities are entirely passive, the components must be able to hand entities off to the next component, know what the next component is, and receive entities from the previous component.
First, here’s the model itself, which takes 80 or so clicks to run to the end.
Here’s the code for the entry component, which contains the methods needed to receive and forward entities. The forwarding mechanisms have clearly been added to the Arrivals component as well.
The only interesting thing the entry component does is clear its data display after two seconds, unless its data has been overwritten by the arrival of a newer entity.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
function EntryComponent(displayDelay) { setOfEntities.push(this); this.componentID = getNewID(); this.componentName = "entry"; this.entryTime = ""; this.currentEntityID = ""; this.activity = ""; this.endDisplayTime = 0; this.displayDelay = displayDelay; this.nextComponent = null; //this.nextState = "clearState"; this.dataGroup = new DisplayGroup(this.componentName,10,126,80,"#00FFFF","#FF0000","#FFFF00"); this.dataGroup.addValue(this.componentID,"comp. ID","integer"); this.dataGroup.addValue(this.entryTime,"Entry Time","numdec",5); this.dataGroup.addValue(this.currentEntityID,"Entity ID","integer"); this.dataGroup.addValue(this.activity,"Activity","text"); this.assignDisplayValues = function() { this.dataGroup.valueList[0].value = this.componentID; this.dataGroup.valueList[1].value = this.entryTime; this.dataGroup.valueList[2].value = this.currentEntityID; this.dataGroup.valueList[3].value = this.activity; }; this.drawData = function() { this.assignDisplayValues(); this.dataGroup.drawBasic(); }; this.clearDisplay = function() { //only clear display if a new one hasn't started a new timer if (globalSimClock >= this.endDisplayTime) { this.entryTime = ""; this.currentEntityID = ""; this.activity = ""; } displayProgressText("Entry component "+this.componentID+" cleared at "+globalSimClock); }; this.assignNextComponent = function(next) { this.nextComponent = next; }; this.forwardEntity = function(entity) { this.nextComponent.receiveEntity(entity); }; this.receiveEntity = function(entity) { //send it someplace //this.forwardEntity(entity); //but not until it actually exists //display what was done this.entryTime = globalSimClock; this.currentEntityID = entity.entityID; this.activity = "New Entity"; entity.entryTime = globalSimClock; //set timer to clear the display after a bit this.endDisplayTime = globalSimClock+this.displayDelay; feq.newItem(this.endDisplayTime,this,"clearDisplay"); } this.activate = function() { if (this.nextState = "clearDisplay") { this.clearDisplay(); } else { errorUndefinedAdvanceState(this.entityID,this.nextState); } }; //this.activate } //EntryComponent |
The lines that initialize the components are here.
1 2 3 4 5 6 7 8 9 |
var arrivalSchedule = [0,0,1,3,4,4,5,6,3,2,1,0]; var arrival1 = new ArrivalsComponent(30.0,arrivalSchedule); var entry1 = new EntryComponent(2.0); arrival1.assignNextComponent(entry1); //entry1.assignNextComponent(queue1); //not defined yet |
I also had to modify the function that displays formatted data, to make sure the desired formats are appropriate for the type of data expected. This came up when functions like toFixed
and toPrecision
choked when I assigned empty strings to generate a blank display. The fact that JavaScript is weakly typed makes it possible to do and one gets tempted to take advantage of such features.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
function DisplayValue(value,label,format,places) { //assumes alignment and color/fillStyle are set before calling this.value = value; this.label = label + ":"; this.format = format; this.places = places; globalCTX.font = "12px Arial"; this.width = globalCTX.measureText(label).width; this.getWidth = function() { return this.width; }; //this.drawLabel = function(x,y) { // globalCTX.fillText(this.label,x,y); //} this.drawValue = function(x,y) { var s; if (this.format == "integer") { s = this.value; } else if (this.format == "numdec") { if (typeof this.value === "number") { s = this.value.toFixed(this.places); } else { s = this.value; } } else if (this.format == "numwide") { if (typeof this.value === "number") { s = this.value.toPrecision(this.places); } else { s = this.value; } } else if (this.format == "text") { s = this.value; } else if (this.format == "bool") { if (typeof this.value === "boolean") { if (this.value) { s = "TRUE"; } else { s = "FALSE"; } } else { s = this.value; } } globalCTX.fillText(s,x,y); } } //displayValue |