Difference between revisions of "Team:Newcastle"

Line 430: Line 430:
  
 
<script>
 
<script>
// One of my first <canvas> experiments, woop! :D
+
var PI2 = Math.PI * 2;
 +
var HALF_PI = Math.PI / 2;
  
var SCREEN_WIDTH = window.innerWidth;
+
var isTouch = 'ontouchstart' in window;
var SCREEN_HEIGHT = window.innerHeight;
+
var isSafari = !!navigator.userAgent.match(/Version\/[\d\.]+.*Safari/);
  
var RADIUS = 70;
+
function Canvas(options) {
 +
  options = _.clone(options || {});
 +
  this.options = _.defaults(options, this.options);
 +
 
 +
  this.el = this.options.el;
 +
  this.ctx = this.el.getContext('2d');
 +
 
 +
  this.dpr = window.devicePixelRatio || 1;
 +
 
 +
  this.updateDimensions();
 +
  window.addEventListener('resize', this.updateDimensions.bind(this), false);
 +
  this.resetTarget();
 +
 
 +
  if(isTouch){
 +
      // touch
 +
  this.el.addEventListener('touchstart', this.touchMove.bind(this), false);
 +
this.el.addEventListener('touchmove', this.touchMove.bind(this), false);
 +
//  this.el.addEventListener('touchend', this.resetTarget.bind(this), false);
 +
  } else {
 +
    // Mouse
 +
    window.addEventListener('mousemove', this.mouseMove.bind(this), false);
 +
window.addEventListener('mouseout', this.resetTarget.bind(this), false);
 +
  }
 +
 
 +
  this.setupParticles();
  
var RADIUS_SCALE = 1;
+
  this.loop();
var RADIUS_SCALE_MIN = 1;
+
}
var RADIUS_SCALE_MAX = 1.5;
+
  
var QUANTITY = 25;
+
Canvas.prototype.updateDimensions = function() {
 +
  this.width = this.el.width = _.result(this.options, 'width') * this.dpr;
 +
  this.height = this.el.height = _.result(this.options, 'height') * this.dpr;
 +
  this.el.style.width = _.result(this.options, 'width') + 'px';
 +
  this.el.style.height = _.result(this.options, 'height') + 'px';
 +
}
  
var canvas;
+
// Update the orb target
var context;
+
Canvas.prototype.mouseMove = function(event) {
var particles;
+
this.target = new Vector(event.clientX * this.dpr, event.clientY* this.dpr);
 +
}
  
var mouseX = SCREEN_WIDTH * 0.5;
+
// Reset to center when we mouse out
var mouseY = SCREEN_HEIGHT * 0.5;
+
Canvas.prototype.resetTarget = function() {
var mouseIsDown = false;
+
this.target = new Vector(this.width / 2, this.height /2);
 +
}
  
function init() {
+
// Touch Eent
 +
Canvas.prototype.touchMove = function(event) {
 +
  if(event.touches.length === 1) {  event.preventDefault(); }
  
  canvas = document.getElementById( 'world' );
+
this.target = new Vector(event.touches[0].pageX * this.dpr, event.touches[0].pageY * this.dpr);
 
+
  if (canvas && canvas.getContext) {
+
        context = canvas.getContext('2d');
+
       
+
        // Register event listeners
+
        window.addEventListener('mousemove', documentMouseMoveHandler, false);
+
        window.addEventListener('mousedown', documentMouseDownHandler, false);
+
        window.addEventListener('mouseup', documentMouseUpHandler, false);
+
        document.addEventListener('touchstart', documentTouchStartHandler, false);
+
        document.addEventListener('touchmove', documentTouchMoveHandler, false);
+
        window.addEventListener('resize', windowResizeHandler, false);
+
       
+
        createParticles();
+
       
+
        windowResizeHandler();
+
       
+
        setInterval( loop, 1000 / 60 );
+
    }
+
 
}
 
}
  
function createParticles() {
+
// Defaults
    particles = [];
+
Canvas.prototype.options = {
   
+
  count: 20,
    for (var i = 0; i < QUANTITY; i++) {
+
  speed: 0.5,
        var particle = {
+
  width: 400,
            size: 1,
+
  height: 400,
            position: { x: mouseX, y: mouseY },
+
  size: 10,
            offset: { x: 0, y: 0 },
+
  radius: 5,
            shift: { x: mouseX, y: mouseY },
+
  background: '29, 22, 52',
            speed: 0.01+Math.random()*0.04,
+
  maxDistance: 100
            targetSize: 1,
+
            fillColor: '#' + (Math.random() * 0x404040 + 0xaaaaaa | 0).toString(16),
+
            orbit: RADIUS*.5 + (RADIUS * .5 * Math.random())
+
        };
+
       
+
        particles.push( particle );
+
    }
+
 
}
 
}
  
