github.com/chalford/terraform@v0.3.7-0.20150113080010-a78c69a8c81f/website/source/assets/javascripts/app/Engine.js (about)

     1  (function(
     2  	Base,
     3  	Vector,
     4  	Logo,
     5  	Grid,
     6  	Chainable
     7  ){
     8  
     9  var sqrt, pow, Engine;
    10  
    11  if (!window.requestAnimationFrame) {
    12  	window.requestAnimationFrame = (function(){
    13  		return  window.requestAnimationFrame   ||
    14  			window.webkitRequestAnimationFrame ||
    15  			window.mozRequestAnimationFrame    ||
    16  			function( callback ){
    17  				window.setTimeout(callback, 1000 / 60);
    18  			};
    19  	})();
    20  }
    21  
    22  sqrt = Math.sqrt;
    23  pow  = Math.pow;
    24  
    25  Engine = Base.extend({
    26  
    27  	scale: window.devicePixelRatio || 1,
    28  	// scale:1,
    29  
    30  	shapes     : [],
    31  	particles  : [],
    32  	particlesA : [],
    33  	particlesB : [],
    34  
    35  	_deferredParticles: [],
    36  
    37  	ticks: [],
    38  
    39  	starGeneratorRate: 600,
    40  
    41  	mouse: {
    42  		x: -9999,
    43  		y: -9999
    44  	},
    45  
    46  	constructor: function(canvas, background, tagLine){
    47  		this.canvas     = canvas;
    48  		this.background = background;
    49  		this.tagLine    = tagLine;
    50  
    51  		if (!this.canvas.getContext) {
    52  			return null;
    53  		}
    54  
    55  		this.context = this.canvas.getContext('2d');
    56  
    57  		this.setupEvents();
    58  		this.setupStarfield();
    59  		this.setupTessellation();
    60  		this.setupMisc();
    61  
    62  		this.startEngine();
    63  	},
    64  
    65  	startEngine: function(){
    66  		var parent = this.canvas.parentNode;
    67  
    68  		this.background.className += ' show';
    69  		this.canvas.style.opacity = 1;
    70  
    71  		new Chainable()
    72  			.wait(1000)
    73  			.then(function(){
    74  				this.starGeneratorRate = 200;
    75  			}, this)
    76  			.wait(500)
    77  			.then(function(){
    78  				parent.className += ' state-one';
    79  			})
    80  			.wait(150)
    81  			.then(function(){
    82  				parent.className += ' state-two';
    83  			})
    84  			.wait(150)
    85  			.then(function(){
    86  				parent.className += ' state-three';
    87  			})
    88  			.wait(500)
    89  			.then(function(){
    90  				parent.className += ' state-four';
    91  			})
    92  			.wait(100)
    93  			.then(function(){
    94  				this.showShapes = true;
    95  			}, this)
    96  			.wait(1000)
    97  			.then(function(){
    98  				this.logo.startBreathing();
    99  				this.showGrid = true;
   100  			}, this)
   101  			.wait(1000)
   102  			.then(function(){
   103  				this.typewriter.start();
   104  			}, this);
   105  
   106  		this.render();
   107  	},
   108  
   109  
   110  	setupMisc: function(){
   111  		this.last = Date.now() / 1000;
   112  		this.render = this.render.bind(this);
   113  
   114  		this.typewriter = new Engine.Typewriter(this.tagLine);
   115  	},
   116  
   117  	setupEvents: function(){
   118  		this.resize = this.resize.bind(this);
   119  		this.resize();
   120  		window.addEventListener('resize', this.resize, false);
   121  
   122  		this._handleScroll = this._handleScroll.bind(this);
   123  		this._handleScroll();
   124  		window.addEventListener('scroll', this._handleScroll, false);
   125  
   126  		this._handleMouseCoords = this._handleMouseCoords.bind(this);
   127  		window.addEventListener('mousemove', this._handleMouseCoords, false);
   128  	},
   129  
   130  	setupStarfield: function(){
   131  		this.particles = [];
   132  		// this.generateParticles(50, true);
   133  		this.generateParticles(400);
   134  	},
   135  
   136  	setupTessellation: function(canvas){
   137  		var size, offset;
   138  		this.shapes = [];
   139  		if (window.innerWidth < 570) {
   140  			size = 300;
   141  			offset = 0;
   142  		} else {
   143  			size = 360;
   144  			offset = 40;
   145  		}
   146  
   147  		this.logo = new Engine.Shape(
   148  			-(size / 2),
   149  			-(size / 2 + offset),
   150  			size,
   151  			size,
   152  			Logo.points,
   153  			Logo.polygons
   154  		);
   155  
   156  		this.grid = new Engine.Shape.Puller(this.width, this.height, Grid);
   157  	},
   158  
   159  
   160  	getAverageTickTime: function(){
   161  		var sum = 0, s;
   162  
   163  		for (s = 0; s < this.ticks.length; s++) {
   164  			sum += this.ticks[s];
   165  		}
   166  
   167  		window.console.log('Average Tick Time:', sum / this.ticks.length);
   168  	},
   169  
   170  	getLongestTick: function(){
   171  		var max = 0, index, s;
   172  
   173  		for (s = 0; s < this.ticks.length; s++) {
   174  			if (this.ticks[s] > max) {
   175  				max = this.ticks[s];
   176  				index = s;
   177  			}
   178  		}
   179  
   180  		window.console.log('Max tick was:', max, 'at index:', index);
   181  	},
   182  
   183  	render: function(){
   184  		var scale = this.scale, p, particle, index;
   185  
   186  		if (this.paused) {
   187  			return;
   188  		}
   189  
   190  		if (this.scrollY > this.height) {
   191  			window.requestAnimationFrame(this.render);
   192  			return;
   193  		}
   194  
   195  		this.context.clearRect(
   196  			-(this.width  / 2) * scale,
   197  			-(this.height / 2) * scale,
   198  			this.width  * scale,
   199  			this.height * scale
   200  		);
   201  
   202  		this.now = Date.now() / 1000;
   203  		this.tick = Math.min(this.now - this.last, 0.017);
   204  
   205  		// Update all particles... may need to be optimized
   206  		for (p = 0; p < this.particles.length; p++) {
   207  			this.particles[p].update(this);
   208  		}
   209  
   210  		// Batch render particles based on color
   211  		// to prevent unneeded context state change
   212  		this.context.fillStyle = '#8750c2';
   213  		for (p = 0; p < this.particlesA.length; p++) {
   214  			particle = this.particlesA[p];
   215  
   216  			if (particle.radius < 0.25) {
   217  				continue;
   218  			}
   219  			this.context.fillRect(
   220  				particle.pos.x * scale >> 0,
   221  				particle.pos.y * scale >> 0,
   222  				particle.radius * scale,
   223  				particle.radius * scale
   224  			);
   225  		}
   226  
   227  		this.context.fillStyle = '#b976ff';
   228  		for (p = 0; p < this.particlesB.length; p++) {
   229  			particle = this.particlesB[p];
   230  
   231  			if (particle.radius < 0.25) {
   232  				continue;
   233  			}
   234  			this.context.fillRect(
   235  				particle.pos.x * scale >> 0,
   236  				particle.pos.y * scale >> 0,
   237  				particle.radius * scale,
   238  				particle.radius * scale
   239  			);
   240  		}
   241  
   242  		this.particlesA.length = 0;
   243  		this.particlesB.length = 0;
   244  
   245  		// Remove destroyed particles
   246  		for (p = 0; p < this._deferredParticles.length; p++) {
   247  			index = this.particles.indexOf(this._deferredParticles.pop());
   248  			if (index >= 0) {
   249  				this.particles.splice(index, 1);
   250  			}
   251  		}
   252  
   253  		if (this.showGrid) {
   254  			this.grid
   255  				.update(this)
   256  				.draw(this.context, scale, this);
   257  		}
   258  
   259  		if (this.showShapes) {
   260  			this.logo
   261  				.update(this)
   262  				.draw(this.context, scale, this);
   263  		}
   264  
   265  		this.typewriter.update(this);
   266  
   267  		this.last = this.now;
   268  
   269  		this.generateParticles(this.starGeneratorRate * this.tick >> 0);
   270  
   271  		window.requestAnimationFrame(this.render);
   272  	},
   273  
   274  	generateParticles: function(num, fixed){
   275  		var p;
   276  
   277  		for (p = 0; p < num; p++) {
   278  			if (fixed) {
   279  				this.particles.push(new Engine.Particle.Fixed(this.width, this.height));
   280  			} else {
   281  				this.particles.push(new Engine.Particle(this.width, this.height));
   282  			}
   283  		}
   284  	},
   285  
   286  	resize: function(){
   287  		var scale = this.scale,
   288  			size, offset;
   289  
   290  		if (window.innerWidth < 570) {
   291  			this.height = 560;
   292  		} else {
   293  			this.height = 700;
   294  		}
   295  
   296  		this.width  = window.innerWidth;
   297  
   298  		this.canvas.width  = this.width  * scale;
   299  		this.canvas.height = this.height * scale;
   300  
   301  		this.context.translate(
   302  			this.width  / 2 * scale >> 0,
   303  			this.height / 2 * scale >> 0
   304  		);
   305  		this.context.lineJoin = 'bevel';
   306  
   307  		if (this.grid) {
   308  			this.grid.resize(this.width, this.height);
   309  		}
   310  
   311  		if (this.logo) {
   312  			if (this.height === 560) {
   313  				size = 300;
   314  				offset = 0;
   315  			} else {
   316  				size = 360;
   317  				offset = 40;
   318  			}
   319  			this.logo.resize(size, offset);
   320  		}
   321  	},
   322  
   323  	_handleMouseCoords: function(event){
   324  		this.mouse.x = event.pageX;
   325  		this.mouse.y = event.pageY;
   326  	},
   327  
   328  	_handleScroll: function(){
   329  		this.scrollY = window.scrollY;
   330  	},
   331  
   332  	pause: function(){
   333  		this.paused = true;
   334  	},
   335  
   336  	resume: function(){
   337  		if (!this.paused) {
   338  			return;
   339  		}
   340  		this.paused = false;
   341  		this.render();
   342  	},
   343  
   344  	getSnapshot: function(){
   345  		window.open(this.canvas.toDataURL('image/png'));
   346  	}
   347  
   348  });
   349  
   350  Engine.map = function(val, istart, istop, ostart, ostop) {
   351  	return ostart + (ostop - ostart) * ((val - istart) / (istop - istart));
   352  };
   353  
   354  Engine.getRandomFloat = function(min, max) {
   355  	return Math.random() * (max - min) + min;
   356  };
   357  
   358  Engine.getRandomInt = function(min, max) {
   359  	return Math.floor(Math.random() * (max - min + 1) + min);
   360  };
   361  
   362  Engine.clone = function(ref) {
   363  	var clone = {}, key;
   364  	for (key in ref) {
   365  		clone[key] = ref[key];
   366  	}
   367  	return clone;
   368  };
   369  
   370  window.Engine = Engine;
   371  
   372  })(
   373  	window.Base,
   374  	window.Vector,
   375  	window.Logo,
   376  	window.Grid,
   377  	window.Chainable
   378  );