sadasdaswre
This commit is contained in:
parent
5975459f2c
commit
ed9c3ff488
|
@ -3,25 +3,33 @@ body{
|
|||
|
||||
font-family: "FuturaHandwritten";
|
||||
font-size: 20px;
|
||||
cursor: none !important;
|
||||
}
|
||||
|
||||
#slideshow_container{
|
||||
/* SIMULATION and SLIDESHOW */
|
||||
#simulations_container, #slideshow_container{
|
||||
position: absolute;
|
||||
top:0; left:0;
|
||||
width: 100%;
|
||||
height: calc(100% - 60px);
|
||||
}
|
||||
#slideshow{
|
||||
#simulations, #slideshow{
|
||||
position: absolute;
|
||||
width: 960px;
|
||||
height: 540px;
|
||||
margin: auto;
|
||||
top:0; left:0; right:0; bottom:0;
|
||||
background: #eee;
|
||||
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
#slideshow div{
|
||||
#simulations canvas, #slideshow div{
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
/* NAVIGATION */
|
||||
#navigation{
|
||||
position: absolute;
|
||||
bottom:0;
|
||||
|
@ -30,6 +38,15 @@ body{
|
|||
height:60px;
|
||||
}
|
||||
|
||||
/* PENCIL */
|
||||
#pencil{
|
||||
position: absolute;
|
||||
width:100px;
|
||||
height:100px;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* THIS THING'S WORDS */
|
||||
words, bonus, glossary{
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,13 @@
|
|||
<!--
|
||||
|
||||
THE WISDOM AND/OR MADNESS OF CROWDS
|
||||
by Nicky Case | apr 2018
|
||||
|
||||
MY "WHY" FOR MAKING THIS:
|
||||
+ to build a foundation for further curiosity about networks, group dynamics
|
||||
+ to practice teaching with problem-solving, a pre-req for skills
|
||||
+ to instill transcendent sense of "fundamentally people", of Humanity's Brain <3
|
||||
|
||||
SLIDES:
|
||||
Keep all words on index.html. This allows people to translate it to SAME repo!
|
||||
/de.html, etc etc
|
||||
|
@ -15,19 +23,47 @@ Cursor is allowed to flow EVERYWHERE though...
|
|||
<link rel="stylesheet" type="text/css" href="index.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="slideshow_container">
|
||||
<div id="slideshow">
|
||||
</div>
|
||||
|
||||
<!-- Simulation(s) in background -->
|
||||
<div id="simulations_container">
|
||||
<div id="simulations"></div>
|
||||
</div>
|
||||
|
||||
<!-- Slideshow: words & buttons -->
|
||||
<div id="slideshow_container">
|
||||
<div id="slideshow"></div>
|
||||
</div>
|
||||
|
||||
<!-- Navigation: Audio, Contents, Share, Translations -->
|
||||
<div id="navigation">
|
||||
</div>
|
||||
|
||||
<canvas id="pencil"></canvas>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
<script src="js/helpers.js"></script>
|
||||
<script src="js/Slideshow.js"></script>
|
||||
<script src="chapters/0_Introduction.js"></script>
|
||||
|
||||
<!-- THE MAIN EXPLORABLE EXPLANATION -->
|
||||
<script src="js/lib/helpers.js"></script>
|
||||
<script src="js/lib/minpubsub.src.js"></script>
|
||||
<script src="js/lib/Mouse.js"></script>
|
||||
<script src="js/lib/Sprite.js"></script>
|
||||
|
||||
<script src="js/slideshow/Slideshow.js"></script>
|
||||
<script src="js/slideshow/Pencil.js"></script>
|
||||
|
||||
<script src="js/sim/Peep.js"></script>
|
||||
<script src="js/sim/Connection.js"></script>
|
||||
<!--script src="js/sim/Drawing.js"></script>
|
||||
<script src="js/sim/Game.js"></script-->
|
||||
<script src="js/sim/Simulations.js"></script>
|
||||
|
||||
<script src="js/main.js"></script>
|
||||
|
||||
<script src="js/chapters/0_Introduction.js"></script>
|
||||
|
||||
<!-- - - - - - - - - - - - -->
|
||||
<!-- THE SLIDESHOW'S WORDS -->
|
||||
<!-- - - - - - - - - - - - -->
|
||||
|
||||
<!-- 0. Introduction -->
|
||||
<words id="_0a">
|
||||
|
@ -36,6 +72,7 @@ in <i>different</i> groups, can be kind, cruel, smart, stupid?
|
|||
In this explorable explanation,
|
||||
I'll show how the <i>network</i> of a group itself
|
||||
can shape the people caught in its web.
|
||||
<button onclick="slideshow.next()">NEXT</button>
|
||||
</words>
|
||||
<words id="_0b">
|
||||
herp derp herp derp
|
||||
|
@ -57,11 +94,17 @@ herp derp herp derp herp derp
|
|||
|
||||
<!-- 7. Credits -->
|
||||
|
||||
<!-- - - - - - - - - - - - - -->
|
||||
<!-- BONUS BOXES (footnotes) -->
|
||||
<!-- - - - - - - - - - - - - -->
|
||||
|
||||
<bonus>
|
||||
</bonus>
|
||||
|
||||
<!-- GLOSSARY -->
|
||||
<!-- - - - - - -->
|
||||
<!-- GLOSSARY -->
|
||||
<!-- - - - - - -->
|
||||
|
||||
<glossary>
|
||||
</glossary>
|
||||
|
||||
|
|
|
@ -2,8 +2,17 @@
|
|||
SLIDES.push(
|
||||
{
|
||||
chapter: "1",
|
||||
boxes: [
|
||||
boxes:[
|
||||
{words:"_0a", x:20, y:70, w:300, h:200}
|
||||
],
|
||||
sims:[
|
||||
{
|
||||
network: {
|
||||
contagion: 0.25,
|
||||
peeps: [ [100,100],[200,200] ],
|
||||
connections: [ [0,1] ]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
|
@ -1,7 +0,0 @@
|
|||
//////////////////
|
||||
// HELPERS ///////
|
||||
//////////////////
|
||||
|
||||
function $(query){
|
||||
return document.querySelector(query);
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
/////////////////////////////
|
||||
// MOUSE ////////////////////
|
||||
/////////////////////////////
|
||||
|
||||
var Mouse = {
|
||||
x:0, y:0,
|
||||
pressed:false
|
||||
};
|
||||
Mouse.ondown = function(){}; // add your own callback
|
||||
Mouse.onmove = function(){}; // add your own callback
|
||||
Mouse.onup = function(){}; // add your own callback
|
||||
Mouse._ondown = function(event){
|
||||
Mouse.pressed = true;
|
||||
Mouse._onmove(event);
|
||||
Mouse.ondown();
|
||||
};
|
||||
Mouse._onmove = function(event){
|
||||
Mouse.x = event.clientX;
|
||||
Mouse.y = event.clientY;
|
||||
Mouse.onmove();
|
||||
};
|
||||
Mouse._onup = function(event){
|
||||
Mouse.pressed = false;
|
||||
Mouse.onup();
|
||||
};
|
||||
Mouse.update = function(){
|
||||
|
||||
// Just pressed, or just released (one frame ago)
|
||||
Mouse.justPressed = (!Mouse.lastPressed && Mouse.pressed);
|
||||
Mouse.justReleased = (Mouse.lastPressed && !Mouse.pressed);
|
||||
|
||||
// The last frame's stuff
|
||||
Mouse.lastX = Mouse.x;
|
||||
Mouse.lastY = Mouse.y;
|
||||
Mouse.lastPressed = Mouse.pressed;
|
||||
|
||||
};
|
||||
// TOUCH.
|
||||
function _touchWrapper(callback){
|
||||
return function(event){
|
||||
var _event = {};
|
||||
_event.clientX = event.changedTouches[0].clientX;
|
||||
_event.clientY = event.changedTouches[0].clientY;
|
||||
event.preventDefault();
|
||||
callback(_event);
|
||||
};
|
||||
}
|
||||
|
||||
// INIT
|
||||
Mouse.init = function(target){
|
||||
|
||||
// Regular mouse
|
||||
target.addEventListener("mousedown", Mouse._ondown);
|
||||
target.addEventListener("mousemove", Mouse._onmove);
|
||||
window.addEventListener("mouseup", Mouse._onup);
|
||||
|
||||
// Touch events
|
||||
target.addEventListener("touchstart", _touchWrapper(Mouse._ondown), false);
|
||||
target.addEventListener("touchmove", _touchWrapper(Mouse._onmove), false);
|
||||
document.body.addEventListener("touchend", function(){
|
||||
Mouse._onup();
|
||||
}, false);
|
||||
|
||||
};
|
|
@ -0,0 +1,46 @@
|
|||
function Sprite(config){
|
||||
|
||||
var self = this;
|
||||
self.config = config;
|
||||
|
||||
// Properties...
|
||||
self.x = 0;
|
||||
self.y = 0;
|
||||
self.pivotX = 0;
|
||||
self.pivotY = 0;
|
||||
self.scale = 1;
|
||||
self.rotation = 0; // radians
|
||||
|
||||
// The image!
|
||||
self.image = new Image();
|
||||
self.image.src = config.src;
|
||||
|
||||
// Frames
|
||||
self.currentFrame = 0;
|
||||
self.totalFrames = config.frames;
|
||||
self.nextFrame = function(){
|
||||
self.currentFrame = (self.currentFrame+1)%self.totalFrames;
|
||||
};
|
||||
self.gotoFrame = function(frame){
|
||||
self.currentFrame = frame;
|
||||
};
|
||||
|
||||
// Draw
|
||||
self.draw = function(ctx){
|
||||
|
||||
var sw = config.sw;
|
||||
var sh = config.sh;
|
||||
var sx = self.currentFrame*sw;
|
||||
var sy = 0;
|
||||
|
||||
ctx.save();
|
||||
ctx.translate(self.x, self.y);
|
||||
ctx.scale(self.scale, self.scale);
|
||||
ctx.rotate(self.rotation);
|
||||
ctx.translate(-self.pivotX, -self.pivotY);
|
||||
ctx.drawImage(self.image, sx, sy, sw, sh, 0, 0, sw, sh);
|
||||
ctx.restore();
|
||||
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
//////////////////
|
||||
// HELPERS ///////
|
||||
//////////////////
|
||||
|
||||
Math.TAU = 6.2831853072;
|
||||
|
||||
// The poor man's jQuery
|
||||
function $(query){
|
||||
return document.querySelector(query);
|
||||
}
|
||||
function $all(query){
|
||||
return document.querySelectorAll(query);
|
||||
}
|
||||
|
||||
// Wide Sigmoid
|
||||
function sigmoid(x){
|
||||
return x / (1 + Math.abs(x));
|
||||
}
|
||||
|
||||
// Create retina canvas
|
||||
function createCanvas(canvas, width, height){
|
||||
|
||||
// The "canvas" arg not provided? make a new one!
|
||||
if(arguments.length==2){
|
||||
width = arguments[0];
|
||||
height = arguments[1];
|
||||
canvas = document.createElement("canvas");
|
||||
}
|
||||
|
||||
// Set difference in width & height
|
||||
canvas.width = width*2;
|
||||
canvas.height = height*2;
|
||||
canvas.style.width = width;
|
||||
canvas.style.height = height;
|
||||
|
||||
return canvas;
|
||||
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
/*!
|
||||
* MinPubSub
|
||||
* Copyright(c) 2011 Daniel Lamb <daniellmb.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
(function (context) {
|
||||
var MinPubSub = {};
|
||||
|
||||
// the topic/subscription hash
|
||||
var cache = context.c_ || {}; //check for 'c_' cache for unit testing
|
||||
|
||||
MinPubSub.publish = function ( /* String */ topic, /* Array? */ args) {
|
||||
// summary:
|
||||
// Publish some data on a named topic.
|
||||
// topic: String
|
||||
// The channel to publish on
|
||||
// args: Array?
|
||||
// The data to publish. Each array item is converted into an ordered
|
||||
// arguments on the subscribed functions.
|
||||
//
|
||||
// example:
|
||||
// Publish stuff on '/some/topic'. Anything subscribed will be called
|
||||
// with a function signature like: function(a,b,c){ ... }
|
||||
//
|
||||
// publish('/some/topic', ['a','b','c']);
|
||||
|
||||
var subs = cache[topic],
|
||||
len = subs ? subs.length : 0;
|
||||
|
||||
//can change loop or reverse array if the order matters
|
||||
while (len--) {
|
||||
subs[len].apply(context, args || []);
|
||||
}
|
||||
};
|
||||
|
||||
MinPubSub.subscribe = function ( /* String */ topic, /* Function */ callback) {
|
||||
// summary:
|
||||
// Register a callback on a named topic.
|
||||
// topic: String
|
||||
// The channel to subscribe to
|
||||
// callback: Function
|
||||
// The handler event. Anytime something is publish'ed on a
|
||||
// subscribed channel, the callback will be called with the
|
||||
// published array as ordered arguments.
|
||||
//
|
||||
// returns: Array
|
||||
// A handle which can be used to unsubscribe this particular subscription.
|
||||
//
|
||||
// example:
|
||||
// subscribe('/some/topic', function(a, b, c){ /* handle data */ });
|
||||
|
||||
if (!cache[topic]) {
|
||||
cache[topic] = [];
|
||||
}
|
||||
cache[topic].push(callback);
|
||||
return [topic, callback]; // Array
|
||||
};
|
||||
|
||||
MinPubSub.unsubscribe = function ( /* Array */ handle, /* Function? */ callback) {
|
||||
// summary:
|
||||
// Disconnect a subscribed function for a topic.
|
||||
// handle: Array
|
||||
// The return value from a subscribe call.
|
||||
// example:
|
||||
// var handle = subscribe('/some/topic', function(){});
|
||||
// unsubscribe(handle);
|
||||
|
||||
var subs = cache[callback ? handle : handle[0]],
|
||||
callback = callback || handle[1],
|
||||
len = subs ? subs.length : 0;
|
||||
|
||||
while (len--) {
|
||||
if (subs[len] === callback) {
|
||||
subs.splice(len, 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// UMD definition to allow for CommonJS, AMD and legacy window
|
||||
if (typeof module === 'object' && module.exports) {
|
||||
// CommonJS, just export
|
||||
module.exports = exports = MinPubSub;
|
||||
} else if (typeof define === 'function' && define.amd) {
|
||||
// AMD support
|
||||
define(function () {
|
||||
return MinPubSub;
|
||||
});
|
||||
} else if (typeof context === 'object') {
|
||||
// If no AMD and we are in the browser, attach to window
|
||||
context.publish = MinPubSub.publish;
|
||||
context.subscribe = MinPubSub.subscribe;
|
||||
context.unsubscribe = MinPubSub.unsubscribe;
|
||||
}
|
||||
|
||||
})(this.window);
|
|
@ -0,0 +1,23 @@
|
|||
window.onload = function(){
|
||||
|
||||
// Setting up the main stuff
|
||||
window.simulations = new Simulations();
|
||||
window.slideshow = new Slideshow();
|
||||
window.pencil = new Pencil();
|
||||
|
||||
// Initializing the Mouse
|
||||
Mouse.init(document.body);
|
||||
|
||||
// Animation loop IS update loop, whatever
|
||||
function update(){
|
||||
simulations.update();
|
||||
slideshow.update();
|
||||
pencil.update();
|
||||
window.requestAnimationFrame(update);
|
||||
}
|
||||
window.requestAnimationFrame(update);
|
||||
|
||||
// First slide!
|
||||
slideshow.goto(0);
|
||||
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
function Connection(config){
|
||||
|
||||
var self = this;
|
||||
|
||||
// Properties
|
||||
self.from = config.from;
|
||||
self.to = config.to;
|
||||
self.uncuttable = config.uncuttable || false;
|
||||
self.sim = config.sim;
|
||||
|
||||
// Update
|
||||
self.update = function(){};
|
||||
|
||||
// Draw
|
||||
self.draw = function(ctx){
|
||||
ctx.strokeStyle = "#444";
|
||||
ctx.lineWidth = self.uncuttable ? 6 : 2; // thick=uncuttable
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(self.from.x, self.from.y);
|
||||
ctx.lineTo(self.to.x, self.to.y);
|
||||
ctx.stroke();
|
||||
};
|
||||
|
||||
// Hit Test with a LINE SEGMENT
|
||||
// code adapted from https://gist.github.com/Joncom/e8e8d18ebe7fe55c3894
|
||||
self.hitTest = function(line){
|
||||
|
||||
var p0_x, p0_y, p1_x, p1_y, p2_x, p2_y, p3_x, p3_y;
|
||||
p0_x = line[0];
|
||||
p0_y = line[1];
|
||||
p1_x = line[2];
|
||||
p1_y = line[3];
|
||||
p2_x = self.from.x;
|
||||
p2_y = self.from.y;
|
||||
p3_x = self.to.x;
|
||||
p3_y = self.to.y;
|
||||
|
||||
var s1_x, s1_y, s2_x, s2_y;
|
||||
s1_x = p1_x - p0_x;
|
||||
s1_y = p1_y - p0_y;
|
||||
s2_x = p3_x - p2_x;
|
||||
s2_y = p3_y - p2_y;
|
||||
var s, t;
|
||||
s = (-s1_y * (p0_x - p2_x) + s1_x * (p0_y - p2_y)) / (-s2_x * s1_y + s1_x * s2_y);
|
||||
t = ( s2_x * (p0_y - p2_y) - s2_y * (p0_x - p2_x)) / (-s2_x * s1_y + s1_x * s2_y);
|
||||
|
||||
return (s >= 0 && s <= 1 && t >= 0 && t <= 1);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
/*
|
||||
Connection.getConnected = function(peep){
|
||||
var results = [];
|
||||
for(var i=0; i<connections.length; i++){ // in either direction
|
||||
var c = connections[i];
|
||||
if(c.from==peep) results.push(c.to);
|
||||
if(c.to==peep) results.push(c.from);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
function removeAllConnectedTo(peep){
|
||||
for(var i=connections.length-1; i>=0; i--){ // backwards index coz we're deleting
|
||||
var c = connections[i];
|
||||
if(c.from==peep || c.to==peep){ // in either direction
|
||||
connections.splice(i,1); // remove!
|
||||
}
|
||||
}
|
||||
}
|
||||
function _makeUncuttable(arrayOfConnections){
|
||||
for(var i=0; i<arrayOfConnections.length; i++){
|
||||
arrayOfConnections[i].push(true);
|
||||
}
|
||||
}
|
||||
*/
|
|
@ -0,0 +1,75 @@
|
|||
function Drawing(){
|
||||
|
||||
var self = this;
|
||||
|
||||
// Update!
|
||||
self.update = function(){
|
||||
|
||||
// Connection
|
||||
if(self.connectFrom){
|
||||
// Over any peeps? Connect to THAT! Else, connect to Mouse
|
||||
var peepHovered = _mouseOverPeep(CONNECT_TO_BUFFER); // buffer of 20px
|
||||
if(peepHovered==self.connectFrom) peepHovered=null; // if same, nah
|
||||
self.connectTo = peepHovered ? peepHovered : Mouse;
|
||||
}
|
||||
|
||||
// Erase
|
||||
if(self.isErasing){
|
||||
self.eraseTrail.unshift([Mouse.x,Mouse.y]); // add to start
|
||||
if(self.eraseTrail.length>10){
|
||||
self.eraseTrail.pop(); // remove from end
|
||||
}
|
||||
}else{
|
||||
self.eraseTrail.pop(); // remove from end
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// Connection!
|
||||
self.connectFrom = null;
|
||||
self.connectTo = null;
|
||||
self.startConnect = function(from){
|
||||
self.connectFrom = from;
|
||||
};
|
||||
self.endConnect = function(){
|
||||
self.connectFrom = null;
|
||||
};
|
||||
|
||||
// Erase!
|
||||
self.isErasing = false;
|
||||
self.eraseTrail = [];
|
||||
self.startErase = function(){
|
||||
self.isErasing = true;
|
||||
};
|
||||
self.endErase = function(){
|
||||
self.isErasing = false;
|
||||
};
|
||||
|
||||
// Draw
|
||||
self.draw = function(ctx){
|
||||
|
||||
// Connecting...
|
||||
if(self.connectFrom){
|
||||
ctx.strokeStyle = "#ccc";
|
||||
ctx.lineWidth = 1;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(self.connectFrom.x, self.connectFrom.y);
|
||||
ctx.lineTo(self.connectTo.x, self.connectTo.y);
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
// Erase
|
||||
if(self.eraseTrail.length>0){
|
||||
ctx.strokeStyle = "#dd4040";
|
||||
ctx.lineWidth = 1;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(self.eraseTrail[0][0], self.eraseTrail[0][1]);
|
||||
for(var i=1; i<self.eraseTrail.length; i++){
|
||||
ctx.lineTo(self.eraseTrail[i][0], self.eraseTrail[i][1]);
|
||||
}
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,287 @@
|
|||
Math.TAU = Math.PI*2;
|
||||
|
||||
var canvas = document.getElementById("canvas");// || document.createElement("canvas");
|
||||
canvas.style.cursor = "none";
|
||||
var ctx = canvas.getContext('2d');
|
||||
|
||||
var peeps = [];
|
||||
var connections = [];
|
||||
var drawing = new Drawing();
|
||||
var cursor = new Cursor();
|
||||
|
||||
var winnerImage = new Image();
|
||||
winnerImage.src = "img/winner.png";
|
||||
|
||||
var CONTAGION_THRESHOLD = 0;
|
||||
var CONTAGION_THRESHOLD_2 = 0;
|
||||
|
||||
var clearNetwork = function(){
|
||||
peeps = [];
|
||||
connections = [];
|
||||
};
|
||||
var loadNetwork = function(data){
|
||||
|
||||
// Clear!
|
||||
clearNetwork();
|
||||
|
||||
// Peeps
|
||||
data.peeps.forEach(function(p){
|
||||
addPeep(p[0], p[1], p[2]);
|
||||
});
|
||||
|
||||
// Connections
|
||||
data.connections.forEach(function(c){
|
||||
var from = peeps[c[0]];
|
||||
var to = peeps[c[1]];
|
||||
var uncuttable = c[2];
|
||||
addConnection(from, to, uncuttable);
|
||||
});
|
||||
|
||||
// Contagion threshold?
|
||||
if(data.contagion !== undefined){
|
||||
CONTAGION_THRESHOLD = data.contagion;
|
||||
}else{
|
||||
CONTAGION_THRESHOLD = 0;
|
||||
}
|
||||
if(data.contagion2 !== undefined){
|
||||
CONTAGION_THRESHOLD_2 = data.contagion2;
|
||||
}else{
|
||||
CONTAGION_THRESHOLD_2 = 0;
|
||||
}
|
||||
|
||||
}
|
||||
var saveNetwork = function(){
|
||||
var data = {
|
||||
peeps: [],
|
||||
connections: [],
|
||||
contagion: CONTAGION_THRESHOLD,
|
||||
contagion2: CONTAGION_THRESHOLD_2,
|
||||
};
|
||||
peeps.forEach(function(peep){
|
||||
data.peeps.push([peep.x, peep.y, peep.state]);
|
||||
});
|
||||
connections.forEach(function(c){
|
||||
var fromIndex = peeps.indexOf(c.from);
|
||||
var toIndex = peeps.indexOf(c.to);
|
||||
data.connections.push([fromIndex, toIndex, c.uncuttable]);
|
||||
});
|
||||
return data;
|
||||
}
|
||||
|
||||
var DRAW_STATE = 0; // 0-nothing | 1-connecting | 2-erasing
|
||||
var DRAW_CONNECT_FROM = null;
|
||||
var CONNECT_FROM_BUFFER = 15;//25;
|
||||
var CONNECT_TO_BUFFER = 25;
|
||||
|
||||
var YOU_ARE_WINNER = false;
|
||||
|
||||
function update(){
|
||||
|
||||
// Mouse logic...
|
||||
if(SIM_IS_RUNNING){
|
||||
DRAW_STATE = 0; // back to normal
|
||||
Mouse.update();
|
||||
}else{
|
||||
if(Mouse.justPressed && DRAW_STATE===0){
|
||||
|
||||
// Clicked on a peep?
|
||||
var peepClicked = _mouseOverPeep(CONNECT_FROM_BUFFER); // buffer of 20px
|
||||
if(peepClicked){
|
||||
DRAW_CONNECT_FROM = peepClicked;
|
||||
DRAW_STATE = 1; // START CONNECTING
|
||||
drawing.startConnect(peepClicked); // Drawing logic
|
||||
}else{
|
||||
DRAW_STATE = 2; // START ERASING
|
||||
}
|
||||
|
||||
}
|
||||
if(DRAW_STATE==2){ // ERASE
|
||||
|
||||
// Intersect with any CUTTABLE connections?
|
||||
var line = [Mouse.lastX, Mouse.lastY, Mouse.x, Mouse.y];
|
||||
for(var i=connections.length-1; i>=0; i--){ // going BACKWARDS coz killing
|
||||
var c = connections[i];
|
||||
if(c.uncuttable) continue; // don't touch the UNCUTTABLES
|
||||
if(c.hitTest(line)) connections.splice(i,1);
|
||||
}
|
||||
drawing.startErase(); // Drawing logic
|
||||
|
||||
}
|
||||
if(Mouse.justReleased && DRAW_STATE!==0){
|
||||
|
||||
// Connecting peeps, and released on a peep?
|
||||
if(DRAW_STATE==1){
|
||||
var peepReleased = _mouseOverPeep(CONNECT_TO_BUFFER); // buffer of 20px
|
||||
if(peepReleased){ // connect 'em!
|
||||
addConnection(DRAW_CONNECT_FROM, peepReleased);
|
||||
DRAW_CONNECT_FROM = null;
|
||||
}
|
||||
drawing.endConnect(); // Drawing logic
|
||||
}else if(DRAW_STATE==2){
|
||||
drawing.endErase(); // Drawing logic
|
||||
}
|
||||
DRAW_STATE = 0; // back to normal
|
||||
|
||||
}
|
||||
Mouse.update();
|
||||
|
||||
// Cursor Logic
|
||||
if(DRAW_STATE==0){
|
||||
var peepHovered = _mouseOverPeep(CONNECT_FROM_BUFFER); // buffer of 20px
|
||||
if(peepHovered){
|
||||
cursor.setMode(Cursor.CONNECT);
|
||||
}else{
|
||||
cursor.setMode(Cursor.NORMAL);
|
||||
}
|
||||
}
|
||||
if(DRAW_STATE==1){
|
||||
cursor.setMode(Cursor.CONNECT);
|
||||
}
|
||||
if(DRAW_STATE==2){
|
||||
cursor.setMode(Cursor.ERASE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Update Logic
|
||||
connections.forEach(function(connection){
|
||||
connection.update(ctx);
|
||||
});
|
||||
drawing.update();
|
||||
peeps.forEach(function(peep){
|
||||
peep.update();
|
||||
});
|
||||
cursor.update();
|
||||
|
||||
// Draw Logic
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
ctx.fillStyle = SIM_IS_RUNNING ? "#eee" : "#fff";
|
||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||
ctx.save();
|
||||
ctx.scale(2,2);
|
||||
_preUpdate();
|
||||
//ctx.translate(0,100);
|
||||
|
||||
connections.forEach(function(connection){
|
||||
connection.draw(ctx);
|
||||
});
|
||||
drawing.draw(ctx);
|
||||
peeps.forEach(function(peep){
|
||||
peep.draw(ctx);
|
||||
});
|
||||
cursor.draw(ctx);
|
||||
|
||||
_onUpdate();
|
||||
if(YOU_ARE_WINNER){
|
||||
ctx.drawImage(winnerImage, 0, 0, 500, 500);
|
||||
}
|
||||
ctx.restore();
|
||||
|
||||
// RAF
|
||||
requestAnimationFrame(update);
|
||||
|
||||
}
|
||||
function _preUpdate(){
|
||||
// TO IMPLEMENT
|
||||
}
|
||||
function _onUpdate(){
|
||||
// TO IMPLEMENT
|
||||
}
|
||||
|
||||
///////////////////////////////////////
|
||||
// CONTAGION UI, WHY NOT HMMMM ////////
|
||||
///////////////////////////////////////
|
||||
|
||||
function $(query){
|
||||
return document.querySelector(query);
|
||||
}
|
||||
|
||||
function showContagionUI(){
|
||||
|
||||
// Just display the div
|
||||
$("#sim_ui").style.display = "block";
|
||||
_updateSimRunningUI();
|
||||
|
||||
}
|
||||
|
||||
var SIM_IS_RUNNING = false;
|
||||
var SIM_STEP = 0;
|
||||
var _updateSimRunningUI = function(){
|
||||
if(SIM_IS_RUNNING){
|
||||
$("#sim_is_not_running").style.display = "none";
|
||||
$("#sim_is_running").style.display = "inline";
|
||||
//document.body.style.background = "#777";
|
||||
$("#sim_step").innerHTML = SIM_STEP;
|
||||
}else{
|
||||
$("#sim_is_not_running").style.display = "inline";
|
||||
$("#sim_is_running").style.display = "none";
|
||||
//document.body.style.background = "";
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
var _networkBeforeSimulationStarted = null;
|
||||
function _startSim(){
|
||||
SIM_STEP = 0;
|
||||
SIM_IS_RUNNING = true;
|
||||
_networkBeforeSimulationStarted = saveNetwork();
|
||||
_updateSimRunningUI();
|
||||
_startSimulation();
|
||||
};
|
||||
$("#sim_start").onclick = _startSim;
|
||||
function _stopSim(){
|
||||
SIM_IS_RUNNING = false;
|
||||
_resetToBeforeSimStarted();
|
||||
_updateSimRunningUI();
|
||||
_stopSimulation();
|
||||
};
|
||||
$("#sim_stop").onclick = _stopSim;
|
||||
function _simNext(){
|
||||
SIM_STEP++;
|
||||
_updateSimRunningUI();
|
||||
_stepSimulation();
|
||||
};
|
||||
$("#sim_next").onclick = _simNext;
|
||||
|
||||
function _resetToBeforeSimStarted(){
|
||||
loadNetwork(_networkBeforeSimulationStarted);
|
||||
}
|
||||
function _startSimulation(){
|
||||
// To Implement
|
||||
}
|
||||
function _stopSimulation(){
|
||||
// To Implement
|
||||
}
|
||||
function _stepSimulation(){
|
||||
_infectPeople();
|
||||
}
|
||||
|
||||
function _infectPeople(){
|
||||
|
||||
// Consider all peeps, and their friends
|
||||
var toInfect = [];
|
||||
peeps.forEach(function(peep){
|
||||
|
||||
// How many infected friends?
|
||||
if(peep.numFriends==0) return; // No friends? NVM.
|
||||
var ratioOfInfectedFriends = peep.numInfectedFriends/peep.numFriends;
|
||||
|
||||
// Passed threshold?
|
||||
if(CONTAGION_THRESHOLD==0){ // simple contagion, just ANY friend
|
||||
if(peep.numInfectedFriends>0) toInfect.push(peep);
|
||||
}else{
|
||||
// greater OR EQUALS (fuzz coz floating point)
|
||||
if(ratioOfInfectedFriends>=CONTAGION_THRESHOLD-0.0001){
|
||||
toInfect.push(peep);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// "Infect" the peeps who need to get infected
|
||||
toInfect.forEach(function(peep){
|
||||
peep.infect();
|
||||
});
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,272 @@
|
|||
var PEEP_STATE_COLORS = {
|
||||
1: "#ccc",
|
||||
2: "#dd4040"
|
||||
};
|
||||
|
||||
var _hack_SHOW_BOTH_STATES = false;
|
||||
var _hack_HIDE_BARS = false;
|
||||
var _hack_REINTEGRATION_PUZZLE = false;
|
||||
|
||||
var testingImage = new Image();
|
||||
testingImage.src = "img/testing.png";
|
||||
|
||||
function Peep(config){
|
||||
|
||||
var self = this;
|
||||
|
||||
// Properties
|
||||
self.x = config.x;
|
||||
self.y = config.y;
|
||||
self.state = config.state;
|
||||
|
||||
// Update:
|
||||
self.numFriends = 0;
|
||||
self.numInfectedFriends = 0;
|
||||
self.faceX = 0;
|
||||
self.faceY = 0;
|
||||
self.faceBlink = 0;
|
||||
self.isMajority = false;
|
||||
var _faceFollow = 0.75+(Math.random()*0.1);
|
||||
self.update = function(){
|
||||
|
||||
// Face position!
|
||||
var faceVector = {
|
||||
x: (Mouse.x-self.x)/5,
|
||||
y: (Mouse.y-self.y)/5
|
||||
};
|
||||
faceVector.mag = Math.sqrt(faceVector.x*faceVector.x + faceVector.y*faceVector.y);
|
||||
var max_distance = 5;
|
||||
if(faceVector.mag>max_distance){
|
||||
faceVector.x = faceVector.x * (max_distance/faceVector.mag);
|
||||
faceVector.y = faceVector.y * (max_distance/faceVector.mag);
|
||||
}
|
||||
self.faceX = self.faceX*_faceFollow + faceVector.x*(1-_faceFollow);
|
||||
self.faceY = self.faceY*_faceFollow + faceVector.y*(1-_faceFollow);
|
||||
|
||||
// Blink?
|
||||
if(!self.faceBlink){
|
||||
if(Math.random()<0.002) self.faceBlink=true;
|
||||
}else{
|
||||
if(Math.random()<0.09) self.faceBlink=false;
|
||||
}
|
||||
|
||||
// Friends connected... or infected
|
||||
var friends = getConnected(self);
|
||||
self.numFriends = friends.length;
|
||||
self.numInfectedFriends = 0;
|
||||
friends.forEach(function(friend){
|
||||
if(friend.state==2) self.numInfectedFriends++;
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
// Draw
|
||||
var radius = 20;
|
||||
var barWidth = 30;
|
||||
var barHeight = 10;
|
||||
self.draw = function(ctx){
|
||||
|
||||
ctx.save();
|
||||
ctx.translate(self.x, self.y);
|
||||
|
||||
// Circle
|
||||
//ctx.fillStyle = (self.state==1) ? "#ccc" : "#dd4040"; //"#ffdf00";
|
||||
var myColor = PEEP_STATE_COLORS[self.state];
|
||||
ctx.fillStyle = myColor;
|
||||
ctx.beginPath();
|
||||
ctx.arc(0, 0, radius, 0, Math.TAU, false);
|
||||
ctx.fill();
|
||||
|
||||
// INFECT ON NEXT TURN?
|
||||
/*var infectOnNextTurn = (self.numFriends>0 && self.numInfectedFriends/self.numFriends>=CONTAGION_THRESHOLD);
|
||||
if(infectOnNextTurn){
|
||||
ctx.strokeStyle = PEEP_STATE_COLORS[2];
|
||||
ctx.lineWidth = 2;
|
||||
ctx.stroke();
|
||||
}*/
|
||||
|
||||
// Face
|
||||
ctx.save();
|
||||
ctx.translate(self.faceX, self.faceY);
|
||||
ctx.fillStyle = "rgba(0,0,0,0.5)";
|
||||
if(self.faceBlink){
|
||||
ctx.beginPath();
|
||||
ctx.rect(-14, -1, 8, 2);
|
||||
ctx.fill();
|
||||
ctx.beginPath();
|
||||
ctx.rect(6, -1, 8, 2);
|
||||
ctx.fill();
|
||||
}else{
|
||||
ctx.beginPath();
|
||||
ctx.arc(-10, -1, 3, 0, Math.TAU, false);
|
||||
ctx.fill();
|
||||
ctx.beginPath();
|
||||
ctx.arc(10, -1, 3, 0, Math.TAU, false);
|
||||
ctx.fill();
|
||||
}
|
||||
ctx.beginPath();
|
||||
ctx.rect(-7, 4, 14, 2);
|
||||
ctx.fill();
|
||||
ctx.restore();
|
||||
|
||||
//////////////////////////////////////////////////////////
|
||||
// LABEL FOR INFECTED/FRIENDS, BAR, AND CONTAGION LEVEL //
|
||||
//////////////////////////////////////////////////////////
|
||||
|
||||
if(!_hack_HIDE_BARS && !self._hack_TESTED){
|
||||
|
||||
ctx.save();
|
||||
|
||||
// Say: Infected/Friends
|
||||
ctx.translate(0,-42);
|
||||
var labelNum = self.numInfectedFriends+"/"+self.numFriends;
|
||||
var labelPercent = "";
|
||||
if(self.numFriends>0){
|
||||
labelPercent = Math.round(100*(self.numInfectedFriends/self.numFriends)) + "%";
|
||||
}
|
||||
ctx.font = '12px sans-serif';
|
||||
ctx.fillStyle = myColor;
|
||||
ctx.textAlign = "center";
|
||||
ctx.textBaseline = "middle";
|
||||
ctx.fontWeight = "bold";
|
||||
ctx.fillText(labelNum, 0, 0);
|
||||
|
||||
// A nice bar
|
||||
ctx.translate(0,12);
|
||||
ctx.lineWidth = 1;
|
||||
|
||||
// the white fill
|
||||
ctx.fillStyle = "#fff";
|
||||
ctx.beginPath();
|
||||
ctx.rect(-barWidth/2, -barHeight/2, barWidth, barHeight);
|
||||
ctx.fill();
|
||||
|
||||
// The color fills
|
||||
if(self.numFriends>0){
|
||||
if(!_hack_SHOW_BOTH_STATES){
|
||||
ctx.fillStyle = PEEP_STATE_COLORS[2]; // state = 2 infected
|
||||
ctx.beginPath();
|
||||
ctx.rect(-barWidth/2, -barHeight/2, barWidth*(self.numInfectedFriends/self.numFriends), barHeight);
|
||||
ctx.fill();
|
||||
}else{
|
||||
var ratio = self.numInfectedFriends/self.numFriends;
|
||||
if((!_hack_REINTEGRATION_PUZZLE && self.state==1)
|
||||
|| (_hack_REINTEGRATION_PUZZLE && self.state==2)){
|
||||
var w = barWidth*(1-ratio);
|
||||
ctx.fillStyle = PEEP_STATE_COLORS[1];
|
||||
ctx.beginPath();
|
||||
ctx.rect(-barWidth/2, -barHeight/2, w, barHeight);
|
||||
ctx.fill();
|
||||
ctx.fillStyle = PEEP_STATE_COLORS[2];
|
||||
ctx.beginPath();
|
||||
ctx.rect(-barWidth/2+w, -barHeight/2, barWidth*(ratio), barHeight);
|
||||
ctx.fill();
|
||||
}else{
|
||||
var w = barWidth*(ratio);
|
||||
ctx.fillStyle = PEEP_STATE_COLORS[2];
|
||||
ctx.beginPath();
|
||||
ctx.rect(-barWidth/2, -barHeight/2, w, barHeight);
|
||||
ctx.fill();
|
||||
ctx.fillStyle = PEEP_STATE_COLORS[1];
|
||||
ctx.beginPath();
|
||||
ctx.rect(-barWidth/2+w, -barHeight/2, barWidth*(1-ratio), barHeight);
|
||||
ctx.fill();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The outline
|
||||
ctx.strokeStyle = myColor;
|
||||
ctx.beginPath();
|
||||
if(self.numFriends>0){
|
||||
ctx.rect(-barWidth/2, -barHeight/2, barWidth, barHeight);
|
||||
}else{
|
||||
ctx.rect(-barWidth/2, 0, barWidth, 0);
|
||||
}
|
||||
ctx.stroke();
|
||||
|
||||
// a pointer for contagion level
|
||||
ctx.translate(0, barHeight/2+2);
|
||||
if(!_hack_REINTEGRATION_PUZZLE){
|
||||
if(CONTAGION_THRESHOLD && CONTAGION_THRESHOLD>0){
|
||||
self._drawThreshold(ctx, CONTAGION_THRESHOLD);
|
||||
}
|
||||
if(CONTAGION_THRESHOLD_2 && CONTAGION_THRESHOLD_2>0){
|
||||
self._drawThreshold(ctx, CONTAGION_THRESHOLD_2);
|
||||
}
|
||||
}else{
|
||||
if(self.state==1){
|
||||
self._drawThreshold(ctx, 1/3);
|
||||
}else{
|
||||
self._drawThreshold(ctx, 2/3);
|
||||
}
|
||||
}
|
||||
|
||||
// Percent
|
||||
ctx.font = '8px sans-serif';
|
||||
ctx.fillStyle = "rgba(0,0,0,0.8)";
|
||||
ctx.textAlign = "center";
|
||||
ctx.textBaseline = "middle";
|
||||
ctx.fontWeight = "bold";
|
||||
ctx.fillText(labelPercent, 0, -6);
|
||||
|
||||
ctx.restore();
|
||||
|
||||
}
|
||||
|
||||
// AM I BEING TESTED
|
||||
if(self._hack_TESTED){
|
||||
ctx.drawImage(testingImage, -30, -85, 60, 60);
|
||||
}
|
||||
|
||||
ctx.restore();
|
||||
|
||||
};
|
||||
self._drawThreshold = function(ctx, threshold){
|
||||
ctx.save();
|
||||
ctx.translate(barWidth*threshold - barWidth/2, 0);
|
||||
|
||||
ctx.strokeStyle = "#000"; //PEEP_STATE_COLORS[2];
|
||||
ctx.lineWidth = 1;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(0,0);
|
||||
ctx.lineTo(0,-14);
|
||||
ctx.stroke();
|
||||
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
// Hit Test
|
||||
self.hitTest = function(x,y,buffer){
|
||||
if(buffer===undefined) buffer=0;
|
||||
var dx = self.x-x;
|
||||
var dy = self.y-y;
|
||||
var dist2 = dx*dx+dy*dy;
|
||||
var r = radius+buffer;
|
||||
return (dist2<r*r);
|
||||
};
|
||||
|
||||
// Infect
|
||||
self.infect = function(){
|
||||
self.state = 2;
|
||||
}
|
||||
|
||||
}
|
||||
function _mouseOverPeep(buffer){
|
||||
var result;
|
||||
peeps.forEach(function(peep){
|
||||
if(peep.hitTest(Mouse.x, Mouse.y, buffer)) result=peep;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
function addPeep(x,y, state){
|
||||
var peep = new Peep({
|
||||
x:x, y:y,
|
||||
state: state ? state : 1
|
||||
});
|
||||
peeps.push(peep);
|
||||
}
|
||||
function removePeep(peep){
|
||||
removeAllConnectedTo(peep); // remove connections first
|
||||
peeps.splice(peeps.indexOf(peep),1); // BYE peep
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
/******************************
|
||||
|
||||
An interactive game in the BACKGROUND of the Slideshow...
|
||||
(if fullscreen, origin is top-left of slideshow)
|
||||
(if not, allow MULTIPLE canvasses & games.)
|
||||
|
||||
******************************/
|
||||
|
||||
function Simulations(){
|
||||
|
||||
var self = this;
|
||||
self.dom = $("#simulations");
|
||||
|
||||
self.sims = [];
|
||||
|
||||
self.clear = function(){
|
||||
self.sims.forEach(function(sim){
|
||||
self.dom.removeChild(sim.canvas);
|
||||
sim.kill();
|
||||
});
|
||||
};
|
||||
self.showSims = function(simConfigs){
|
||||
self.clear();
|
||||
simConfigs.forEach(function(simConfig){
|
||||
var sim = new Sim(simConfig);
|
||||
self.dom.appendChild(sim.canvas);
|
||||
self.sims.push(sim);
|
||||
});
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
function Sim(config){
|
||||
|
||||
var self = this;
|
||||
self.config = config;
|
||||
self.networkConfig = config.network;
|
||||
|
||||
// Canvas
|
||||
self.canvas = createCanvas(500, 500);
|
||||
self.ctx = self.canvas.getContext('2d');
|
||||
|
||||
// Networks... clear/init
|
||||
self.clear = function(){
|
||||
self.peeps = [];
|
||||
self.connections = [];
|
||||
self.contagion = 0;
|
||||
};
|
||||
self.init = function(){
|
||||
|
||||
// Clear!
|
||||
self.clear();
|
||||
|
||||
// Peeps
|
||||
self.networkConfig.peeps.forEach(function(p){
|
||||
var x = p[0],
|
||||
y = p[1],
|
||||
infected = p[2];
|
||||
self.addPeep(x, y, infected);
|
||||
});
|
||||
|
||||
// Connections
|
||||
self.networkConfig.connections.forEach(function(c){
|
||||
var from = peeps[c[0]],
|
||||
to = peeps[c[1]],
|
||||
uncuttable = c[2];
|
||||
self.addConnection(from, to, uncuttable);
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
// Add Peeps/Connections
|
||||
self.addPeep = function(x, y, infected){
|
||||
var peep = new Peep({ x:x, y:y, infected:infected, sim:self });
|
||||
self.peeps.push(peep);
|
||||
return peep;
|
||||
};
|
||||
self.addConnection = function(from, to, uncuttable){
|
||||
|
||||
// Don't allow connecting to self...
|
||||
if(from==to) return;
|
||||
|
||||
// ...or if already exists, in either direction
|
||||
for(var i=0; i<self.connections.length; i++){
|
||||
var c = self.connections[i];
|
||||
if(c.from==from && c.to==to) return;
|
||||
if(c.from==to && c.to==from) return;
|
||||
}
|
||||
|
||||
// Otherwise, go ahead and add it!
|
||||
var connection = new Connection({ from:from, to:to, uncuttable:uncuttable, sim:self });
|
||||
self.connections.push(connection);
|
||||
return connection;
|
||||
|
||||
};
|
||||
|
||||
// Update
|
||||
self.update = function(){
|
||||
};
|
||||
|
||||
// INIT NOW
|
||||
self.init();
|
||||
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
/******************************************
|
||||
|
||||
THE PENCIL
|
||||
it's purely visual. replace the cursor
|
||||
draw / erase / click
|
||||
|
||||
******************************************/
|
||||
|
||||
function Pencil(){
|
||||
|
||||
var self = this;
|
||||
self.canvas = createCanvas( $("#pencil"), 100, 100 );
|
||||
self.ctx = self.canvas.getContext('2d');
|
||||
|
||||
// Sprite
|
||||
self.sprite = new Sprite({
|
||||
src: "sprites/pencil.png",
|
||||
frames:3, sw:200, sh:200,
|
||||
});
|
||||
self.sprite.pivotX = 0;
|
||||
self.sprite.pivotY = 200;
|
||||
self.sprite.scale = 0.75;
|
||||
var _size = 100;
|
||||
var _margin = 10;
|
||||
var _offset = 10;
|
||||
self.colors = [
|
||||
"#ccc",
|
||||
"#000",
|
||||
"#ff5555"
|
||||
];
|
||||
|
||||
// Update
|
||||
self.update = function(){
|
||||
|
||||
// Pencil's rotation
|
||||
if(isNaN(self.x)) self.x=0;
|
||||
if(isNaN(self.y)) self.y=0;
|
||||
var xy_velocity = ((Mouse.x-self.x) + (Mouse.y-self.y))/10; // in down-right direction
|
||||
var gotoRotation = -sigmoid(xy_velocity) * Math.TAU/8;
|
||||
self.sprite.rotation = self.sprite.rotation*0.8 + gotoRotation*0.2;
|
||||
|
||||
// Pencil's offset
|
||||
var gotoOffset = Mouse.pressed ? -8 : 10;
|
||||
_offset = _offset*0.5 + gotoOffset*0.5;
|
||||
|
||||
// Update position
|
||||
self.x = Mouse.x;
|
||||
self.y = Mouse.y;
|
||||
|
||||
// Move DOM there
|
||||
self.canvas.style.left = self.x-_margin;
|
||||
self.canvas.style.top = self.y-_size+_margin;
|
||||
|
||||
// Reset canvas
|
||||
var ctx = self.ctx;
|
||||
ctx.clearRect(0,0,self.canvas.width,self.canvas.height);
|
||||
ctx.save();
|
||||
ctx.translate(_margin*2, 200-_margin*2);
|
||||
|
||||
// Draw pencil's dot
|
||||
if(!Mouse.pressed){
|
||||
ctx.fillStyle = self.colors[self.sprite.currentFrame];
|
||||
ctx.beginPath();
|
||||
ctx.arc(0, 0, 5, 0, Math.TAU);
|
||||
ctx.fill();
|
||||
}
|
||||
|
||||
// Draw pencil
|
||||
self.sprite.x = _offset;
|
||||
self.sprite.y = -_offset;
|
||||
self.sprite.draw(ctx);
|
||||
|
||||
ctx.restore();
|
||||
|
||||
};
|
||||
|
||||
}
|
|
@ -1,9 +1,12 @@
|
|||
//////////////////////////
|
||||
// THE SLIDESHOW, YO /////
|
||||
//////////////////////////
|
||||
/******************************************
|
||||
|
||||
THE SLIDESHOW
|
||||
- background: fullscreen iframe (so can draw everywhere)
|
||||
- foreground: words & pictures
|
||||
|
||||
******************************************/
|
||||
|
||||
var SLIDES = [];
|
||||
var slideshow = new Slideshow();
|
||||
|
||||
function Slideshow(){
|
||||
|
||||
|
@ -22,6 +25,10 @@ function Slideshow(){
|
|||
// Clear DOM
|
||||
self.clear();
|
||||
|
||||
// Show simulations
|
||||
slide.sims = slide.sims || [];
|
||||
simulations.showSims(slide.sims);
|
||||
|
||||
// Add boxes
|
||||
slide.boxes = slide.boxes || [];
|
||||
slide.boxes.forEach(function(box){
|
||||
|
@ -52,8 +59,3 @@ function Slideshow(){
|
|||
};
|
||||
|
||||
}
|
||||
|
||||
// On load, set slideshow to first slide
|
||||
window.addEventListener("load", function(){
|
||||
slideshow.goto(0);
|
||||
});
|
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
Loading…
Reference in New Issue