github.com/nicgrayson/terraform@v0.4.3-0.20150415203910-c4de50829380/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 // We have to pass the engine into Chainable to 72 // enable the timers to properly attach to the 73 // run/render loop 74 new Chainable(this) 75 .wait(1000) 76 .then(function(){ 77 this.starGeneratorRate = 200; 78 }, this) 79 .wait(500) 80 .then(function(){ 81 parent.className += ' state-one'; 82 }) 83 .wait(150) 84 .then(function(){ 85 parent.className += ' state-two'; 86 }) 87 .wait(150) 88 .then(function(){ 89 parent.className += ' state-three'; 90 }) 91 .wait(500) 92 .then(function(){ 93 parent.className += ' state-four'; 94 }) 95 .wait(100) 96 .then(function(){ 97 this.showShapes = true; 98 }, this) 99 .wait(1000) 100 .then(function(){ 101 this.logo.startBreathing(); 102 this.showGrid = true; 103 }, this) 104 .wait(1000) 105 .then(function(){ 106 this.typewriter.start(); 107 }, this); 108 109 this.render(); 110 }, 111 112 113 setupMisc: function(){ 114 this.last = Date.now() / 1000; 115 this.render = this.render.bind(this); 116 117 this.typewriter = new Engine.Typewriter(this.tagLine); 118 }, 119 120 setupEvents: function(){ 121 this.resize = this.resize.bind(this); 122 this.resize(); 123 window.addEventListener('resize', this.resize, false); 124 125 this._handleScroll = this._handleScroll.bind(this); 126 this._handleScroll(); 127 window.addEventListener('scroll', this._handleScroll, false); 128 129 this._handleMouseCoords = this._handleMouseCoords.bind(this); 130 window.addEventListener('mousemove', this._handleMouseCoords, false); 131 }, 132 133 setupStarfield: function(){ 134 this.particles = []; 135 // this.generateParticles(50, true); 136 this.generateParticles(400); 137 }, 138 139 setupTessellation: function(canvas){ 140 var size, offset; 141 this.shapes = []; 142 if (window.innerWidth < 570) { 143 size = 300; 144 offset = 0; 145 } else { 146 size = 360; 147 offset = 40; 148 } 149 150 this.logo = new Engine.Shape( 151 -(size / 2), 152 -(size / 2 + offset), 153 size, 154 size, 155 Logo.points, 156 Logo.polygons 157 ); 158 159 this.grid = new Engine.Shape.Puller(this.width, this.height, Grid); 160 }, 161 162 163 getAverageTickTime: function(){ 164 var sum = 0, s; 165 166 for (s = 0; s < this.ticks.length; s++) { 167 sum += this.ticks[s]; 168 } 169 170 window.console.log('Average Tick Time:', sum / this.ticks.length); 171 }, 172 173 getLongestTick: function(){ 174 var max = 0, index, s; 175 176 for (s = 0; s < this.ticks.length; s++) { 177 if (this.ticks[s] > max) { 178 max = this.ticks[s]; 179 index = s; 180 } 181 } 182 183 window.console.log('Max tick was:', max, 'at index:', index); 184 }, 185 186 render: function(){ 187 var scale = this.scale, p, particle, index; 188 189 if (this.paused) { 190 return; 191 } 192 193 if (this.scrollY > this.height) { 194 window.requestAnimationFrame(this.render); 195 return; 196 } 197 198 this.context.clearRect( 199 -(this.width / 2) * scale, 200 -(this.height / 2) * scale, 201 this.width * scale, 202 this.height * scale 203 ); 204 205 this.now = Date.now() / 1000; 206 this.tick = Math.min(this.now - this.last, 0.017); 207 208 // We must attach the chainable timer to the engine 209 // run/render loop or else things can get pretty 210 // out of wack 211 if (this.updateChainTimer) { 212 this.updateChainTimer(this.tick); 213 } 214 215 // Update all particles... may need to be optimized 216 for (p = 0; p < this.particles.length; p++) { 217 this.particles[p].update(this); 218 } 219 220 // Batch render particles based on color 221 // to prevent unneeded context state change 222 this.context.fillStyle = '#8750c2'; 223 for (p = 0; p < this.particlesA.length; p++) { 224 particle = this.particlesA[p]; 225 226 if (particle.radius < 0.25) { 227 continue; 228 } 229 this.context.fillRect( 230 particle.pos.x * scale >> 0, 231 particle.pos.y * scale >> 0, 232 particle.radius * scale, 233 particle.radius * scale 234 ); 235 } 236 237 this.context.fillStyle = '#b976ff'; 238 for (p = 0; p < this.particlesB.length; p++) { 239 particle = this.particlesB[p]; 240 241 if (particle.radius < 0.25) { 242 continue; 243 } 244 this.context.fillRect( 245 particle.pos.x * scale >> 0, 246 particle.pos.y * scale >> 0, 247 particle.radius * scale, 248 particle.radius * scale 249 ); 250 } 251 252 this.particlesA.length = 0; 253 this.particlesB.length = 0; 254 255 // Remove destroyed particles 256 for (p = 0; p < this._deferredParticles.length; p++) { 257 index = this.particles.indexOf(this._deferredParticles.pop()); 258 if (index >= 0) { 259 this.particles.splice(index, 1); 260 } 261 } 262 263 if (this.showGrid) { 264 this.grid 265 .update(this) 266 .draw(this.context, scale, this); 267 } 268 269 if (this.showShapes) { 270 this.logo 271 .update(this) 272 .draw(this.context, scale, this); 273 } 274 275 this.typewriter.update(this); 276 277 this.last = this.now; 278 279 this.generateParticles(this.starGeneratorRate * this.tick >> 0); 280 281 window.requestAnimationFrame(this.render); 282 }, 283 284 generateParticles: function(num, fixed){ 285 var p; 286 287 for (p = 0; p < num; p++) { 288 if (fixed) { 289 this.particles.push(new Engine.Particle.Fixed(this.width, this.height)); 290 } else { 291 this.particles.push(new Engine.Particle(this.width, this.height)); 292 } 293 } 294 }, 295 296 resize: function(){ 297 var scale = this.scale, 298 size, offset; 299 300 if (window.innerWidth < 570) { 301 this.height = 560; 302 } else { 303 this.height = 700; 304 } 305 306 this.width = window.innerWidth; 307 308 this.canvas.width = this.width * scale; 309 this.canvas.height = this.height * scale; 310 311 this.context.translate( 312 this.width / 2 * scale >> 0, 313 this.height / 2 * scale >> 0 314 ); 315 this.context.lineJoin = 'bevel'; 316 317 if (this.grid) { 318 this.grid.resize(this.width, this.height); 319 } 320 321 if (this.logo) { 322 if (this.height === 560) { 323 size = 300; 324 offset = 0; 325 } else { 326 size = 360; 327 offset = 40; 328 } 329 this.logo.resize(size, offset); 330 } 331 }, 332 333 _handleMouseCoords: function(event){ 334 this.mouse.x = event.pageX; 335 this.mouse.y = event.pageY; 336 }, 337 338 _handleScroll: function(){ 339 this.scrollY = window.scrollY; 340 }, 341 342 pause: function(){ 343 this.paused = true; 344 }, 345 346 resume: function(){ 347 if (!this.paused) { 348 return; 349 } 350 this.paused = false; 351 this.render(); 352 }, 353 354 getSnapshot: function(){ 355 window.open(this.canvas.toDataURL('image/png')); 356 } 357 358 }); 359 360 Engine.map = function(val, istart, istop, ostart, ostop) { 361 return ostart + (ostop - ostart) * ((val - istart) / (istop - istart)); 362 }; 363 364 Engine.getRandomFloat = function(min, max) { 365 return Math.random() * (max - min) + min; 366 }; 367 368 Engine.getRandomInt = function(min, max) { 369 return Math.floor(Math.random() * (max - min + 1) + min); 370 }; 371 372 Engine.clone = function(ref) { 373 var clone = {}, key; 374 for (key in ref) { 375 clone[key] = ref[key]; 376 } 377 return clone; 378 }; 379 380 window.Engine = Engine; 381 382 })( 383 window.Base, 384 window.Vector, 385 window.Logo, 386 window.Grid, 387 window.Chainable 388 );