From cf4ba999e04bce01fd755c0a377da392d4513e9c Mon Sep 17 00:00:00 2001 From: Nicky Case Date: Tue, 3 Apr 2018 13:32:26 -0400 Subject: [PATCH] a hella lotta stuff --- slides/index.css | 36 ++- slides/index.html | 47 +++- slides/js/chapters/1_Networks.js | 1 - slides/js/chapters/2_Simple_Contagion.js | 92 +++++++- slides/js/chapters/3_Complex_Contagion.js | 231 +++++++++++++++++-- slides/js/chapters/4_Bonding_And_Bridging.js | 78 ++++++- slides/js/lib/helpers.js | 5 +- slides/js/main.js | 2 +- slides/js/sim/ConnectorCutter.js | 61 +++-- slides/js/sim/Peep.js | 4 +- slides/js/sim/Simulations.js | 42 +++- slides/js/slideshow/Boxes.js | 30 ++- slides/js/slideshow/Slideshow.js | 1 + 13 files changed, 541 insertions(+), 89 deletions(-) diff --git a/slides/index.css b/slides/index.css index 7d0cd32..024b5cb 100644 --- a/slides/index.css +++ b/slides/index.css @@ -19,6 +19,9 @@ body{ width: 100%; height: calc(100% - 60px); } +#container[sim_is_running]{ + background: #eee; +} #container > div{ position: absolute; width: 100%; height: 100%; @@ -44,7 +47,8 @@ body{ background-size: 100% 100%; } #slideshow .next_button{ - margin: 0 auto; + display: inline-block; + /*margin: 0 auto;*/ position: relative; top: -10px; width: 300px; @@ -58,7 +62,9 @@ body{ background-position: 0 -100px; } .transitionable{ - transition: opacity 0.3s ease-in-out; + transition: opacity 0.3s ease-in-out, + left 0.3s ease-in-out, + top 0.3s ease-in-out; } #scratch{ display: none; @@ -68,7 +74,31 @@ body{ background-position: 0% 0%; } .sim_button{ - + position: absolute; + width: 200px; + height: 100px; + border: none !important; +} +.sim_button > div{ + position: absolute; + background: #dd4040; + color: #fff; + text-align: center; + border-radius: 10px; +} +.sim_button > #reset_button{ + width: 150px; + left:25px; + top:0px; + font-size: 0.8em; + transition: top 0.3s ease-in-out; +} +.sim_button > #start_button{ + width: 200px; + padding: 0.5em 0; +} +.sim_button[active] > #reset_button{ + top:60px; } /* MODAL */ diff --git a/slides/index.html b/slides/index.html index b72d5c9..7e5782c 100644 --- a/slides/index.html +++ b/slides/index.html @@ -153,13 +153,56 @@ blah blah post-puzzle + +blah blah simple + + + +next + + + +blah blah simple cascade + + + +onwards... + + + +blah blah complex vs simple + + + +herp derp blah blah +next + + + +blah blah complex cascade + + + +fweeee + + + +blah blah complex prevention + + + +herp derp blah blah +next + + + @@ -168,13 +211,13 @@ blah blah post-puzzle WIN -> start sim +> start >> next -reset sim +↺ reset diff --git a/slides/js/chapters/1_Networks.js b/slides/js/chapters/1_Networks.js index 2647bbe..82e63dd 100644 --- a/slides/js/chapters/1_Networks.js +++ b/slides/js/chapters/1_Networks.js @@ -188,7 +188,6 @@ SLIDES.push( ], - // Logic to fade in/out words & stuff onupdate:function(slideshow, state){ // Win only if EVERYONE hits threshold diff --git a/slides/js/chapters/2_Simple_Contagion.js b/slides/js/chapters/2_Simple_Contagion.js index b5175ec..ed49acb 100644 --- a/slides/js/chapters/2_Simple_Contagion.js +++ b/slides/js/chapters/2_Simple_Contagion.js @@ -6,9 +6,9 @@ var CONTAGION_PUZZLE = { "connections":[[0,1],[1,3],[3,2],[3,7],[7,8],[8,6],[6,4],[4,2],[6,5],[5,9]] }; var CASCADE_PUZZLE = { - "peeps":[[34,63,1],[171,97,0],[311,179,0],[191,240,0],[309,312,0],[542,77,0],[450,164,0],[528,264,0],[654,229,0],[661,117,0],[869,295,0],[720,337,0],[926,428,0],[845,508,0],[706,464,0]], - "connections":[[0,1],[3,2],[2,4],[4,3],[6,7],[7,8],[8,9],[9,5],[5,6],[6,9],[9,7],[7,5],[5,8],[8,6],[11,10],[11,14],[14,13],[13,12],[12,10],[11,12],[12,14],[14,10],[10,13],[13,11]] -}; + "peeps":[[31,201,1],[148,238,0],[267,317,0],[166,392,0],[282,437,0],[481,202,0],[401,284,0],[472,367,0],[590,340,0],[602,236,0],[843,313,0],[719,376,0],[930,413,0],[846,514,0],[728,488,0]], + "connections":[[0,1,1],[3,2,1],[2,4,1],[4,3,1],[6,7,1],[7,8,1],[8,9,1],[9,5,1],[5,6,1],[6,9,1],[9,7,1],[7,5,1],[5,8,1],[8,6,1],[11,10,1],[11,14,1],[14,13,1],[13,12,1],[12,10,1],[11,12,1],[12,14,1],[14,10,1],[10,13,1],[13,11,1]] +} SLIDES.push( { @@ -17,6 +17,13 @@ SLIDES.push( add:[ + // Intro text + { + type:"box", + text:"_2_simple", + x:0, y:0, w:350, h:200 + }, + // Lil' contagion { type:"sim", @@ -36,11 +43,38 @@ SLIDES.push( // UI for the simulation { type:"box", - x:380, y:180, + x:380, y:165, sim_button:"red" }, - ] + // Outro text + { + id:"end", + type:"box", + text:"_2_simple_end", + x:660, y:440, w:300, h:100, + hidden:true + } + + ], + + onupdate:function(slideshow, state){ + + // Show end if EVERYONE is infected + if(!state.ended){ + var sim = slideshow.simulations.sims[0]; + var peepCount = 0; + sim.peeps.forEach(function(peep){ + if(peep.infected) peepCount++; + }); + if(peepCount==sim.peeps.length){ + var boxes = slideshow.boxes; + boxes.showChildByID("end", true); + state.ended = true; + } + } + + } }, { @@ -49,10 +83,10 @@ SLIDES.push( add:[ - // Lil' contagion + // Sim { type:"sim", - x:0, y:0, + x:0, y:-140, fullscreen: true, network: { "contagion":0, @@ -66,7 +100,49 @@ SLIDES.push( } }, - ] + // UI for the simulation + { + type:"box", + x:380, y:290, + sim_button:"red" + }, + + // Intro text + { + type:"box", + text:"_2_cascade", + x:0, y:400, w:600, h:140 + }, + + // End text + { + id:"end", + type:"box", + text:"_2_cascade_end", + x:660, y:440, w:300, h:100, + hidden:true + }, + + ], + + onupdate:function(slideshow, state){ + + // Show end if EVERYONE is infected + if(!state.ended){ + var sim = slideshow.simulations.sims[0]; + var peepCount = 0; + sim.peeps.forEach(function(peep){ + if(peep.infected) peepCount++; + }); + if(peepCount==sim.peeps.length){ + var boxes = slideshow.boxes; + boxes.showChildByID("end", true); + state.ended = true; + sim.win(); + } + } + + } }, ); \ No newline at end of file diff --git a/slides/js/chapters/3_Complex_Contagion.js b/slides/js/chapters/3_Complex_Contagion.js index 15b5dd9..bd5b521 100644 --- a/slides/js/chapters/3_Complex_Contagion.js +++ b/slides/js/chapters/3_Complex_Contagion.js @@ -1,11 +1,156 @@ // 3 - Complex Contagion SLIDES.push( + { chapter: "Complex", clear:true, add:[ + + // Intro text + { + type:"box", + text:"_3_complex", + x:0, y:0, w:360, h:370 + }, + + // Sim + { + type:"sim", + x:0, y:0, + fullscreen: true, + network: { + "contagion":0.25, + "peeps":[[432,144,1],[438,410,1],[636,139,0],[638,414,0],[789,68,0],[916,101,0],[855,195,0],[798,320,0],[887,346,0],[917,445,0],[840,503,0]], + "connections":[[0,2,0],[2,4,0],[2,5,0],[6,2,0],[1,3,0],[3,10,0],[3,7,0],[8,3,0],[9,3,0]] + }, + options:{ + infectedFrame: 3, + scale: 1.25 + } + }, + + // UI for the simulation + { + type:"box", + x:440, y:225, + sim_button:"red" + }, + + // End text + { + id:"end", + type:"box", + text:"_3_complex_end", + x:0, y:370, w:360, h:170, align:"right", + hidden:true + }, + + ], + + onupdate:function(slideshow, state){ + + // Show end if at least 5 infected + if(!state.ended){ + var sim = slideshow.simulations.sims[0]; + var peepCount = 0; + sim.peeps.forEach(function(peep){ + if(peep.infected) peepCount++; + }); + if(peepCount>=5){ + var boxes = slideshow.boxes; + boxes.showChildByID("end", true); + state.ended = true; + } + } + + } + +}, + +{ + chapter: "Complex-Cascade", + clear:true, + + add:[ + + // Sim + { + type:"sim", + x:0, y:-140, + fullscreen: true, + network: { + "contagion":0.25, + "peeps":CASCADE_PUZZLE.peeps, + "connections":CASCADE_PUZZLE.connections + }, + options:{ + infectedFrame: 3, + scale: 1.25, + startUncuttable: true + } + }, + + // UI for the simulation + { + type:"box", + x:380, y:290, + sim_button:"red" + }, + + // Intro text + { + type:"box", + text:"_3_cascade", + x:0, y:400, w:600, h:140 + }, + + // End text + { + id:"end", + type:"box", + text:"_3_cascade_end", + x:660, y:440, w:300, h:100, + hidden:true + }, + + ], + + onupdate:function(slideshow, state){ + + // Show end if EVERYONE is infected + if(!state.ended){ + var sim = slideshow.simulations.sims[0]; + var peepCount = 0; + sim.peeps.forEach(function(peep){ + if(peep.infected) peepCount++; + }); + if(peepCount==sim.peeps.length){ + var boxes = slideshow.boxes; + boxes.showChildByID("end", true); + state.ended = true; + sim.win(); + } + } + + } + +}, + +{ + chapter: "Complex-Prevent", + clear:true, + + add:[ + + // Intro text + { + type:"box", + text:"_3_prevent", + x:0, y:0, w:350, h:200 + }, + // Lil' contagion { type:"sim", @@ -22,31 +167,71 @@ SLIDES.push( startUncuttable: true } }, - ] -}, -{ - chapter: "Complex-Cascade", - clear:true, - - add:[ - // Lil' contagion + // UI for the simulation { - type:"sim", - x:0, y:0, - fullscreen: true, - network: { - "contagion":0, - "peeps":CASCADE_PUZZLE.peeps, - "connections":CASCADE_PUZZLE.connections - }, - options:{ - infectedFrame: 3, - scale: 1.25, - startUncuttable: true - } + type:"box", + x:380, y:140, + sim_button:"red" }, - ] -}, + // Outro text + { + id:"end", + type:"box", + text:"_3_prevent_end", + x:660, y:440, w:300, h:100, + hidden:true + } + + ], + + onupdate:function(slideshow, state){ + + // Show end if sim is running AND no one left to infect + // that is, it's stalled... YAY! + var sim = slideshow.simulations.sims[0]; + + if(!state.ended){ + if(Simulations.IS_RUNNING){ + + // if it's a new step... + if(sim.STEP > state.lastStep){ + + // ...but the infected count is the same as last step + var countInfected = 0; + sim.peeps.forEach(function(peep){ if(peep.infected) countInfected++; }); + if(state.lastInfected == countInfected){ + + // oh, and it's NOT coz ALL of 'em are infected + if(countInfected!=sim.peeps.length){ + + // WIN + var boxes = slideshow.boxes; + setTimeout(function(){ + boxes.showChildByID("end", true); + state.ended = true; + sim.win(); + },500); + + } + + }else{ + state.lastInfected = countInfected; + } + + } + state.lastStep = sim.STEP; + + }else{ + state.lastStep = 0; + state.lastInfected = 1; + } + + } + + } + +} + ); \ No newline at end of file diff --git a/slides/js/chapters/4_Bonding_And_Bridging.js b/slides/js/chapters/4_Bonding_And_Bridging.js index d02b14b..862fb22 100644 --- a/slides/js/chapters/4_Bonding_And_Bridging.js +++ b/slides/js/chapters/4_Bonding_And_Bridging.js @@ -1,6 +1,80 @@ // 0 - INTRODUCTION SLIDES.push( + { - chapter: "BB" -} + chapter: "BB", + clear:true, + + add:[ + // Sim + { + type:"sim", + x:0, y:130, + fullscreen: true, + network: { + "contagion":0.25, + "peeps":[[92,52,1],[178,54,0],[25,131,0],[83,213,0],[174,213,0],[233,135,0],[421,50,1],[365,141,0],[423,230,0],[527,228,0],[586,135,0],[522,54,0],[772,50,1],[711,128,0],[770,211,0],[864,210,0],[933,126,0],[858,52,0]], + "connections":[[13,12,0],[12,17,0],[16,15,0],[15,14,0],[14,13,0],[13,16,0],[16,14,0],[14,17,0],[17,15,0],[15,12,0],[12,16,0],[15,13,0],[17,16,0],[14,12,0],[13,17,0],[0,1,0],[2,5,0],[4,3,0]] + }, + options:{ + infectedFrame: 3, + scale: 1 + } + }, + ] + +}, + +{ + chapter: "BB-Bridge", + clear:true, + + add:[ + // Sim + { + type:"sim", + x:0, y:0, + fullscreen: true, + network: { + "contagion":0.25, + "peeps":[[314,58,1],[418,87,0],[234,139,0],[277,234,0],[386,264,0],[460,180,0],[538,390,0],[617,309,0],[719,333,0],[766,432,0],[680,514,0],[572,491,0]], + "connections":[[7,6,0],[6,11,0],[11,10,0],[9,8,0],[8,7,0],[6,10,0],[6,9,0],[9,11,0],[11,7,0],[7,10,0],[9,7,0],[8,10,0],[10,9,0],[6,8,0],[8,11,0],[0,1,0],[2,5,0],[4,3,0]] + }, + options:{ + infectedFrame: 3, + scale: 1, + startUncuttable: true + } + }, + ] + +}, + +{ + chapter: "BB-Both", + clear:true, + + add:[ + // Sim + // use a DRAWING to impose SOFT CONSTRAINTS + { + type:"sim", + x:0, y:0, + fullscreen: true, + network: { + "contagion":0.25, + "peeps":[[474,46,1],[578,100,0],[388,94,0],[568,195,0],[392,190,0],[486,233,0],[273,318,0],[183,363,0],[183,447,0],[256,498,0],[355,376,0],[347,469,0],[630,367,0],[696,308,0],[791,360,0],[784,442,0],[725,495,0],[637,450,0]], + "connections":[] + }, + options:{ + infectedFrame: 3, + scale: 1, + startUncuttable: true + } + }, + ] + +}, + + ); \ No newline at end of file diff --git a/slides/js/lib/helpers.js b/slides/js/lib/helpers.js index aaa3555..a83e804 100644 --- a/slides/js/lib/helpers.js +++ b/slides/js/lib/helpers.js @@ -57,7 +57,8 @@ function removeFromArray(array, item){ function fadeIn(container, dom){ dom.style.opacity = 0; dom.classList.add("transitionable"); - container.appendChild(dom); + dom.style.display = "block"; + if(!container.contains(dom)) container.appendChild(dom); setTimeout(function(){ dom.style.opacity = 1; },50); @@ -66,7 +67,7 @@ function fadeOut(container, dom){ dom.classList.add("transitionable"); dom.style.opacity = 0; setTimeout(function(){ - container.removeChild(dom); + if(container.contains(dom)) container.removeChild(dom); },300); } diff --git a/slides/js/main.js b/slides/js/main.js index 064e07c..6a1ff09 100644 --- a/slides/js/main.js +++ b/slides/js/main.js @@ -28,6 +28,6 @@ window.onload = function(){ window.requestAnimationFrame(update); // First slide! - slideshow.gotoChapter("Simple"); + slideshow.gotoChapter("BB-Both"); } \ No newline at end of file diff --git a/slides/js/sim/ConnectorCutter.js b/slides/js/sim/ConnectorCutter.js index 08d7b34..2bcb61c 100644 --- a/slides/js/sim/ConnectorCutter.js +++ b/slides/js/sim/ConnectorCutter.js @@ -16,40 +16,51 @@ function ConnectorCutter(config){ var mouse = self.sim.mouse; - // JUST CLICKED, and state=0... can either start connecting or cutting! - if(mouse.justPressed && self.state===0){ - - // Clicked on a peep? - var peepClicked = self.sim.getHoveredPeep(0); - if(peepClicked){ - self.state = 1; // START CONNECTING - self.connectFrom = peepClicked; - }else{ - self.state = 2; // START ERASING - } + // only if sim is NOT RUNNING + if(!Simulations.IS_RUNNING){ - } - - // JUST RELEASED, and state!=0... can either stop connecting or cutting! - if(mouse.justReleased && self.state!==0){ - - // End connect? - if(self.state==1){ - var peepReleased = self.sim.getHoveredPeep(20); - if(peepReleased){ - self.sim.addConnection(self.connectFrom, peepReleased); + // JUST CLICKED, and state=0... can either start connecting or cutting! + if(mouse.justPressed && self.state===0){ + + // Clicked on a peep? + var peepClicked = self.sim.getHoveredPeep(0); + if(peepClicked){ + self.state = 1; // START CONNECTING + self.connectFrom = peepClicked; + }else{ + self.state = 2; // START ERASING } + } - // back to normal - self.state = 0; + // JUST RELEASED, and state!=0... can either stop connecting or cutting! + if(mouse.justReleased && self.state!==0){ + // End connect? + if(self.state==1){ + var peepReleased = self.sim.getHoveredPeep(20); + if(peepReleased){ + self.sim.addConnection(self.connectFrom, peepReleased); + } + } + + // back to normal + self.state = 0; + + } + + }else{ + self.state = 0; } // In "NORMAL" state... tell Pencil what frame to go to if(self.state==0){ - var peepHovered = self.sim.getHoveredPeep(0); - pencil.gotoFrame( peepHovered ? 1 : 0 ); + if(!Simulations.IS_RUNNING){ + var peepHovered = self.sim.getHoveredPeep(0); + pencil.gotoFrame( peepHovered ? 1 : 0 ); + }else{ + pencil.gotoFrame(0); + } } // In "CONNECTING" state... show where to connect to diff --git a/slides/js/sim/Peep.js b/slides/js/sim/Peep.js index 28546b4..4e76968 100644 --- a/slides/js/sim/Peep.js +++ b/slides/js/sim/Peep.js @@ -135,8 +135,8 @@ function Peep(config){ ctx.save(); - var bgColor = "#eee"; - var uiColor = "#666"; + var bgColor = "#ddd"; + var uiColor = "#333"; // Say: Infected/Friends (% then n/n) ctx.translate(0,-43); diff --git a/slides/js/sim/Simulations.js b/slides/js/sim/Simulations.js index 4caa9a8..015afad 100644 --- a/slides/js/sim/Simulations.js +++ b/slides/js/sim/Simulations.js @@ -15,11 +15,16 @@ function Simulations(){ // Clear All Sims self.clear = function(){ + + Simulations.IS_RUNNING = false; + $("#container").removeAttribute("sim_is_running"); + self.sims.forEach(function(sim){ self.dom.removeChild(sim.canvas); sim.kill(); }); self.sims = []; + }; // Add Sims @@ -49,18 +54,27 @@ function Simulations(){ // SIMULATION RUNNING // //////////////////////// + subscribe("sim/start", function(){ + Simulations.IS_RUNNING = true; + $("#container").setAttribute("sim_is_running",true); + self.sims.forEach(function(sim){ sim.save(); // save for later resetting }); - publish("sim/next"); + //publish("sim/next"); + }); subscribe("sim/reset", function(){ + Simulations.IS_RUNNING = false; + $("#container").removeAttribute("sim_is_running"); + self.sims.forEach(function(sim){ sim.reload(); // reload the network pre-sim }); + }); subscribe("sim/next", function(){ self.sims.forEach(function(sim){ @@ -134,14 +148,10 @@ function Sim(config){ // Connections self.networkConfig.connections.forEach(function(c){ var from = self.peeps[c[0]], - to = self.peeps[c[1]]; - self.addConnection(from, to, false); + to = self.peeps[c[1]], + uncuttable = c[2]||false + self.addConnection(from, to, uncuttable); }); - if(self.options.startUncuttable){ - self.connections.forEach(function(c){ - c.uncuttable = true; - }); - } // Contagion self.contagion = self.networkConfig.contagion; @@ -343,16 +353,22 @@ function Sim(config){ // SIMULATION RUNNING // //////////////////////// + self.STEP = 0; + self.save = function(){ + self.STEP = 0; self.networkConfig = self.getCurrentNetwork(); }; self.reload = function(){ + self.STEP = 0; self.init(); }; self.nextStep = function(){ + self.STEP++; + // "Infect" the peeps who need to get infected // TODO: Connection animation self.peeps.filter(function(peep){ @@ -413,7 +429,8 @@ function Sim(config){ self.connections.forEach(function(c){ var fromIndex = self.peeps.indexOf(c.from); var toIndex = self.peeps.indexOf(c.to); - savedNetwork.connections.push([fromIndex, toIndex]); + var uncuttable = c.uncuttable ? 1 : 0; + savedNetwork.connections.push([fromIndex, toIndex, uncuttable]); }); return savedNetwork; }; @@ -494,6 +511,13 @@ function Sim(config){ // INIT NOW // ////////////// + // Start Uncuttable? + if(self.options.startUncuttable){ + self.networkConfig.connections.forEach(function(c){ + c[2] = 1; + }); + } + self.init(); } diff --git a/slides/js/slideshow/Boxes.js b/slides/js/slideshow/Boxes.js index f4c5f6b..4c55d0b 100644 --- a/slides/js/slideshow/Boxes.js +++ b/slides/js/slideshow/Boxes.js @@ -95,9 +95,13 @@ function Boxes(){ return box.id==id; }); }; - self.showChildByID = function(id){ + self.showChildByID = function(id, withFade){ var toShow = self.getChildByID(id); - toShow.style.display = "block"; + if(!withFade){ + toShow.style.display = "block"; + }else{ + fadeIn(self.dom, toShow); + } }; self.hideChildByID = function(id){ var toHide = self.getChildByID(id); @@ -124,10 +128,11 @@ function SimButton(container, color){ self.container.classList.add("sim_button"); // RESET - var smallButton = document.createElement("div"); - smallButton.innerHTML = getWords("sim_reset"); - self.container.appendChild(smallButton); - smallButton.onclick = function(){ + var resetButton = document.createElement("div"); + resetButton.id = "reset_button"; + resetButton.innerHTML = getWords("sim_reset"); + self.container.appendChild(resetButton); + resetButton.onclick = function(){ if(Simulations.IS_RUNNING){ publish("sim/reset"); _updateButtonUI(); @@ -135,9 +140,10 @@ function SimButton(container, color){ }; // START / NEXT - var bigButton = document.createElement("div"); - self.container.appendChild(bigButton); - bigButton.onclick = function(){ + var startButton = document.createElement("div"); + startButton.id = "start_button"; + self.container.appendChild(startButton); + startButton.onclick = function(){ if(!Simulations.IS_RUNNING){ publish("sim/start"); _updateButtonUI(); @@ -149,9 +155,11 @@ function SimButton(container, color){ // Update button UI var _updateButtonUI = function(){ if(!Simulations.IS_RUNNING){ - bigButton.innerHTML = getWords("sim_start"); + startButton.innerHTML = getWords("sim_start"); + self.container.removeAttribute("active"); }else{ - bigButton.innerHTML = getWords("sim_next"); + startButton.innerHTML = getWords("sim_next"); + self.container.setAttribute("active",true); } }; _updateButtonUI(); diff --git a/slides/js/slideshow/Slideshow.js b/slides/js/slideshow/Slideshow.js index 7db27a2..6e9a30c 100644 --- a/slides/js/slideshow/Slideshow.js +++ b/slides/js/slideshow/Slideshow.js @@ -37,6 +37,7 @@ function Slideshow(){ if(slide.clear && !isFirstSlide){ _delayNewSlide = 700; self.scratch.scratchOut(); // Scratch out + $("#container").removeAttribute("sim_is_running"); // remove that UI } _setTimeout(function(){