2020-03-31 19:02:59 +00:00
|
|
|
window.$ = (query,el=document)=>{
|
|
|
|
return el.querySelector(query);
|
|
|
|
};
|
|
|
|
window.$all = (query,el=document)=>{
|
|
|
|
return [...el.querySelectorAll(query)];
|
|
|
|
};
|
|
|
|
|
2020-04-19 18:03:23 +00:00
|
|
|
/////////////////////////////////////
|
|
|
|
// PARAMETERS ///////////////////////
|
|
|
|
/////////////////////////////////////
|
2020-03-31 19:02:59 +00:00
|
|
|
|
|
|
|
let S,I,R;
|
|
|
|
|
2020-04-19 18:03:23 +00:00
|
|
|
let params = {};
|
|
|
|
|
|
|
|
$all('.sim_input').forEach((slider)=>{
|
|
|
|
let id = slider.id;
|
|
|
|
let label = $('#label_'+id);
|
|
|
|
let onChange = ()=>{
|
|
|
|
let val = parseFloat(slider.value);
|
|
|
|
label.innerHTML = val;
|
|
|
|
params[id] = val;
|
|
|
|
};
|
|
|
|
slider.oninput = onChange;
|
|
|
|
onChange();
|
|
|
|
});
|
|
|
|
|
|
|
|
/////////////////////////////////////
|
|
|
|
// UPDATE ///////////////////////////
|
|
|
|
/////////////////////////////////////
|
2020-03-31 19:02:59 +00:00
|
|
|
|
2020-04-19 18:03:23 +00:00
|
|
|
let updateModel = (days)=>{
|
2020-03-31 19:02:59 +00:00
|
|
|
|
2020-04-19 18:03:23 +00:00
|
|
|
let transmissionRate = 1/params.p_transmission,
|
|
|
|
recoveryRate = 1/params.p_recovery,
|
|
|
|
immunityLossRate = 1/(params.p_waning*365);
|
2020-03-31 19:02:59 +00:00
|
|
|
|
2020-04-19 18:03:23 +00:00
|
|
|
let newlyInfected = S*I*transmissionRate*days;
|
2020-03-31 19:02:59 +00:00
|
|
|
S -= newlyInfected;
|
|
|
|
I += newlyInfected;
|
|
|
|
|
2020-04-19 18:03:23 +00:00
|
|
|
let newlyRecovered = I*recoveryRate*days;
|
2020-03-31 19:02:59 +00:00
|
|
|
I -= newlyRecovered;
|
|
|
|
R += newlyRecovered;
|
|
|
|
|
2020-04-19 18:03:23 +00:00
|
|
|
let newlySusceptible = R*immunityLossRate*days;
|
|
|
|
R -= newlySusceptible;
|
|
|
|
S += newlySusceptible;
|
2020-03-31 19:02:59 +00:00
|
|
|
|
2020-04-19 18:03:23 +00:00
|
|
|
}
|
2020-03-31 19:02:59 +00:00
|
|
|
|
2020-04-19 18:03:23 +00:00
|
|
|
/////////////////////////////////////
|
|
|
|
// DRAW /////////////////////////////
|
|
|
|
/////////////////////////////////////
|
2020-03-31 19:02:59 +00:00
|
|
|
|
2020-04-19 18:03:23 +00:00
|
|
|
let canvas = $('#graphCanvas');
|
|
|
|
let context = canvas.getContext('2d');
|
|
|
|
canvas.width = 1000;
|
|
|
|
canvas.height = 1000;
|
|
|
|
canvas.style.width = (canvas.width/2)+"px";
|
|
|
|
canvas.style.height = (canvas.height/2)+"px";
|
2020-03-31 19:02:59 +00:00
|
|
|
|
2020-04-19 18:03:23 +00:00
|
|
|
let daysCurrent, daysDrawn, daysTotal, daysPerFrame;
|
2020-03-31 19:02:59 +00:00
|
|
|
|
|
|
|
let draw = ()=>{
|
|
|
|
|
|
|
|
// Redraw
|
|
|
|
requestAnimationFrame(draw);
|
|
|
|
|
2020-04-19 18:03:23 +00:00
|
|
|
// At the end? No!
|
|
|
|
if(daysCurrent > daysTotal) return;
|
|
|
|
|
|
|
|
// For each new day, draw a new pixel
|
|
|
|
daysPerFrame = (daysTotal / params.p_speed) / 60; // (days/second) / (frames/second) = (days/frame)
|
|
|
|
daysCurrent += daysPerFrame;
|
|
|
|
while(daysDrawn < daysCurrent && daysDrawn<=daysTotal){
|
|
|
|
|
|
|
|
updateModel(1); // one day
|
|
|
|
|
|
|
|
// DRAWING TIME
|
|
|
|
let ctx = context;
|
|
|
|
let y=0, h;
|
|
|
|
let pixelsPerDay = canvas.width/daysTotal;
|
|
|
|
let w = Math.ceil(pixelsPerDay);
|
|
|
|
ctx.translate(Math.floor(daysDrawn * pixelsPerDay),0);
|
|
|
|
|
|
|
|
// S
|
|
|
|
h = S * canvas.height;
|
|
|
|
ctx.fillStyle = "#eeeeee";
|
|
|
|
ctx.fillRect(0,y,w,h);
|
|
|
|
|
|
|
|
// R
|
|
|
|
y += h;
|
|
|
|
h = R * canvas.height;
|
|
|
|
ctx.fillStyle = "#cccccc";
|
|
|
|
ctx.fillRect(0,y,w,h);
|
|
|
|
|
|
|
|
// I
|
|
|
|
y += h;
|
|
|
|
h = I * canvas.height;
|
|
|
|
ctx.fillStyle = "#ff4040";
|
|
|
|
ctx.fillRect(0,y,w,h);
|
|
|
|
|
|
|
|
// ICU bed capacity
|
|
|
|
y = (1-0.02)*canvas.height;
|
|
|
|
h = 2;
|
|
|
|
ctx.fillStyle = "#000000";
|
|
|
|
ctx.fillRect(0,y,w,h);
|
|
|
|
|
|
|
|
// RESET
|
|
|
|
ctx.setTransform(1,0,0,1,0,0);
|
|
|
|
daysDrawn += 1;
|
2020-03-31 19:02:59 +00:00
|
|
|
|
2020-04-19 18:03:23 +00:00
|
|
|
}
|
2020-03-31 19:02:59 +00:00
|
|
|
|
|
|
|
};
|
|
|
|
requestAnimationFrame(draw);
|
|
|
|
|
|
|
|
|
2020-04-19 18:03:23 +00:00
|
|
|
/////////////////////////////////////
|
|
|
|
// RESTART //////////////////////////
|
|
|
|
/////////////////////////////////////
|
2020-03-31 19:02:59 +00:00
|
|
|
|
2020-04-19 18:03:23 +00:00
|
|
|
let restart = ()=>{
|
2020-03-31 19:02:59 +00:00
|
|
|
|
2020-04-19 18:03:23 +00:00
|
|
|
S = 0.999;
|
|
|
|
I = 0.001;
|
|
|
|
R = 0.000;
|
2020-03-31 19:02:59 +00:00
|
|
|
|
2020-04-19 18:03:23 +00:00
|
|
|
daysCurrent = 0;
|
|
|
|
daysDrawn = 0;
|
|
|
|
daysTotal = params.p_years*365;
|
|
|
|
daysPerFrame = 0; // calc it on the fly
|
2020-03-31 19:02:59 +00:00
|
|
|
|
2020-04-19 18:03:23 +00:00
|
|
|
let ctx = context;
|
|
|
|
ctx.setTransform(1,0,0,1,0,0);
|
|
|
|
ctx.clearRect(0,0,canvas.width,canvas.height);
|
2020-03-31 19:02:59 +00:00
|
|
|
|
|
|
|
};
|
|
|
|
restart();
|
2020-04-19 18:03:23 +00:00
|
|
|
$('#restart').onclick = restart;
|
2020-03-31 19:02:59 +00:00
|
|
|
|