ALL STAGES AHHH
This commit is contained in:
parent
9c457d33b8
commit
3be30e6d28
18
index.html
18
index.html
|
@ -1,8 +1,22 @@
|
|||
<!--
|
||||
|
||||
Pause/Play @done
|
||||
Colors for all interventions @done
|
||||
|
||||
Hospital Capacity slider
|
||||
Herd Immunity dashed
|
||||
R shown with arrows
|
||||
Calendar at bottom
|
||||
|
||||
Replay what you just did @done
|
||||
|
||||
Share/Embed!
|
||||
|
||||
---
|
||||
|
||||
Trapezoid
|
||||
No Recovered
|
||||
No Waning
|
||||
No Recovered @done
|
||||
No Waning @done
|
||||
Pause / Play
|
||||
Interventions - % Susceptible, Hygeine, Physical Distancing, Isolate Symptomatic, Quarantine Pre/A-Symptomatic Contacts, Face Masks, Deep Cleaning
|
||||
Seasonality
|
||||
|
|
19
sim.css
19
sim.css
|
@ -1,14 +1,15 @@
|
|||
body{
|
||||
font-family: Helvetica, Arial, sans-serif;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
|
||||
#controls{
|
||||
width:300px;
|
||||
width:250px;
|
||||
/*height:500px;*/
|
||||
float:left;
|
||||
position: relative;
|
||||
}
|
||||
/*
|
||||
#controls > div{
|
||||
overflow: hidden;
|
||||
margin-bottom: 1em;
|
||||
|
@ -64,16 +65,24 @@ body{
|
|||
right: 0;
|
||||
width: 50px;
|
||||
height: 20px;
|
||||
}
|
||||
}*/
|
||||
|
||||
#controls > input{
|
||||
#controls input[type=range]{
|
||||
width: 100%;
|
||||
}
|
||||
#controls > div[strikethrough]{
|
||||
text-decoration: line-through;
|
||||
}
|
||||
#controls > div[strikethrough] > input[type=range]{
|
||||
pointer-events: none;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
/*
|
||||
#controls > div[locked]{
|
||||
opacity: 0.2;
|
||||
pointer-events: none;
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
#graph{
|
||||
|
|
608
sim.js
608
sim.js
|
@ -1,3 +1,6 @@
|
|||
Math.TAU = 6.283185307179586;
|
||||
Math.PI = 3;
|
||||
|
||||
window.$ = (query,el=document)=>{
|
||||
return el.querySelector(query);
|
||||
};
|
||||
|
@ -13,40 +16,158 @@ let S,I,R;
|
|||
|
||||
let params = {};
|
||||
|
||||
// Sliders
|
||||
let DONT_RECORD_HISTORY = true;
|
||||
$all('.sim_input').forEach((slider)=>{
|
||||
let id = slider.id;
|
||||
let label = $('#label_'+id);
|
||||
let isRecordable = slider.classList.contains('recordable');
|
||||
let onChange = ()=>{
|
||||
|
||||
// Change label & param
|
||||
let val = parseFloat(slider.value);
|
||||
label.innerHTML = val;
|
||||
if(label){
|
||||
let digits = parseInt(label.getAttribute('toFixed'));
|
||||
label.innerHTML = digits ? val.toFixed(digits) : val;
|
||||
}
|
||||
params[id] = val;
|
||||
|
||||
// Record history (@ this day)
|
||||
if(isRecordable){
|
||||
if(!DONT_RECORD_HISTORY){
|
||||
recordedHistory.push([id, val, Math.round(daysCurrent)]);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
slider.oninput = onChange;
|
||||
onChange();
|
||||
});
|
||||
DONT_RECORD_HISTORY = false;
|
||||
|
||||
// Checkboxes
|
||||
$all('.sim_checkbox').forEach((checkbox)=>{
|
||||
let id = checkbox.id;
|
||||
let label = $('#label_'+id);
|
||||
let onChange = ()=>{
|
||||
if(label){
|
||||
if(!checkbox.checked){
|
||||
label.setAttribute("strikethrough","yes");
|
||||
}else{
|
||||
label.removeAttribute("strikethrough");
|
||||
}
|
||||
}
|
||||
params[id] = checkbox.checked;
|
||||
};
|
||||
checkbox.oninput = onChange;
|
||||
onChange();
|
||||
});
|
||||
|
||||
/////////////////////////////////////
|
||||
// UPDATE ///////////////////////////
|
||||
/////////////////////////////////////
|
||||
|
||||
let updateModel = (days)=>{
|
||||
let int = {
|
||||
hygiene: 0,
|
||||
distancing: 0,
|
||||
isolate: 0,
|
||||
quarantine: 0,
|
||||
cleaning: 0,
|
||||
masks: 0,
|
||||
summer: 0,
|
||||
vaccines: 0
|
||||
};
|
||||
|
||||
let updateModel = (days, fake)=>{
|
||||
|
||||
let real_S=S, real_I=I, real_R=R;
|
||||
|
||||
let transmissionRate = 1/params.p_transmission,
|
||||
recoveryRate = 1/params.p_recovery,
|
||||
immunityLossRate = 1/(params.p_waning*365);
|
||||
|
||||
let newlyInfected = S*I*transmissionRate*days;
|
||||
// R0
|
||||
let r0_dom = $('#p_r0');
|
||||
r0_dom.value = transmissionRate/recoveryRate;
|
||||
r0_dom.oninput();
|
||||
|
||||
// Transmission affected by interventions
|
||||
|
||||
int.hygiene = params.p_hygiene;
|
||||
transmissionRate *= 1 - int.hygiene*0.5;
|
||||
|
||||
int.distancing = params.p_distancing;
|
||||
transmissionRate *= 1 - int.distancing*0.7;
|
||||
|
||||
int.isolate = params.p_isolate;
|
||||
transmissionRate *= 1 - int.isolate*0.4;
|
||||
|
||||
int.quarantine = params.p_quarantine;
|
||||
transmissionRate *= 1 - int.quarantine*0.5;
|
||||
|
||||
int.cleaning = params.p_cleaning;
|
||||
transmissionRate *= 1 - int.cleaning*0.1;
|
||||
|
||||
int.masks = params.p_masks;
|
||||
transmissionRate *= 1 - int.masks*0.1;
|
||||
|
||||
int.summer = (1 - Math.cos((daysCurrent-30)/365 * Math.TAU))/2;
|
||||
//int.summer = Math.max(0, int.summer);
|
||||
int.summer *= params.p_summer;
|
||||
transmissionRate *= 1 - int.summer* 0.333; // 15°C diff * 0.0225 (Wang et al)
|
||||
|
||||
// Vaccination...
|
||||
if(S > 1-params.p_vaccines){
|
||||
let newlyVaccinated = S - (1-params.p_vaccines);
|
||||
S -= newlyVaccinated;
|
||||
R += newlyVaccinated;
|
||||
}
|
||||
int.vaccines = params.p_vaccines;
|
||||
|
||||
// S...
|
||||
let s_dom = $('#p_s');
|
||||
if(!s_dom.disabled){
|
||||
S = parseFloat(s_dom.value);
|
||||
}
|
||||
|
||||
// Update Model
|
||||
let newlyInfected;
|
||||
if(params.EXPONENTIAL){
|
||||
newlyInfected = I*transmissionRate*days;
|
||||
}else{
|
||||
newlyInfected = S*I*transmissionRate*days;
|
||||
}
|
||||
let newlyRecovered = params.c_recovery ? (I*recoveryRate*days) : 0;
|
||||
let newlySusceptible = params.c_waning ? (R*immunityLossRate*days) : 0;
|
||||
|
||||
S -= newlyInfected;
|
||||
I += newlyInfected;
|
||||
|
||||
let newlyRecovered = I*recoveryRate*days;
|
||||
I -= newlyRecovered;
|
||||
R += newlyRecovered;
|
||||
|
||||
let newlySusceptible = R*immunityLossRate*days;
|
||||
R -= newlySusceptible;
|
||||
S += newlySusceptible;
|
||||
|
||||
// bounds
|
||||
if(S<0) S=0;
|
||||
if(I>1) I=1;
|
||||
|
||||
// Susceptible & Re
|
||||
if(s_dom.disabled){
|
||||
s_dom.value = S;
|
||||
}
|
||||
let re_dom = $('#p_re');
|
||||
re_dom.value = newlyInfected/newlyRecovered;
|
||||
re_dom.oninput();
|
||||
|
||||
// IF FAKE, UNDO EVERYTHING
|
||||
if(fake){
|
||||
S = real_S;
|
||||
I = real_I;
|
||||
R = real_R;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/////////////////////////////////////
|
||||
|
@ -62,26 +183,64 @@ canvas.style.height = (canvas.height/2)+"px";
|
|||
|
||||
let daysCurrent, daysDrawn, daysTotal, daysPerFrame;
|
||||
|
||||
let interventionColors = [
|
||||
['hygiene', 'hsl(230,100%,63%)', 0.1],
|
||||
['distancing', 'hsl(200,100%,63%)', 0.2],
|
||||
['isolate', 'hsl(140,100%,63%)', 0.2],
|
||||
['quarantine', 'hsl(100,100%,63%)', 0.2],
|
||||
['cleaning', 'hsl(290,100%,63%)', 0.2],
|
||||
['masks', 'hsl(260,100%,63%)', 0.2],
|
||||
['summer', 'hsl(20,100%,63%)', 0.3],
|
||||
['vaccines', 'hsl(53, 100%, 73%)', 0.6],
|
||||
];
|
||||
|
||||
let draw = ()=>{
|
||||
|
||||
// Redraw
|
||||
requestAnimationFrame(draw);
|
||||
updateModel(1, true); // one day
|
||||
|
||||
// At the end? No!
|
||||
// Paused? At the end?
|
||||
if(!IS_PLAYING) return;
|
||||
if(params.FROZEN_IN_TIME) return;
|
||||
if(daysCurrent > daysTotal) return;
|
||||
|
||||
// Replay History!
|
||||
if(IS_REPLAYING_HISTORY){
|
||||
let keepLooping = true;
|
||||
while(keepLooping){
|
||||
|
||||
let record = recordedHistory[0];
|
||||
if(!record || daysCurrent<record[2]){
|
||||
keepLooping = false;
|
||||
}else{
|
||||
|
||||
recordedHistory.shift(); // remove first element
|
||||
|
||||
let slider = $('#'+record[0]);
|
||||
slider.value = record[1];
|
||||
DONT_RECORD_HISTORY = true;
|
||||
slider.oninput();
|
||||
DONT_RECORD_HISTORY = false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// For each new day, draw a new pixel
|
||||
daysPerFrame = (daysTotal / params.p_speed) / 60; // (days/second) / (frames/second) = (days/frame)
|
||||
daysCurrent += daysPerFrame;
|
||||
let timeDelta = params.TIME_DELTA || 1;
|
||||
while(daysDrawn < daysCurrent && daysDrawn<=daysTotal){
|
||||
|
||||
updateModel(1); // one day
|
||||
updateModel(timeDelta); // one day
|
||||
|
||||
// DRAWING TIME
|
||||
let ctx = context;
|
||||
let y=0, h;
|
||||
let pixelsPerDay = canvas.width/daysTotal;
|
||||
let w = Math.ceil(pixelsPerDay);
|
||||
let w = Math.ceil(pixelsPerDay * timeDelta);
|
||||
ctx.translate(Math.floor(daysDrawn * pixelsPerDay),0);
|
||||
|
||||
// S
|
||||
|
@ -101,15 +260,25 @@ let draw = ()=>{
|
|||
ctx.fillStyle = "#ff4040";
|
||||
ctx.fillRect(0,y,w,h);
|
||||
|
||||
// INTERVENTIONS
|
||||
y = 0;
|
||||
h = canvas.height;
|
||||
interventionColors.forEach((ic)=>{
|
||||
ctx.fillStyle = ic[1];
|
||||
ctx.globalAlpha = int[ic[0]] * ic[2];
|
||||
ctx.fillRect(0,y,w,h);
|
||||
ctx.globalAlpha = 1;
|
||||
});
|
||||
|
||||
// ICU bed capacity
|
||||
y = (1-0.02)*canvas.height;
|
||||
y = (1-((params.p_hospital/100)*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;
|
||||
daysDrawn += timeDelta;
|
||||
|
||||
}
|
||||
|
||||
|
@ -118,25 +287,430 @@ requestAnimationFrame(draw);
|
|||
|
||||
|
||||
/////////////////////////////////////
|
||||
// RESTART //////////////////////////
|
||||
// (RE)START ////////////////////////
|
||||
/////////////////////////////////////
|
||||
|
||||
let IS_PLAYING = true;
|
||||
let togglePlaying = ()=>{
|
||||
IS_PLAYING = !IS_PLAYING;
|
||||
};
|
||||
$('#start').onclick = togglePlaying;
|
||||
|
||||
let recordedHistory = [];
|
||||
let IS_REPLAYING_HISTORY = false;
|
||||
|
||||
let START_S = 0.999,
|
||||
START_I = 0.001,
|
||||
START_R = 0.000;
|
||||
|
||||
let restart = ()=>{
|
||||
|
||||
S = 0.999;
|
||||
I = 0.001;
|
||||
R = 0.000;
|
||||
// Model
|
||||
S = START_S;
|
||||
I = START_I;
|
||||
R = START_R;
|
||||
|
||||
// Drawing
|
||||
daysCurrent = 0;
|
||||
daysDrawn = 0;
|
||||
daysTotal = params.p_years*365;
|
||||
daysPerFrame = 0; // calc it on the fly
|
||||
|
||||
let ctx = context;
|
||||
ctx.setTransform(1,0,0,1,0,0);
|
||||
ctx.clearRect(0,0,canvas.width,canvas.height);
|
||||
|
||||
};
|
||||
restart();
|
||||
$('#restart').onclick = restart;
|
||||
$('#restart').onclick = ()=>{
|
||||
IS_REPLAYING_HISTORY = false;
|
||||
recordedHistory = [];
|
||||
restart();
|
||||
};
|
||||
$('#replay').onclick = ()=>{
|
||||
IS_REPLAYING_HISTORY = true;
|
||||
restart();
|
||||
};
|
||||
|
||||
/////////////////////////////////////
|
||||
// SIM STAGES ///////////////////////
|
||||
/////////////////////////////////////
|
||||
|
||||
/*
|
||||
|
||||
01 Just exponential
|
||||
02 Just logistic
|
||||
03 Decay
|
||||
04 The famous curve
|
||||
05 R
|
||||
|
||||
06 Do Nothing
|
||||
07 Flatten The Curve
|
||||
08 Lockdown for a while
|
||||
09 Intermittent Lockdown
|
||||
10 Lockdown, then Test & Trace... and with VaccinatioN!
|
||||
11 Also deep cleaning & masks & summer
|
||||
|
||||
12 Decay of Recovered
|
||||
13 Oscillations (Hospital Capacity)
|
||||
14 Oscillations with Summer (Hospital Capacity)
|
||||
15 Intermittent Vaccines
|
||||
|
||||
SB Full Sandbox
|
||||
|
||||
*/
|
||||
|
||||
const STAGES = {
|
||||
|
||||
//////////////////////////////////////////
|
||||
// THE SIMULATION ////////////////////////
|
||||
//////////////////////////////////////////
|
||||
|
||||
"01": {
|
||||
hide: ["section_r","section_meta","label_c_recovery","label_c_waning"],
|
||||
inputs: [
|
||||
["p_years",0.5],
|
||||
["p_speed",10],
|
||||
["TIME_DELTA", 0.1],
|
||||
["EXPONENTIAL",true]
|
||||
]
|
||||
},
|
||||
|
||||
"02": {
|
||||
hide: ["section_r","section_meta","label_c_recovery","label_c_waning"],
|
||||
inputs: [
|
||||
["p_years",0.5],
|
||||
["p_speed",10],
|
||||
["TIME_DELTA", 0.1],
|
||||
]
|
||||
},
|
||||
|
||||
"03": {
|
||||
hide: ["section_r","section_meta","label_transmission","label_c_waning","c_recovery"],
|
||||
inputs: [
|
||||
["p_years",0.5],
|
||||
["p_speed",10],
|
||||
["TIME_DELTA", 0.1],
|
||||
],
|
||||
checkboxes: [
|
||||
["c_recovery", true]
|
||||
],
|
||||
SIR: [0,1,0]
|
||||
},
|
||||
|
||||
"04": {
|
||||
hide: ["section_r","section_meta","label_c_waning","c_recovery"],
|
||||
inputs: [
|
||||
["p_years",0.5],
|
||||
["p_speed",10],
|
||||
["TIME_DELTA", 0.1],
|
||||
],
|
||||
checkboxes: [
|
||||
["c_recovery", true]
|
||||
]
|
||||
},
|
||||
|
||||
"05a": {
|
||||
hide: [
|
||||
"section_meta","label_c_waning","c_recovery",
|
||||
"int_block_0","int_block_1","int_block_2","int_block_3","int_block_4","hospital_capacity",
|
||||
"graph",
|
||||
"label_s","label_re",
|
||||
"sim_controls"
|
||||
],
|
||||
checkboxes: [
|
||||
["c_recovery", true]
|
||||
],
|
||||
inputs: [
|
||||
["FROZEN_IN_TIME", true],
|
||||
],
|
||||
},
|
||||
|
||||
"05b": {
|
||||
hide: [
|
||||
"section_meta","label_c_waning","c_recovery",
|
||||
"int_block_0","int_block_1","int_block_2","int_block_3","int_block_4","hospital_capacity",
|
||||
"graph",
|
||||
"sim_controls"
|
||||
],
|
||||
checkboxes: [
|
||||
["c_recovery", true]
|
||||
],
|
||||
inputs: [
|
||||
["FROZEN_IN_TIME", true],
|
||||
],
|
||||
disabled:[
|
||||
["p_s", false]
|
||||
]
|
||||
},
|
||||
|
||||
"05": {
|
||||
hide: [
|
||||
"section_meta","label_c_waning","c_recovery",
|
||||
"int_block_0","int_block_1","int_block_2","int_block_3","int_block_4","hospital_capacity"
|
||||
],
|
||||
inputs: [
|
||||
["p_years",0.5],
|
||||
["p_speed",30],
|
||||
["TIME_DELTA", 0.1],
|
||||
],
|
||||
checkboxes: [
|
||||
["c_recovery", true]
|
||||
]
|
||||
},
|
||||
|
||||
//////////////////////////////////////////
|
||||
// THE NEXT FEW MONTHS ///////////////////
|
||||
//////////////////////////////////////////
|
||||
|
||||
"06": {
|
||||
hide: [
|
||||
"section_dynamics",
|
||||
"section_meta","label_c_waning","c_recovery",
|
||||
"int_block_0","int_block_1","int_block_2","int_block_3","int_block_4","int_block_5","hospital_capacity"
|
||||
],
|
||||
inputs: [
|
||||
["p_years",2],
|
||||
["p_speed",20],
|
||||
//["TIME_DELTA", 0.2],
|
||||
],
|
||||
checkboxes: [
|
||||
["c_recovery", true]
|
||||
]
|
||||
},
|
||||
|
||||
"07": {
|
||||
hide: [
|
||||
"section_dynamics",
|
||||
"section_meta","label_c_waning","c_recovery",
|
||||
"int_block_1","int_block_2","int_block_3","int_block_4","int_block_5","hospital_capacity"
|
||||
],
|
||||
inputs: [
|
||||
["p_years",2],
|
||||
["p_speed",20],
|
||||
//["TIME_DELTA", 0.2],
|
||||
],
|
||||
checkboxes: [
|
||||
["c_recovery", true]
|
||||
]
|
||||
},
|
||||
|
||||
"08": {
|
||||
hide: [
|
||||
"section_dynamics",
|
||||
"section_meta","label_c_waning","c_recovery",
|
||||
"int_block_2","int_block_3","int_block_4","int_block_5","hospital_capacity"
|
||||
],
|
||||
inputs: [
|
||||
["p_years",2],
|
||||
["p_speed",20],
|
||||
//["TIME_DELTA", 0.2],
|
||||
],
|
||||
checkboxes: [
|
||||
["c_recovery", true]
|
||||
]
|
||||
},
|
||||
|
||||
"09": {
|
||||
hide: [
|
||||
"section_dynamics",
|
||||
"section_meta","label_c_waning","c_recovery",
|
||||
"int_block_2","int_block_3","int_block_4","int_block_5","hospital_capacity"
|
||||
],
|
||||
inputs: [
|
||||
["p_years",2],
|
||||
["p_speed",20],
|
||||
//["TIME_DELTA", 0.2],
|
||||
],
|
||||
checkboxes: [
|
||||
["c_recovery", true]
|
||||
]
|
||||
},
|
||||
|
||||
"10": {
|
||||
hide: [
|
||||
"section_dynamics",
|
||||
"section_meta","label_c_waning","c_recovery",
|
||||
"int_block_3","int_block_4","hospital_capacity"
|
||||
],
|
||||
inputs: [
|
||||
["p_years",2],
|
||||
["p_speed",20],
|
||||
//["TIME_DELTA", 0.2],
|
||||
],
|
||||
checkboxes: [
|
||||
["c_recovery", true]
|
||||
]
|
||||
},
|
||||
|
||||
"11": {
|
||||
hide: [
|
||||
"section_dynamics",
|
||||
"section_meta","label_c_waning","c_recovery",
|
||||
"hospital_capacity"
|
||||
],
|
||||
inputs: [
|
||||
["p_years",2],
|
||||
["p_speed",20],
|
||||
//["TIME_DELTA", 0.2],
|
||||
],
|
||||
checkboxes: [
|
||||
["c_recovery", true]
|
||||
]
|
||||
},
|
||||
|
||||
//////////////////////////////////////////
|
||||
// THE NEXT FEW YEARS ////////////////////
|
||||
//////////////////////////////////////////
|
||||
|
||||
"12": {
|
||||
hide: ["section_r","section_meta","label_transmission","label_c_recovery","c_waning"],
|
||||
inputs: [
|
||||
["p_years",5],
|
||||
["p_speed",10]
|
||||
],
|
||||
checkboxes: [
|
||||
["c_waning", true]
|
||||
],
|
||||
SIR: [0,0,1]
|
||||
},
|
||||
|
||||
"13": {
|
||||
hide: [
|
||||
"section_meta","c_waning","c_recovery",
|
||||
"int_block_0","int_block_1","int_block_2","int_block_3","int_block_4","int_block_5","hospital_capacity"
|
||||
],
|
||||
inputs: [
|
||||
["p_years",5],
|
||||
["p_speed",20],
|
||||
//["TIME_DELTA", 0.2],
|
||||
],
|
||||
checkboxes: [
|
||||
["c_recovery", true],
|
||||
["c_waning", true]
|
||||
],
|
||||
//SIR: [0.09,0.01,0.9]
|
||||
},
|
||||
|
||||
"13b": {
|
||||
hide: [
|
||||
"section_dynamics",
|
||||
"section_meta","c_waning","c_recovery",
|
||||
"int_block_0","int_block_1","int_block_2","int_block_3","int_block_4","int_block_5",
|
||||
],
|
||||
inputs: [
|
||||
["p_years",5],
|
||||
["p_speed",20],
|
||||
//["TIME_DELTA", 0.2],
|
||||
],
|
||||
checkboxes: [
|
||||
["c_recovery", true],
|
||||
["c_waning", true]
|
||||
],
|
||||
SIR: [0.09,0.01,0.9]
|
||||
},
|
||||
|
||||
"14": {
|
||||
hide: [
|
||||
"section_dynamics",
|
||||
"section_meta","c_waning","c_recovery",
|
||||
"int_block_0","int_block_1","int_block_2","int_block_3","int_block_5",
|
||||
],
|
||||
inputs: [
|
||||
["p_years",5],
|
||||
["p_speed",20],
|
||||
["p_summer",1],
|
||||
//["TIME_DELTA", 0.2],
|
||||
],
|
||||
checkboxes: [
|
||||
["c_recovery", true],
|
||||
["c_waning", true]
|
||||
],
|
||||
SIR: [0.09,0.01,0.9]
|
||||
},
|
||||
|
||||
"15": {
|
||||
hide: [
|
||||
"section_dynamics",
|
||||
"section_meta","c_waning","c_recovery",
|
||||
"int_block_0","int_block_1","int_block_2","int_block_3",
|
||||
],
|
||||
inputs: [
|
||||
["p_years",5],
|
||||
["p_speed",20],
|
||||
["p_summer",1],
|
||||
//["TIME_DELTA", 0.2],
|
||||
],
|
||||
checkboxes: [
|
||||
["c_recovery", true],
|
||||
["c_waning", true]
|
||||
],
|
||||
SIR: [0.09,0.01,0.9]
|
||||
},
|
||||
|
||||
//////////////////////////////////////////
|
||||
// SANDBOX ///////////////////////////////
|
||||
//////////////////////////////////////////
|
||||
"SB": {
|
||||
checkboxes: [
|
||||
["c_recovery", true],
|
||||
["c_waning", true]
|
||||
]
|
||||
},
|
||||
|
||||
|
||||
};
|
||||
|
||||
let setStage = (stageID)=>{
|
||||
|
||||
let stage = STAGES[stageID];
|
||||
|
||||
// Hide what
|
||||
stage.hide = stage.hide || [];
|
||||
stage.hide.forEach((domID)=>{
|
||||
$('#'+domID).style.display = 'none';
|
||||
});
|
||||
|
||||
// Sliders
|
||||
stage.inputs = stage.inputs || [];
|
||||
DONT_RECORD_HISTORY = true;
|
||||
stage.inputs.forEach((idValPair)=>{
|
||||
let [id,val] = idValPair;
|
||||
let slider = $('#'+id);
|
||||
if(slider){
|
||||
slider.value = val;
|
||||
slider.oninput();
|
||||
}
|
||||
params[id] = val;
|
||||
});
|
||||
DONT_RECORD_HISTORY = false;
|
||||
|
||||
// Checkboxes
|
||||
stage.checkboxes = stage.checkboxes || [];
|
||||
stage.checkboxes.forEach((idValPair)=>{
|
||||
let [id,val] = idValPair;
|
||||
let checkbox = $('#'+id);
|
||||
checkbox.checked = val;
|
||||
checkbox.oninput();
|
||||
params[id] = val;
|
||||
});
|
||||
|
||||
// Disabled Sliders
|
||||
stage.disabled = stage.disabled || [];
|
||||
stage.disabled.forEach((idValPair)=>{
|
||||
let [id,val] = idValPair;
|
||||
let slider = $('#'+id);
|
||||
slider.disabled = val;
|
||||
});
|
||||
|
||||
// Start SIR
|
||||
if(stage.SIR){
|
||||
START_S = stage.SIR[0];
|
||||
START_I = stage.SIR[1];
|
||||
START_R = stage.SIR[2];
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
let stageParams = new URLSearchParams(location.search);
|
||||
if(stageParams.has('stage')) setStage(stageParams.get('stage'));
|
||||
|
||||
restart();
|
||||
|
|
165
wip.html
165
wip.html
|
@ -2,68 +2,133 @@
|
|||
|
||||
<div id="controls">
|
||||
|
||||
On <i>average</i>, in the beginning,<br>
|
||||
each infected person...
|
||||
<br>
|
||||
<br>
|
||||
Infects a new person every <span id="label_p_transmission">N</span> days
|
||||
<br>
|
||||
<input class="sim_input" type="range" id="p_transmission" min="1" max="28" step="1" value="4">
|
||||
<br>
|
||||
Recovers in <span id="label_p_recovery">N</span> days
|
||||
<br>
|
||||
<input class="sim_input" type="range" id="p_recovery" min="1" max="28" step="1" value="14">
|
||||
<br>
|
||||
Then loses immunity in <span id="label_p_waning">N</span> years
|
||||
<br>
|
||||
<input class="sim_input" type="range" id="p_waning" min="0.5" max="5" step="0.5" value="1">
|
||||
<div id="section_dynamics">
|
||||
|
||||
<hr>
|
||||
On <i>average</i>,
|
||||
each infected person...
|
||||
<br><br>
|
||||
|
||||
<div id="label_transmission">
|
||||
Infects a new person every <span id="label_p_transmission">N</span> days
|
||||
(in the beginning)
|
||||
<br>
|
||||
<input class="sim_input" type="range" id="p_transmission" min="1" max="28" step="1" value="4">
|
||||
</div>
|
||||
|
||||
<div id="label_c_recovery">
|
||||
<input class="sim_checkbox" type="checkbox" id="c_recovery">
|
||||
Recovers in <span id="label_p_recovery">N</span> days
|
||||
<br>
|
||||
<input class="sim_input" type="range" id="p_recovery" min="1" max="28" step="1" value="14">
|
||||
</div>
|
||||
|
||||
<div id="label_c_waning">
|
||||
<input class="sim_checkbox" type="checkbox" id="c_waning">
|
||||
Loses immunity in <span id="label_p_waning">N</span> years
|
||||
<br>
|
||||
<input class="sim_input" type="range" id="p_waning" min="0.5" max="5" step="0.5" value="1">
|
||||
</div>
|
||||
|
||||
R0 is ...
|
||||
<hr>
|
||||
|
||||
<br><br>
|
||||
But with % Susceptible,
|
||||
<br>
|
||||
Hygeine,
|
||||
<br>
|
||||
Physical distancing
|
||||
<br>
|
||||
Isolating (symptomatic) cases
|
||||
<br>
|
||||
Quarantining (pre/a-symptomatic) contacts
|
||||
<br>
|
||||
Deep cleaning (fomites)
|
||||
<br>
|
||||
Face masks
|
||||
<br>
|
||||
& Summer...
|
||||
</div>
|
||||
|
||||
<br><br>
|
||||
<div id="section_r">
|
||||
|
||||
R is now...
|
||||
R0 is <span id="label_p_r0" toFixed="2"></span>
|
||||
<input class="sim_input" type="range" id="p_r0" min="0" max="6" step="0.01" disabled>
|
||||
<br>
|
||||
|
||||
<hr>
|
||||
<span id="label_s">
|
||||
But R is changed by...
|
||||
<br>
|
||||
Susceptible population
|
||||
<input class="sim_input" type="range" id="p_s" min="0" max="1" step="0.001" disabled>
|
||||
<br>
|
||||
</span>
|
||||
|
||||
Vaccinate until N% are <i>not</i> Susceptible
|
||||
<br>
|
||||
<span id="int_block_0">
|
||||
Personal Hygiene
|
||||
<br>
|
||||
<input class="sim_input recordable" type="range" id="p_hygiene" min="0" max="1" step="0.001" value="0">
|
||||
<br>
|
||||
</span>
|
||||
<span id="int_block_1">
|
||||
Physical Distancing
|
||||
<br>
|
||||
<input class="sim_input recordable" type="range" id="p_distancing" min="0" max="1" step="0.001" value="0">
|
||||
<br>
|
||||
</span>
|
||||
<span id="int_block_2">
|
||||
Isolating Cases
|
||||
<br>
|
||||
<input class="sim_input recordable" type="range" id="p_isolate" min="0" max="1" step="0.001" value="0">
|
||||
<br>
|
||||
Quarantining Contacts
|
||||
<br>
|
||||
<input class="sim_input recordable" type="range" id="p_quarantine" min="0" max="1" step="0.001" value="0">
|
||||
<br>
|
||||
</span>
|
||||
<span id="int_block_3">
|
||||
Deep Cleaning
|
||||
<br>
|
||||
<input class="sim_input recordable" type="range" id="p_cleaning" min="0" max="1" step="0.001" value="0">
|
||||
<br>
|
||||
Face Masks
|
||||
<br>
|
||||
<input class="sim_input recordable" type="range" id="p_masks" min="0" max="1" step="0.001" value="0">
|
||||
<br>
|
||||
</span>
|
||||
<span id="int_block_4">
|
||||
Summer
|
||||
<br>
|
||||
<input class="sim_input recordable" type="range" id="p_summer" min="0" max="1" step="0.001" value="0">
|
||||
<br>
|
||||
</span>
|
||||
<span id="int_block_5">
|
||||
Vaccinations
|
||||
<br>
|
||||
<input class="sim_input recordable" type="range" id="p_vaccines" min="0" max="1" step="0.001" value="0">
|
||||
<br>
|
||||
</span>
|
||||
|
||||
Change hospital capacity to...
|
||||
<br>
|
||||
<br>
|
||||
|
||||
<hr>
|
||||
<span id="label_re">
|
||||
R is now <span id="label_p_re" toFixed="2"></span>
|
||||
<input class="sim_input" type="range" id="p_re" min="0" max="6" step="0.01" disabled>
|
||||
</span>
|
||||
|
||||
Simulate <span id="label_p_years">N</span> years
|
||||
<br>
|
||||
<input class="sim_input" type="range" id="p_years" min="0.5" max="5" step="0.5" value="2">
|
||||
<br>
|
||||
In <span id="label_p_speed">N</span> seconds
|
||||
<br>
|
||||
<input class="sim_input" type="range" id="p_speed" min="1" max="60" step="1" value="30">
|
||||
<span id="hospital_capacity">
|
||||
Hospital capacity at <span id="label_p_hospital">N</span>%
|
||||
<br>
|
||||
<input class="sim_input recordable" type="range" id="p_hospital" min="0" max="500" step="1" value="100">
|
||||
</span>
|
||||
|
||||
<hr>
|
||||
<hr>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="section_meta">
|
||||
|
||||
Simulate <span id="label_p_years">N</span> years...
|
||||
<br>
|
||||
<input class="sim_input" type="range" id="p_years" min="0.5" max="10" step="0.5" value="2">
|
||||
<br>
|
||||
...in <span id="label_p_speed">N</span> seconds
|
||||
<br>
|
||||
<input class="sim_input" type="range" id="p_speed" min="1" max="60" step="1" value="30">
|
||||
|
||||
<hr>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="sim_controls">
|
||||
<button id="start">start/stop</button>
|
||||
<button id="restart">restart</button>
|
||||
<button id="replay">replay recording</button>
|
||||
</div>
|
||||
|
||||
<button id="restart">restart</button>
|
||||
</div>
|
||||
|
||||
<div id="graph">
|
||||
|
|
Loading…
Reference in New Issue