Animation 2 finished.

master
Ben Burlingham 8 years ago
parent 0d97878596
commit f6f690837e
  1. 3
      css/index.scss
  2. 3
      css/style.css
  3. 15
      index.html
  4. 0
      js/_ORIGINAL.js
  5. 131
      js/_SCARE.js
  6. 0
      js/_WALLDETECT-BUGGY.js
  7. 93
      js/animation1.js
  8. 168
      js/animation2.js
  9. 110
      js/animation4.js
  10. 287
      js/bundle.js
  11. 58
      js/controls.js
  12. 2
      js/index.js
  13. 4
      js/particle.js

@ -21,9 +21,10 @@
.animationContainer {
background: rgba(102, 51, 153, 0.05);
// background: #f0f0f0;
height: 100%;
height: 450px;
margin-top: 50px;
position: relative;
width: 100%;
z-index: 0;
}

@ -25,9 +25,10 @@ body {
.animationContainer {
background: rgba(102, 51, 153, 0.05);
height: 100%;
height: 450px;
margin-top: 50px;
position: relative;
width: 100%;
z-index: 0; }
.particle {
background-color: #555;

@ -24,7 +24,7 @@
<hr>
<p>
<h4>Iteration 1: Organic movement at 32fps</h4>
<h4>Exploration 1: Organic movement at 32fps</h4>
</p>
<p>
@ -39,6 +39,19 @@
<div id="controls1" class='controlsContainer'></div>
</div>
<p>
This method can handle quite a few particles.
</p>
<div class='outerContainer'>
<div id="animation2" class='animationContainer'></div>
<div id="controls2" class='controlsContainer'></div>
</div>
<p>
<h4>Exploration 2: Grid-based vision</h4>
</p>
<!--

@ -0,0 +1,131 @@
// Scare mechanic, single particle.
import Rx, { Observable } from 'rxjs';
import AnimationBase from './animationBase';
import DOM from './dom';
import Store from './store';
const evtScare = (scareX, scareY) => new CustomEvent("scare", { detail: { scareX, scareY } });
const particleDiv = document.createElement('div');
particleDiv.className = 'anim2-particle';
function checkScare([evt, store]) {
const state = store.get();
const { evtX, evtY } = DOM.getEventOffsetCoords(evt, DOM.containerBounds);
const diffX = Math.abs(state.x - evtX);
const diffY = Math.abs(state.y - evtY);
if (evt.target === particleDiv) {
DOM.container.dispatchEvent(evtScare(evtX, evtY));
}
};
function move(acc, i) {
let { x, y, dx, dy } = acc;
const east = DOM.containerBounds.width - particleDiv.offsetWidth;
const south = DOM.containerBounds.height - particleDiv.offsetHeight;
x += dx;
y += dy;
if (x < 0) {
x = Math.abs(x);
dx = -dx;
}
if (x > east) {
x = Math.round(2 * east - x);
dx = -dx;
}
if (y < 0) {
y = Math.abs(y);
dy = -dy;
}
if (y > south) {
y = Math.round(2 * south - y);
dy = -dy;
}
return { x, y, dx, dy };
};
function flee([evt, store]) {
const initialState = store.get();
const fleeRadius = 200;
const { scareX, scareY } = evt.detail;
const fps$ = Rx.Observable.interval(1000 / 32);
const frames$ = fps$
.scan(move, initialState)
.takeWhile(state => {
const xDanger = Math.abs(initialState.x - state.x) < fleeRadius;
const yDanger = Math.abs(initialState.y - state.y) < fleeRadius;
return xDanger && yDanger;
})
frames$.last().subscribe(finalState => {
store.set(finalState);
store.set(randomMoveVector());
});
frames$.subscribe(state => {
particleDiv.style.left = `${state.x}px`;
particleDiv.style.top = `${state.y}px`;
});
};
function randomMoveVector() {
const speed = 10;
let dx = Math.round(Math.random() * speed);
let dy = Math.pow(Math.pow(speed, 2) - Math.pow(dx, 2), 0.5);
const negX = Math.random() < 0.5 ? -1 : 1;
const negY = Math.random() < 0.5 ? -1 : 1;
dx *= negX;
dy *= negY;
return { dx, dy };
}
function reset() {
if (particleDiv.parentNode) {
DOM.container.removeChild(particleDiv);
}
const { dx, dy } = randomMoveVector();
const store = new Store({ x: 0, y: 0, dx, dy });
const state = store.get();
particleDiv.style.top = `${state.y}px`;
particleDiv.style.left = `${state.x}px`;
DOM.container.appendChild(particleDiv);
return store;
};
function init() {
const store = reset();
const click$ = Rx.Observable
.fromEvent(DOM.container, 'click')
// .do(DOM.calcBounds)
.do(DOM.highlight)
.map(evt => [evt, store])
.subscribe(checkScare);
Rx.Observable
.fromEvent(DOM.container, 'scare')
.map(evt => [evt, store])
.subscribe(flee);
};
const Animation2 = Object.assign({}, AnimationBase, { init, reset });
export default Animation2;

@ -18,49 +18,88 @@ function Animation1() {
this.container = document.getElementById('animation1');
this.bounds = this.container.getBoundingClientRect();
this.movementCircleCtrl = createMovementCircleControl();
this.randomRadiusCtrl = createRandomRadiusControl();
this.randomRotationCtrl = createRandomRotationControl();
this.particles = [];
const controls = new Controls(
document.getElementById('controls1'),
this.options,
[this.movementCircleCtrl]
[this.movementCircleCtrl, this.randomRadiusCtrl, this.randomRotationCtrl]
);
const eventStack = controls.mount()
.merge(Rx.Observable.fromEvent(this.movementCircleCtrl, 'change')
.map(evt => ({ key: CONTROLS.MOVEMENT_CIRCLE, value: evt.target.checked }))
);
const circle$ = Rx.Observable.fromEvent(this.movementCircleCtrl, 'change')
.map(evt => ({ key: CONTROLS.MOVEMENT_CIRCLE, value: evt.target.checked }));
const radius$ = Rx.Observable.fromEvent(this.randomRadiusCtrl, 'change')
.map(evt => ({ key: CONTROLS.RADIUS, value: evt.target.checked }));
const rotation$ = Rx.Observable.fromEvent(this.randomRotationCtrl, 'change')
.map(evt => ({ key: CONTROLS.ROTATION, value: evt.target.checked }));
const eventStack = controls.mount().merge(circle$, radius$, rotation$);
eventStack.subscribe(this.subscriber.bind(this));
this.updateAnimating(this.options.animating);
this.updateCount(this.options.count);
this.updateMovementCircle(this.options.showMovementCircle);
this.updateRadius(this.options.randomizeRadius);
this.updateRotation(this.options.randomizeRotation);
};
// TODO particle starts offscreen sometimes
function createMovementCircleControl() {
const label = document.createElement('label');
label.className = 'controls-checkbox';
// TODO ANIM2 Max out to 1000 or 2000 particles
const text = document.createElement('span');
text.innerHTML = 'Show movement circle';
text.className = 'controls-checkbox-text';
// TODO ANIM3 Show vision grid (including touches!)
// TODO ANIM3 regen vision grid is option updated
// TODO ANIM3 cleanup vision grid
const checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.className = 'controls-checkbox-input';
// TODO ANIM4 Pallet avoidance
label.appendChild(checkbox);
label.appendChild(text);
// TODO ANIM5 Flocking
};
return label;
}
function createMovementCircleControl() {
function createRandomRadiusControl(value) {
const label = document.createElement('label');
label.className = 'controls-checkbox';
const text = document.createElement('span');
text.innerHTML = 'Show movement circle';
text.innerHTML = 'Random radii';
text.className = 'controls-checkbox-text';
const checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.className = 'controls-checkbox-input';
checkbox.checked = value;
label.appendChild(checkbox);
label.appendChild(text);
return label;
}
function createRandomRotationControl(value) {
const label = document.createElement('label');
label.className = 'controls-checkbox';
const text = document.createElement('span');
text.innerHTML = 'Random rotation';
text.className = 'controls-checkbox-text';
const checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.className = 'controls-checkbox-input';
checkbox.checked = value;
label.appendChild(checkbox);
label.appendChild(text);
@ -106,24 +145,26 @@ Animation1.prototype.updateCount = function(count) {
}
}
Animation1.prototype.updateMovementCircle = function(showMovementCircle) {
this.options.showMovementCircle = showMovementCircle;
this.movementCircleCtrl.querySelector('[type=checkbox]').checked = showMovementCircle;
this.particles.forEach(p => p.updateOptions({ showMovementCircle }));
Animation1.prototype.updateMovementCircle = function(value) {
// this.options.showMovementCircle = value;
this.movementCircleCtrl.querySelector('[type=checkbox]').checked = value;
this.particles.forEach(p => p.updateOptions({ showMovementCircle: value }));
}
Animation1.prototype.updateRadius = function(randomizeRadius) {
this.options.randomizeRadius = randomizeRadius;
this.particles.forEach(p => p.updateOptions({ randomizeRadius }));
Animation1.prototype.updateRadius = function(value) {
// this.options.randomizeRadius = value;
this.randomRadiusCtrl.querySelector('[type=checkbox]').checked = value;
this.particles.forEach(p => p.updateOptions({ randomizeRadius: value }));
}
Animation1.prototype.updateRotation = function(randomizeRotation) {
this.options.randomizeRotation = randomizeRotation;
this.particles.forEach(p => p.updateOptions({ randomizeRotation }));
Animation1.prototype.updateRotation = function(value) {
// this.options.randomizeRotation = value;
this.randomRotationCtrl.querySelector('[type=checkbox]').checked = value;
this.particles.forEach(p => p.updateOptions({ randomizeRotation: value }));
}
Animation1.prototype.updateSpeed = function(speed) {
this.options.speed = speed;
// this.options.speed = speed;
this.particles.forEach(p => p.updateOptions({ speed }));
}

@ -1,131 +1,87 @@
// Scare mechanic, single particle.
import Rx, { Observable } from 'rxjs';
import AnimationBase from './animationBase';
import DOM from './dom';
import Particle from './particle';
import Store from './store';
import Controls from './controls';
import { CONTROLS } from './enums';
const evtScare = (scareX, scareY) => new CustomEvent("scare", { detail: { scareX, scareY } });
function Animation2() {
this.options = {
animating: false,
count: 1,
maxCount: 3000,
speed: 4
};
const particleDiv = document.createElement('div');
particleDiv.className = 'anim2-particle';
this.container = document.getElementById('animation2');
this.bounds = this.container.getBoundingClientRect();
function checkScare([evt, store]) {
const state = store.get();
this.particles = [];
const { evtX, evtY } = DOM.getEventOffsetCoords(evt, DOM.containerBounds);
const diffX = Math.abs(state.x - evtX);
const diffY = Math.abs(state.y - evtY);
const controls = new Controls(
document.getElementById('controls2'),
this.options
);
if (evt.target === particleDiv) {
DOM.container.dispatchEvent(evtScare(evtX, evtY));
}
};
controls.mount().subscribe(this.subscriber.bind(this));
function move(acc, i) {
let { x, y, dx, dy } = acc;
this.updateAnimating(this.options.animating);
this.updateCount(this.options.count);
const east = DOM.containerBounds.width - particleDiv.offsetWidth;
const south = DOM.containerBounds.height - particleDiv.offsetHeight;
// TODO X dimension modified by core UI
// TODO "shaky" / "stuck" bug
x += dx;
y += dy;
if (x < 0) {
x = Math.abs(x);
dx = -dx;
}
// TODO ANIM3 Show vision grid (including touches!)
// TODO ANIM3 regen vision grid is option updated
// TODO ANIM3 cleanup vision grid
// TODO ANIM3 Pallet avoidance
if (x > east) {
x = Math.round(2 * east - x);
dx = -dx;
}
if (y < 0) {
y = Math.abs(y);
dy = -dy;
}
if (y > south) {
y = Math.round(2 * south - y);
dy = -dy;
}
return { x, y, dx, dy };
// TODO ANIM4 Flocking
};
function flee([evt, store]) {
const initialState = store.get();
const fleeRadius = 200;
const { scareX, scareY } = evt.detail;
const fps$ = Rx.Observable.interval(1000 / 32);
const frames$ = fps$
.scan(move, initialState)
.takeWhile(state => {
const xDanger = Math.abs(initialState.x - state.x) < fleeRadius;
const yDanger = Math.abs(initialState.y - state.y) < fleeRadius;
return xDanger && yDanger;
})
frames$.last().subscribe(finalState => {
store.set(finalState);
store.set(randomMoveVector());
});
frames$.subscribe(state => {
particleDiv.style.left = `${state.x}px`;
particleDiv.style.top = `${state.y}px`;
});
};
Animation2.prototype.subscriber = function({ key, value }) {
switch(key) {
case CONTROLS.ANIMATING: this.updateAnimating(value); break;
case CONTROLS.COUNT: this.updateCount(value); break;
case CONTROLS.SPEED: this.updateSpeed(value); break;
}
}
function randomMoveVector() {
const speed = 10;
let dx = Math.round(Math.random() * speed);
let dy = Math.pow(Math.pow(speed, 2) - Math.pow(dx, 2), 0.5);
Animation2.prototype.nextFrame = function() {
this.particles.forEach(p => p.nextFrame());
}
const negX = Math.random() < 0.5 ? -1 : 1;
const negY = Math.random() < 0.5 ? -1 : 1;
Animation2.prototype.updateAnimating = function(isAnimating) {
this.options.animating = isAnimating;
dx *= negX;
dy *= negY;
if (isAnimating) {
const fps$ = Rx.Observable.interval(1000 / 32)
.takeWhile(_ => this.options.animating);
return { dx, dy };
fps$.subscribe(this.nextFrame.bind(this));
}
}
function reset() {
if (particleDiv.parentNode) {
DOM.container.removeChild(particleDiv);
Animation2.prototype.updateCount = function(count) {
while (this.particles.length >= count) {
const p = this.particles.pop();
this.container.removeChild(p.node);
}
const { dx, dy } = randomMoveVector();
const store = new Store({ x: 0, y: 0, dx, dy });
const state = store.get();
particleDiv.style.top = `${state.y}px`;
particleDiv.style.left = `${state.x}px`;
DOM.container.appendChild(particleDiv);
return store;
};
function init() {
const store = reset();
const click$ = Rx.Observable
.fromEvent(DOM.container, 'click')
// .do(DOM.calcBounds)
.do(DOM.highlight)
.map(evt => [evt, store])
.subscribe(checkScare);
while (this.particles.length < count) {
const p = new Particle(this.container, this.bounds, this.options);
this.particles.push(p);
}
}
Rx.Observable
.fromEvent(DOM.container, 'scare')
.map(evt => [evt, store])
.subscribe(flee);
};
Animation2.prototype.updateMovementCircle = function(showMovementCircle) {
this.options.showMovementCircle = showMovementCircle;
this.movementCircleCtrl.querySelector('[type=checkbox]').checked = showMovementCircle;
this.particles.forEach(p => p.updateOptions({ showMovementCircle }));
}
const Animation2 = Object.assign({}, AnimationBase, { init, reset });
Animation2.prototype.updateSpeed = function(speed) {
this.options.speed = speed;
this.particles.forEach(p => p.updateOptions({ speed }));
}
export default Animation2;

@ -1,110 +0,0 @@
// Join mechanic, multiple particles
// ????? Chase, maybe?
// ???? Occupied?
// called each frame update
// find if going to hit a wall
// find if palette nearby
// const grid = {};
// for (let x = 0; x <= 600; x += 5) {
// grid[x] = {};
// for (let y = 0; y <= 600; y += 5) {
// grid[x][y] = { type: null };
//
// if (x === 0 || y === 0 || x === 600 || y === 600) {
// grid[x][y] = { type: 'wall' };
// }
// }
// }
import Rx, { Observable } from 'rxjs';
import AnimationBase from './animationBase';
import DOM from './dom';
import Store from './store';
const evtScare = (detail) => new CustomEvent('scare', { detail });
const [particles, state] = (new Array(5)).fill(null).reduce((acc, v, i) => {
const div = document.createElement('div');
div.className = 'anim3-particle';
div.innerHTML = ''
const x = 0;
const y = i * 25;
div.style.left = 0
div.style.top = `${y}px`;
acc[0].push(div);
acc[1].push({ x, y });
return acc;
}, [[], []]);
const palettes = (new Array(1)).fill(null).reduce((acc, v, i) => {
const div = document.createElement('div');
div.className = 'palette';
div.style.left = '200px';
div.style.top = '200px';
acc.push(div);
return acc;
}, []);
function scare(evt) {
const bounds = DOM.container.getBoundingClientRect();
const { evtX: x, evtY: y } = DOM.getEventOffsetCoords(evt, bounds);
const scareRadius = 50;
state.forEach((coord, i) => {
const diffX = Math.abs(coord.x - x + 10);
const diffY = Math.abs(coord.y - y + 10);
if (diffX < 100 && diffY < 100) {
coord.lastScare = { x, y } // TODO set state with last scare, then judge per frame based on that number to avoid jump
DOM.container.dispatchEvent(evtScare({ x, y, i }));
}
});
}
function reset() {
while (DOM.container.childNodes.length) {
DOM.container.removeChild(DOM.container.firstChild);
}
particles.forEach((div) => {
div.innerHTML = '';
DOM.container.appendChild(div)
});
console.warn(palettes)
palettes.forEach((div) => {
DOM.container.appendChild(div)
});
};
function init() {
reset();
const click$ = Rx.Observable.fromEvent(DOM.container, 'click');
const scare$ = Rx.Observable.fromEvent(DOM.container, 'scare').auditTime(100);
scare$.subscribe(evt => {
particles[evt.detail.i].innerHTML = 'S'
DOM.addClass(particles[evt.detail.i], 'scared');
const p = particles[evt.detail.i];
setTimeout(() => {
p.innerHTML = '';
DOM.removeClass(p, 'scared');
}, 1000);
});
click$.subscribe(scare);
};
const Animation3 = Object.assign({}, AnimationBase, { init, reset });
export default Animation3;

@ -3468,22 +3468,16 @@ function Controls(container, _ref, customNodes) {
var animating = _ref.animating,
count = _ref.count,
maxCount = _ref.maxCount,
randomizeRadius = _ref.randomizeRadius,
randomizeRotation = _ref.randomizeRotation,
speed = _ref.speed;
this.nodes = {
animating: createAnimatingControl(animating),
count: createCountControl(count, maxCount),
radius: createRadiusControl(randomizeRadius),
rotation: createRotationControl(randomizeRotation),
speed: createSpeedControl(speed)
};
container.appendChild(this.nodes.count);
container.appendChild(this.nodes.speed);
container.appendChild(this.nodes.radius);
container.appendChild(this.nodes.rotation);
if (customNodes !== undefined) {
customNodes.forEach(function (node) {
@ -3495,8 +3489,6 @@ function Controls(container, _ref, customNodes) {
this.updateOptions({ key: _enums.CONTROLS.ANIMATING, value: animating });
this.updateOptions({ key: _enums.CONTROLS.COUNT, value: count });
this.updateOptions({ key: _enums.CONTROLS.RADIUS, value: randomizeRadius });
this.updateOptions({ key: _enums.CONTROLS.ROTATION, value: randomizeRotation });
this.updateOptions({ key: _enums.CONTROLS.SPEED, value: speed });
}
@ -3526,25 +3518,15 @@ Controls.prototype.mount = function (customNodes) {
return { key: _enums.CONTROLS.COUNT, value: evt.target.value * 1 };
});
var radiusStream = _rxjs2.default.Observable.fromEvent(this.nodes.radius, 'change').map(function (evt) {
return { key: _enums.CONTROLS.RADIUS, value: evt.target.checked };
});
var rotationStream = _rxjs2.default.Observable.fromEvent(this.nodes.rotation, 'change').map(function (evt) {
return { key: _enums.CONTROLS.ROTATION, value: evt.target.checked };
});
var speedStream = _rxjs2.default.Observable.fromEvent(this.nodes.speed, 'input').map(function (evt) {
return { key: _enums.CONTROLS.SPEED, value: evt.target.value * 1 };
});
animatingStream.subscribe(this.updateOptions.bind(this));
countStream.subscribe(this.updateOptions.bind(this));
radiusStream.subscribe(this.updateOptions.bind(this));
rotationStream.subscribe(this.updateOptions.bind(this));
speedStream.subscribe(this.updateOptions.bind(this));
return _rxjs2.default.Observable.merge(animatingStream, countStream, radiusStream, rotationStream, speedStream);
return _rxjs2.default.Observable.merge(animatingStream, countStream, speedStream);
};
var createAnimatingControl = function createAnimatingControl(value) {
@ -3586,44 +3568,6 @@ var createCountControl = function createCountControl(value, max) {
return label;
};
var createRadiusControl = function createRadiusControl(value) {
var label = document.createElement('label');
label.className = 'controls-checkbox';
var text = document.createElement('span');
text.innerHTML = 'Random radii';
text.className = 'controls-checkbox-text';
var checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.className = 'controls-checkbox-input';
checkbox.checked = value;
label.appendChild(checkbox);
label.appendChild(text);
return label;
};
var createRotationControl = function createRotationControl(value) {
var label = document.createElement('label');
label.className = 'controls-checkbox';
var text = document.createElement('span');
text.innerHTML = 'Random rotation';
text.className = 'controls-checkbox-text';
var checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.className = 'controls-checkbox-input';
checkbox.checked = value;
label.appendChild(checkbox);
label.appendChild(text);
return label;
};
var createSpeedControl = function createSpeedControl(value) {
var label = document.createElement('label');
label.className = 'controls-range';
@ -3634,7 +3578,7 @@ var createSpeedControl = function createSpeedControl(value) {
var slider = document.createElement('input');
slider.type = 'range';
slider.min = 1;
slider.max = 50;
slider.max = 20;
slider.value = value;
slider.className = 'controls-range-input';
@ -6284,44 +6228,87 @@ function Animation1() {
this.container = document.getElementById('animation1');
this.bounds = this.container.getBoundingClientRect();
this.movementCircleCtrl = createMovementCircleControl();
this.randomRadiusCtrl = createRandomRadiusControl();
this.randomRotationCtrl = createRandomRotationControl();
this.particles = [];
var controls = new _controls2.default(document.getElementById('controls1'), this.options, [this.movementCircleCtrl]);
var eventStack = controls.mount().merge(_rxjs2.default.Observable.fromEvent(this.movementCircleCtrl, 'change').map(function (evt) {
var controls = new _controls2.default(document.getElementById('controls1'), this.options, [this.movementCircleCtrl, this.randomRadiusCtrl, this.randomRotationCtrl]);
var circle$ = _rxjs2.default.Observable.fromEvent(this.movementCircleCtrl, 'change').map(function (evt) {
return { key: _enums.CONTROLS.MOVEMENT_CIRCLE, value: evt.target.checked };
}));
});
var radius$ = _rxjs2.default.Observable.fromEvent(this.randomRadiusCtrl, 'change').map(function (evt) {
return { key: _enums.CONTROLS.RADIUS, value: evt.target.checked };
});
var rotation$ = _rxjs2.default.Observable.fromEvent(this.randomRotationCtrl, 'change').map(function (evt) {
return { key: _enums.CONTROLS.ROTATION, value: evt.target.checked };
});
var eventStack = controls.mount().merge(circle$, radius$, rotation$);
eventStack.subscribe(this.subscriber.bind(this));
this.updateAnimating(this.options.animating);
this.updateCount(this.options.count);
this.updateMovementCircle(this.options.showMovementCircle);
this.updateRadius(this.options.randomizeRadius);
this.updateRotation(this.options.randomizeRotation);
};
// TODO particle starts offscreen sometimes
function createMovementCircleControl() {
var label = document.createElement('label');
label.className = 'controls-checkbox';
// TODO ANIM2 Max out to 1000 or 2000 particles
var text = document.createElement('span');
text.innerHTML = 'Show movement circle';
text.className = 'controls-checkbox-text';
// TODO ANIM3 Show vision grid (including touches!)
// TODO ANIM3 regen vision grid is option updated
// TODO ANIM3 cleanup vision grid
var checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.className = 'controls-checkbox-input';
// TODO ANIM4 Pallet avoidance
label.appendChild(checkbox);
label.appendChild(text);
// TODO ANIM5 Flocking
};
return label;
}
function createMovementCircleControl() {
function createRandomRadiusControl(value) {
var label = document.createElement('label');
label.className = 'controls-checkbox';
var text = document.createElement('span');
text.innerHTML = 'Show movement circle';
text.innerHTML = 'Random radii';
text.className = 'controls-checkbox-text';
var checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.className = 'controls-checkbox-input';
checkbox.checked = value;
label.appendChild(checkbox);
label.appendChild(text);
return label;
}
function createRandomRotationControl(value) {
var label = document.createElement('label');
label.className = 'controls-checkbox';
var text = document.createElement('span');
text.innerHTML = 'Random rotation';
text.className = 'controls-checkbox-text';
var checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.className = 'controls-checkbox-input';
checkbox.checked = value;
label.appendChild(checkbox);
label.appendChild(text);
@ -6381,30 +6368,32 @@ Animation1.prototype.updateCount = function (count) {
}
};
Animation1.prototype.updateMovementCircle = function (showMovementCircle) {
this.options.showMovementCircle = showMovementCircle;
this.movementCircleCtrl.querySelector('[type=checkbox]').checked = showMovementCircle;
Animation1.prototype.updateMovementCircle = function (value) {
// this.options.showMovementCircle = value;
this.movementCircleCtrl.querySelector('[type=checkbox]').checked = value;
this.particles.forEach(function (p) {
return p.updateOptions({ showMovementCircle: showMovementCircle });
return p.updateOptions({ showMovementCircle: value });
});
};
Animation1.prototype.updateRadius = function (randomizeRadius) {
this.options.randomizeRadius = randomizeRadius;
Animation1.prototype.updateRadius = function (value) {
// this.options.randomizeRadius = value;
this.randomRadiusCtrl.querySelector('[type=checkbox]').checked = value;
this.particles.forEach(function (p) {
return p.updateOptions({ randomizeRadius: randomizeRadius });
return p.updateOptions({ randomizeRadius: value });
});
};
Animation1.prototype.updateRotation = function (randomizeRotation) {
this.options.randomizeRotation = randomizeRotation;
Animation1.prototype.updateRotation = function (value) {
// this.options.randomizeRotation = value;
this.randomRotationCtrl.querySelector('[type=checkbox]').checked = value;
this.particles.forEach(function (p) {
return p.updateOptions({ randomizeRotation: randomizeRotation });
return p.updateOptions({ randomizeRotation: value });
});
};
Animation1.prototype.updateSpeed = function (speed) {
this.options.speed = speed;
// this.options.speed = speed;
this.particles.forEach(function (p) {
return p.updateOptions({ speed: speed });
});
@ -6485,6 +6474,10 @@ var _animation = __webpack_require__(71);
var _animation2 = _interopRequireDefault(_animation);
var _animation3 = __webpack_require__(355);
var _animation4 = _interopRequireDefault(_animation3);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
__webpack_require__(75);
@ -6493,6 +6486,7 @@ __webpack_require__(74);
__webpack_require__(72);
new _animation2.default();
new _animation4.default();
/***/ }),
/* 78 */
@ -6587,6 +6581,10 @@ Particle.prototype.nextFrame = function () {
// }
};
Particle.prototype.updateBounds = function (bounds) {
this.bounds = bounds;
};
Particle.prototype.updateOptions = function (options) {
Object.assign(this.options, options);
@ -20639,5 +20637,130 @@ exports.toSubscriber = toSubscriber;
/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(70), __webpack_require__(79)))
/***/ }),
/* 355 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var _rxjs = __webpack_require__(19);
var _rxjs2 = _interopRequireDefault(_rxjs);
var _particle = __webpack_require__(78);
var _particle2 = _interopRequireDefault(_particle);
var _store = __webpack_require__(39);
var _store2 = _interopRequireDefault(_store);
var _controls = __webpack_require__(38);
var _controls2 = _interopRequireDefault(_controls);
var _enums = __webpack_require__(76);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function Animation2() {
this.options = {
animating: false,
count: 1,
maxCount: 3000,
speed: 4
};
this.container = document.getElementById('animation2');
this.bounds = this.container.getBoundingClientRect();
this.particles = [];
var controls = new _controls2.default(document.getElementById('controls2'), 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
// TODO "shaky" / "stuck" bug
// TODO ANIM3 Show vision grid (including touches!)
// TODO ANIM3 regen vision grid is option updated
// TODO ANIM3 cleanup vision grid
// TODO ANIM3 Pallet avoidance
// TODO ANIM4 Flocking
};
Animation2.prototype.subscriber = function (_ref) {
var key = _ref.key,
value = _ref.value;
switch (key) {
case _enums.CONTROLS.ANIMATING:
this.updateAnimating(value);break;
case _enums.CONTROLS.COUNT:
this.updateCount(value);break;
case _enums.CONTROLS.SPEED:
this.updateSpeed(value);break;
}
};
Animation2.prototype.nextFrame = function () {
this.particles.forEach(function (p) {
return p.nextFrame();
});
};
Animation2.prototype.updateAnimating = function (isAnimating) {
var _this = this;
this.options.animating = isAnimating;
if (isAnimating) {
var fps$ = _rxjs2.default.Observable.interval(1000 / 32).takeWhile(function (_) {
return _this.options.animating;
});
fps$.subscribe(this.nextFrame.bind(this));
}
};
Animation2.prototype.updateCount = function (count) {
while (this.particles.length >= count) {
var p = this.particles.pop();
this.container.removeChild(p.node);
}
while (this.particles.length < count) {
var _p = new _particle2.default(this.container, this.bounds, this.options);
this.particles.push(_p);
}
};
Animation2.prototype.updateMovementCircle = function (showMovementCircle) {
this.options.showMovementCircle = showMovementCircle;
this.movementCircleCtrl.querySelector('[type=checkbox]').checked = showMovementCircle;
this.particles.forEach(function (p) {
return p.updateOptions({ showMovementCircle: showMovementCircle });
});
};
Animation2.prototype.updateSpeed = function (speed) {
this.options.speed = speed;
this.particles.forEach(function (p) {
return p.updateOptions({ speed: speed });
});
};
exports.default = Animation2;
/***/ })
/******/ ]);

58
js/controls.js vendored

@ -1,19 +1,15 @@
import Rx, { Observable } from 'rxjs';
import { CONTROLS } from './enums';
function Controls(container, { animating, count, maxCount, randomizeRadius, randomizeRotation, speed }, customNodes) {
function Controls(container, { animating, count, maxCount, speed }, customNodes) {
this.nodes = {
animating: createAnimatingControl(animating),
count: createCountControl(count, maxCount),
radius: createRadiusControl(randomizeRadius),
rotation: createRotationControl(randomizeRotation),
speed: createSpeedControl(speed),
}
container.appendChild(this.nodes.count);
container.appendChild(this.nodes.speed);
container.appendChild(this.nodes.radius);
container.appendChild(this.nodes.rotation);
if (customNodes !== undefined) {
customNodes.forEach(node => { container.appendChild(node); });
@ -23,8 +19,6 @@ function Controls(container, { animating, count, maxCount, randomizeRadius, rand
this.updateOptions({ key: CONTROLS.ANIMATING, value: animating });
this.updateOptions({ key: CONTROLS.COUNT, value: count });
this.updateOptions({ key: CONTROLS.RADIUS, value: randomizeRadius });
this.updateOptions({ key: CONTROLS.ROTATION, value: randomizeRotation });
this.updateOptions({ key: CONTROLS.SPEED, value: speed });
}
@ -52,26 +46,16 @@ Controls.prototype.mount = function(customNodes) {
const countStream = Rx.Observable.fromEvent(this.nodes.count, 'input')
.map(evt => ({ key: CONTROLS.COUNT, value: evt.target.value * 1 }));
const radiusStream = Rx.Observable.fromEvent(this.nodes.radius, 'change')
.map(evt => ({ key: CONTROLS.RADIUS, value: evt.target.checked }));
const rotationStream = Rx.Observable.fromEvent(this.nodes.rotation, 'change')
.map(evt => ({ key: CONTROLS.ROTATION, value: evt.target.checked }));
const speedStream = Rx.Observable.fromEvent(this.nodes.speed, 'input')
.map(evt => ({ key: CONTROLS.SPEED, value: evt.target.value * 1 }));
animatingStream.subscribe(this.updateOptions.bind(this));
countStream.subscribe(this.updateOptions.bind(this));
radiusStream.subscribe(this.updateOptions.bind(this));
rotationStream.subscribe(this.updateOptions.bind(this));
speedStream.subscribe(this.updateOptions.bind(this));
return Rx.Observable.merge(
animatingStream,
countStream,
radiusStream,
rotationStream,
speedStream,
);
}
@ -115,44 +99,6 @@ const createCountControl = function(value, max) {
return label;
}
const createRadiusControl = function(value) {
const label = document.createElement('label');
label.className = 'controls-checkbox';
const text = document.createElement('span');
text.innerHTML = 'Random radii';
text.className = 'controls-checkbox-text';
const checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.className = 'controls-checkbox-input';
checkbox.checked = value;
label.appendChild(checkbox);
label.appendChild(text);
return label;
}
const createRotationControl = function(value) {
const label = document.createElement('label');
label.className = 'controls-checkbox';
const text = document.createElement('span');
text.innerHTML = 'Random rotation';
text.className = 'controls-checkbox-text';
const checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.className = 'controls-checkbox-input';
checkbox.checked = value;
label.appendChild(checkbox);
label.appendChild(text);
return label;
}
const createSpeedControl = function(value) {
const label = document.createElement('label');
label.className = 'controls-range';
@ -163,7 +109,7 @@ const createSpeedControl = function(value) {
const slider = document.createElement('input');
slider.type = 'range';
slider.min = 1;
slider.max = 50;
slider.max = 20;
slider.value = value;
slider.className = 'controls-range-input';

@ -1,6 +1,7 @@
import Rx, { Observable } from 'rxjs';
import Controls from './controls';
import Animation1 from './animation1';
import Animation2 from './animation2';
require('../css/reset.scss');
require('../css/index.scss');
@ -8,3 +9,4 @@ require('../css/particle.scss');
require('../css/controls.scss');
new Animation1();
new Animation2();

@ -65,6 +65,10 @@ Particle.prototype.nextFrame = function() {
// if (this.options.showVisionGrid === true) {
// repaintVisionGrid(this.arc, this.particle, this.visionGridPoints);
// }
};
Particle.prototype.updateBounds = function(bounds) {
this.bounds = bounds;
}
Particle.prototype.updateOptions = function(options) {

Loading…
Cancel
Save