Created
June 25, 2015 15:16
-
-
Save jdherg/6a8632b2f5da6f85a97a to your computer and use it in GitHub Desktop.
Contrapositive 20150624 Progress
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var tau = 2*Math.PI; | |
var Hands4 = function(center, radius, dance) { | |
this.center = center; | |
this.radius = radius; | |
this.dancers = []; | |
this.dance = dance; | |
}; | |
Hands4.prototype.getX = function(count, pos) { | |
return this.center[0] + this.dance.getX(count, pos); | |
}; | |
Hands4.prototype.getY = function(count, pos) { | |
return this.center[1] + this.dance.getY(count, pos); | |
}; | |
var Dance = function(repeatFlag) { | |
this.repeat = repeatFlag; | |
this.moves = []; | |
this.defaultMove = new Stand(0,75); | |
this.danceLength = 0; | |
}; | |
Dance.prototype.getX = function(count, pos) { | |
var moveInfo = this.currentMove(count); | |
return moveInfo[0].getX(moveInfo[1], pos); | |
}; | |
Dance.prototype.getY = function(count, pos) { | |
var moveInfo = this.currentMove(count); | |
return moveInfo[0].getY(moveInfo[1], pos); | |
}; | |
Dance.prototype.currentMove = function(count) { | |
if(this.repeat) { | |
count %= this.danceLength; | |
} | |
for(var i = 0; i < this.moves.length; i++) { | |
if(count > this.moves[i].duration) { | |
count -= this.moves[i].duration; | |
} else { | |
return [this.moves[i], count]; | |
} | |
} | |
return [this.defaultMove, 0]; | |
}; | |
Dance.prototype.addMove = function(move) { | |
this.moves.push(move); | |
this.danceLength += move.duration; | |
}; | |
var Move = function() { | |
}; | |
Move.prototype.getX = function(count, pos) { | |
throw "not implemented"; | |
}; | |
Move.prototype.getY = function(count, pos) { | |
throw "not implemented"; | |
}; | |
Move.prototype.posTransform = function(pos) { | |
return pos; | |
}; | |
var Circle = function(duration, direction, radius) { | |
this.radius = radius; | |
this.direction = direction; | |
this.speed = 1/8; | |
this.duration = duration; | |
}; | |
Circle.prototype.__proto__ = Move.prototype; | |
Circle.prototype.getX = function(count, pos) { | |
return Math.cos(tau/8 + tau/4 * pos + this.direction * this.speed * count * tau) * this.radius | |
}; | |
Circle.prototype.getY = function(count, pos) { | |
return Math.sin(tau/8 + tau/4 * pos + this.direction * this.speed * count * tau) * this.radius | |
}; | |
Circle.prototype.posTransform = function(pos) { | |
var posDelta = this.direction * this.duration * this.speed * 4; | |
pos = (pos + posDelta) % 4; | |
pos += pos < 0 ? 4 :0; | |
return pos; | |
}; | |
var Stand = function(duration, radius) { | |
this.duration = duration; | |
this.radius = radius; | |
}; | |
Stand.prototype.__proto__ = Move.prototype; | |
Stand.prototype.getX = function(count, pos) { | |
return Math.cos(tau/8 + tau/4 * pos) * this.radius; | |
}; | |
Stand.prototype.getY = function(count, pos) { | |
return Math.sin(tau/8 + tau/4 * pos) * this.radius; | |
}; | |
var Allemande = function(duration, direction, radius) { | |
this.duration = duration; | |
this.direction = direction; | |
this.radius = radius; | |
this.speed = 1/4; | |
} | |
Allemande.prototype.__proto__ = Move.prototype; | |
Allemande.prototype.getX = function(count, pos) { | |
var startingPosition = Math.cos(tau/8 + tau/4 * pos) * this.radius; | |
if(count === 0) { | |
return startingPosition; | |
} | |
var cx = (this.getX(0,pos) + this.getX(0,pos^1))/2; | |
var cy = (this.getY(0,pos) + this.getY(0,pos^1))/2; | |
var polar = cartesianToPolar([cx,cy],[this.getX(0,pos),this.getY(0,pos)]); | |
var theta_delta = tau * this.speed * count * this.direction; | |
var theta_end = polar[1] + theta_delta; | |
return Math.cos(theta_end) * polar[0] + cx; | |
} | |
Allemande.prototype.getY = function(count, pos) { | |
var startingPosition = Math.sin(tau/8 + tau/4 * pos) * this.radius; | |
if(count === 0) { | |
return startingPosition; | |
} | |
var cx = (this.getX(0,pos) + this.getX(0,pos^1))/2; | |
var cy = (this.getY(0,pos) + this.getY(0,pos^1))/2; | |
var polar = cartesianToPolar([cx,cy],[this.getX(0,pos),this.getY(0,pos)]); | |
var theta_delta = tau * this.speed * count * this.direction; | |
var theta_end = polar[1] + theta_delta; | |
return Math.sin(theta_end) * polar[0] + cy; | |
} | |
function cartesianToPolar(center, point){ | |
var dx = point[0] - center[0], | |
dy = point[1] - center[1], | |
d2 = dx * dx + dy * dy, | |
dist = Math.sqrt(d2), | |
sin = dy / dist, | |
cos = dx / dist, | |
asin = Math.asin(sin), | |
acos = Math.acos(cos); | |
var theta = 0; | |
if(sin < 0) { | |
theta = -1 * acos; | |
} else { | |
if(cos < 0) { | |
theta = 2 * Math.PI - acos; | |
} else { | |
theta = acos; | |
} | |
} | |
return [dist, theta]; | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<meta charset="utf-8"> | |
<style> | |
svg { | |
border: solid 1px #000; | |
} | |
circle { | |
r: 25; | |
stroke: #000; | |
} | |
</style> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js" charset="utf-8"></script> | |
<script src="dance_model.js" charset="utf-8"></script> | |
<body> | |
<script> | |
var width = 960, | |
height = 500, | |
tau = 2*Math.PI; | |
var counts_per_second = 4, | |
taus_per_count = 1/8; | |
var svg = d3.select("body").append("svg") | |
.attr("width", width) | |
.attr("height", height); | |
var count_display = d3.select("body").append("p") | |
.text(0); | |
var dance = new Dance(true); | |
dance.addMove(new Allemande(4, 1, 75)); | |
dance.addMove(new Circle(6, 1, 75)); | |
dance.addMove(new Circle(10, -1, 75)); | |
var h4s = []; | |
h4s.push(new Hands4([240,250], 75, dance)); | |
h4s.push(new Hands4([720,250], 75, dance)); | |
var dancers = []; | |
for (var i = 0; i < h4s.length*4; i++) { | |
dancers.push( | |
{id: i, | |
pos: i % 4, | |
theta: 0}); | |
h4s[Math.floor(i/4)].dancers.push(dancers[i]); | |
dancers[i].h4 = h4s[Math.floor(i/4)]; | |
} | |
var dots = svg.selectAll("circle") | |
.data(dancers) | |
.enter().append("circle") | |
.attr("fill", function(d) { | |
switch(d.id % 4) { | |
case 0: | |
return "red"; | |
case 1: | |
return "blue"; | |
case 2: | |
return "green"; | |
case 3: | |
return "yellow"; | |
} | |
}); | |
var previousMove = dance.currentMove(0)[0]; | |
draw(0); | |
d3.timer(animate); | |
function draw(count) { | |
dots.attr("cx", function(d) { | |
return d.h4.getX(count, d.pos); | |
}) | |
.attr("cy", function(d) { | |
return d.h4.getY(count, d.pos); | |
}); | |
count_display.text(Math.floor(count) % dance.danceLength); | |
} | |
function animate(elapsed) { | |
var count = elapsed/1000 * counts_per_second; | |
var currentMove = dance.currentMove(count)[0]; | |
if(previousMove !== currentMove) { | |
dancers.forEach(function(dancer){ | |
dancer.pos = previousMove.posTransform(dancer.pos); | |
}); | |
previousMove = currentMove; | |
} | |
draw(count); | |
} | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment