Template:Team:Valencia Biocampus/Templates/js/simuelegans2.js

From 2013.igem.org

Raphael.fn.arrow = function(x1, y1, x2, y2, size) { var angle = Raphael.angle(x1, y1, x2, y2); var a45 = Raphael.rad(angle-45); var a45m = Raphael.rad(angle+45); var a135 = Raphael.rad(angle-135); var a135m = Raphael.rad(angle+135); var x1a = x1 + Math.cos(a135) * size; var y1a = y1 + Math.sin(a135) * size; var x1b = x1 + Math.cos(a135m) * size; var y1b = y1 + Math.sin(a135m) * size; var x2a = x2 + Math.cos(a45) * size; var y2a = y2 + Math.sin(a45) * size; var x2b = x2 + Math.cos(a45m) * size; var y2b = y2 + Math.sin(a45m) * size; return this.path( "M"+x1+" "+y1+"L"+x1a+" "+y1a+ "M"+x1+" "+y1+"L"+x1b+" "+y1b+ "M"+x1+" "+y1+"L"+x2+" "+y2+ "M"+x2+" "+y2+"L"+x2a+" "+y2a+ "M"+x2+" "+y2+"L"+x2b+" "+y2b ); };

simuelegans = function() {};

var initialx = -1; var initialy = -1;

var initialr; var initiala;


var canvas = Raphael("raphael", 500, 500); // Back canvas (contains the drawing)


var path_in_coords = new Array(); function xytopath(x, y){ var guide_path, path, full_path;

if(initialx==-1 && initialy==-1){ initialx = 0; initialy = 0; }

var path2return = new Array(x.length);

var tmpx, tmpy;

tmpx = (x[0] * plate.attrs.r / simulator.plate_radius + plate.attrs.cx); tmpy = (y[0] * plate.attrs.r / simulator.plate_radius + plate.attrs.cy);

path2return[-1] = "[\"M"+tmpx+","+tmpy+"\"";


for(var i =1; i<x.length ; i++){

tmpx = (x[i-1] * plate.attrs.r / simulator.plate_radius + plate.attrs.cx); tmpy = (y[i-1] * plate.attrs.r / simulator.plate_radius + plate.attrs.cy);

path2return[i-1] = "[\"M"+tmpx+","+tmpy+"\", ";

tmpx = (x[i] * plate.attrs.r / simulator.plate_radius + plate.attrs.cx); tmpy = (y[i] * plate.attrs.r / simulator.plate_radius + plate.attrs.cy);


path2return[i-1] += "\"L"+tmpx+","+tmpy+"\" ]";

path_in_coords.push({x: tmpx, y: tmpy});


} return path2return; }

function Attractant(Xpx, Ypx){ this.Xpx = Xpx; this.Ypx = Ypx;

   this.R = (Math.sqrt( (Xpx - plate.attrs.cx )*(Xpx - plate.attrs.cx ) + (Ypx - plate.attrs.cy)*(Ypx - plate.attrs.cy ) ) / plate.attrs.r) * simulator.plate_radius;
   this.A = Math.atan2(Ypx - plate.attrs.cy, Xpx - plate.attrs.cx)


this.x = this.R * Math.cos(this.A); // x on the plate this.y = this.R * Math.sin(this.A); // y on the plate

}


simuelegans.RandNorm = function(m, s){

this.mean = m; this.stdDev = s; this.isSpareReady = false; this.spare = 0; this.valuern = 0; }

simuelegans.RandNorm.prototype.getRandNorm = function() { if (this.isSpareReady) { this.isSpareReady = false; this.valuern = this.spare * this.stdDev + this.mean; } else { var u, v, s; do { u = Math.random() * 2 - 1; v = Math.random() * 2 - 1; s = u * u + v * v; } while (s >= 1 || s == 0); var mul = Math.sqrt(-2.0 * Math.log(s) / s); this.spare = v * mul; this.isSpareReady = true; this.valuern = this.mean + this.stdDev * u * mul; } return this.valuern; }; simuelegans.RandNorm = function(m, s){

this.mean = m; this.stdDev = s; this.isSpareReady = false; this.spare = 0; this.valuern = 0; }

simuelegans.RandNorm.prototype.getRandNorm = function() { if (this.isSpareReady) { this.isSpareReady = false; this.valuern = this.spare * this.stdDev + this.mean; } else { var u, v, s; do { u = Math.random() * 2 - 1; v = Math.random() * 2 - 1; s = u * u + v * v; } while (s >= 1 || s == 0); var mul = Math.sqrt(-2.0 * Math.log(s) / s); this.spare = v * mul; this.isSpareReady = true; this.valuern = this.mean + this.stdDev * u * mul; } return this.valuern; };

