At the moment, the world is fighting COVID-19. There have been many scientists who made simulations to demonstrate how the disease would spread. There was one simulation which I liked. It was a video in which people were put up as a dot that moved around the canvas. I want to reproduce that in JavaScript and make it tunable.
First, let us create a
canvas div, in which all the people would exist. I am feeling a bit lazy to create a separate stylesheet. I will keep all the styles within the HTML Tags.
<div id="canvas" style="position: absolute; width: 500px; height: 500px; background: #efefef"></div>
Next, let us define a class named Person. The person starts at a random coordinate and moves in a random direction.
const maxVel = 5;
class Person{
constructor(){
this.div = document.createElement("div");
this.div.style.width = "4px";
this.div.style.height = "4px";
this.div.style.borderRadius = "50%";
this.div.style.background = "#000000";
this.div.style.position = "absolute";
// Init position
this.div.style.left = Math.random() * 500;
this.div.style.top = Math.random() * 500;
// Init velocity
this.Velx = Math.random() * maxVel;
this.Vely = Math.random() * maxVel;
document.getElementById("canvas").appendChild(this.div);
this.updatePosition(this);
}
updatePosition(that){
setInterval(function(){
that.div.style.left = that.div.offsetLeft + that.Velx;
that.div.style.top = that.div.offsetTop + that.Vely;
if((that.div.offsetLeft >= 500 && that.Velx > 0) || (that.div.offsetLeft <= 0 && that.Velx < 0))
that.Velx = - that.Velx;
if((that.div.offsetTop >= 500 && that.Vely > 0) || (that.div.offsetTop <= 0 && that.Vely < 0))
that.Vely = - that.Vely;
},50);
}
}
Now, if we can simply create a few objects of the class Person and watch the animation.
for(var i = 0; i < 20; i++){
new Person();
}
Now, let's bring in the disease factor. Let us make the following assumptions:
- If a healthy person comes close to a sick person by a certain distance, the healthy person gets infected.
- The person has a small probability of dying at every time step.
- After a certain amount of time, the sick person gets cured.
- Once cured, the person shall no longer get sick ever again as the person gained immunity.
I went ahead with implementing it. It would be hard to explain everything step by step, but just have a look at the final code.
The following is the final HTML part:
<div id="canvas" style="position: absolute; width: 500px; height: 500px; background: #efefef; z-index: 900"></div>
<div style="position:absolute;z-index: 999;">
<div id="numHealthy" style="display:block;"></div>
<div id="numSick" style="display:block;"></div>
<div id="numCured" style="display:block;"></div>
<div id="numDead" style="display:block;"></div>
</div>
And the JavaScript Part:
const numInitHealthyPeople = 30;
const numInitSickPeople = 2;
const maxVel = 5;
const curePeriod = 50;
const killProbability = 0.005;
const spreadRadius = 20;
const divHealthy = document.getElementById("numHealthy");
const divSick = document.getElementById("numSick");
const divCured = document.getElementById("numCured");
const divDead = document.getElementById("numDead");
class Person{
static allPersons = [];
constructor(isSick = false){
this.div = document.createElement("div");
this.div.style.width = "4px";
this.div.style.height = "4px";
this.div.style.borderRadius = "50%";
this.div.style.background = "#000000";
this.div.style.position = "absolute";
// Init position
this.div.style.left = Math.random() * 500;
this.div.style.top = Math.random() * 500;
// Init velocity
this.Velx = Math.random() * maxVel;
this.Vely = Math.random() * maxVel;
document.getElementById("canvas").appendChild(this.div);
if(isSick){
this.getSick(this);
}
this.sickDuration = 0;
this.isCured = false;
this.isDead = false;
this.update(this);
Person.allPersons.push(this);
}
update(that){
var updateVar = setInterval(function(){
// Position and Velocity:
that.div.style.left = that.div.offsetLeft + that.Velx;
that.div.style.top = that.div.offsetTop + that.Vely;
if((that.div.offsetLeft >= 500 && that.Velx > 0) || (that.div.offsetLeft <= 0 && that.Velx < 0))
that.Velx = - that.Velx;
if((that.div.offsetTop >= 500 && that.Vely > 0) || (that.div.offsetTop <= 0 && that.Vely < 0))
that.Vely = - that.Vely;
// Receive disease if sick people nearby
if(!(that.isCured || that.isSick)){
for(var i = 0; i < Person.allPersons.length; i++){
var person2 = Person.allPersons[i];
// if person is nearby
if(person2.isSick){
var dist = Math.sqrt(Math.pow(that.div.offsetLeft - person2.div.offsetLeft, 2) + Math.pow(that.div.offsetTop - person2.div.offsetTop, 2));
if(dist < spreadRadius){
that.getSick(that);
break;
}
}
}
}
// Sickness
if(that.isSick){
that.sickDuration++;
if(that.sickDuration > curePeriod){
that.getCured(that);
} else {
// Kill with probability:
if(Math.random() < killProbability){
that.kill(that);
clearInterval(updateVar);
}
}
}
// Statistics Display:
divHealthy.innerText = "Healthy: " + numHealthyPeople;
divSick.innerText = "Sick: " + numSickPeople;
divCured.innerText = "Cured: " + numCuredPeople;
divDead.innerText = "Dead: " + numDeadPeople;
},100);
}
getCured(that){
that.isSick = false;
that.isCured = true;
that.div.style.background = "#00ff00";
numCuredPeople++;
numSickPeople--;
}
getSick(that){
that.isSick = true;
that.div.style.background = "#ff0000";
numSickPeople++;
numHealthyPeople--;
}
kill(that){
that.div.parentElement.removeChild(that.div);
that.isDead = true;
numDeadPeople++;
numSickPeople--;
}
}
var numHealthyPeople = numInitHealthyPeople + numInitSickPeople;
var numSickPeople = 0; // get sick is called in the constructor
var numCuredPeople = 0;
var numDeadPeople = 0;
for(var i = 0; i < numInitHealthyPeople; i++){
new Person();
}
for(var i = 0; i < numInitSickPeople; i++){
new Person(true);
}
Comments
Post a Comment