function documentMouseMoveHandler(event) {
+
Canvas.prototype.setupParticles = function() {
    mouseX = event.clientX - (window.innerWidth - SCREEN_WIDTH) * .5;
+
  this.particles = [];
     mouseY = event.clientY - (window.innerHeight - SCREEN_HEIGHT) * .5;
+
  var index = -1;
}
+
  var between = PI2 / this.options.count;
 +
  while(++index < this.options.count) {
 +
    var x;
 +
    var y;
 +
    var angle;
 +
     var max = Math.max(this.width, this.height);
 +
   
 +
    angle = (index + 1) * between;
 +
   
 +
    x = Math.cos(angle) * max;
 +
    x += this.width / 2;
  
function documentMouseDownHandler(event) {
+
    y = Math.sin(angle) * max;
     mouseIsDown = true;
+
     y += this.height / 2;
 +
   
 +
    var particle = new Particle({
 +
      x: x,
 +
      y: y,
 +
      radius: this.options.radius,
 +
      size: this.options.size,
 +
      angle: angle,
 +
      color: this.options.color
 +
    });
 +
   
 +
    this.particles.push(particle);
 +
  }
 
}
 
}
  
function documentMouseUpHandler(event) {
+
Canvas.prototype.findClosest = function() {
    mouseIsDown = false;
+
  var index = -1;
}
+
  var pointsLength = this.particles.length;
  
function documentTouchStartHandler(event) {
+
  while(++index < pointsLength) {
     if(event.touches.length == 1) {
+
     var closestIndex = -1;
        event.preventDefault();
+
    this.particles[index].closest = [];
 
+
   
         mouseX = event.touches[0].pageX - (window.innerWidth - SCREEN_WIDTH) * .5;;
+
    while(++closestIndex < pointsLength) {
         mouseY = event.touches[0].pageY - (window.innerHeight - SCREEN_HEIGHT) * .5;
+
      var closest = this.particles[closestIndex];
 +
      var distance = this.particles[index].position.distanceTo(closest.position);
 +
      if(distance < this.options.maxDistance) {
 +
         var vector = new Vector(closest.position.x, closest.position.y);
 +
        vector.opacity = 1 - (distance / this.options.maxDistance);
 +
         vector.distance = distance;
 +
        this.particles[index].closest.push(vector);
 +
      }
 
     }
 
     }
 +
  }
 
}
 
}
  
function documentTouchMoveHandler(event) {
+
Canvas.prototype.loop = function() {
    if(event.touches.length == 1) {
+
//  this.clear();
        event.preventDefault();
+
  if(isTouch || isSafari) {
 +
  this.ghost();
 +
  } else {
 +
  this.ghostGradient();
 +
  }   
 +
  if(this.options.maxDistance > 0) {
 +
  this.findClosest();
 +
  }   
 +
  this.draw();
 +
 
 +
  window.requestAnimationFrame(_.bind(this.loop, this));
 +
}
  
        mouseX = event.touches[0].pageX - (window.innerWidth - SCREEN_WIDTH) * .5;;
+
Canvas.prototype.clear = function() {
        mouseY = event.touches[0].pageY - (window.innerHeight - SCREEN_HEIGHT) * .5;
+
  this.ctx.clearRect(0, 0 , this.width, this.height);
    }
+
 
}
 
}
  
function windowResizeHandler() {
+
Canvas.prototype.ghost = function() {
    SCREEN_WIDTH = window.innerWidth;
+
  this.ctx.globalCompositeOperation = "source-over";
     SCREEN_HEIGHT = window.innerHeight;
+
  this.ctx.rect(0, 0 , this.width, this.height);
 +
  if(typeof this.options.background === 'string') {
 +
  this.ctx.fillStyle = "rgb(" + this.options.background + ")";
 +
  } else  {
 +
     this.ctx.fillStyle = "rgb(" + this.options.background[0] + ")";
 +
  }
 
      
 
      
    canvas.width = SCREEN_WIDTH;
+
  this.ctx.fill();
    canvas.height = SCREEN_HEIGHT;
+
 
}
 
}
  
