i hate web development so much

This commit is contained in:
Nicky Case 2020-04-30 17:28:25 -04:00
parent 7253482a89
commit 649c1c7bd9
10 changed files with 403 additions and 165 deletions

View file

@ -61,8 +61,8 @@
<div>
<h1>What Happens Next?</h1>
<h2>COVID-19 Futures, Explained With Playable Simulations</h2>
<h3>by Marcel Salathé (epidemiologist) and Nicky Case (art/code)</h3>
<h3>🕐 28 min play/read</h3>
<h3>by <a href='https://scholar.google.com/citations?user=_wHMGkUAAAAJ&hl=en'>Marcel Salathé</a> (epidemiologist) and <a href='https://ncase.me/'>Nicky Case</a> (art/code)</h3>
<h3>🕐 30 min play/read</h3>
</div>
</div>
@ -78,7 +78,7 @@
<ul>
<li><strong>The Last Few Months</strong> (epidemiology 101, SEIR model, R &amp; R<sub>0</sub>)</li>
<li><strong>The Next Few Months</strong> (lockdowns, contact tracing, masks?)</li>
<li><strong>The Next Few Months</strong> (lockdowns, contact tracing, masks)</li>
<li><strong>The Next Few Years</strong> (loss of immunity? no vaccine?)</li>
</ul>
@ -304,7 +304,7 @@
<p>That was the other finding of the March 16 Imperial College report, which convinced the UK to abandon its original plan. Any attempt at <strong>mitigation</strong> (reduce R, but R &gt; 1) will fail. The only way out is <strong>suppression</strong> (reduce R so that R &lt; 1).</p>
<p>// TODO: pic difference</p>
<p><img src="pics/mitigation_vs_suppression.png" alt=""></p>
<p>That is, don&#39;t merely &quot;flatten&quot; the curve, <em>crush</em> the curve. For example, with a...</p>
@ -326,7 +326,7 @@
<h3 id="toc_3">Scenario 3: Intermittent Lockdown</h3>
<p>This solution was first suggested by the March 16 Imperial College report, and later again by a Harvard paper<sup id="fnref19"><a href="#fn19" rel="footnote">19</a></sup>.</p>
<p>This solution was first suggested by the March 16 Imperial College report, and later again by a Harvard paper.<sup id="fnref19"><a href="#fn19" rel="footnote">19</a></sup></p>
<p><strong>Here&#39;s a simulation:</strong> (After playing the &quot;recorded scenario&quot;, you can try simulating your <em>own</em> lockdown schedule, by changing the sliders <em>while</em> the simulation is running! Remember you can pause &amp; continue the sim, and change the simulation speed)</p>
@ -537,7 +537,7 @@
<p>But for COVID-19 <em>in humans</em>, as of May 1st 2020, &quot;how long&quot; is the big unknown.</p>
<p>For these simulations, let&#39;s say it&#39;s 1 year.
<strong>Here&#39;s a simulation starting with 100% <icon r></icon></strong>, exponentially decaying into susceptible, no-immunity <icon s></icon>s after 1 year, on <em>average</em>:</p>
<strong>Here&#39;s a simulation starting with 100% <icon r></icon></strong>, exponentially decaying into susceptible, no-immunity <icon s></icon>s after 1 year, on <em>average</em>, with variation:</p>
<div class="sim">
<iframe src="sim?stage=yrs-1&format=lines&height=600" width="800" height="600"></iframe>
@ -608,7 +608,7 @@
<p><strong>Here&#39;s an (optional) Sandbox Mode, with <em>everything</em> available. Simulate &amp; play around to your heart&#39;s content:</strong></p>
<div class="sim">
<iframe src="sim?stage=SB&format=sb&height=1000" width="800" height="1000"></iframe>
<iframe src="sim?stage=SB&format=sb" width="800" height="540"></iframe>
</div>
<p>This basic &quot;epidemic flight simulator&quot; has taught us so much. It&#39;s let us answer questions about the past few months, next few months, and next few years.</p>
@ -718,9 +718,7 @@
</li>
<li id="fn15">
<p>“[Graham Medley] says that the actual goal is the same as that of other countries: flatten the curve by staggering the onset of infections. As a consequence, the nation may achieve herd immunity; its a side effect, not an aim. [...]&nbsp;<a href="#fnref15" rev="footnote">&#8617;</a></p>
<p>The governments actual coronavirus action plan, available online, doesnt mention herd immunity at all. [...] “Its been a case of how not to communicate during an outbreak,” says Devi Sridhar, a public-health specialist at the University of Edinburgh.”</p>
<p>“He says that the actual goal is the same as that of other countries: flatten the curve by staggering the onset of infections. As a consequence, the nation may achieve herd immunity; its a side effect, not an aim. [...] The governments actual coronavirus action plan, available online, doesnt mention herd immunity at all.”&nbsp;<a href="#fnref15" rev="footnote">&#8617;</a></p>
<p>From a <a href="https://www.theatlantic.com/health/archive/2020/03/coronavirus-pandemic-herd-immunity-uk-boris-johnson/608065/">The Atlantic article by Ed Yong</a></p>
</li>

