/** * Particle animation class. * * @copyright Dennis Eichhorn * @license OMS License 2.2 * @version 1.0.0 * @since 1.0.0 */ (function (jsOMS) { 'use strict'; /** @namespace jsOMS.Animation.Canvas */ jsOMS.Autoloader.defineNamespace('jsOMS.Animation.Canvas'); jsOMS.Animation.Canvas.ParticleAnimation = class { /** * * @param {Object} canvas Canvas * * @constructor * * @since 1.0.0 */ constructor (canvas) { this.canvas = canvas; this.ctx = canvas.getContext('2d'); /** global: screen */ this.width = screen.width; this.height = screen.height; this.canvas.width = this.width; this.canvas.height = this.height; this.particles = []; this.maxDistance = 70; this.gravitation = 10000000; for (let i = 0; i < this.width * this.height / 3000; ++i) { this.particles.push(new jsOMS.Animation.Canvas.Particle( Math.random() * this.width, Math.random() * this.height, -1 + Math.random() * 2, -1 + Math.random() * 2, 1 )); } }; /** * Draw everything * * @param {Object} self Object reference for self invoke * * @return {void} * * @method * * @since 1.0.0 */ draw (self) { self = typeof self !== 'undefined' ? self : this; self.invalidate(); const length = self.particles.length; for (let i = 0; i < length; ++i) { self.particles[i].draw(self.ctx); } self.updateParticles(); jsOMS.Animation.Animation.requestAnimationFrame.call(window, function () { self.draw(self); }); }; /** * Invalidate/clean canvas * * @return {void} * * @method * * @since 1.0.0 */ invalidate () { this.ctx.clearRect(0, 0, this.width, this.height); }; /** * Update particle * * @return {void} * * @method * * @since 1.0.0 */ updateParticles () { let particle; let pos; let vel; let radius; const length = this.particles.length; for (let i = 0; i < length; ++i) { particle = this.particles[i]; pos = particle.getPosition(); vel = particle.getVelocity(); radius = particle.getRadius(); pos.x += vel.x; pos.y += vel.y; // Change on wall hit if (pos.x + radius > this.width) { pos.x = radius; } else if (pos.x - radius < 0) { pos.x = this.width - radius; } if (pos.y + radius > this.height) { pos.y = radius; } else if (pos.y - radius < 0) { pos.y = this.height - radius; } particle.setPosition(pos.x, pos.y); particle.setVelocity(vel.x, vel.y); for (let j = i + 1; j < length; ++j) { this.updateDistance(particle, this.particles[j]); } } }; /** * Handle distance between particles * * @param {Particle} p1 Particle * @param {Particle} p2 Particle * * @return {void} * * @method * * @since 1.0.0 */ updateDistance (p1, p2) { const pos1 = p1.getPosition(); const pos2 = p2.getPosition(); const dx = pos1.x - pos2.x; const dy = pos1.y - pos2.y; const dist = Math.sqrt(dx * dx + dy * dy); const vel1 = p1.getVelocity(); const vel2 = p2.getVelocity(); // Draw line if particles are close if (dist <= this.maxDistance) { this.ctx.beginPath(); this.ctx.strokeStyle = 'rgba(255, 255, 255, ' + ((1.2 - dist / this.maxDistance) * 0.5) + ')'; this.ctx.moveTo(pos1.x, pos1.y); this.ctx.lineTo(pos2.x, pos2.y); this.ctx.stroke(); this.ctx.closePath(); // Accelerate based on distance (no acceleration yet) const ax = dx / this.gravitation; const ay = dy / this.gravitation; vel1.x -= ax; vel1.y -= ay; p1.setVelocity(vel1.x, vel1.y); vel2.x -= ax; vel2.y -= ay; p2.setVelocity(vel2.x, vel2.y); } }; }; }(window.jsOMS = window.jsOMS || {}));