function loop() {
+
Canvas.prototype.ghostGradient = function() {
 +
  var gradient;
 +
 
 +
  if(typeof this.options.background === 'string') {
 +
    this.ctx.fillStyle = 'rgb(' + this.options.background + ')'; 
 +
  } else {
 +
var gradient = this.ctx.createRadialGradient(this.width/2, this.height/2, 0, this.width/2, this.height/2, Math.max(this.width, this.height)/2);
 
      
 
      
     if( mouseIsDown ) {
+
     var length = this.options.background.length;
        RADIUS_SCALE += ( RADIUS_SCALE_MAX - RADIUS_SCALE ) * (0.02);
+
     for(var i = 0; i < length; i++){
     }
+
      gradient.addColorStop((i+1) / length, 'rgb(' + this.options.background[i] + ')');
    else {
+
        RADIUS_SCALE -= ( RADIUS_SCALE - RADIUS_SCALE_MIN ) * (0.02);
+
 
     }
 
     }
 +
    this.ctx.fillStyle = gradient;
 +
  }
 +
 
 +
  this.ctx.globalOpacity = 0.1;
 +
  this.ctx.globalCompositeOperation = "darken";
 +
  this.ctx.fillRect(0, 0 , this.width, this.height);
 +
}
 +
 +
// Draw
 +
Canvas.prototype.draw = function() {
 +
  var index = -1;
 +
  var length = this.particles.length;
 +
  while(++index < length) {
 +
    var point = this.particles[index];
 +
    var color = point.color || this.options.color;
 +
    point.update(this.target, index);
 
      
 
      
     RADIUS_SCALE = Math.min( RADIUS_SCALE, RADIUS_SCALE_MAX );
+
     this.ctx.globalAlpha = 0.3;
 +
    this.ctx.globalCompositeOperation = "lighten";
 +
    this.ctx.fillStyle = 'rgb(' + color + ')';
 +
    this.ctx.beginPath();
 +
    this.ctx.arc(point.position.x, point.position.y, point.size, 0, PI2, false);
 +
    this.ctx.closePath();
 +
    this.ctx.fill();
 
      
 
      
     context.fillStyle = 'rgba(0,0,0,0.05)';
+
     if(this.options.maxDistance > 0) {
        context.fillRect(0, 0, context.canvas.width, context.canvas.height);
+
    this.drawLines(point, color);
 +
    }
 +
  } 
 +
}
 +
 
 +
// Draw connecting lines
 +
Canvas.prototype.drawLines = function (point, color) {
 +
  color = color || this.options.color;
 +
  var index = -1;
 +
  var length = point.closest.length;
 +
  this.ctx.globalAlpha = 0.2;
 +
  this.ctx.globalCompositeOperation = "screen";
 +
  this.ctx.lineCap = 'round';
 +
  while(++index < length) {
 +
    this.ctx.lineWidth = (point.size * 2) *  point.closest[index].opacity;
 +
    this.ctx.strokeStyle = 'rgba(' + color + ', ' + point.closest[index].opacity + ')';
 +
    this.ctx.beginPath();
 +
    this.ctx.moveTo(point.position.x, point.position.y);
 +
    this.ctx.lineTo(point.closest[index].x, point.closest[index].y);
 +
    this.ctx.stroke();
 +
  }
 +
}
 +
 
 +
function Particle(options) {
 +
  options = _.clone(options || {});
 +
  this.options = _.defaults(options, this.options);
 +
 
 +
  this.position = this.shift = new Vector(this.options.x, this.options.y);
 +
 
 +
  this.speed = this.options.speed || 0.01 + Math.random() * 0.04;
 +
 
 +
  this.angle = this.options.angle || 0;
 
      
 
      
    for (i = 0, len = particles.length; i < len; i++) {
+
  if(this.options.color) {
        var particle = particles[i];
+
    var color = this.options.color.split(',');
       
+
  var colorIndex = -1;
        var lp = { x: particle.position.x, y: particle.position.y };
+
    while(++colorIndex < 3) {     
       
+
      color[colorIndex] = Math.round(parseInt(color[colorIndex], 10) + (Math.random()*100)-50);
        // Rotation
+
     
        particle.offset.x += particle.speed;
+
      // Clamp
        particle.offset.y += particle.speed;
+
      color[colorIndex] = Math.min(color[colorIndex], 255);
       
+
      color[colorIndex] = Math.max(color[colorIndex], 0);
        // Follow mouse with some lag
+
        particle.shift.x += ( mouseX - particle.shift.x) * (particle.speed);
+
        particle.shift.y += ( mouseY - particle.shift.y) * (particle.speed);
+
       
+
        // Apply position
+
        particle.position.x = particle.shift.x + Math.cos(i + particle.offset.x) * (particle.orbit*RADIUS_SCALE);
+
        particle.position.y = particle.shift.y + Math.sin(i + particle.offset.y) * (particle.orbit*RADIUS_SCALE);
+
       
+
        // Limit to screen bounds
+
        particle.position.x = Math.max( Math.min( particle.position.x, SCREEN_WIDTH ), 0 );
+
        particle.position.y = Math.max( Math.min( particle.position.y, SCREEN_HEIGHT ), 0 );
+
       
+
        particle.size += ( particle.targetSize - particle.size ) * 0.05;
+
       
+
        if( Math.round( particle.size ) == Math.round( particle.targetSize ) ) {
+
            particle.targetSize = 1 + Math.random() * 7;
+
        }
+
       
+
        context.beginPath();
+
        context.fillStyle = particle.fillColor;
+
        context.strokeStyle = particle.fillColor;
+
        context.lineWidth = particle.size;
+
        context.moveTo(lp.x, lp.y);
+
        context.lineTo(particle.position.x, particle.position.y);
+
        context.stroke();
+
        context.arc(particle.position.x, particle.position.y, particle.size/2, 0, Math.PI*2, true);
+
        context.fill();
+
 
     }
 
     }
 +
    this.color = color.join(', ');
 +
  }
 +
 
 +
  // Size
 +
  this.options.size = this.options.size || 7;
 +
  this.size = 1 + Math.random() * this.options.size;
 +
  this.targetSize = this.options.targetSize || this.options.size;
 +
 
 +
  this.orbit = this.options.radius * 0.5 + (this.options.radius * 0.5 * Math.random());
 
}
 
}
  