View file

@ -31,6 +31,7 @@ div{
/*height:500px;*/
float:left;
position: relative;
padding-bottom: 40px;
}
#label_s{
@ -198,6 +199,7 @@ hr{
right:15px;
top:8px;
width: 500px;
pointer-events: none;
}
#graphCanvas{
width:500px;
@ -236,16 +238,16 @@ icon{
background-size: 100% 100%;
}
icon[s]{
background-image: url(../icons/s.png);
background-image: url(../../icons/s.png);
}
icon[e]{
background-image: url(../icons/e.png);
background-image: url(../../icons/e.png);
}
icon[i]{
background-image: url(../icons/i.png);
background-image: url(../../icons/i.png);
}
icon[r]{
background-image: url(../icons/r.png);
background-image: url(../../icons/r.png);
}
#legend{
@ -279,7 +281,7 @@ icon[r]{
}
#hand{
position: absolute;
background: url(../icons/hand.png);
background: url(../../icons/hand.png);
background-size: 100% 100%;
width:80px; height:80px;
@ -310,7 +312,7 @@ icon[r]{
.control_icon{
width:36px;
height:36px;
background: url(../icons/controls.png);
background: url(../../icons/controls.png);
background-size: auto 100%;
display: inline-block;
@ -326,3 +328,7 @@ icon[r]{
.control_icon[reset]{
background-position: -300% 0;
}
.simplebar-wrapper{
height: 450px !important;
}

215
sim/css/simplebar.css Normal file
View file

@ -0,0 +1,215 @@
[data-simplebar] {
position: relative;
flex-direction: column;
flex-wrap: wrap;
justify-content: flex-start;
align-content: flex-start;
align-items: flex-start;
}
.simplebar-wrapper {
overflow: hidden;
width: inherit;
height: inherit;
max-width: inherit;
max-height: inherit;
}
.simplebar-mask {
direction: inherit;
position: absolute;
overflow: hidden;
padding: 0;
margin: 0;
left: 0;
top: 0;
bottom: 0;
right: 0;
width: auto !important;
height: auto !important;
z-index: 0;
}
.simplebar-offset {
direction: inherit !important;
box-sizing: inherit !important;
resize: none !important;
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
padding: 0;
margin: 0;
-webkit-overflow-scrolling: touch;
}
.simplebar-content-wrapper {
direction: inherit;
box-sizing: border-box !important;
position: relative;
display: block;
height: 100%; /* Required for horizontal native scrollbar to not appear if parent is taller than natural height */
width: auto;
visibility: visible;
max-width: 100%; /* Not required for horizontal scroll to trigger */
max-height: 100%; /* Needed for vertical scroll to trigger */
scrollbar-width: none;
-ms-overflow-style: none;
}
.simplebar-content-wrapper::-webkit-scrollbar,
.simplebar-hide-scrollbar::-webkit-scrollbar {
width: 0;
height: 0;
}
.simplebar-content:before,
.simplebar-content:after {
content: ' ';
display: table;
}
.simplebar-placeholder {
max-height: 100%;
max-width: 100%;
width: 100%;
pointer-events: none;
}
.simplebar-height-auto-observer-wrapper {
box-sizing: inherit !important;
height: 100%;
width: 100%;
max-width: 1px;
position: relative;
float: left;
max-height: 1px;
overflow: hidden;
z-index: -1;
padding: 0;
margin: 0;
pointer-events: none;
flex-grow: inherit;
flex-shrink: 0;
flex-basis: 0;
}
.simplebar-height-auto-observer {
box-sizing: inherit;
display: block;
opacity: 0;
position: absolute;
top: 0;
left: 0;
height: 1000%;
width: 1000%;
min-height: 1px;
min-width: 1px;
overflow: hidden;
pointer-events: none;
z-index: -1;
}
.simplebar-track {
z-index: 1;
position: absolute;
right: 0;
bottom: 0;
pointer-events: none;
overflow: hidden;
background: #333;
}
[data-simplebar].simplebar-dragging .simplebar-content {
pointer-events: none;
user-select: none;
-webkit-user-select: none;
}
[data-simplebar].simplebar-dragging .simplebar-track {
pointer-events: all;
}
.simplebar-scrollbar {
position: absolute;
left: 0;
right: 0;
min-height: 10px;
}
.simplebar-scrollbar:before {
position: absolute;
content: '';
/*background: black;*/
background: #fff;
border-radius: 7px;
left: 2px;
right: 2px;
opacity: 0;
transition: opacity 0.2s linear;
}
.simplebar-scrollbar.simplebar-visible:before {
/* When hovered, remove all transitions from drag handle */
opacity: 0.5;
transition: opacity 0s linear;
}
.simplebar-track.simplebar-vertical {
top: 0;
width: 11px;
}
.simplebar-track.simplebar-vertical .simplebar-scrollbar:before {
top: 2px;
bottom: 2px;
}
.simplebar-track.simplebar-horizontal {
left: 0;
height: 11px;
}
.simplebar-track.simplebar-horizontal .simplebar-scrollbar:before {
height: 100%;
left: 2px;
right: 2px;
}
.simplebar-track.simplebar-horizontal .simplebar-scrollbar {
right: auto;
left: 0;
top: 2px;
height: 7px;
min-height: 0;
min-width: 10px;
width: auto;
}
/* Rtl support */
[data-simplebar-direction='rtl'] .simplebar-track.simplebar-vertical {
right: auto;
left: 0;
}
.hs-dummy-scrollbar-size {
direction: rtl;
position: fixed;
opacity: 0;
visibility: hidden;
height: 500px;
width: 500px;
overflow-y: hidden;
overflow-x: scroll;
}
.simplebar-hide-scrollbar {
position: fixed;
left: 0;
visibility: hidden;
overflow-y: scroll;
scrollbar-width: none;
-ms-overflow-style: none;
}

View file

@ -2,7 +2,8 @@
<html>
<head>
<link rel="stylesheet" type="text/css" href="sim.css" />
<link rel="stylesheet" type="text/css" href="css/sim.css" />
<link rel="stylesheet" type="text/css" href="css/simplebar.css" />
</head>
<body>
@ -256,4 +257,8 @@
<script src="js/Model.js"></script>
<script src="js/Controls.js"></script>
<script src="js/Stages.js"></script>
<script src="js/main.js"></script>
<script src="js/Params.js"></script>
<script src="js/main.js"></script>
<script src="js/simplebar.min.js"></script>

137
sim/js/Params.js Normal file
View file

@ -0,0 +1,137 @@
let changeSliders = (idValPair)=>{
DONT_RECORD_HISTORY = true;
_DO_NOT_RECURSE = true;
idValPair.forEach((idValPair)=>{
let [id,val] = idValPair;
let slider = $('#'+id);
if(slider){
slider.value = val;
slider.oninput();
}
params[id] = val;
});
DONT_RECORD_HISTORY = false;
_DO_NOT_RECURSE = false;
};
let CURRENT_STAGE;
let setStage = (stageID)=>{
let stage = STAGES[stageID];
CURRENT_STAGE = stage;
// Hide what
stage.hide = stage.hide || [];
stage.hide.forEach((domID)=>{
$('#'+domID).style.display = 'none';
});
// Sliders
stage.inputs = stage.inputs || [];
changeSliders(defaultParams);
changeSliders(stage.inputs);
// 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_E = 0;
START_I = stage.SIR[1];
START_R = stage.SIR[2];
}
// Show all?
if(stage.SHOW_ALL_AT_START){
_showAllControls();
}
// Show hand?
if(stage.SHOW_HAND){
if(stage.SHOW_HAND=="tutorial_2"){
showHand('recording');
}else{
showHand('start');
}
}
// Show herd immunity?
if(params.DO_NOT_SHOW_HERD_IMMUNITY){
$('.herd').style.display = 'none';
}
// PLAY BACK?
if(stage.PLAY_RECORDING){
IS_PLAYING_RECORDING = true;
recordedHistory = JSON.parse(JSON.stringify(stage.PLAY_RECORDING));
}
};
let stageParams = new URLSearchParams(location.search);
if(stageParams.has('stage')) setStage(stageParams.get('stage'));
if(stageParams.has('format')){
if(stageParams.get('format')=='calc'){
document.body.style.overflow = 'hidden';
$('#sandbox').style.margin = '0';
}
if(stageParams.get('format')=='lines'){
$all('.lines').forEach((dom)=>{
dom.style.display = 'none';
});
}
}
window.onload = ()=>{
if(stageParams.get('format')=='sb'){
$('#legend').style.display = 'none';
/*$('#sandbox').style.margin = '0';*/
setTimeout(()=>{
let sbDOM = $('#sandbox');
sbDOM.style.overflow = 'auto';
sbDOM.style.height = 'auto';
sbDOM.setAttribute('data-simplebar-direction','rtl');
new SimpleBar(sbDOM,{
autoHide: false,
direction: 'rtl'
});
sbDOM.scrollTop = 0;
$('#graph').style.position = 'fixed';
},2000);
}
};
if(stageParams.has('height')){
$('#sandbox').style.height = stageParams.get('height')+'px';
}

View file

@ -37,25 +37,6 @@ SB Full Sandbox
const STAGES = {
"00": {
hide: [
"section_dynamics",
"c_recovery","label_c_waning","section_meta_years","c_exposed",
"int_block_1","int_block_2","int_block_3","int_block_4","int_block_5","hospital_capacity"
],
inputs: [
["p_transmission",4],
["p_years",1],
["p_speed",5],
["TIME_DELTA", 0.5],
//["EXPONENTIAL",true],
],
checkboxes: [
["c_recovery", true],
["c_exposed",true]
],
},
//////////////////////////////////////////
// THE SIMULATION ////////////////////////
//////////////////////////////////////////
@ -707,124 +688,12 @@ const STAGES = {
["c_waning", true],
["c_exposed",true],
],
inputs: [
["p_years",5],
["p_speed",10]
],
SHOW_ALL_AT_START: true,
},
};
let changeSliders = (idValPair)=>{
DONT_RECORD_HISTORY = true;
_DO_NOT_RECURSE = true;
idValPair.forEach((idValPair)=>{
let [id,val] = idValPair;
let slider = $('#'+id);
if(slider){
slider.value = val;
slider.oninput();
}
params[id] = val;
});
DONT_RECORD_HISTORY = false;
_DO_NOT_RECURSE = false;
};
let CURRENT_STAGE;
let setStage = (stageID)=>{
let stage = STAGES[stageID];
CURRENT_STAGE = stage;
// Hide what
stage.hide = stage.hide || [];
stage.hide.forEach((domID)=>{
$('#'+domID).style.display = 'none';
});
// Sliders
stage.inputs = stage.inputs || [];
changeSliders(defaultParams);
changeSliders(stage.inputs);
// 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_E = 0;
START_I = stage.SIR[1];
START_R = stage.SIR[2];
}
// Show all?
if(stage.SHOW_ALL_AT_START){
_showAllControls();
}
// Show hand?
if(stage.SHOW_HAND){
if(stage.SHOW_HAND=="tutorial_2"){
showHand('recording');
}else{
showHand('start');
}
}
// Show herd immunity?
if(params.DO_NOT_SHOW_HERD_IMMUNITY){
$('.herd').style.display = 'none';
}
// PLAY BACK?
if(stage.PLAY_RECORDING){
IS_PLAYING_RECORDING = true;
recordedHistory = JSON.parse(JSON.stringify(stage.PLAY_RECORDING));
}
};
let stageParams = new URLSearchParams(location.search);
if(stageParams.has('stage')) setStage(stageParams.get('stage'));
if(stageParams.has('format')){
if(stageParams.get('format')=='calc'){
document.body.style.overflow = 'hidden';
$('#sandbox').style.margin = '0';
}
if(stageParams.get('format')=='lines'){
$all('.lines').forEach((dom)=>{
dom.style.display = 'none';
});
}
if(stageParams.get('format')=='sb'){
$('#legend').style.display = 'none';
$('#sandbox').style.margin = '0';
}
}
if(stageParams.has('height')){
$('#sandbox').style.height = stageParams.get('height')+'px';
}
};

