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 );