mirror of
https://github.com/opentffoundation/opentf.git
synced 2026-01-06 16:00:32 -05:00
Previous to this commit, the Chainable class which is responsible for iterating on the sequence of events in the intro Terraform animation, was using setTimeout and thus could result in very messed up race conditions when triggering physics changes. This commit attaches the .wait timers to the Engine.render loop which should enable everything to stay in sync.
389 lines
7.4 KiB
JavaScript
389 lines
7.4 KiB
JavaScript
(function(
|
|
Base,
|
|
Vector,
|
|
Logo,
|
|
Grid,
|
|
Chainable
|
|
){
|
|
|
|
var sqrt, pow, Engine;
|
|
|
|
if (!window.requestAnimationFrame) {
|
|
window.requestAnimationFrame = (function(){
|
|
return window.requestAnimationFrame ||
|
|
window.webkitRequestAnimationFrame ||
|
|
window.mozRequestAnimationFrame ||
|
|
function( callback ){
|
|
window.setTimeout(callback, 1000 / 60);
|
|
};
|
|
})();
|
|
}
|
|
|
|
sqrt = Math.sqrt;
|
|
pow = Math.pow;
|
|
|
|
Engine = Base.extend({
|
|
|
|
scale: window.devicePixelRatio || 1,
|
|
// scale:1,
|
|
|
|
shapes : [],
|
|
particles : [],
|
|
particlesA : [],
|
|
particlesB : [],
|
|
|
|
_deferredParticles: [],
|
|
|
|
ticks: [],
|
|
|
|
starGeneratorRate: 600,
|
|
|
|
mouse: {
|
|
x: -9999,
|
|
y: -9999
|
|
},
|
|
|
|
constructor: function(canvas, background, tagLine){
|
|
this.canvas = canvas;
|
|
this.background = background;
|
|
this.tagLine = tagLine;
|
|
|
|
if (!this.canvas.getContext) {
|
|
return null;
|
|
}
|
|
|
|
this.context = this.canvas.getContext('2d');
|
|
|
|
this.setupEvents();
|
|
this.setupStarfield();
|
|
this.setupTessellation();
|
|
this.setupMisc();
|
|
|
|
this.startEngine();
|
|
},
|
|
|
|
startEngine: function(){
|
|
var parent = this.canvas.parentNode;
|
|
|
|
this.background.className += ' show';
|
|
this.canvas.style.opacity = 1;
|
|
|
|
// We have to pass the engine into Chainable to
|
|
// enable the timers to properly attach to the
|
|
// run/render loop
|
|
new Chainable(this)
|
|
.wait(1000)
|
|
.then(function(){
|
|
this.starGeneratorRate = 200;
|
|
}, this)
|
|
.wait(500)
|
|
.then(function(){
|
|
parent.className += ' state-one';
|
|
})
|
|
.wait(150)
|
|
.then(function(){
|
|
parent.className += ' state-two';
|
|
})
|
|
.wait(150)
|
|
.then(function(){
|
|
parent.className += ' state-three';
|
|
})
|
|
.wait(500)
|
|
.then(function(){
|
|
parent.className += ' state-four';
|
|
})
|
|
.wait(100)
|
|
.then(function(){
|
|
this.showShapes = true;
|
|
}, this)
|
|
.wait(1000)
|
|
.then(function(){
|
|
this.logo.startBreathing();
|
|
this.showGrid = true;
|
|
}, this)
|
|
.wait(1000)
|
|
.then(function(){
|
|
this.typewriter.start();
|
|
}, this);
|
|
|
|
this.render();
|
|
},
|
|
|
|
|
|
setupMisc: function(){
|
|
this.last = Date.now() / 1000;
|
|
this.render = this.render.bind(this);
|
|
|
|
this.typewriter = new Engine.Typewriter(this.tagLine);
|
|
},
|
|
|
|
setupEvents: function(){
|
|
this.resize = this.resize.bind(this);
|
|
this.resize();
|
|
window.addEventListener('resize', this.resize, false);
|
|
|
|
this._handleScroll = this._handleScroll.bind(this);
|
|
this._handleScroll();
|
|
window.addEventListener('scroll', this._handleScroll, false);
|
|
|
|
this._handleMouseCoords = this._handleMouseCoords.bind(this);
|
|
window.addEventListener('mousemove', this._handleMouseCoords, false);
|
|
},
|
|
|
|
setupStarfield: function(){
|
|
this.particles = [];
|
|
// this.generateParticles(50, true);
|
|
this.generateParticles(400);
|
|
},
|
|
|
|
setupTessellation: function(canvas){
|
|
var size, offset;
|
|
this.shapes = [];
|
|
if (window.innerWidth < 570) {
|
|
size = 300;
|
|
offset = 0;
|
|
} else {
|
|
size = 360;
|
|
offset = 40;
|
|
}
|
|
|
|
this.logo = new Engine.Shape(
|
|
-(size / 2),
|
|
-(size / 2 + offset),
|
|
size,
|
|
size,
|
|
Logo.points,
|
|
Logo.polygons
|
|
);
|
|
|
|
this.grid = new Engine.Shape.Puller(this.width, this.height, Grid);
|
|
},
|
|
|
|
|
|
getAverageTickTime: function(){
|
|
var sum = 0, s;
|
|
|
|
for (s = 0; s < this.ticks.length; s++) {
|
|
sum += this.ticks[s];
|
|
}
|
|
|
|
window.console.log('Average Tick Time:', sum / this.ticks.length);
|
|
},
|
|
|
|
getLongestTick: function(){
|
|
var max = 0, index, s;
|
|
|
|
for (s = 0; s < this.ticks.length; s++) {
|
|
if (this.ticks[s] > max) {
|
|
max = this.ticks[s];
|
|
index = s;
|
|
}
|
|
}
|
|
|
|
window.console.log('Max tick was:', max, 'at index:', index);
|
|
},
|
|
|
|
render: function(){
|
|
var scale = this.scale, p, particle, index;
|
|
|
|
if (this.paused) {
|
|
return;
|
|
}
|
|
|
|
if (this.scrollY > this.height) {
|
|
window.requestAnimationFrame(this.render);
|
|
return;
|
|
}
|
|
|
|
this.context.clearRect(
|
|
-(this.width / 2) * scale,
|
|
-(this.height / 2) * scale,
|
|
this.width * scale,
|
|
this.height * scale
|
|
);
|
|
|
|
this.now = Date.now() / 1000;
|
|
this.tick = Math.min(this.now - this.last, 0.017);
|
|
|
|
// We must attach the chainable timer to the engine
|
|
// run/render loop or else things can get pretty
|
|
// out of wack
|
|
if (this.updateChainTimer) {
|
|
this.updateChainTimer(this.tick);
|
|
}
|
|
|
|
// Update all particles... may need to be optimized
|
|
for (p = 0; p < this.particles.length; p++) {
|
|
this.particles[p].update(this);
|
|
}
|
|
|
|
// Batch render particles based on color
|
|
// to prevent unneeded context state change
|
|
this.context.fillStyle = '#8750c2';
|
|
for (p = 0; p < this.particlesA.length; p++) {
|
|
particle = this.particlesA[p];
|
|
|
|
if (particle.radius < 0.25) {
|
|
continue;
|
|
}
|
|
this.context.fillRect(
|
|
particle.pos.x * scale >> 0,
|
|
particle.pos.y * scale >> 0,
|
|
particle.radius * scale,
|
|
particle.radius * scale
|
|
);
|
|
}
|
|
|
|
this.context.fillStyle = '#b976ff';
|
|
for (p = 0; p < this.particlesB.length; p++) {
|
|
particle = this.particlesB[p];
|
|
|
|
if (particle.radius < 0.25) {
|
|
continue;
|
|
}
|
|
this.context.fillRect(
|
|
particle.pos.x * scale >> 0,
|
|
particle.pos.y * scale >> 0,
|
|
particle.radius * scale,
|
|
particle.radius * scale
|
|
);
|
|
}
|
|
|
|
this.particlesA.length = 0;
|
|
this.particlesB.length = 0;
|
|
|
|
// Remove destroyed particles
|
|
for (p = 0; p < this._deferredParticles.length; p++) {
|
|
index = this.particles.indexOf(this._deferredParticles.pop());
|
|
if (index >= 0) {
|
|
this.particles.splice(index, 1);
|
|
}
|
|
}
|
|
|
|
if (this.showGrid) {
|
|
this.grid
|
|
.update(this)
|
|
.draw(this.context, scale, this);
|
|
}
|
|
|
|
if (this.showShapes) {
|
|
this.logo
|
|
.update(this)
|
|
.draw(this.context, scale, this);
|
|
}
|
|
|
|
this.typewriter.update(this);
|
|
|
|
this.last = this.now;
|
|
|
|
this.generateParticles(this.starGeneratorRate * this.tick >> 0);
|
|
|
|
window.requestAnimationFrame(this.render);
|
|
},
|
|
|
|
generateParticles: function(num, fixed){
|
|
var p;
|
|
|
|
for (p = 0; p < num; p++) {
|
|
if (fixed) {
|
|
this.particles.push(new Engine.Particle.Fixed(this.width, this.height));
|
|
} else {
|
|
this.particles.push(new Engine.Particle(this.width, this.height));
|
|
}
|
|
}
|
|
},
|
|
|
|
resize: function(){
|
|
var scale = this.scale,
|
|
size, offset;
|
|
|
|
if (window.innerWidth < 570) {
|
|
this.height = 560;
|
|
} else {
|
|
this.height = 700;
|
|
}
|
|
|
|
this.width = window.innerWidth;
|
|
|
|
this.canvas.width = this.width * scale;
|
|
this.canvas.height = this.height * scale;
|
|
|
|
this.context.translate(
|
|
this.width / 2 * scale >> 0,
|
|
this.height / 2 * scale >> 0
|
|
);
|
|
this.context.lineJoin = 'bevel';
|
|
|
|
if (this.grid) {
|
|
this.grid.resize(this.width, this.height);
|
|
}
|
|
|
|
if (this.logo) {
|
|
if (this.height === 560) {
|
|
size = 300;
|
|
offset = 0;
|
|
} else {
|
|
size = 360;
|
|
offset = 40;
|
|
}
|
|
this.logo.resize(size, offset);
|
|
}
|
|
},
|
|
|
|
_handleMouseCoords: function(event){
|
|
this.mouse.x = event.pageX;
|
|
this.mouse.y = event.pageY;
|
|
},
|
|
|
|
_handleScroll: function(){
|
|
this.scrollY = window.scrollY;
|
|
},
|
|
|
|
pause: function(){
|
|
this.paused = true;
|
|
},
|
|
|
|
resume: function(){
|
|
if (!this.paused) {
|
|
return;
|
|
}
|
|
this.paused = false;
|
|
this.render();
|
|
},
|
|
|
|
getSnapshot: function(){
|
|
window.open(this.canvas.toDataURL('image/png'));
|
|
}
|
|
|
|
});
|
|
|
|
Engine.map = function(val, istart, istop, ostart, ostop) {
|
|
return ostart + (ostop - ostart) * ((val - istart) / (istop - istart));
|
|
};
|
|
|
|
Engine.getRandomFloat = function(min, max) {
|
|
return Math.random() * (max - min) + min;
|
|
};
|
|
|
|
Engine.getRandomInt = function(min, max) {
|
|
return Math.floor(Math.random() * (max - min + 1) + min);
|
|
};
|
|
|
|
Engine.clone = function(ref) {
|
|
var clone = {}, key;
|
|
for (key in ref) {
|
|
clone[key] = ref[key];
|
|
}
|
|
return clone;
|
|
};
|
|
|
|
window.Engine = Engine;
|
|
|
|
})(
|
|
window.Base,
|
|
window.Vector,
|
|
window.Logo,
|
|
window.Grid,
|
|
window.Chainable
|
|
);
|