10
sim/js/simplebar.min.js vendored Normal file

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

View file

@ -16,8 +16,8 @@
<div>
<h1>What Happens Next?</h1>
<h2>COVID-19 Futures, Explained With Playable Simulations</h2>
<h3>by Marcel Salathé (epidemiologist) and Nicky Case (art/code)</h3>
<h3>🕐 28 min play/read</h3>
<h3>by <a href='https://scholar.google.com/citations?user=_wHMGkUAAAAJ&hl=en'>Marcel Salathé</a> (epidemiologist) and <a href='https://ncase.me/'>Nicky Case</a> (art/code)</h3>
<h3>🕐 30 min play/read</h3>
</div>
</div>
@ -33,7 +33,7 @@
<ul>
<li><strong>The Last Few Months</strong> (epidemiology 101, SEIR model, R &amp; R<sub>0</sub>)</li>
<li><strong>The Next Few Months</strong> (lockdowns, contact tracing, masks?)</li>
<li><strong>The Next Few Months</strong> (lockdowns, contact tracing, masks)</li>
<li><strong>The Next Few Years</strong> (loss of immunity? no vaccine?)</li>
</ul>
@ -259,7 +259,7 @@ the <em>second</em>-most important idea in Epidemiology 101:</p>
<p>That was the other finding of the March 16 Imperial College report, which convinced the UK to abandon its original plan. Any attempt at <strong>mitigation</strong> (reduce R, but R &gt; 1) will fail. The only way out is <strong>suppression</strong> (reduce R so that R &lt; 1).</p>
<p>// TODO: pic difference</p>
<p><img src="pics/mitigation_vs_suppression.png" alt=""></p>
<p>That is, don&#39;t merely &quot;flatten&quot; the curve, <em>crush</em> the curve. For example, with a...</p>
@ -281,7 +281,7 @@ the <em>second</em>-most important idea in Epidemiology 101:</p>
<h3 id="toc_3">Scenario 3: Intermittent Lockdown</h3>
<p>This solution was first suggested by the March 16 Imperial College report, and later again by a Harvard paper<sup id="fnref19"><a href="#fn19" rel="footnote">19</a></sup>.</p>
<p>This solution was first suggested by the March 16 Imperial College report, and later again by a Harvard paper.<sup id="fnref19"><a href="#fn19" rel="footnote">19</a></sup></p>
<p><strong>Here&#39;s a simulation:</strong> (After playing the &quot;recorded scenario&quot;, you can try simulating your <em>own</em> lockdown schedule, by changing the sliders <em>while</em> the simulation is running! Remember you can pause &amp; continue the sim, and change the simulation speed)</p>
@ -492,7 +492,7 @@ the <em>second</em>-most important idea in Epidemiology 101:</p>
<p>But for COVID-19 <em>in humans</em>, as of May 1st 2020, &quot;how long&quot; is the big unknown.</p>
<p>For these simulations, let&#39;s say it&#39;s 1 year.
<strong>Here&#39;s a simulation starting with 100% <icon r></icon></strong>, exponentially decaying into susceptible, no-immunity <icon s></icon>s after 1 year, on <em>average</em>:</p>
<strong>Here&#39;s a simulation starting with 100% <icon r></icon></strong>, exponentially decaying into susceptible, no-immunity <icon s></icon>s after 1 year, on <em>average</em>, with variation:</p>
<div class="sim">
<iframe src="sim?stage=yrs-1&format=lines&height=600" width="800" height="600"></iframe>
@ -563,7 +563,7 @@ the <em>second</em>-most important idea in Epidemiology 101:</p>
<p><strong>Here&#39;s an (optional) Sandbox Mode, with <em>everything</em> available. Simulate &amp; play around to your heart&#39;s content:</strong></p>
<div class="sim">
<iframe src="sim?stage=SB&format=sb&height=1000" width="800" height="1000"></iframe>
<iframe src="sim?stage=SB&format=sb" width="800" height="450"></iframe>
</div>
<p>This basic &quot;epidemic flight simulator&quot; has taught us so much. It&#39;s let us answer questions about the past few months, next few months, and next few years.</p>
@ -673,9 +673,7 @@ the <em>second</em>-most important idea in Epidemiology 101:</p>
</li>
<li id="fn15">
<p>“[Graham Medley] says that the actual goal is the same as that of other countries: flatten the curve by staggering the onset of infections. As a consequence, the nation may achieve herd immunity; its a side effect, not an aim. [...]&nbsp;<a href="#fnref15" rev="footnote">&#8617;</a></p>
<p>The governments actual coronavirus action plan, available online, doesnt mention herd immunity at all. [...] “Its been a case of how not to communicate during an outbreak,” says Devi Sridhar, a public-health specialist at the University of Edinburgh.”</p>
<p>“He says that the actual goal is the same as that of other countries: flatten the curve by staggering the onset of infections. As a consequence, the nation may achieve herd immunity; its a side effect, not an aim. [...] The governments actual coronavirus action plan, available online, doesnt mention herd immunity at all.”&nbsp;<a href="#fnref15" rev="footnote">&#8617;</a></p>
<p>From a <a href="https://www.theatlantic.com/health/archive/2020/03/coronavirus-pandemic-herd-immunity-uk-boris-johnson/608065/">The Atlantic article by Ed Yong</a></p>
</li>

View file

@ -658,7 +658,7 @@ Maybe you'd like to challenge our assumptions, and try different R<sub>0</sub>'s
**Here's an (optional) Sandbox Mode, with *everything* available. Simulate & play around to your heart's content:**
<div class="sim">
<iframe src="sim?stage=SB&format=sb&height=1000" width="800" height="1000"></iframe>
<iframe src="sim?stage=SB&format=sb" width="800" height="540"></iframe>
</div>
This basic "epidemic flight simulator" has taught us so much. It's let us answer questions about the past few months, next few months, and next few years.