window.onload = init;
+
Particle.prototype.update = function(target, index) {
 +
  this.angle += this.speed;
 +
 
 +
  this.shift.x += (target.x - this.shift.x) * this.speed;
 +
  this.shift.y += (target.y - this.shift.y) * this.speed;
 +
 
 +
  this.position.x = this.shift.x + Math.cos(index + this.angle) * this.orbit;
 +
  this.position.y = this.shift.y + Math.sin(index + this.angle) * this.orbit;
 +
 
 +
  if(!isSafari) {
 +
    this.size += (this.targetSize - this.size) * 0.03;
 +
 
 +
    if(Math.round(this.size) === Math.round(this.targetSize)) {
 +
      this.targetSize = 1 + Math.random() * this.options.size;
 +
    }
 +
  }
 +
}
 +
 
 +
function Vector(x, y) {
 +
  this.x = x || 0;
 +
  this.y = y || 0;
 +
}
 +
 
 +
Vector.prototype.distanceTo = function(vector, abs) {
 +
  var distance = Math.sqrt(Math.pow(this.x - vector.x, 2) + Math.pow(this.y - vector.y, 2));
 +
  return abs || false ? Math.abs(distance) : distance;
 +
};
 +
 
 +
new Canvas({
 +
  el: document.getElementById('canvas'),
 +
 
 +
  count: 25,
 +
  speed: 0.3,
 +
  radius: 6,
 +
  width: function() { return window.innerWidth; },
 +
  height: function() { return window.innerHeight; },
 +
  size: 15,
 +
  color: '30, 180, 1',
 +
  maxDistance: 100,
 +
  background: ['1, 62, 66', '1, 40, 60']
 +
});
 
</script>
 
</script>
  

Revision as of 13:52, 25 September 2018

Menu
Alternative Roots

Welcome to Alternative Roots

Alternative Roots
Newcastle iGEM

Alternative Roots

PROJECT OVERVIEW

1 / 15
All soils have a unique, diverse microbial community
2 / 15
Within each microbial community there are many microbes with useful abilities
3 / 15
The bacterium Pseudomonas fluorescens lives in plant roots and helps them to grow
4 / 15
By introducing new genes for our Pseudomonas to express we can influence the microbial community
5 / 15
We can attract or repel certain species in any way desired
6 / 15
In our case, we use flavonoids to attract free-living nitrogen fixers, that convert nitrogen gas to nitrate for plant growth
7 / 15
P. fluorescens has many other abilities, including the ability to repel parasitic nematode worms [1], produce antifungals and insecticides [2] and induce plant stress tolerance [3]

Our Sponsors

Newcastle iGEM is proud to be sponsored by:

The iGEM Foundation is an independent, non-profit organization dedicated to the advancement of synthetic biology, education and competition, and the development of an open community and collaboration. This is done by fostering an open, cooperative community and friendly competition.

Author image

iGEMers are building a better world by solving problems with the help of synthetic biology. We inspire responsible innovation through our efforts in biosafety, biosecurity and public outreach.

Author image

This global network is leading the field, taking what they learned in the competition and expanding it to continue to build a better world.

Author image

Contact Us

Reach out for a collaboration or just say hello

Get Involved


We are always happy to hear from individuals, groups or organisations that would like to support our project. If you wish to discuss a collaboration, sponsorship or if you just want to learn more about the project, please get in touch using the contact details on the right. Alternatively, if you would like to donate a small amount to fund our project, you can do so through Experiment.com - an online platform for discovering, funding, and sharing scientific research.

Any support is greatly appreciated and funds raised will be used in all areas of the iGEM project - such as lab equipment, human practices research, merchandise and travel to jamboree in Boston, USA.

Contact Info

Where to Find Us

Devonshire Building
Newcastle University
Newcastle upon Tyne
NE1 7RU

Email Us At

igem.team@newcastle.ac.uk