|
<!DOCTYPE html> |
|
<meta charset="utf-8"> |
|
<style> |
|
|
|
.node { |
|
stroke-width: 1.5px; |
|
} |
|
|
|
</style> |
|
<body> |
|
<script src="http://d3js.org/d3.v3.min.js"></script> |
|
<script> |
|
|
|
var width = 900, |
|
height = 500, |
|
spf =400, |
|
kalapha = 2, |
|
totalmonomer = 140; |
|
|
|
|
|
var fill = d3.scale.category10(); |
|
var delta = 300; |
|
var nodes = [], |
|
foci = [{x: width/2-delta, y: 100}, {x: width/2+delta, y: 100}, {x: width/2, y: 350}, |
|
{x: width/2, y:20} ]; |
|
|
|
|
|
pools = { |
|
'a': { |
|
x:100, |
|
y:100, |
|
pool : [] |
|
}, |
|
'b': { |
|
x:150, |
|
y:150, |
|
pool : [] |
|
}, |
|
'c': { |
|
x:250, |
|
y:250, |
|
pool : [] |
|
}, |
|
} |
|
|
|
|
|
var ft = function(from,to){ |
|
var monom = pools[from].pool.shift(); |
|
if(!monom) return |
|
monom.id = to |
|
pools[to].pool.push(monom) |
|
} |
|
|
|
var svg = d3.select("body").append("svg") |
|
.attr("width", width) |
|
.attr("height", height); |
|
|
|
var force = d3.layout.force() |
|
.nodes(nodes) |
|
.links([]) |
|
.linkStrength(function(){return 0}) |
|
.chargeDistance(100) |
|
.charge(function(o,i){return (o.id==factinid)? -0: -15}) |
|
.gravity(-0.0) |
|
.size([width, height]) |
|
.on("tick", tick); |
|
|
|
var node = svg.selectAll("rect"); |
|
|
|
function tick(e) { |
|
var k = .035 * kalapha* e.alpha; |
|
|
|
// Push nodes toward their designated focus. |
|
nodes.forEach(function(o, i) { |
|
var dx=o.dx||0; |
|
var dy=o.dy||0; |
|
if(o.id == factinid){ |
|
//k= 0.1*e.alpha |
|
} |
|
try{ |
|
ddy = (foci[o.id].y+dy - o.y) * k; |
|
ddx = (foci[o.id].x+dx - o.x) * k; |
|
//dmax = 0.60 |
|
//if(Math.abs(ddy) > dmax){ ddy = ddy/Math.abs(ddy)*dmax} |
|
//if(Math.abs(ddx) > dmax){ ddx = ddx/Math.abs(ddx)*dmax} |
|
|
|
o.y += ddy; |
|
o.x += ddx; |
|
} catch (e){ |
|
} |
|
}); |
|
|
|
node |
|
.attr("x", function(d) { return d.x; }) |
|
.attr("y", function(d) { return d.y; }) |
|
.style("fill", function(d) { |
|
if (d.atp){ |
|
return d3.rgb(fill(d.id*0)).brighter(1); |
|
} else { |
|
return d3.rgb(fill(d.id*0)).darker(0.5); |
|
} |
|
} |
|
|
|
) |
|
.style("stroke", function(d) { return d3.rgb(fill(d.id)).darker(2); }); |
|
} |
|
var subset = [[],[],[]] |
|
|
|
actinpool = []; |
|
adppool = []; |
|
adpid = 0; |
|
atppool = []; |
|
atpid = 1; |
|
factinid = 2; |
|
|
|
profilinepool = []; |
|
profilineid = 3; |
|
|
|
|
|
var renumberThreadmill = function(actin){ |
|
actin.forEach(function(o,i){ |
|
o.dx=(i-actin.length/2)*8; |
|
o.dy=o.parity*5 |
|
}) |
|
} |
|
|
|
var hydrolyse = function(monomer){ |
|
monomer.atp=false; |
|
} |
|
|
|
var addToBarbedEnd = function(monomer){ |
|
if(!monomer) return |
|
monomer.id = factinid; |
|
var lastm = actinpool[actinpool.length-1]||{} |
|
monomer.parity = (lastm.parity==-1)?1:-1 |
|
actinpool.push(monomer) |
|
renumberThreadmill(actinpool) |
|
} |
|
|
|
var addToPointedEnd = function(monomer){ |
|
if(!monomer) return |
|
monomer.id = factinid; |
|
var firstm = actinpool[0]||{} |
|
monomer.parity = (firstm.parity==1)?-1:1; |
|
actinpool.unshift(monomer) |
|
renumberThreadmill(actinpool) |
|
} |
|
|
|
|
|
//setInterval(function(){ |
|
//console.log('>>>>> ', actinpool.length+ adppool.length+ atppool.length) |
|
//},100) |
|
|
|
var removeBarbedEnd = function(){ |
|
var monomer = actinpool.pop(); |
|
if(!monomer) return; |
|
monomer.dx = 0 |
|
monomer.dy = 0 |
|
if(monomer.atp){ |
|
monomer.id = atpid |
|
atppool.push(monomer) |
|
} else { |
|
monomer.id = adpid |
|
adppool.push(monomer) |
|
} |
|
renumberThreadmill(actinpool) |
|
return monomer |
|
} |
|
|
|
setInterval(removeBarbedEnd, 1.907*spf) |
|
|
|
var removePointedEnd = function(){ |
|
if(Math.random() < 0.10) { |
|
var rd= Math.random()*atppool.length |
|
if (rd > 4*totalmonomer/5){ |
|
addAtpToPointedEnd(); |
|
} else if (rd > 3*totalmonomer/5){ |
|
addAdpToPointedEnd(); |
|
} |
|
return |
|
} |
|
var monomer = actinpool.shift(); |
|
if(!monomer) return; |
|
monomer.dx = 0 |
|
monomer.dy = 0 |
|
if(monomer.atp){ |
|
monomer.id = atpid |
|
atppool.push(monomer) |
|
} else { |
|
monomer.id = adpid |
|
adppool.push(monomer) |
|
} |
|
renumberThreadmill(actinpool) |
|
return monomer |
|
} |
|
|
|
|
|
var fromPoolToPool = function(from, to, proba, transform){ |
|
var rnd = Math.random() |
|
if(rnd < proba*from.length){ |
|
monomer = from.shift(); |
|
if(!monomer) return; |
|
transform(monomer); |
|
to.push(monomer) |
|
} |
|
} |
|
|
|
// slow atp regeneration |
|
reg = function(){fromPoolToPool(adppool, atppool, 0.00, function(m){m.id=atpid, m.atp=true });} |
|
setInterval(reg, 1.0*spf) |
|
|
|
// fast atp regeneration |
|
reg = function(){fromPoolToPool(adppool, profilinepool, 41.0/1000, function(m){m.id=profilineid});} |
|
setInterval(reg, 1.0*spf) |
|
|
|
reg = function(){fromPoolToPool(profilinepool, atppool, 20.0/1000, function(m){m.id=atpid, m.atp=true});} |
|
setInterval(reg, 1.0*spf) |
|
|
|
reg = function(){fromPoolToPool(atppool, adppool, 0.00, function(m){m.id=adpid, m.atp=false });} |
|
setInterval(reg, 1.0*spf) |
|
|
|
//slow atp hydrolysis |
|
setInterval(function(){ |
|
return |
|
var rd = Math.random()*atppool.length; |
|
if(rd > 0.25*totalmonomer){ |
|
var matp = atppool.shift() |
|
matp.atp=false; |
|
matp.id = adpid; |
|
adppool.push(matp); |
|
} |
|
}, 0.3*spf) |
|
|
|
|
|
|
|
setInterval(function(){ |
|
var rd = Math.random()*atppool.length; |
|
if(rd > totalmonomer/20){ |
|
var monomer = atppool.shift(); |
|
addToBarbedEnd(monomer) |
|
} |
|
}, 0.45*spf) |
|
|
|
setInterval(function(){ |
|
monomer = removePointedEnd() |
|
}, 1.00*spf) |
|
|
|
|
|
|
|
// fast hydrolyse in actin filament |
|
setInterval(function(){ |
|
var index = ~~(Math.random() * actinpool.length-7) |
|
for(var i= index; i>0; i--){ |
|
if(actinpool[index] && actinpool[index].atp==true){ |
|
hydrolyse(actinpool[index]) |
|
return |
|
} |
|
} |
|
|
|
},0.36*spf) |
|
|
|
// addAtpPointed |
|
var addAtpToPointedEnd = function(){ |
|
var monomer = atppool.shift(); |
|
console.log('adding to pointed end'); |
|
addToPointedEnd(monomer); |
|
} |
|
|
|
// adddtpPointed |
|
var addAdpToPointedEnd = function(){ |
|
var monomer = adppool.shift(); |
|
console.log('adding to pointed end (ADP)'); |
|
addToPointedEnd(monomer); |
|
} |
|
|
|
//setInterval(addAtpToPointedEnd, 4*1000); |
|
|
|
var addmon = function(){ |
|
var monom = {id: ~~(Math.random() * foci.length), atp:true, weight:0} |
|
//nowhere.push(monom) |
|
nodes.push(monom); |
|
var roll = Math.random(); |
|
if(roll < 0.3){ |
|
monom.atp=true; |
|
monom.id = atpid; |
|
atppool.push(monom); |
|
} else if( roll < 0.6){ |
|
addToBarbedEnd(monom); |
|
} else { |
|
monom.atp=false; |
|
monom.id = adpid; |
|
adppool.push(monom); |
|
} |
|
force.start(); |
|
|
|
node = node.data(nodes); |
|
|
|
node.enter().append("rect") |
|
.attr("class", "node") |
|
.attr("width", 18) |
|
.attr("height", 8) |
|
.attr("x", function(d) { return d.x; }) |
|
.attr("y", function(d) { return d.y; }) |
|
.style("fill", function(d) { return fill(d.id); }) |
|
.style("stroke", function(d) { return d3.rgb(fill(d.id)).darker(2); }) |
|
.call(force.drag); |
|
}; |
|
|
|
setInterval( function(){force.start()} , 600) |
|
|
|
for( var i=0; i<totalmonomer; i++){ |
|
addmon(); |
|
} |
|
|
|
|
|
setTimeout(function(){ location.reload()}, 60*1000) |
|
|
|
</script> |