diff --git a/css/index.css b/css/index.css index 95f5f73..c8ff4cb 100644 --- a/css/index.css +++ b/css/index.css @@ -273,9 +273,9 @@ words, bonus, glossary{ } /* TO SEE LAYOUT */ -/*.box, #simulations{ +.box, #simulations{ border: 1px solid #eee; -}*/ +} /* A NICE CIRCLE */ /* Thanks to: https://skeate.github.io/2015/07/13/Wrapping-Text-to-Fit-Shaped-Containers-with-CSS.html */ diff --git a/index.html b/index.html index 1f66268..7866b15 100644 --- a/index.html +++ b/index.html @@ -184,64 +184,120 @@ let's play! → -Let's draw a network! -Each connection represents a friendship between two people: + Let's draw a network! + Each connection represents a friendship between two people: -draw to connect + draw to connect -scratch to   disconnect + scratch to   disconnect -feel free to play around! when you're done, -let's continue → + + feel free to keep playing around, and draw whatever friendship network you want! + when you're done, + let's continue → + -blah blah blah blah -blah blah blah blah -blah blah blah blah - -blah blah blah blah -blah blah blah blah -thresholds NOT COUNTING THEMSELVES + + But people don't just have social connections to make pretty pictures. + People look at their social connections, to understand their social world. + In this example, people look to their peers to + find out what % of their friends (not counting selves) are, + say, binge-drinkers. (img) + - -# of drinker friends / # of total friends + + + Draw/erase connections, and see what happens! → - -% of friends are drinkers - - -(black line shows the 50% "majority" mark) + + + top-left: + # of drinker friends / # of total friends      +
+ top-right: + % of drinker friends → +
+ black line: + the 50% "majority" threshold      +
(they'll glow if past threshold)     
+ -and next... + cool, got it -blah blah drinking -blah blah next + + However, networks can fool people. + Just like how you see the earth as flat because you're on it, + people get wrong ideas about society because they're in it. + +

+ + (BONUS BOX: OTHER CONNECTIONS) + +

+ + For example, a 1991 study(*) showed that + “virtually all [college] students reported that their friends drank more than they did.” + But that seems impossible! + How can that be? + Well, you're about to invent the answer yourself, by drawing a network. + It's time to... + + FOOL EVERYONE → +
-blah blah puzzle + + PUZZLE TIME! +
+ Fool everyone into thinking + the majority of their friends are binge-drinkers (img) + (even though binge-drinkers are outnumbered 2-to-1) +
-HOW MANY PEEPS FOOLED: + FOOLED: + + + out of 9 people -blah blah puzzle -a winrar is you + Congrats! You manipulated a group of students into believing + in the prevalance of an incredibly unhealthy social norm! Good going! + ...uh. thanks? -blah blah post-puzzle -simple contagion... + + What you just created is called The Majority Illusion(*), + which also explains why people think their political views are consensus, + or why extremism seems more common than it actually is. + Madness. + +

+ + But ideas/behaviors aren't just passively observed, they actively spread. + So now, let's look at something network scientists call... + + “Simple Contagion!” → + + ← bonus challenge: make everyone think + less than half of their friends are binge-drinkers + +
+ + 🙌 yay you did it 🙌 @@ -333,19 +389,19 @@ Select a tool...
-Draw Connections +Draw Network -Add Peep +Add Person Add "Infected" -Move Peep +Move Person -Delete Peep +Delete Person CLEAR IT ALL @@ -355,13 +411,13 @@ Delete Peep (...or, use keyboard shortcuts!) -[1]: Add Peep +[1]: Add Person
-[2]: Add "Infected" Peep +[2]: Add "Infected" Person
-[Space]: Move Peep +[Space]: Move Person
-[Backspace]: Delete Peep +[Backspace]: Delete Person
diff --git a/js/chapters/1_Networks.js b/js/chapters/1_Networks.js index 0b9e7b5..d3ebfda 100644 --- a/js/chapters/1_Networks.js +++ b/js/chapters/1_Networks.js @@ -22,8 +22,8 @@ SLIDES.push( fullscreen: true, network: { "contagion":0, - "peeps":[[44,184,0],[155,215,0],[237,105,0],[309,213,0],[646,211,0],[328,305,0],[629,308,0],[417,111,0],[539,375,0],[216,299,0],[107,311,0],[-61,220,0],[87,452,0],[733,147,0],[760,293,0],[753,448,0],[744,46,0],[134,33,0],[929,181,0],[848,111,0],[1013,330,0],[880,269,0],[538,128,0],[208,391,0],[853,356,0]], - "connections":[[5,6]] + "peeps":[[44,184,0],[155,215,0],[237,105,0],[309,213,0],[646,211,0],[328,305,0],[629,308,0],[417,111,0],[538,362,0],[216,299,0],[94,314,0],[-61,220,0],[68,455,0],[733,147,0],[760,293,0],[776,437,0],[759,48,0],[134,33,0],[929,181,0],[848,111,0],[1013,330,0],[880,269,0],[538,128,0],[189,388,0],[853,356,0]], + "connections":[[5,6,0]] } }, @@ -55,7 +55,7 @@ SLIDES.push( { type:"box", id:"end_words", - text:"_1_tutorial_end", x:230, y:425, w:500, h:70, align:"center", + text:"_1_tutorial_end", x:230, y:400, w:500, h:70, align:"center", hidden:true } @@ -110,23 +110,38 @@ SLIDES.push( { type:"box", id:"_1_threshold", - text:"_1_threshold", x:80, y:25, w:300 + text:"_1_threshold", x:60, y:25, w:400 + }, + { + type:"box", + id:"_1_threshold_instruction", + text:"_1_threshold_instruction", x:110, y:260, w:300, + align:"center" + }, + { + type:"box", + id:"_1_threshold_explanation", + text:"_1_threshold_explanation", x:105, y:340, w:400, + align:"right", + color:"#bbb", + fontSize:"0.75em", + lineHeight:"1.2em" }, { type:"box", id:"_1_threshold_end", - text:"_1_threshold_end", x:80, y:400, w:300 + text:"_1_threshold_end", x:60, y:430, w:400 }, // SIMULATION: THRESHOLD { type:"sim", - x:400, y:70, + x:420, y:70, fullscreen: true, network: { "contagion":0.5, - "peeps":[[95,65,0],[417,380,1],[52,340,0],[399,92,1]], - "connections":[[2,3],[3,1]], + "peeps":[[141,99,0],[444,373,1],[442,103,1],[144,371,0]], + "connections":[[2,1,0],[3,2,0]] }, options:{ infectedFrame: 2, @@ -141,13 +156,15 @@ SLIDES.push( { remove:[ { type:"box", id:"_1_threshold" }, + { type:"box", id:"_1_threshold_instruction" }, + { type:"box", id:"_1_threshold_explanation" }, { type:"box", id:"_1_threshold_end" } ], add:[ { type:"box", id:"_1_pre_puzzle", - text:"_1_pre_puzzle", x:80, y:25, w:325, h:540 + text:"_1_pre_puzzle", x:60, y:0, w:400 } ] }, @@ -165,7 +182,7 @@ SLIDES.push( { id:"puzzle", type:"sim", - x:480-250, y:25, + x:410, y:25, fullscreen: true, network: { "contagion":0.5, @@ -179,31 +196,80 @@ SLIDES.push( }, // Done? Let's go... (hidden at first...) + { + type:"box", + id:"_1_puzzle", + text:"_1_puzzle", x:60, y:10, w:300 + }, + { + type:"box", + id:"_1_puzzle_metric", + text:"_1_puzzle_metric", x:60, y:220, w:300 + }, { type:"box", id:"_1_puzzle_end", - text:"_1_puzzle_end", x:680, y:430, w:300, align:"center", + text:"_1_puzzle_end", x:60, y:220, w:300, hidden:true } ], + onstart:function(slideshow, state){ + + // Modify puzzle metric box + var metric = slideshow.boxes.getChildByID("_1_puzzle_metric"); + metric.innerHTML = ""; + + var COLOR = "hsl(50, 100%, 50%)"; + + // label + var label = document.createElement("div"); + metric.appendChild(label); + label.style.color = COLOR; + + // bar + var bar_container = document.createElement("div"); + metric.appendChild(bar_container); + bar_container.style.border = "2px solid "+COLOR; + bar_container.style.width = "100%"; + bar_container.style.height = "1em"; + bar_container.style.position = "relative"; + var bar = document.createElement("div"); + bar_container.appendChild(bar); + bar.style.background = COLOR; + bar.style.height = "100%"; + bar.style.position = "absolute"; + + // Save this cool DOM into state + state.metric_label = label; + state.metric_bar = bar; + + }, + onupdate:function(slideshow, state){ + // How many peeps? + var sim = slideshow.simulations.sims[0]; + var peepCount = 0; + sim.peeps.forEach(function(peep){ + if(peep.isPastThreshold) peepCount++; + }); + + // Modify metric box! + var label = getWords("_1_puzzle_metric") + " " + peepCount + " " + getWords("_1_puzzle_metric_2"); + state.metric_label.innerHTML = label; + state.metric_bar.style.width = Math.round((peepCount/9)*100)+"%"; + // Win only if EVERYONE hits threshold if(!state.won){ - - var sim = slideshow.simulations.sims[0]; - var peepCount = 0; - sim.peeps.forEach(function(peep){ - if(peep.isPastThreshold) peepCount++; - }); if(peepCount==9){ + var boxes = slideshow.boxes; state.won = true; - slideshow.boxes.showChildByID("_1_puzzle_end"); + boxes.hideChildByID("_1_puzzle_metric"); + boxes.showChildByID("_1_puzzle_end"); sim.win(); } - } } @@ -213,20 +279,50 @@ SLIDES.push( // post-puzzle ramble, introduce simple contagion { remove:[ + { type:"box", id:"_1_puzzle" }, + { type:"box", id:"_1_puzzle_metric" }, { type:"box", id:"_1_puzzle_end" } ], move:[ // shift sim to side - {type:"sim", id:"puzzle", x:0} + {type:"sim", id:"puzzle", x:20} ], add:[ // new text { type:"box", id:"_1_post_puzzle", - text:"_1_post_puzzle", x:600, y:0, w:300 + text:"_1_post_puzzle", x:560, y:0, w:400 + }, + { + type:"box", + id:"_1_post_puzzle_bonus", + text:"_1_post_puzzle_bonus", x:170, y:1000 // offscreen! + }, + ], + + onupdate:function(slideshow, state){ + + // How many peeps passed? + var sim = slideshow.simulations.sims[0]; + var peepCount = 0; + sim.peeps.forEach(function(peep){ + if(peep.numFriends>0 && !peep.isPastThreshold) peepCount++; + }); + + // Win Bonus + if(!state.won){ + if(peepCount==9){ + var winbox = slideshow.boxes.getChildByID("_1_post_puzzle_bonus"); + if(winbox){ + winbox.style.top = "270px"; + state.won = true; + } + } } - ] + + } + } ); \ No newline at end of file diff --git a/js/lib/helpers.js b/js/lib/helpers.js index d22bc33..e34d18d 100644 --- a/js/lib/helpers.js +++ b/js/lib/helpers.js @@ -72,7 +72,7 @@ function fadeOut(container, dom){ } // Tween position -function tweenPosition(from, to){ +function tweenPosition(from, to, callback){ var x1 = from.x; var y1 = from.y; var x2 = to.x; @@ -95,8 +95,25 @@ function tweenPosition(from, to){ from.x = x1 + dx*easeInOutSine(t); from.y = y1 + dy*easeInOutSine(t); + // Callback + if(callback){ + callback(from); + } + }); } +/*function tweenBox(box, to){ + var from = { + x: parseInt(box.style.left), + y: parseInt(box.style.top) + }; + to.x = (to.x===undefined) ? from.x : to.x; + to.y = (to.y===undefined) ? from.y : to.y; + tweenPosition(from, to, function(position){ + box.style.left = position.x + "px"; + box.style.top = position.y + "px"; + }); +}*/ // From Robert Penner: http://robertpenner.com/scripts/easing_equations.txt function easeInOutSine(t) { return -1/2 * (Math.cos((Math.TAU/2)*t) - 1); diff --git a/js/main.js b/js/main.js index 0573dee..596e7f8 100644 --- a/js/main.js +++ b/js/main.js @@ -29,6 +29,6 @@ window.onload = function(){ window.requestAnimationFrame(update); // First slide! - slideshow.gotoChapter("Networks"); + slideshow.gotoChapter("Networks-Majority"); } \ No newline at end of file diff --git a/js/sim/Peep.js b/js/sim/Peep.js index 7f939b3..28134b6 100644 --- a/js/sim/Peep.js +++ b/js/sim/Peep.js @@ -152,7 +152,7 @@ function Peep(config){ // Draw var radius = 25; - var barWidth = radius*1.75; + var barWidth = radius*2; var barHeight = 10; var bodyRotation = Math.TAU*Math.random(); var PEEP_COLORS = [ @@ -214,17 +214,25 @@ function Peep(config){ // Say: Infected/Friends (% then n/n) ctx.translate(0,-43); - ctx.font = '10px FuturaHandwritten'; + ctx.font = '9px FuturaHandwritten'; ctx.fillStyle = uiColor; ctx.textBaseline = "middle"; ctx.fontWeight = "bold"; - ctx.textAlign = "center"; if(self.numFriends>0){ + + // # + ctx.textAlign = "left"; var labelNum = self.numInfectedFriends+"/"+self.numFriends; + ctx.fillText(labelNum, -barWidth/2, 0); + + // % + ctx.textAlign = "right"; var labelPercent = Math.round(100*(self.numInfectedFriends/self.numFriends)) + "%"; - var label = labelNum + "=" + labelPercent; - ctx.fillText(label, 0, 0); + ctx.fillText(labelPercent, barWidth/2, 0); + + }else{ + ctx.textAlign = "center"; ctx.fillText("∅", 0, -1); } diff --git a/js/sim/Simulations.js b/js/sim/Simulations.js index 8757af1..06ac02c 100644 --- a/js/sim/Simulations.js +++ b/js/sim/Simulations.js @@ -351,7 +351,7 @@ function Sim(config){ frame: frame, spinSpeed: spinSpeed, spin: Math.random()*Math.TAU, - g: 0.05+Math.random()*0.10 + g: 0.10+Math.random()*0.10 }; self.confetti.push(confetti); } diff --git a/js/slideshow/Boxes.js b/js/slideshow/Boxes.js index 53879af..f4a0d21 100644 --- a/js/slideshow/Boxes.js +++ b/js/slideshow/Boxes.js @@ -53,6 +53,8 @@ function Boxes(){ box.innerHTML = getWords(config.text); if(config.align) box.style.textAlign = config.align; if(config.color) box.style.color = config.color; + if(config.fontSize) box.style.fontSize = config.fontSize; + if(config.lineHeight) box.style.lineHeight = config.lineHeight; } // pics: diff --git a/js/slideshow/Slideshow.js b/js/slideshow/Slideshow.js index d6ab500..81f6347 100644 --- a/js/slideshow/Slideshow.js +++ b/js/slideshow/Slideshow.js @@ -72,7 +72,8 @@ function Slideshow(){ slide.move.forEach(function(childConfig){ switch(childConfig.type){ case "box": - //self.boxes.add(childConfig); + //var box = self.boxes.getChildByID(childConfig.id); + //tweenBox(box, childConfig); break; case "sim": var sim = self.simulations.getChildByID(childConfig.id);