From 4b456ac54cc553d56272fc6329876683c395884d Mon Sep 17 00:00:00 2001 From: Nicky Case Date: Fri, 6 Apr 2018 12:06:55 -0400 Subject: [PATCH] hecka cool sandbox --- index.css | 53 +++++++++- index.html | 49 +++++++++ js/chapters/2_Simple_Contagion.js | 4 +- js/chapters/3_Complex_Contagion.js | 6 +- js/chapters/5_Sandbox.js | 17 ++++ js/lib/helpers.js | 2 +- js/sim/Simulations.js | 30 ++++-- js/slideshow/Boxes.js | 58 ++--------- js/slideshow/SandboxUI.js | 157 ++++++++++++++++++++++++++++- js/slideshow/Scratch.js | 1 - js/slideshow/SimUI.js | 44 ++++++++ js/slideshow/Slideshow.js | 11 ++ 12 files changed, 359 insertions(+), 73 deletions(-) create mode 100644 js/slideshow/SimUI.js diff --git a/index.css b/index.css index 15ce521..bfdb8be 100644 --- a/index.css +++ b/index.css @@ -73,34 +73,77 @@ body{ background-size: 200% 2000%; background-position: 0% 0%; } -.sim_button{ + +/* Sim UI */ +.sim_ui{ position: absolute; width: 200px; height: 100px; border: none !important; } -.sim_button > div{ +.sim_ui > div{ position: absolute; background: #dd4040; color: #fff; text-align: center; border-radius: 10px; } -.sim_button > #reset_button{ +.sim_ui > #reset_button{ width: 150px; left:25px; top:0px; font-size: 0.8em; transition: top 0.3s ease-in-out; } -.sim_button > #start_button{ +.sim_ui > #start_button{ width: 200px; padding: 0.5em 0; } -.sim_button[active] > #reset_button{ +.sim_ui[active] > #reset_button{ top:60px; } +/* Sandbox UI */ +.sandbox_ui{ + width: 270px; +} +.sandbox_ui input[type="range"]{ + width: 100%; +} +.choose_one{ + overflow: hidden; +} +.choose_one > div{ + float: left; + margin: 3px; + opacity: 0.25; +} +.choose_one > div[selected]{ + opacity: 1; +} +.choose_color{ + width: 40px; + height: 40px; + background: url(sprites/peeps.png); + background-size: auto 100%; + transform: scale(1.2); +} +.choose_tool{ + font-size: 16px; + line-height: 16px; + border: 1px solid black; + padding: 3px; + border-radius: 5px; +} +#sandbox_shortcuts_label{ + font-size: 18px; +} +#sandbox_shortcuts{ + font-size: 14px; + line-height: 1.5em; + color: #999; +} + /* MODAL */ #modal{ display: none; diff --git a/index.html b/index.html index 489dffb..dec18b4 100644 --- a/index.html +++ b/index.html @@ -278,6 +278,53 @@ WIN ↺ reset + +Contagion: + + +simple + + +complex + + +The Contagion's Color: + + +Select a tool... + + + +Draw Connections + + +Add Peep + + +Add "Infected" Peep + + +Move Peep + + +Delete Peep + + +CLEAR IT ALL + + + +(...or, use keyboard shortcuts!) + + +[1]: Add Peep +
+[2]: Add Infected Peep +
+[Space]: Move Peep +
+[Backspace]: Delete Peep +
@@ -312,6 +359,8 @@ WIN + + diff --git a/js/chapters/2_Simple_Contagion.js b/js/chapters/2_Simple_Contagion.js index ed49acb..0fb352b 100644 --- a/js/chapters/2_Simple_Contagion.js +++ b/js/chapters/2_Simple_Contagion.js @@ -44,7 +44,7 @@ SLIDES.push( { type:"box", x:380, y:165, - sim_button:"red" + sim_ui:"red" }, // Outro text @@ -104,7 +104,7 @@ SLIDES.push( { type:"box", x:380, y:290, - sim_button:"red" + sim_ui:"red" }, // Intro text diff --git a/js/chapters/3_Complex_Contagion.js b/js/chapters/3_Complex_Contagion.js index bd5b521..0ca92df 100644 --- a/js/chapters/3_Complex_Contagion.js +++ b/js/chapters/3_Complex_Contagion.js @@ -35,7 +35,7 @@ SLIDES.push( { type:"box", x:440, y:225, - sim_button:"red" + sim_ui:"red" }, // End text @@ -96,7 +96,7 @@ SLIDES.push( { type:"box", x:380, y:290, - sim_button:"red" + sim_ui:"red" }, // Intro text @@ -172,7 +172,7 @@ SLIDES.push( { type:"box", x:380, y:140, - sim_button:"red" + sim_ui:"red" }, // Outro text diff --git a/js/chapters/5_Sandbox.js b/js/chapters/5_Sandbox.js index 291b210..01c0b34 100644 --- a/js/chapters/5_Sandbox.js +++ b/js/chapters/5_Sandbox.js @@ -5,6 +5,7 @@ SLIDES.push( clear:true, add:[ + // The fullscreen simulation { type:"sim", @@ -15,7 +16,23 @@ SLIDES.push( "peeps":[[443,213,1],[570,309,0],[686,194,0]], "connections":[[0,1,0],[1,2,0]] } + }, + + // The Sandbox UI + { + type:"box", + x:0, y:0, + sandbox:true + }, + + // Simulation UI + { + type:"box", + x:35, y:450, + sim_ui:"red" } + + ] } diff --git a/js/lib/helpers.js b/js/lib/helpers.js index a83e804..4ccad9e 100644 --- a/js/lib/helpers.js +++ b/js/lib/helpers.js @@ -44,7 +44,7 @@ function cloneObject(obj){ // Get words function getWords(wordsID){ - return $("words#"+wordsID).innerHTML; + return $("words#"+wordsID).innerHTML.trim(); } // Remove from array diff --git a/js/sim/Simulations.js b/js/sim/Simulations.js index 015afad..22a65fb 100644 --- a/js/sim/Simulations.js +++ b/js/sim/Simulations.js @@ -295,7 +295,14 @@ function Sim(config){ // Kill self.kill = function(){ + self.clear(); + + // key handlers, too + _keyHandlers.forEach(function(_handler){ + unsubscribe(_handler); + }); + }; /////////////////// @@ -361,8 +368,10 @@ function Sim(config){ }; self.reload = function(){ + var contagionLevel = self.contagion; // hack for sandbox: keep contagion the same self.STEP = 0; self.init(); + self.contagion = contagionLevel; }; self.nextStep = function(){ @@ -387,7 +396,8 @@ function Sim(config){ var _draggingPeep = null; var _draggingOffset = {x:0,y:0}; - subscribe("key/down/space",function(){ + var _keyHandlers = []; + _keyHandlers.push(subscribe("key/down/space",function(){ if(!_draggingPeep){ // prevent double-activation var hoveredPeep = self.getHoveredPeep(0); if(hoveredPeep){ @@ -396,26 +406,26 @@ function Sim(config){ _draggingOffset.y = _draggingPeep.y-self.mouse.y; } } - }); - subscribe("key/up/space",function(){ + })); + _keyHandlers.push(subscribe("key/up/space",function(){ _draggingPeep = null; - }); - subscribe("key/down/1",function(){ + })); + _keyHandlers.push(subscribe("key/down/1",function(){ _addPeepAtMouse(false); - }); - subscribe("key/down/2",function(){ + })); + _keyHandlers.push(subscribe("key/down/2",function(){ _addPeepAtMouse(true); - }); + })); var _addPeepAtMouse = function(infected){ var overlapPeep = self.getHoveredPeep(20); if(!overlapPeep){ self.addPeep(self.mouse.x, self.mouse.y, infected); } }; - subscribe("key/down/delete",function(){ + _keyHandlers.push(subscribe("key/down/delete",function(){ var toDeletePeep = self.getHoveredPeep(0); if(toDeletePeep) self.removePeep(toDeletePeep); - }); + })); self.getCurrentNetwork = function(){ var savedNetwork = { diff --git a/js/slideshow/Boxes.js b/js/slideshow/Boxes.js index 66a82a1..53879af 100644 --- a/js/slideshow/Boxes.js +++ b/js/slideshow/Boxes.js @@ -61,9 +61,14 @@ function Boxes(){ box.style.backgroundImage = "url("+config.img+")" } - // Sim Button - if(config.sim_button){ - var simButton = SimButton(box, config.sim_button); + // Sim UI + if(config.sim_ui){ + var simUI = new SimUI(box, config.sim_ui); + } + + // Sandbox UI + if(config.sandbox){ + var sandboxUI = new SandboxUI(box); } // Replace "next" buttons! @@ -128,49 +133,4 @@ function Boxes(){ }; -} - -function SimButton(container, color){ - - var self = this; - self.container = container; - self.container.classList.add("sim_button"); - - // RESET - 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(); - } - }; - - // START / NEXT - var startButton = document.createElement("div"); - startButton.id = "start_button"; - self.container.appendChild(startButton); - startButton.onclick = function(){ - if(!Simulations.IS_RUNNING){ - publish("sim/start"); - _updateButtonUI(); - }else{ - publish("sim/next"); - } - }; - - // Update button UI - var _updateButtonUI = function(){ - if(!Simulations.IS_RUNNING){ - startButton.innerHTML = getWords("sim_start"); - self.container.removeAttribute("active"); - }else{ - startButton.innerHTML = getWords("sim_next"); - self.container.setAttribute("active",true); - } - }; - _updateButtonUI(); - -} +} \ No newline at end of file diff --git a/js/slideshow/SandboxUI.js b/js/slideshow/SandboxUI.js index 846fd16..c4e23ec 100644 --- a/js/slideshow/SandboxUI.js +++ b/js/slideshow/SandboxUI.js @@ -1,2 +1,155 @@ -function SandboxUI(){ -} \ No newline at end of file +function SandboxUI(container){ + + var self = this; + self.container = container; + self.container.classList.add("sandbox_ui"); + + ////////////////////// + // Contagion Slider // + ////////////////////// + + var contagionLabel = document.createElement("div"); + var contagionInput = document.createElement("input"); + contagionInput.type = "range"; + contagionInput.min = 0; + contagionInput.max = 1; + contagionInput.step = 0.05; + contagionInput.value = 0.25; + contagionInput.oninput = function(){ + _updateContagion(); + }; + var _labelContagion0 = getWords("sandbox_contagion"); + var _labelContagion1 = getWords("sandbox_contagion_simple"); + var _labelContagion2 = getWords("sandbox_contagion_complex"); + var _updateContagion = function(){ + + // update sim + var contagion = contagionInput.value; + slideshow.simulations.sims[0].contagion = contagion; + + // update label + var label = _labelContagion0+" "; + label += Math.round(contagion*100)+"% "; + label += "("+((contagion==0) ? _labelContagion1 : _labelContagion2)+")"; + contagionLabel.innerHTML = label; + + }; + container.appendChild(contagionLabel); + container.appendChild(contagionInput); + setTimeout(function(){ + _updateContagion(); + },1); + + /////////////////////////// + // Choose Color of Peeps // + /////////////////////////// + + var colorChooserLabel = document.createElement("div"); + colorChooserLabel.innerHTML = getWords("sandbox_color_chooser"); + colorChooserLabel.style.marginTop = "1em"; + var colorChooser = new ChooseOne({ + options:[ + 1, // red + 2, // yellow + 3, // blue + 4, // green + 5, // pink + ], + makeButton:function(value){ + var button = document.createElement("div"); + button.className = "choose_color"; + button.style.backgroundPosition = (-40*value)+"px 0px"; + return button; + }, + oninput:function(value){ + // update sim + slideshow.simulations.sims[0].options.infectedFrame = value; + } + }); + container.appendChild(colorChooserLabel); + container.appendChild(colorChooser.dom); + + //////////////////////////// + // Choose Tool for Pencil // + //////////////////////////// + + var toolChooserLabel = document.createElement("div"); + toolChooserLabel.innerHTML = getWords("sandbox_tool_chooser"); + toolChooserLabel.style.marginTop = "1em"; + var toolChooser = new ChooseOne({ + options:[ + "pencil", + "add", + "add_infected", + "move", + "delete", + "clear" + ], + makeButton: function(value){ + var button = document.createElement("div"); + button.className = "choose_tool"; + button.innerHTML = getWords("sandbox_tool_"+value); + return button; + }, + oninput:function(value){ + } + }); + container.appendChild(toolChooserLabel); + container.appendChild(toolChooser.dom); + + //////////////////////// + // Keyboard Shortcuts // + //////////////////////// + + var shortcutsLabel = document.createElement("div"); + shortcutsLabel.innerHTML = getWords("sandbox_shortcuts_label"); + shortcutsLabel.id = "sandbox_shortcuts_label"; + shortcutsLabel.style.marginTop = "1em"; + var shortcuts = document.createElement("div"); + shortcuts.innerHTML = getWords("sandbox_shortcuts"); + shortcuts.id = "sandbox_shortcuts"; + container.appendChild(shortcutsLabel); + container.appendChild(shortcuts); + + +} + +function ChooseOne(config){ + + var self = this; + + // Container + self.dom = document.createElement("div"); + self.dom.className = "choose_one"; + + // Make Buttons + var buttons = []; + config.options.forEach(function(option){ + + var buttonConfig = option;//.button; + var value = option;//.value; + + // New Button + var buttonDOM = config.makeButton(buttonConfig); + self.dom.appendChild(buttonDOM); + buttons.push(buttonDOM); + + // On Input + buttonDOM.onclick = function(){ + self.highlight(buttonDOM); // highlight + config.oninput(value); // input + }; + + }); + + // Highlight + self.highlight = function(toHighlight){ + buttons.forEach(function(button){ + button.removeAttribute("selected"); + }); + toHighlight.setAttribute("selected",true); + }; + self.highlight(buttons[0]); // highlight 1st one always, whatever + +} + diff --git a/js/slideshow/Scratch.js b/js/slideshow/Scratch.js index 555d91d..e7b7ae3 100644 --- a/js/slideshow/Scratch.js +++ b/js/slideshow/Scratch.js @@ -20,7 +20,6 @@ function Scratch(){ var handle = subscribe("update", function(){ var yOffset = Math.floor(frame)*(-100); self.dom.style.backgroundPosition = xOffset+"% "+yOffset+"%"; - console.log(xOffset, yOffset); if(frame>19){ unsubscribe(handle); if(callback) callback(); diff --git a/js/slideshow/SimUI.js b/js/slideshow/SimUI.js new file mode 100644 index 0000000..1d4f92c --- /dev/null +++ b/js/slideshow/SimUI.js @@ -0,0 +1,44 @@ +function SimUI(container, color){ + + var self = this; + self.container = container; + self.container.classList.add("sim_ui"); + + // RESET + 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(); + } + }; + + // START / NEXT + var startButton = document.createElement("div"); + startButton.id = "start_button"; + self.container.appendChild(startButton); + startButton.onclick = function(){ + if(!Simulations.IS_RUNNING){ + publish("sim/start"); + _updateButtonUI(); + }else{ + publish("sim/next"); + } + }; + + // Update button UI + var _updateButtonUI = function(){ + if(!Simulations.IS_RUNNING){ + startButton.innerHTML = getWords("sim_start"); + self.container.removeAttribute("active"); + }else{ + startButton.innerHTML = getWords("sim_next"); + self.container.setAttribute("active",true); + } + }; + _updateButtonUI(); + +} diff --git a/js/slideshow/Slideshow.js b/js/slideshow/Slideshow.js index b2edc01..d6ab500 100644 --- a/js/slideshow/Slideshow.js +++ b/js/slideshow/Slideshow.js @@ -25,8 +25,14 @@ function Slideshow(){ // GOTO and NEXT var _delay = 300; + self.IS_TRANSITIONING = false; self.goto = function(index){ + + // Wait for transition to finish! + if(self.IS_TRANSITIONING) return; + self.IS_TRANSITIONING = true; + // Which slide? self.slideIndex = index; var isFirstSlide = (self.currentSlide==null); var slide = SLIDES[self.slideIndex]; @@ -105,6 +111,11 @@ function Slideshow(){ self.currentState = {}; if(slide.onstart) slide.onstart(self, self.currentState); + // Transition done... sorta! + _setTimeout(function(){ + self.IS_TRANSITIONING = false; + },800); + }, _delayNewSlide); // Tell everyone it's a new chapter