After defining things more clearly yesterday I offer this version of an arrivals component. Here’s how it’s supposed to work.
The component is created using an external call.
The graphic properties are initialized using a separate call to this.basicDefine
. Most of the graphic characteristics are fixed; only the location and colors can be changed. Once we’re done debugging this capability would no longer be needed, but for now it demonstrates something of the separation between the model and what is displayed. The method to draw the component is this.basicDisplay
, and it should be called whenever the status is updated.
this.blockIncrement
is called using the discrete-event mechanism to generate the entities for that time span.
this.entityStatus
is called when the generated entities wake up for the first time. The entities have to be able to refer back to the generator that created them in order to display the activation status in this way.
this.destroy
is probably not needed, but is included for completeness and because good housekeeping is usually desirable.
this.activate
is the standard discrete-event activity mechanism for timed activities.
All values needed to display the component’s status are declared as properties.
All of the initialization, display, and activity code is folded directly into the element’s object definition.
It has not been debugged and run yet so there are doubtless some errors and omissions. Remember that any updates to the display involve clearing the screen and cycling through all of the objects to get them to draw themselves. This being the case the call to draw things should not be evoked as shown here. Rather, a global redraw flag should be set which initiates that process if appropriate when events are pulled from the future events queue or current events queue.
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 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
var globalCTX; //function to generate new entities this.generateNewEntity = function(generator,start) { //generator is an arrivals component //start is an initial activation time var newEntity = new entityA(start); setOfEntities.push(newEntity); generator.entityStatus(); } //Arrivals component: generates entities that will be processed by the model function arrivalsComponent(scheduleBlockMinutes,scheduleArray) { setOfEntities.push(this); this.componentID = getNewID(); this.componentName = "arrivals"; this.startBlockTime = globalSimClock; this.incrementTime = scheduleBlockMinutes; this.endBlockTime = globalSimClock + this.incrementTime; this.entitiesScheduled = 0; this.entitiesRemaining = 0; this.currentEntityID = ""; this.activity = "creation"; this.scheduleIndex = 0; this.endTime = endSimTime; this.nextState = "increment"; feq.newItem(globalSimClock,this); //assume all components created at time zero this.basicDefine = function(x,y,cs,cl,cv,ctx) { this.xLocation = x; this.yLocation = y; this.width = 150; this.height = 112; this.colorShape = cs; this.colorLabels = cl; this.colorValues = cv; this.ctx = ctx; //ctx is a canvas context handle } this.basicDisplay = function() { this.ctx.strokeStyle = this.colorShape; this.ctx.beginPath(); this.ctx.moveTo(this.xLocation+0.5,this.yLocation+0.5); this.ctx.lineTo(this.xLocation+this.width+0.5,this.yLocation+0.5); this.ctx.lineTo(this.xLocation+this.width+0.5,this.yLocation+this.height+0.5); this.ctx.lineTo(this.xLocation+0.5,this.yLocation+this.height+0.5); this.ctx.lineTo(this.xLocation+0.5,this.yLocation+0.5); this.ctx.stroke(); this.ctx.font = "12px Arial"; this.ctx.fillStyle = this.colorLabels; this.ctx.textAlign = "center"; this.ctx.fillText(this.componentName,x+(this.width*0.5),y+12); this.ctx.textAlign = "right"; this.ctx.fillText("Comp. ID:",this.xLocation+78,this.yLocation+24); this.ctx.fillText("Start Time:",this.xLocation+78,this.yLocation+36); this.ctx.fillText("Current Time:",this.xLocation+78,this.yLocation+48); this.ctx.fillText("End Time:",this.xLocation+78,this.yLocation+60); this.ctx.fillText("# Entities:",this.xLocation+78,this.yLocation+72); this.ctx.fillText("# Remaining:",this.xLocation+78,this.yLocation+84); this.ctx.fillText("Entity ID:",this.xLocation+78,this.yLocation+96); this.ctx.fillText("Activity:",this.xLocation+78,this.yLocation+108); this.ctx.fillStyle = this.colorValues; this.ctx.textAlign = "left"; this.ctx.fillText(this.componentID,this.xLocation+83,this.yLocation+24); this.ctx.fillText(this.startBlockTime.toFixed(5),this.xLocation+83,this.yLocation+36); this.ctx.fillText(globalSimClock.toFixed(5),this.xLocation+83,this.yLocation+48); this.ctx.fillText(this.endBlockTime.toFixed(0),this.xLocation+83,this.yLocation+60); this.ctx.fillText(this.entitiesScheduled.toFixed(0),this.xLocation+83,this.yLocation+72); this.ctx.fillText(this.entitiesRemaining,this.xLocation+83,this.yLocation+84); this.ctx.fillText(this.currentEntityID,this.xLocation+83,this.yLocation+96); this.ctx.fillText(activity,this.xLocation+83,this.yLocation+108); }; this.entityStatus = function(entity) { this.currentEntityID = entity.entityID; this.activity = "activate"; this.entitiesRemaining--; //this.basicDisplay(ctx); //set global redraw flag instead }; this.blockIncrement = function() { //should be called at the beginning of every time block //get arrival count per array index this.entitiesScheduled = scheduleArray[this.scheduleIndex]; if (this.entitiesScheduled > 0) { var arrivalArray = []; for (var i=0; i<this.entitiesScheduled; i++) { arrivalArray[i] = Math.random() * scheduleBlockMinutes; } //sort the array arrivalArray.sort(compareNumeric); //generate the arrivals for (var i=0; i<this.entitiesScheduled; i++) { var arrivalBump = arrivalArray[i]; this.generateNewEntity(this,globalSimClock + arrivalBump); } //set global redraw flag } this.scheduleIndex++; displayProgressText("Entry component "+this.componentID+" generates "+this.entitiesScheduled+" new entities at time "+globalSimClock); //set values for display------------- this.startBlockTime = globalSimClock; this.endBlockTime = globalSimClock + this.incrementTime; this.entitiesRemaining = this.entitiesScheduled; this.currentEntityID = ""; this.activity = "generate"; //---------------------------------- if (globalSimClock + this.incrementTime >= this.endTime) { this.nextState = "destroy"; } advance(this.incrementTime); } this.destroy = function() { displayProgressText("Entry component "+this.entityID+" terminated at time "+globalSimClock); //do something to take this element out of the global element list - setOfEntities }; this.activate = function() { if (this.nextState == "increment") { this.blockIncrement(); } else if (this.nextState == "destroy") { this.destroy(); } else { errorUndefinedAdvanceState(this.entityID,this.nextState); } } }; //arrivalComponent //schedule for six hours of arrivals in half-hour blocks var arrivalSchedule = [0,0,1,3,4,4,5,6,3,2,1,0]; var arrival1 = new arrivalComponent(30.0,arrivalSchedule); arrival1.basicDefine(20,20,"#00FFFF","#8888FF","#FF0000",globalCTX); |