import Rx, { Observable } from 'rxjs'; import Particle from './particle'; import Store from './store'; import Controls from './controls'; import { CONTROLS } from './enums'; function Animation2a() { this.options = { count: 1, maxCount: 10, randomize: true, showMovementCircle: true, showVisionGrid: true, speed: 4 }; this.container = document.getElementById('animation2a'); this.bounds = this.container.getBoundingClientRect(); this.particles = []; this.globalGrid = createGlobalGrid(this.container, this.bounds); const controls = new Controls( document.getElementById('controls2a'), this.options ); controls.mount().subscribe(this.subscriber.bind(this)); this.updateAnimating(this.options.animating); this.updateCount(this.options.count); // TODO X dimension modified by core UI, maybe recalc grid in animation start? // TODO remove bottom padding from Disqus // TODO perf - cache trig or perform operations // TODO only randomize movement on 1a // TODO ANIM2a Vision grid touches trig transform // TODO ANIM2a randomize hazards // TODO ANIM2 particle evade // TODO ANIM2b Scale vision grid to 1000 particles // TODO ANIM3 flocking }; Animation2a.prototype.subscriber = function({ key, value }) { switch(key) { case CONTROLS.ANIMATING: this.updateAnimating(value); break; case CONTROLS.COUNT: this.updateCount(value); break; case CONTROLS.RANDOMIZE: this.updateRandomize(value); break; case CONTROLS.SPEED: this.updateSpeed(value); break; } } Animation2a.prototype.nextFrame = function() { this.particles.forEach(p => p.nextFrame()); } Animation2a.prototype.updateAnimating = function(isAnimating) { this.options.animating = isAnimating; if (isAnimating) { const fps$ = Rx.Observable.interval(1000 / 32) .takeWhile(_ => this.options.animating); fps$.subscribe(this.nextFrame.bind(this)); } } Animation2a.prototype.updateCount = function(count) { while (this.particles.length >= count) { delete this.particles.pop().remove(); } while (this.particles.length < count) { const p = new Particle(this.container, this.bounds, this.options, this.globalGrid); this.particles.push(p); } } Animation2a.prototype.updateRandomize = function(value) { this.options.randomize = value; this.particles.forEach(p => p.updateConfig({ randomize: value })); } Animation2a.prototype.updateSpeed = function(value) { this.options.speed = value; this.particles.forEach(p => p.updateConfig({ speed: value })); } function createGlobalGrid(container, bounds) { const grid = {}; const gridSize = 5; const hazards = [ { x: 100, y: 100, w: 200, h: 200 }, { x: 600, y: 200, w: 200, h: 200 }, ]; return hazards.reduce((acc, { x, y, w, h }) => { const div = document.createElement('div'); div.className = 'hazard'; div.style.left = `${x}px`; div.style.top = `${y}px`; div.style.height = `${h}px`; div.style.width = `${w}px`; container.appendChild(div); for (let i = x; i <= (x + w); i += gridSize) { for (let j = y; j <= (y + h); j += gridSize) { if (acc[i] === undefined) { acc[i] = {}; } if (acc[i][j] !== undefined) { continue; } const dot = document.createElement('dot'); dot.className = 'hazard-dot'; dot.style.left = `${i - x}px`; dot.style.top = `${j - y}px`; div.appendChild(dot); acc[i][j] = true; } } return acc; }, {}); } export default Animation2a;