Isolating Arc namespace.

master
Ben Burlingham 8 years ago
parent 9c4145f8b7
commit 3cd03243db
  1. 2
      js/animation3a.js
  2. 133
      js/arc.js
  3. 43
      js/bundle.js
  4. 15
      js/grid.js
  5. 192
      js/particle.js
  6. 15
      js/random.js
  7. 14
      js/store.js

@ -1,7 +1,6 @@
import Rx, { Observable } from 'rxjs';
import Grid from './grid';
import Particle from './particle';
import Store from './store';
import Controls from './controls';
import { CONTROLS, ENTITIES } from './enums';
@ -30,7 +29,6 @@ function Animation3a() {
this.updateAnimating(this.options.animating);
this.updateCount(this.options.count);
// TODO extract Arc
// TODO get "top" leader, once...don't update each time?
// TODO if leader sees follower, assign to this leader?
// TODO X dimension modified by core UI, maybe recalc grid in animation start?

@ -0,0 +1,133 @@
import { RAD } from './enums';
import Random from './random';
const Arc = {
create: function(bounds, grids) {
let arc = {
centerX: Random.num(0, bounds.width),
centerY: Random.num(0, bounds.height),
clockwise: Random.bool(),
endX: 0,
endY: 0,
length: Random.num(RAD.t90, RAD.t360),
radius: Random.num(100, 200),
theta: Random.num(RAD.t90, RAD.t360)
};
arc.endX = arc.centerX + arc.radius * Math.cos(arc.theta);
arc.endY = arc.centerY - arc.radius * Math.sin(arc.theta);
arc = Arc.overflow(arc, bounds);
const x = arc.endX - arc.endX % 5;
const y = arc.endY - arc.endY % 5;
// If starting in a hazard, recurse.
// if (grids.global[x] !== undefined && grids.global[x][y] !== undefined) {
// arc = createArc(bounds, grids);
// }
return arc;
},
step: function(arc, { bounds, speed }) {
// Ensure constant velocity and theta between 0 and 2π.
const delta = speed / arc.radius;
arc.length -= delta;
arc.theta += (arc.clockwise ? -delta : +delta);
arc.theta = (arc.theta > 0 ? arc.theta % RAD.t360 : RAD.t360 + arc.theta);
arc.endX = arc.centerX + arc.radius * Math.cos(arc.theta); // TODO perf here
arc.endY = arc.centerY - arc.radius * Math.sin(arc.theta); // TODO perf here
// Overflow.
arc = Arc.overflow(arc, bounds);
return arc;
},
randomize: function(arc) {
arc.length = Random.num(RAD.t90, RAD.t360);
arc = Arc.changeRadius(arc, Random.num(100, 200));
if (Random.bool(0.8)) {
arc = Arc.reverse(arc);
}
return arc;
},
overflow: function(arc, bounds) {
if (arc.endX < 0) {
arc.endX += bounds.width;
arc.centerX += bounds.width
} else if (arc.endX > bounds.width) {
arc.endX -= bounds.width;
arc.centerX -= bounds.width
}
if (arc.endY < 0) {
arc.endY += bounds.height;
arc.centerY += bounds.height
} else if (arc.endY > bounds.height) {
arc.endY -= bounds.height;
arc.centerY -= bounds.height
}
return arc;
},
changeRadius: function(arc, newRadius) {
const r0 = arc.radius;
const r1 = newRadius;
// Moves arc center to new radius while keeping theta constant.
arc.centerX -= (r1 - r0) * Math.cos(arc.theta); // TODO perf here
arc.centerY += (r1 - r0) * Math.sin(arc.theta); // TODO perf here
arc.radius = r1;
return arc;
},
reverse: function(arc) {
arc.clockwise = !arc.clockwise;
arc.theta = (arc.theta + RAD.t180) % RAD.t360;
arc.centerX -= (2 * arc.radius) * Math.cos(arc.theta); // TODO perf here
arc.centerY += (2 * arc.radius) * Math.sin(arc.theta); // TODO perf here
return arc;
},
follow: function(arc, arcToFollow) {
if (arc.clockwise !== arcToFollow.clockwise) {
arc = Arc.reverse(arc);
}
if (Math.abs(arc.theta - arcToFollow.theta) > 0.1) {
arc = Arc.changeRadius(arc, 20);
} else {
arc = Arc.changeRadius(arc, arcToFollow.radius);
}
return arc;
},
evade: function(arc, visionGrid) {
// const danger = visionGrid.reduce((acc, v) => acc || v.touch, false);
//
// if (danger === false) {
// return arc;
// }
//
// const evasionArc = moveArc(arc, 20);
// evasionArc.length = 1;
//
// return evasionArc;
}
}
export default Arc;

File diff suppressed because one or more lines are too long

@ -29,3 +29,18 @@ Grid.prototype.deletePoint = function({ x, y, type }) {
// }
// }
// };
// const Store = function(initialProps) {
// this.state = Object.freeze(initialProps);
// }
//
// Store.prototype.set = function(props) {
// this.state = Object.freeze(Object.assign({}, this.state, props));
// return this.state;
// };
//
// Store.prototype.get = function() {
// return this.state;
// }
//
// export default Store;

@ -1,20 +1,7 @@
import Rx, { Observable } from 'rxjs';
import { BEHAVIOR, ENTITIES, RAD } from './enums';
import Store from './store';
const random = {
bool: (weight) => Math.random() < (weight || 0.5),
color: () => `rgb(
${Math.floor(Math.random() * 230)},
${Math.floor(Math.random() * 230)},
${Math.floor(Math.random() * 230)}
)`,
id: () => String.fromCharCode(
random.num(65, 90), random.num(97, 122), random.num(97, 122)
// random.num(97, 122), random.num(97, 122), random.num(97, 122)
),
num: (min, max) => min + Math.round(Math.random() * (max - min)),
}
import Arc from './arc';
import Random from './random';
// ===== Constructor =====
@ -23,7 +10,7 @@ function Particle(parent, bounds, config, globalGrid) {
value: Object.assign({}, {
behavior: BEHAVIOR.COHESION,
bounds,
color: random.color(),
color: Random.color(),
gridSize: 5,
randomize: true,
showMovementCircle: false,
@ -41,7 +28,7 @@ function Particle(parent, bounds, config, globalGrid) {
});
Object.defineProperty(this, 'id', {
value: random.id(6)
value: Random.id(6)
});
Object.defineProperty(this, 'nodes', {
@ -61,7 +48,7 @@ function Particle(parent, bounds, config, globalGrid) {
this.nodes.container.appendChild(this.nodes.body);
parent.appendChild(this.nodes.container);
this.arc = createArc(bounds, this.grids);
this.arc = Arc.create(bounds, this.grids);
this.updateConfig(this.config);
this.nextFrame(globalGrid);
};
@ -76,13 +63,13 @@ Particle.prototype.remove = function() {
Particle.prototype.nextFrame = function(globalGrid) {
// Randomly change radius and rotation direction.
if (this.arc.length <= 0 && this.config.randomize) {
this.arc = randomizeArc(this.arc);
this.arc = Arc.randomize(this.arc);
}
this.arc = step(this.arc, this.config);
this.arc = Arc.step(this.arc, this.config);
if (this.leader !== null) {
this.arc = followArc(this.arc, this.leader.arc);
this.arc = Arc.follow(this.arc, this.leader.arc);
}
this.grids.global = globalGrid;
@ -159,36 +146,28 @@ Particle.prototype.updateLeader = function() {
}
}
// ===== CREATION =====
function createArc(bounds, grids) {
let arc = {
centerX: random.num(0, bounds.width),
centerY: random.num(0, bounds.height),
clockwise: random.bool(),
endX: 0,
endY: 0,
length: random.num(RAD.t90, RAD.t360),
radius: random.num(100, 200),
theta: random.num(RAD.t90, RAD.t360),
};
arc.endX = arc.centerX + arc.radius * Math.cos(arc.theta);
arc.endY = arc.centerY - arc.radius * Math.sin(arc.theta);
function look(arc, grids) {
const { global, vision } = grids;
arc = overflowArc(arc, bounds);
return vision.reduce((acc, point) => {
const x = arc.endX + point.x;
const y = arc.endY + point.y;
const p = global.getPoint({ x, y, type: ENTITIES.PARTICLE });
const x = arc.endX - arc.endX % 5;
const y = arc.endY - arc.endY % 5;
if (p) {
acc.particles.push(p);
}
// If starting in a hazard, recurse.
if (grids.global[x] !== undefined && grids.global[x][y] !== undefined) {
arc = createArc(bounds, grids);
}
// if (global.getPoint({ x, y, type: ENTITIES.HAZARD })) {
// acc.hazards.push({ x, y });
// }
return arc;
return acc;
}, { hazards: [], particles: [] });
}
// ===== DOM CREATION =====
function createBodyNode(config) {
const node = document.createElement('div');
node.className = 'particle-body';
@ -263,93 +242,6 @@ function createVisionGridNodes(config, grids, nodes) {
}, []);
}
// ===== CALCULATIONS =====
function step(arc, { bounds, speed }) {
// Ensure constant velocity and theta between 0 and 2π.
const delta = speed / arc.radius;
arc.length -= delta;
arc.theta += (arc.clockwise ? -delta : +delta);
arc.theta = (arc.theta > 0 ? arc.theta % RAD.t360 : RAD.t360 + arc.theta);
arc.endX = arc.centerX + arc.radius * Math.cos(arc.theta); // TODO perf here
arc.endY = arc.centerY - arc.radius * Math.sin(arc.theta); // TODO perf here
// Overflow.
arc = overflowArc(arc, bounds);
return arc;
}
function randomizeArc(arc) {
arc.length = random.num(RAD.t90, RAD.t360);
arc = moveArc(arc, random.num(100, 200));
if (random.bool(0.8)) {
arc = reverseArc(arc);
}
return arc;
}
function overflowArc(arc, bounds) {
if (arc.endX < 0) {
arc.endX += bounds.width;
arc.centerX += bounds.width
} else if (arc.endX > bounds.width) {
arc.endX -= bounds.width;
arc.centerX -= bounds.width
}
if (arc.endY < 0) {
arc.endY += bounds.height;
arc.centerY += bounds.height
} else if (arc.endY > bounds.height) {
arc.endY -= bounds.height;
arc.centerY -= bounds.height
}
return arc;
}
function moveArc(arc, newRadius) {
const r0 = arc.radius;
const r1 = newRadius;
// Moves arc center to new radius while keeping theta constant.
arc.centerX -= (r1 - r0) * Math.cos(arc.theta); // TODO perf here
arc.centerY += (r1 - r0) * Math.sin(arc.theta); // TODO perf here
arc.radius = r1;
return arc;
}
function reverseArc(arc) {
arc.clockwise = !arc.clockwise;
arc.theta = (arc.theta + RAD.t180) % RAD.t360;
arc.centerX -= (2 * arc.radius) * Math.cos(arc.theta); // TODO perf here
arc.centerY += (2 * arc.radius) * Math.sin(arc.theta); // TODO perf here
return arc;
}
function followArc(arc, arcToFollow) {
if (arc.clockwise !== arcToFollow.clockwise) {
arc = reverseArc(arc);
}
if (Math.abs(arc.theta - arcToFollow.theta) > 0.1) {
arc = moveArc(arc, 20);
} else {
arc = moveArc(arc, arcToFollow.radius);
}
return arc;
}
function updateVisionGrid(arc, config, grids) {
const { global, vision } = grids;
@ -366,41 +258,7 @@ function updateVisionGrid(arc, config, grids) {
}, []);
}
// ===== ACTIONS =====
function look(arc, grids) {
const { global, vision } = grids;
return vision.reduce((acc, point) => {
const x = arc.endX + point.x;
const y = arc.endY + point.y;
const p = global.getPoint({ x, y, type: ENTITIES.PARTICLE });
if (p) {
acc.particles.push(p);
}
// if (global.getPoint({ x, y, type: ENTITIES.HAZARD })) {
// acc.hazards.push({ x, y });
// }
return acc;
}, { hazards: [], particles: [] });
}
function evade(arc, visionGrid) {
// const danger = visionGrid.reduce((acc, v) => acc || v.touch, false);
//
// if (danger === false) {
// return arc;
// }
//
// const evasionArc = moveArc(arc, 20);
// evasionArc.length = 1;
//
// return evasionArc;
}
// ===== RENDERING =====
// ===== DOM RENDERING =====
function repaintContainer(node, arc) {
node.style.left = `${arc.endX}px`;
node.style.top = `${arc.endY}px`;

@ -0,0 +1,15 @@
const random = {
bool: (weight) => Math.random() < (weight || 0.5),
color: () => `rgb(
${Math.floor(Math.random() * 230)},
${Math.floor(Math.random() * 230)},
${Math.floor(Math.random() * 230)}
)`,
id: () => String.fromCharCode(
random.num(65, 90), random.num(97, 122), random.num(97, 122)
// random.num(97, 122), random.num(97, 122), random.num(97, 122)
),
num: (min, max) => min + Math.round(Math.random() * (max - min)),
};
export default random;

@ -1,14 +0,0 @@
const Store = function(initialProps) {
this.state = Object.freeze(initialProps);
}
Store.prototype.set = function(props) {
this.state = Object.freeze(Object.assign({}, this.state, props));
return this.state;
};
Store.prototype.get = function() {
return this.state;
}
export default Store;
Loading…
Cancel
Save