simuelegans.Chemotaxis = function(h, t, r0, a0){

this.tmax = t; this.h = h; a0 *= Math.PI / 180.0; this.x0 = r0 * Math.cos(a0); this.y0 = r0 * Math.sin(a0); this.tsize = this.tmax / h; this.x = new Array(this.tsize); this.y = new Array(this.tsize); this.c = new Array(this.tsize); this.dc = new Array(this.tsize); this.v = new Array(this.tsize); this.g = new Array(this.tsize); this.dg = new Array(this.tsize); this.d = new Array(this.tsize); this.temp = new Array(this.tsize);

this.attractants = new Array(); // array list of Attractant objects


} simuelegans.Chemotaxis.prototype.addAttractant = function(attractant) {

this.attractants.push(attractant); } simuelegans.Chemotaxis.prototype.correctionFactor = function(dc) { if (dc < 0) { return 1.5 - Math.exp(11.2536 * dc); } else { return 0.5; } } // x0, y0 --> attractant coords // x, y --> where is calculated simuelegans.Chemotaxis.prototype.attractantDiffusion = function(x0, y0, x, y) {

var t1 = 19 * 3600; var t2 = 4.5 * 3600; var N0 = 500; var de = 0.264; var D = 1.861e-5; var temp = 1;

return N0 * (Math.exp(-((x-x0)*(x-x0) + (y-y0)*(y-y0)) / 4 * D * (temp + t1)) / (4 * Math.PI * de * D * (temp + t1)) + Math.exp(-((x-x0)*(x-x0) + (y-y0)*(y-y0)) / 4 * D * (temp + t2)) / (4 * Math.PI * de * D * (temp + t2)) );

};

simuelegans.Chemotaxis.prototype.simulate = function(r0, a0) { this.x0 = r0 * Math.cos(a0); this.y0 = r0 * Math.sin(a0); this.x[0] = this.x0; this.y[0] = this.y0; this.temp[0] = 0;

this.c[0] = 0; for (var i in this.attractants) { this.c[0] += this.attractantDiffusion(this.attractants[i].x, this.attractants[i].y, this.x0, this.y0); };

this.dc[0] = 0; this.v[0] = 0;

this.g[0] = 2 * Math.PI * Math.random(); this.dg[0] = 0;

var rnd1 = new simuelegans.RandNorm(0.0152, 0.00702); var rnd2 = new simuelegans.RandNorm(0.861 * Math.PI / 180, 38.9 * Math.PI / 180); var rnd3 = new simuelegans.RandNorm(0.441 * Math.PI / 180, 2.12 * Math.PI / 180);

this.d[0] = rnd3.getRandNorm();

for (var i = 0; i < this.tsize - 1; i++) { this.temp[i + 1] = this.h * i; this.x[i + 1] = this.x[0] - 0.01; this.y[i + 1] = this.y[0] - 0.01; this.v[i + 1] = 0.01;


do { this.c[i+1] = 0; for (var j in this.attractants) { this.c[i+1] += this.attractantDiffusion(this.attractants[j].x, this.attractants[j].y, this.x[i], this.y[i]); };

this.dc[i + 1] = (this.c[i + 1] - this.c[i]) / this.h;

this.v[i + 1] = rnd1.getRandNorm(); var cf = this.correctionFactor(this.dc[i + 1]); this.dg[i + 1] = rnd2.getRandNorm() * cf; this.d[i + 1] = rnd3.getRandNorm(); var l = this.h * this.v[i + 1]; this.g[i + 1] = this.h * (this.dg[i + 1] + this.d[i + 1]) + this.g[i]; this.x[i + 1] = l * Math.cos(this.g[i + 1]) + this.x[i]; this.y[i + 1] = l * Math.sin(this.g[i + 1]) + this.y[i];

} while ((Math.sqrt(this.x[i + 1] * this.x[i + 1] + this.y[i + 1] * this.y[i + 1]) > simulator.plate_radius)); } }


var strpath; var path1; var pathcolor = {stroke : "#5a7881"};

var plate;

var circle; var arrow_radius; var arrow_title;

var c_elegans;

var attractant; var attractantX, attractantY; var attractantsArray = new Array();

var gui = new dat.GUI({ autoPlace: false }); var customContainer = document.getElementById('simuelegans_gui'); customContainer.appendChild(gui.domElement);

