411 lines
8.3 KiB
JavaScript
411 lines
8.3 KiB
JavaScript
/////////////////////////////////////
|
|
// PARAMETERS ///////////////////////
|
|
/////////////////////////////////////
|
|
|
|
let S,E,I,R;
|
|
|
|
let params = {};
|
|
|
|
// Update Month Ticks!
|
|
let mn = [...$('#month_names').children].map((dom)=>{
|
|
return dom.innerHTML;
|
|
});
|
|
let updateMonthTicks = ()=>{
|
|
|
|
let ticks;
|
|
|
|
switch(params.p_years){
|
|
case 0.5:
|
|
ticks = [
|
|
mn[0]+" 2020",
|
|
mn[1]+" 2020",
|
|
mn[2]+" 2020",
|
|
mn[3]+" 2020",
|
|
mn[4]+" 2020",
|
|
mn[5]+" 2020",
|
|
null
|
|
];
|
|
break;
|
|
case 1.0:
|
|
ticks = [
|
|
mn[0]+" 2020",
|
|
mn[3]+" 2020",
|
|
mn[6]+" 2020",
|
|
mn[9]+" 2020",
|
|
null
|
|
];
|
|
break;
|
|
default:
|
|
ticks = [];
|
|
for(let time=0; time<=params.p_years; time+=0.5){
|
|
if(time%1 != 0){
|
|
ticks.push(null);
|
|
}else{
|
|
ticks.push(time+2020);
|
|
}
|
|
}
|
|
ticks[ticks.length-1] = null;
|
|
break;
|
|
}
|
|
|
|
let monthTicksDOM = $('#month_ticks');
|
|
monthTicksDOM.innerHTML = '';
|
|
|
|
ticks.forEach((tick,i)=>{
|
|
|
|
if(i==ticks.length-1 || !tick) return;
|
|
|
|
let tickDOM = document.createElement('div');
|
|
let tickSpanDOM = document.createElement('span');
|
|
tickSpanDOM.innerHTML = tick;
|
|
tickDOM.style.left = ((i/(ticks.length-1))*500)+"px";
|
|
tickDOM.appendChild(tickSpanDOM);
|
|
monthTicksDOM.appendChild(tickDOM);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
// Sliders
|
|
//let DONT_RECORD_HISTORY = true;
|
|
let _DO_NOT_RECURSE = true;
|
|
let INPUTS_WERE_CHANGED = false;
|
|
let yearsSlider = $('#p_years');
|
|
$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);
|
|
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){
|
|
let lastRecordedEntry = recordedHistory[recordedHistory.length-1];
|
|
if(!lastRecordedEntry || id!=lastRecordedEntry[0] || Math.round(daysCurrent)!=lastRecordedEntry[2]){ // not same thing/time
|
|
recordedHistory.push([id, val, Math.round(daysCurrent)]);
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
|
|
// Just to update other random crap
|
|
if(!_DO_NOT_RECURSE){
|
|
_DO_NOT_RECURSE = true;
|
|
updateModel(1, true); // one day
|
|
_DO_NOT_RECURSE = false;
|
|
}
|
|
|
|
// HACK: If this is years, RESET SIM & CHANGE THE MONTHS
|
|
if(slider==yearsSlider){
|
|
if(daysCurrent>0){
|
|
_resetTheSim();
|
|
_updateButtons();
|
|
}
|
|
updateMonthTicks();
|
|
}
|
|
|
|
// MORE HAX
|
|
if(daysCurrent==0){
|
|
sbDOM.setAttribute('label','params');
|
|
}
|
|
|
|
// HAX
|
|
INPUTS_WERE_CHANGED = true;
|
|
|
|
};
|
|
slider.oninput = onChange;
|
|
onChange();
|
|
});
|
|
//DONT_RECORD_HISTORY = false;
|
|
_DO_NOT_RECURSE = 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();
|
|
});
|
|
|
|
|
|
/////////////////////////////////////
|
|
// (RE)START ////////////////////////
|
|
/////////////////////////////////////
|
|
|
|
let IS_PLAYING = false;
|
|
|
|
//let recordedHistory = [];
|
|
//let IS_REPLAYING_HISTORY = false;
|
|
|
|
let START_S = 0.999,
|
|
START_E = 0.001,
|
|
START_I = 0.001,
|
|
START_R = 0.000;
|
|
|
|
let restart = ()=>{
|
|
|
|
// Model
|
|
S = START_S;
|
|
E = START_E;
|
|
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);
|
|
|
|
// Force refresh DOM
|
|
s_dom.oninput();
|
|
|
|
};
|
|
|
|
|
|
/////////////////////////////////////
|
|
// BIG & SMALL BUTTONS //////////////
|
|
/////////////////////////////////////
|
|
|
|
let bbDOM = $('.big_button');
|
|
let sbDOM = $('.small_button');
|
|
|
|
let handTutorial = 0;
|
|
|
|
bbDOM.onclick = ()=>{
|
|
|
|
if(CURRENT_STAGE.SHOW_HAND=="tutorial_0"){
|
|
if(handTutorial==0){
|
|
hideHand();
|
|
handTutorial = 1;
|
|
}else if(handTutorial==1){
|
|
hideHand();
|
|
}else if(handTutorial==2){
|
|
hideHand();
|
|
setTimeout(()=>{
|
|
showHand('end');
|
|
},1);
|
|
handTutorial = 3;
|
|
}
|
|
}
|
|
if(CURRENT_STAGE.SHOW_HAND=="tutorial_1"){
|
|
if(handTutorial==0){
|
|
hideHand();
|
|
handTutorial = 1;
|
|
}else if(handTutorial==1){
|
|
hideHand();
|
|
handTutorial = 2;
|
|
}
|
|
}
|
|
|
|
if(CURRENT_STAGE.SHOW_HAND=="tutorial_2"){
|
|
if(handTutorial==0){
|
|
hideHand();
|
|
handTutorial = 1;
|
|
}
|
|
}
|
|
|
|
if(daysCurrent>daysTotal || params._HACK_RESET_WHEN_I_100=="go" || params._HACK_RESET_WHEN_R_100=="go"){
|
|
|
|
_resetTheSim();
|
|
params._HACK_RESET_WHEN_I_100 = undefined;
|
|
params._HACK_RESET_WHEN_R_100 = undefined;
|
|
|
|
if(CURRENT_STAGE.SHOW_HAND=="tutorial_0" && handTutorial<=1){
|
|
setTimeout(()=>{
|
|
showHand('params');
|
|
},1000);
|
|
handTutorial = 2;
|
|
}
|
|
|
|
}else{
|
|
if(daysCurrent==0){
|
|
restart();
|
|
}
|
|
IS_PLAYING = !IS_PLAYING;
|
|
}
|
|
_updateButtons();
|
|
};
|
|
|
|
let defaultParams = [
|
|
["p_transmission", 4],
|
|
["p_exposed", 3],
|
|
["p_recovery", 10],
|
|
["p_waning", 1],
|
|
["p_hospital", 333],
|
|
["p_years", 2],
|
|
["p_speed", 30],
|
|
|
|
["p_non_s", 0],
|
|
["p_hygiene", 0],
|
|
["p_distancing", 0],
|
|
["p_isolate", 0],
|
|
["p_quarantine", 0],
|
|
["p_masks", 0],
|
|
["p_summer", 0],
|
|
];
|
|
|
|
sbDOM.onclick = ()=>{
|
|
if(daysCurrent==0){
|
|
|
|
changeSliders(defaultParams);
|
|
changeSliders(CURRENT_STAGE.inputs);
|
|
|
|
}else if(daysCurrent>daysTotal){
|
|
//_replayTheSim();
|
|
}else{
|
|
_resetTheSim();
|
|
}
|
|
_updateButtons();
|
|
};
|
|
|
|
let _updateButtons = ()=>{
|
|
|
|
if(daysCurrent > daysTotal){
|
|
|
|
bbDOM.setAttribute('label','reset');
|
|
sbDOM.setAttribute('label','');
|
|
|
|
}else if(IS_PLAYING){
|
|
|
|
bbDOM.setAttribute('label','pause');
|
|
sbDOM.setAttribute('label','reset');
|
|
|
|
}else{
|
|
|
|
if(daysCurrent==0){
|
|
bbDOM.setAttribute('label','start');
|
|
sbDOM.setAttribute('label','NONE');
|
|
}else{
|
|
bbDOM.setAttribute('label','continue');
|
|
sbDOM.setAttribute('label','reset');
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
let hofp = $('#hide_on_first_playthrough');
|
|
let _showAllControls = ()=>{
|
|
|
|
let originalHeight = hofp.getBoundingClientRect().height;
|
|
if(originalHeight>0) return;
|
|
|
|
hofp.style.height = "auto";
|
|
hofp.style.position = "absolute";
|
|
hofp.style.top = "-1000px";
|
|
setTimeout(()=>{
|
|
let newHeight = hofp.getBoundingClientRect().height + 10;
|
|
hofp.style.position = "";
|
|
hofp.style.top = "";
|
|
hofp.style.height = originalHeight+"px";
|
|
setTimeout(()=>{
|
|
hofp.style.marginTop = "";
|
|
hofp.style.height = newHeight+"px";
|
|
},20);
|
|
},20);
|
|
};
|
|
let _hideAllControls = ()=>{
|
|
hofp.style.height = "0px";
|
|
};
|
|
|
|
let _resetTheSim = ()=>{
|
|
_showAllControls();
|
|
//IS_REPLAYING_HISTORY = false;
|
|
//recordedHistory = [];
|
|
restart();
|
|
IS_PLAYING = false;
|
|
};
|
|
/*
|
|
let _replayTheSim = ()=>{
|
|
_hideAllControls();
|
|
//IS_REPLAYING_HISTORY = true;
|
|
restart();
|
|
IS_PLAYING = true;
|
|
};
|
|
|
|
*/
|
|
|
|
/////////////////////////////////////
|
|
// THE HAND /////////////////////////
|
|
/////////////////////////////////////
|
|
|
|
let pointerDOM = $('#pointer');
|
|
let handDOM = $('#hand_container');
|
|
let wordsDOM = $('#pointer_words');
|
|
let HAND_IS_VISIBLE = false;
|
|
let showHand = (position)=>{
|
|
|
|
HAND_IS_VISIBLE = true;
|
|
pointerDOM.style.display = 'block';
|
|
|
|
$all('span',pointerDOM).forEach((span)=>{
|
|
span.style.display = 'none';
|
|
});
|
|
|
|
switch(position){
|
|
case 'start':
|
|
handDOM.style.top = '111px';
|
|
handDOM.style.left = '98px';
|
|
break;
|
|
case 'params': case 'params2':
|
|
handDOM.style.top = '100px';
|
|
handDOM.style.left = '280px';
|
|
handDOM.style.transform = 'rotate(270deg)';
|
|
wordsDOM.style.top = '117px';
|
|
wordsDOM.style.left = '377px';
|
|
wordsDOM.style.textAlign = 'left';
|
|
$('#pointer_params').style.display = 'inline';
|
|
$('#pointer_params_2').style.display = (position=='params2') ? 'inline' : 'none';
|
|
break;
|
|
case 'end':
|
|
handDOM.style.top = '445px';
|
|
handDOM.style.left = '101px';
|
|
handDOM.style.transform = 'rotate(180deg) scaleX(-1)';
|
|
wordsDOM.style.top = '363px';
|
|
wordsDOM.style.left = '17px';
|
|
wordsDOM.style.textAlign = 'center';
|
|
$('#pointer_scroll').style.display = 'inline';
|
|
break;
|
|
case 'recording':
|
|
handDOM.style.top = '300px';
|
|
handDOM.style.left = '280px';
|
|
handDOM.style.transform = 'rotate(270deg)';
|
|
wordsDOM.style.top = '317px';
|
|
wordsDOM.style.left = '377px';
|
|
wordsDOM.style.textAlign = 'left';
|
|
$('#pointer_replay').style.display = 'inline';
|
|
break;
|
|
}
|
|
|
|
|
|
};
|
|
let hideHand = ()=>{
|
|
|
|
HAND_IS_VISIBLE = false;
|
|
pointerDOM.style.display = 'none';
|
|
|
|
};
|
|
|
|
|