A 2D array of radial fibres connected by springs (thanks to Traer physics). When the fibres are stretched beyond a point, the springs break, creating openings in the fibres like in (some) human irises.
Created
November 20, 2013 04:32
-
-
Save maggiben/7557762 to your computer and use it in GitHub Desktop.
A Pen by Benjamin.
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
<div class="middle"> | |
<canvas id="iris" class="stage" width="400" height="400"></canvas> | |
<h4 id="fps" class="fps"></h4> | |
<span id=""></span> | |
</div> |
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
(function () { | |
var lastTime = 0; | |
var vendors = ['ms', 'moz', 'webkit', 'o']; | |
for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { | |
window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame']; | |
window.cancelAnimationFrame = | |
window[vendors[x] + 'CancelAnimationFrame'] || window[vendors[x] + 'CancelRequestAnimationFrame']; | |
} | |
if (!window.requestAnimationFrame) | |
window.requestAnimationFrame = function (callback, element) { | |
var currTime = new Date().getTime(); | |
var timeToCall = Math.max(0, 16 - (currTime - lastTime)); | |
var id = window.setTimeout(function () { | |
callback(currTime + timeToCall); | |
}, | |
timeToCall); | |
lastTime = currTime + timeToCall; | |
return id; | |
}; | |
if (!window.cancelAnimationFrame) | |
window.cancelAnimationFrame = function (id) { | |
clearTimeout(id); | |
}; | |
}()); | |
$(document).ready(function () { | |
Array.prototype.fill = function(x,n) { | |
"use strict" | |
if(typeof(n)=='undefined') { | |
var n = this.length; | |
} | |
while (n--) { | |
this[n] = x; | |
}; | |
return this | |
} | |
Array.prototype.copy = function(src, sstart, dst, dstart, length) { | |
for(var i = sstart; i < sstart+length;i+=1 ) { | |
dst[dstart++] = src[i]; | |
} | |
} | |
// Given : low <= high | |
// Returns : a random number in the range [low, high) | |
RandomRange = function(low, high) { | |
return Math.random()*(high-low) + low; | |
} | |
var recording; | |
var i, j, x, y; | |
var angle; | |
var irisRadius = 200; | |
var pupilFraction = 0.2; | |
var pupilRadius = irisRadius * pupilFraction; | |
var r; | |
var numFibres = 75; | |
var numCircles = 75 * (1 - pupilFraction); // fewer circles if the pupil is bigger | |
var storedradius = new Array(numCircles); | |
var SPRING_STRENGTH = 0.4; | |
var SPRING_DAMPING = 0.1; | |
var maxstretch; | |
var springnumber; var springnumber2; var springnumber3; | |
var springnumber4; var springnumber5; var springnumber6; var springnumber7; | |
var doRemoveSprings = true; | |
var initialNumSprings = 0; | |
var physics; | |
var particles; | |
var canvas = document.getElementById('iris'); | |
var context = canvas.getContext('2d'); | |
var width = canvas.width; | |
var height = canvas.height; | |
var isRunning = false; | |
var lastCalledTime; | |
var fps; | |
var setup = function() { | |
physics = new ParticleSystem(0.0, 0.1); | |
physics.setIntegrator = physics.EULER; | |
particles = new Array(numCircles); | |
for(i = 0; i < numCircles; i++) { | |
particles[i] = new Array(numFibres); | |
} | |
initialNumSprings = physics.numberOfSprings(); | |
for (i=0; i<numCircles; i++){ | |
r = pupilRadius + i*(irisRadius - pupilRadius)/numCircles; | |
storedradius[i] = r; | |
for (j = 0; j < numFibres; j++) { | |
angle = j * (Math.PI * 2) / numFibres; | |
x = Math.cos(angle) * r; | |
y = Math.sin(angle) * r; | |
particles[i][j] = physics.makeParticle(0.2, x, y, 0.0); | |
} | |
} | |
// make radial springs | |
for (i = 1; i < numCircles; i++) { | |
for (j = 0; j < numFibres; j++) { | |
physics.makeSpring(particles[i - 1][j], particles[i][j], | |
SPRING_STRENGTH, | |
SPRING_DAMPING, | |
(irisRadius - pupilRadius) / numCircles); // outer springs longer | |
} | |
} | |
// make concentric springs | |
for (i = 0; i < numCircles; i++) { | |
for (j = 1; j < numFibres; j++) { | |
physics.makeSpring(particles[i][j-1], particles[i][j], | |
RandomRange(0.01, 0.1) * SPRING_STRENGTH, | |
SPRING_DAMPING, | |
RandomRange(0.2, 0.4) * (Math.PI * 2) * storedradius[i] / numFibres * (0.8 + 0.2 * (1 - Math.sin(Math.PI * i / numCircles)))); | |
} | |
} | |
// stich up last set concentric springs | |
for (i = 0; i < numCircles; i++) { | |
physics.makeSpring(particles[i][numFibres-1], particles[i][0], | |
RandomRange(0.01, 0.1) * SPRING_STRENGTH, | |
SPRING_DAMPING, | |
RandomRange(0.2, 0.4)* (Math.PI * 2) *storedradius[i] / numFibres * (0.8 + 0.2 * (1 - Math.sin(Math.PI * i / numCircles)))); | |
} | |
for (j = 0; j < numFibres; j++) { | |
particles[0][j].makeFixed(); | |
} | |
for (j=0; j < numFibres; j++) { | |
particles[numCircles-1][j].makeFixed(); | |
} | |
} | |
var draw = function() { | |
// Store the current transformation matrix | |
context.save(); | |
// Use the identity matrix while clearing the canvas | |
context.setTransform(1, 0, 0, 1, 0, 0); | |
context.clearRect(0, 0, canvas.width, canvas.height); | |
// Restore the transform | |
context.restore(); | |
if(!lastCalledTime) { | |
lastCalledTime = new Date().getTime(); | |
fps = 0; | |
} | |
delta = (new Date().getTime() - lastCalledTime)/1000; | |
lastCalledTime = new Date().getTime(); | |
fps = Math.floor(1 / delta); | |
fpswrite()(fps); | |
if(isRunning) | |
requestAnimationFrame(draw); | |
physics.tick(1); | |
makeFibreLines(); | |
if (doRemoveSprings){ | |
removeSprings(); | |
} | |
} | |
var makeFibreLines = function() { | |
context.lineWidth = "1"; | |
context.strokeStyle = "#f1f1f1"; | |
for (i=1; i < numCircles; i++){ // Go through the circles | |
for (j=0; j < numFibres; j++) { // Go through the radiating particles | |
// draw lines between all the radiating points | |
context.beginPath(); | |
context.moveTo(width / 2, height / 2); | |
context.moveTo(particles[i][j].position.x + (width / 2), particles[i][j].position.y + (height / 2)); | |
context.lineTo(particles[i-1][j].position.x + (width / 2), particles[i-1][j].position.y + (height / 2)); | |
context.stroke(); | |
} | |
} | |
for (j=1; j < numFibres; j++) { // Go through the radiating points | |
// draw a line from each outer point to the point next to it | |
context.beginPath(); | |
context.moveTo(width / 2, height / 2); | |
context.moveTo(particles[numCircles-1][j].position.x + (width / 2), particles[numCircles-1][j].position.y + (height / 2)); | |
context.lineTo(particles[numCircles-1][j-1].position.x + (width / 2), particles[numCircles-1][j-1].position.y + (height / 2)); | |
context.stroke(); | |
// draw a line from each inner point to the point next to it | |
context.beginPath(); | |
context.moveTo(width / 2, height / 2); | |
context.moveTo(particles[0][j].position.x + (width / 2), particles[0][j].position.y + (height / 2)); | |
context.lineTo(particles[0][j-1].position.x + (width / 2), particles[0][j-1].position.y + (height / 2)); | |
context.stroke(); | |
} | |
// For the first (outermost) radiating point | |
// connect the first and last points on the outer circle | |
context.beginPath(); | |
context.moveTo(particles[numCircles-1][0].position.x + (width / 2), particles[numCircles-1][0].position.y + (height / 2)); | |
context.lineTo(particles[numCircles-1][numFibres-1].position.x + (width / 2), particles[numCircles-1][numFibres-1].position.y + (height / 2)); | |
context.stroke(); | |
// connect the first and last points on the inner circle | |
context.beginPath(); | |
context.moveTo(particles[0][numFibres-1].position.x + (width / 2), particles[0][numFibres-1].position.y + (height / 2)); | |
context.lineTo(particles[0][0].position.x + (width / 2), particles[0][0].position.y + (height / 2)); | |
context.stroke(); | |
} | |
var fpswrite = (function (){ | |
var el = document.getElementById("fps"); | |
return function(fps) { | |
el.innerText = fps + "fps"; | |
} | |
}) | |
var removeSprings = function() { // function to create circular voids | |
maxstretch = 0.0; | |
if (physics.numberOfSprings() > (0.9 * initialNumSprings)) { | |
// If most of the original springs still exist | |
for (i = 0; i < physics.numberOfSprings(); i++) { | |
var S = physics.getSpring(i); | |
if (S.currentLength()/ S.restLength() > maxstretch) { | |
// springnumber7=springnumber6; | |
// springnumber6=springnumber5; | |
springnumber5 = springnumber4; | |
springnumber4 = springnumber3; | |
springnumber3 = springnumber2; // pass 2's value to 3 | |
springnumber2 = springnumber; // pass the highest value to 2 | |
springnumber = i; | |
maxstretch = S.currentLength() / S.restLength(); | |
// make that most-stretched one 'springnumber' | |
} | |
} | |
physics.removeSpring(springnumber); // remove that spring | |
physics.removeSpring(springnumber2); | |
physics.removeSpring(springnumber3); | |
physics.removeSpring(springnumber4); | |
physics.removeSpring(springnumber5); | |
// physics.removeSpring(springnumber6); | |
// physics.removeSpring(springnumber7); | |
} | |
else { | |
return; | |
} // otherwise, stop removing springs | |
} | |
setup(); | |
isRunning = true; | |
draw(); | |
setTimeout(function(){ | |
isRunning = false; | |
}, 10 * 30000); | |
document.onkeydown = function checkKey(event) { | |
event = event || window.event; | |
if (event.keyCode == '38') { | |
// up arrow | |
doRemoveSprings = true; | |
} | |
else if (event.keyCode == '40') { | |
// down arrow | |
doRemoveSprings = false; | |
} | |
} | |
}); |
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
html, body { | |
overflow: hidden; | |
} | |
body { | |
background-color: rgb(1, 1, 1); | |
} | |
.middle { | |
padding-top: 100px; | |
position: relative; | |
display: table; | |
margin: 0 auto; | |
} | |
.stage { | |
width:400px; | |
height:400px; | |
background-color: rgb(1, 1, 1); | |
display: block; | |
} | |
.fps { | |
color: #c0c0c0; | |
text-align: center; | |
display: none; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment