covid-19/sim.js

143 lines
2.9 KiB
JavaScript
Raw Normal View History

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