function simulator(){

   this.plate_radius = 4;
   this.simulation_length = 2000;
   this.duration = 50;
   this.initSimulation = function() { 
       simndraw(circle.attrs.cx, circle.attrs.cy);
       circle.toFront();   // C.elegans circle 
       c_elegans.toFront();
       plate.toFront();
   };

}


var simulator = new simulator();

 gui.add(simulator, 'plate_radius', 0.8, 4.5).name("Plate radius (cm)");
 gui.add(simulator, 'simulation_length', 200, 4000).name("Duration ");
 gui.add(simulator, 'initSimulation').name("Init animation");

function initPlate(){

   plate = canvas.circle(250, 250, 230);
   plate.attr("stroke", "#cac0b0");
   plate.attr("fill", "#cac0b0");  
   plate.attr("fill-opacity", "0"); // fill with opacity 0 to be clickable 
   plate.attr("cursor", "crosshair");
   plate.click(onclickplate);
   plate.node.oncontextmenu = function(e){ 
       attractantX = e.clientX - $("#raphael").offset().left;
       attractantY = e.clientY - $("#raphael").offset().top;
   
       attractant = new Attractant(attractantX, attractantY); // x & y in px
       canvas.circle(attractant.Xpx, attractant.Ypx, 30).attr("fill","rgba(225,217,30,0.25)").attr("stroke", "rgba(200,199,10,0.55)");


       attractantsArray.push(attractant);
       return false;
   }
   arrow_radius = canvas.arrow(250, 493, 470, 493, 10);
   arrow_title  = canvas.text(360, 487, "Radius: "+simulator.plate_radius.toFixed(1)+"cm").attr({fill: '#000'});

}


function initCircle(x, y){

   circle = canvas.circle(x, y, 3);
   circle.attr("stroke-width", 1);
   circle.attr("stroke", "#f00");
   circle.attr("fill", "#f00");
   //c_elegans = canvas.image("elegans.png", x - 120/7/2, y - 120/7/2, 120/7, 74/7);
   c_elegans = canvas.circle(x, y, 3);
   c_elegans.attr("stroke-width", 1);
   c_elegans.attr("stroke", "#5a7881");

}

function animateCircle(step, strpath){


   if(step <= strpath.length){
       path1 = canvas.path(strpath[step]).attr( { stroke: "#5a7881", fill: "none" });


       //c_elegans.attr({guide : path1, along : 1}).animate({along : 0}, 50, "linear");
       //c_elegans.attr({along: 0});
       //c_elegans.rotate(Math.atan2(c_elegans.attrs.y, c_elegans.attrs.x))


       c_elegans.animate({ cx: path_in_coords[step+1].x, cy: path_in_coords[step+1].y}, 50);


       path1.animate({path: strpath[step+1]}, 50, function(){
           animateCircle(step+1, strpath);
       })  
   }


}

function simndraw(x, y){

   initialx = x ;
   initialy = y;



   initialr = (Math.sqrt( (initialx - plate.attrs.cx )*(initialx - plate.attrs.cx ) + (initialy - plate.attrs.cy)*(initialy - plate.attrs.cy ) ) / plate.attrs.r) * simulator.plate_radius;
   initiala = Math.atan2(initialy - plate.attrs.cy, initialx - plate.attrs.cx)


   //chemotaxis.attractants.length = 0;
   chemotaxis = new simuelegans.Chemotaxis(1.0, simulator.simulation_length.toFixed(), initialr, initiala);
   for(var i in attractantsArray){
       chemotaxis.addAttractant(attractantsArray[i]);
 
   }


   chemotaxis.simulate(initialr, initiala);


   strpath = xytopath(chemotaxis.x, chemotaxis.y);
   animateCircle(-1, strpath);


}


var x0, y0;


initPlate(); initCircle(plate.attrs.cx, plate.attrs.cy);

//simndraw(plate.attrs.cx, plate.attrs.cy);

var chemotaxis;



   function onclickplate(e) {


   circle.remove();
   c_elegans.remove();
   if(typeof path1 !== 'undefined'){
      path1.remove();
      path_in_coords.length = 0;
   }
   canvas.clear();
   initPlate();
   x0 = e.clientX - $("#raphael").offset().left;
   y0 = e.clientY - $("#raphael").offset().top;
   initCircle(x0, y0); // C.elegans starting position
   circle.toFront();   // C.elegans circle 



   //simndraw(x0, y0);   // simulates and loads data, and then starts animation


};