Debugging. Finalize UI.

master
Ben Burlingham 8 years ago
parent 466f0f400f
commit 0d97878596
  1. 44
      css/controls.scss
  2. 21
      css/index.scss
  3. 51
      css/particle.scss
  4. 94
      css/style.css
  5. 6
      index.html
  6. 63
      js/animation1.js
  7. 179
      js/bundle.js
  8. 42
      js/controls.js
  9. 7
      js/enums.js
  10. 66
      js/particle.js

@ -1,32 +1,48 @@
.controls-label {
.controls-checkbox {
cursor: pointer;
font-size: 13px;
margin-bottom: 5px;
padding: 10px;
line-height: 45px;
padding: 0 10px;
&:hover {
background: #fff;
background: #d7d7d7;
}
}
.controls-label-checkbox {
.controls-checkbox-text {
font-size: 11px;
}
.controls-checkbox-input {
margin-right: 5px;
}
.controls-label-text {
.controls-range {
cursor: pointer;
line-height: 20px;
padding: 0 10px;
&:hover {
background: #d7d7d7;
}
}
.controls-range-text {
cursor: pointer;
font-size: 11px;
}
.controls-slider {
.controls-range-input {
cursor: pointer;
width: 100%;
display: block;
width: 100px;
}
.controls-animating {
cursor: pointer;
font-size: 18px;
line-height: 20px;
padding: 10px;
line-height: 45px;
margin-left: auto;
padding: 0 10px;
user-select: none;
[type=checkbox] {
@ -34,14 +50,10 @@
}
&:hover {
background: #fff;
background: #d7d7d7;
}
&:focus {
outline: 0;
}
}
.controls-bottom {
margin-top: auto;
}

@ -1,29 +1,28 @@
.outerContainer {
height: 400px;
margin: 10px auto;
height: 500px;
margin: 10px 0;
overflow: hidden;
position: relative;
width: 90%;
width: 100%;
}
.controlsContainer {
background: #ccc;
border-left: 2px groove #c0c0c0;
bottom: 0;
background: #e7e7e7;
border-bottom: 5px solid #aaa;
display: flex;
flex-direction: column;
padding: 10px;
height: 50px;
left: 0;
position: absolute;
right: 0;
top: 0;
width: 170px;
z-index: 1;
}
.animationContainer {
background: rgba(102, 51, 153, 0.1);
background: rgba(102, 51, 153, 0.05);
// background: #f0f0f0;
height: 100%;
margin-right: 170px;
margin-top: 50px;
position: relative;
z-index: 0;
}

@ -1,10 +1,12 @@
.particle {
$side: 20px;
background: url('../res/seahorse.svg') no-repeat center center #aaa;
// background: url('../res/seahorse.svg') no-repeat center center #aaa;
background-color: #555;
background-size: $side $side;
border-radius: $side / 2;
color: #fff;
font-size: 11px;
height: $side;
line-height: $side;
margin: #{-$side / 2} 0 0 #{-$side / 2};
@ -13,40 +15,29 @@
width: $side;
z-index: 1;
&.has-vision::after {
border: 50px solid;
border-color: lightgreen transparent transparent turquoise;
border-radius: 50px;
content: ' ';
height: 0;
left: -50px;
margin: #{$side / 2} 0 0 #{$side / 2};
opacity: 0.5;
position: absolute;
transform: rotate(45deg);
top: -50px;
width: 0;
}
// &.has-vision::after {
// border: 50px solid;
// border-color: lightgreen transparent transparent turquoise;
// border-radius: 50px;
// content: ' ';
// height: 0;
// left: -50px;
// margin: #{$side / 2} 0 0 #{$side / 2};
// opacity: 0.5;
// position: absolute;
// transform: rotate(45deg);
// top: -50px;
// width: 0;
// z-index: 0;
// }
}
.particle-movement-circle {
border: 2px dotted darkturquoise;
border: 3px dotted darkturquoise;
margin-left: 10px;
margin-top: 10px;
position: absolute;
transition: left 0.2s, top 0.2s, height 0.2s, width 0.2s;
z-index: 0;
&:after {
background: darkturquoise;
border-radius: 2px;
content:' ';
height: 4px;
left: 50%;
margin-left: -2px;
margin-top: -2px;
position: absolute;
top: 50%;
width: 4px;
}
}
.particle-vision-grid {

@ -6,36 +6,35 @@
body {
font-family: sans-serif; }
.outerContainer {
height: 400px;
margin: 10px auto;
height: 500px;
margin: 10px 0;
overflow: hidden;
position: relative;
width: 90%; }
width: 100%; }
.controlsContainer {
background: #ccc;
border-left: 2px groove #c0c0c0;
bottom: 0;
background: #e7e7e7;
border-bottom: 5px solid #aaa;
display: flex;
flex-direction: column;
padding: 10px;
height: 50px;
left: 0;
position: absolute;
right: 0;
top: 0;
width: 170px;
z-index: 1; }
.animationContainer {
background: rgba(102, 51, 153, 0.1);
background: rgba(102, 51, 153, 0.05);
height: 100%;
margin-right: 170px;
margin-top: 50px;
position: relative;
z-index: 0; }
.particle {
background: url(../res/seahorse.svg) no-repeat center center #aaa;
background-color: #555;
background-size: 20px 20px;
border-radius: 10px;
color: #fff;
font-size: 11px;
height: 20px;
line-height: 20px;
margin: -10px 0 0 -10px;
@ -43,36 +42,13 @@ body {
text-align: center;
width: 20px;
z-index: 1; }
.particle.has-vision::after {
border: 50px solid;
border-color: lightgreen transparent transparent turquoise;
border-radius: 50px;
content: ' ';
height: 0;
left: -50px;
margin: 10px 0 0 10px;
opacity: 0.5;
position: absolute;
transform: rotate(45deg);
top: -50px;
width: 0; }
.particle-movement-circle {
border: 2px dotted darkturquoise;
border: 3px dotted darkturquoise;
margin-left: 10px;
margin-top: 10px;
position: absolute;
transition: left 0.2s, top 0.2s, height 0.2s, width 0.2s;
z-index: 0; }
.particle-movement-circle:after {
background: darkturquoise;
border-radius: 2px;
content: ' ';
height: 4px;
left: 50%;
margin-left: -2px;
margin-top: -2px;
position: absolute;
top: 50%;
width: 4px; }
.particle-vision-grid {
height: 100px;
@ -91,33 +67,45 @@ body {
background: green; }
.particle-vision-dot.touching {
outline: 2px solid yellow; }
.controls-label {
.controls-checkbox {
cursor: pointer;
font-size: 13px;
margin-bottom: 5px;
padding: 10px; }
.controls-label:hover {
background: #fff; }
line-height: 45px;
padding: 0 10px; }
.controls-checkbox:hover {
background: #d7d7d7; }
.controls-checkbox-text {
font-size: 11px; }
.controls-label-checkbox {
.controls-checkbox-input {
margin-right: 5px; }
.controls-slider {
.controls-range {
cursor: pointer;
width: 100%; }
line-height: 20px;
padding: 0 10px; }
.controls-range:hover {
background: #d7d7d7; }
.controls-range-text {
cursor: pointer;
font-size: 11px; }
.controls-range-input {
cursor: pointer;
display: block;
width: 100px; }
.controls-animating {
cursor: pointer;
font-size: 18px;
line-height: 20px;
padding: 10px;
line-height: 45px;
margin-left: auto;
padding: 0 10px;
user-select: none; }
.controls-animating [type=checkbox] {
display: none; }
.controls-animating:hover {
background: #fff; }
background: #d7d7d7; }
.controls-animating:focus {
outline: 0; }
.controls-bottom {
margin-top: auto; }

@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="css/style.css">
<!-- <script src='/core/js/ui.js'></script> STARTING ANIMATIOn RIGHT AWAY PERF HIT IF ENABLED -->
<script src='/core/js/ui.js'></script>
</head>
<body>
<h1>Dust</h1>
@ -23,6 +23,10 @@
<hr>
<p>
<h4>Iteration 1: Organic movement at 32fps</h4>
</p>
<p>
The trickiest portion of this iteration was animating the curved paths. Elliptical geometry was the initial goal,
but calculating arc length (to maintain a scalar speed) is quite difficult. Smoothstep cubic curves

@ -8,40 +8,71 @@ function Animation1() {
this.options = {
animating: false,
count: 1,
maxCount: 25,
randomizeRadius: true,
randomizeRotation: true,
// showMovementCircle: false,
// showVIsionGrid: false,
showMovementCircle: false,
// showVisionGrid: false,
speed: 4
};
this.container = document.getElementById('animation1');
this.bounds = this.container.getBoundingClientRect();
this.movementCircleCtrl = createMovementCircleControl();
this.particles = [];
const controls = new Controls(document.getElementById('controls1'), this.options);
const eventStack = controls.mount();
const controls = new Controls(
document.getElementById('controls1'),
this.options,
[this.movementCircleCtrl]
);
const eventStack = controls.mount()
.merge(Rx.Observable.fromEvent(this.movementCircleCtrl, 'change')
.map(evt => ({ key: CONTROLS.MOVEMENT_CIRCLE, value: evt.target.checked }))
);
eventStack.subscribe(this.subscriber.bind(this));
this.updateAnimating(this.options.animating);
this.updateCount(this.options.count);
this.updateMovementCircle(this.options.showMovementCircle);
// TODO particle starts offscreen sometimes
// TODO ANIM2 Max out to 1000 or 2000 particles
// TODO Change animal pic OR - use particle ##???
// TODO show movement circle
// TODO cleanup movement circle
// TODO cleanup vision grid
// TODO add core UI
// TODO regen vision grid is option updated
// TODO expose particle ##
// TODO kill hover on slider, finalize control panel location
// TODO ANIM3 Show vision grid (including touches!)
// TODO ANIM3 regen vision grid is option updated
// TODO ANIM3 cleanup vision grid
// TODO ANIM2 Show vision grid (including touches!)
// TODO ANIM4 Pallet avoidance
// TODO ANIM5 Flocking
};
function createMovementCircleControl() {
const label = document.createElement('label');
label.className = 'controls-checkbox';
const text = document.createElement('span');
text.innerHTML = 'Show movement circle';
text.className = 'controls-checkbox-text';
const checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.className = 'controls-checkbox-input';
label.appendChild(checkbox);
label.appendChild(text);
return label;
}
Animation1.prototype.subscriber = function({ key, value }) {
switch(key) {
case CONTROLS.ANIMATING: this.updateAnimating(value); break;
case CONTROLS.COUNT: this.updateCount(value); break;
case CONTROLS.MOVEMENT_CIRCLE: this.updateMovementCircle(value); break;
case CONTROLS.RADIUS: this.updateRadius(value); break;
case CONTROLS.ROTATION: this.updateRotation(value); break;
case CONTROLS.SPEED: this.updateSpeed(value); break;
@ -75,6 +106,12 @@ 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.updateRadius = function(randomizeRadius) {
this.options.randomizeRadius = randomizeRadius;
this.particles.forEach(p => p.updateOptions({ randomizeRadius }));

@ -3464,25 +3464,33 @@ var _enums = __webpack_require__(76);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function Controls(container, _ref) {
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),
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);
container.appendChild(this.nodes.speed);
if (customNodes !== undefined) {
customNodes.forEach(function (node) {
container.appendChild(node);
});
}
container.appendChild(this.nodes.animating);
this.updateOptions({ key: _enums.CONTROLS.ANIMATING, value: animating });
@ -3557,20 +3565,20 @@ var createAnimatingControl = function createAnimatingControl(value) {
return label;
};
var createCountControl = function createCountControl(value) {
var createCountControl = function createCountControl(value, max) {
var label = document.createElement('label');
label.className = 'controls-label';
label.className = 'controls-range';
var text = document.createElement('span');
text.innerHTML = '...';
text.className = 'controls-label-text';
text.className = 'controls-range-text';
var slider = document.createElement('input');
slider.type = 'range';
slider.min = 1;
slider.max = 5;
slider.max = max;
slider.value = value;
slider.className = 'controls-slider';
slider.className = 'controls-range-input';
label.appendChild(text);
label.appendChild(slider);
@ -3580,15 +3588,15 @@ var createCountControl = function createCountControl(value) {
var createRadiusControl = function createRadiusControl(value) {
var label = document.createElement('label');
label.className = 'controls-label';
label.className = 'controls-checkbox';
var text = document.createElement('span');
text.innerHTML = 'Random radii';
text.className = 'controls-label-text';
text.className = 'controls-checkbox-text';
var checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.className = 'controls-label-checkbox';
checkbox.className = 'controls-checkbox-input';
checkbox.checked = value;
label.appendChild(checkbox);
@ -3599,15 +3607,15 @@ var createRadiusControl = function createRadiusControl(value) {
var createRotationControl = function createRotationControl(value) {
var label = document.createElement('label');
label.className = 'controls-label';
label.className = 'controls-checkbox';
var text = document.createElement('span');
text.innerHTML = 'Random rotation';
text.className = 'controls-label-text';
text.className = 'controls-checkbox-text';
var checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.className = 'controls-label-checkbox';
checkbox.className = 'controls-checkbox-input';
checkbox.checked = value;
label.appendChild(checkbox);
@ -3618,17 +3626,17 @@ var createRotationControl = function createRotationControl(value) {
var createSpeedControl = function createSpeedControl(value) {
var label = document.createElement('label');
label.className = 'controls-label';
label.className = 'controls-range';
var text = document.createElement('span');
text.className = 'controls-label-text';
text.className = 'controls-range-text';
var slider = document.createElement('input');
slider.type = 'range';
slider.min = 1;
slider.max = 10;
slider.max = 50;
slider.value = value;
slider.className = 'controls-slider';
slider.className = 'controls-range-input';
label.appendChild(text);
label.appendChild(slider);
@ -6266,36 +6274,61 @@ function Animation1() {
this.options = {
animating: false,
count: 1,
maxCount: 25,
randomizeRadius: true,
randomizeRotation: true,
// showMovementCircle: false,
// showVIsionGrid: false,
showMovementCircle: false,
// showVisionGrid: false,
speed: 4
};
this.container = document.getElementById('animation1');
this.bounds = this.container.getBoundingClientRect();
this.movementCircleCtrl = createMovementCircleControl();
this.particles = [];
var controls = new _controls2.default(document.getElementById('controls1'), this.options);
var eventStack = controls.mount();
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) {
return { key: _enums.CONTROLS.MOVEMENT_CIRCLE, value: evt.target.checked };
}));
eventStack.subscribe(this.subscriber.bind(this));
this.updateAnimating(this.options.animating);
this.updateCount(this.options.count);
this.updateMovementCircle(this.options.showMovementCircle);
// TODO particle starts offscreen sometimes
// TODO Change animal pic OR - use particle ##???
// TODO show movement circle
// TODO cleanup movement circle
// TODO cleanup vision grid
// TODO add core UI
// TODO regen vision grid is option updated
// TODO expose particle ##
// TODO kill hover on slider, finalize control panel location
// TODO ANIM2 Max out to 1000 or 2000 particles
// TODO ANIM2 Show vision grid (including touches!)
// TODO ANIM3 Show vision grid (including touches!)
// TODO ANIM3 regen vision grid is option updated
// TODO ANIM3 cleanup vision grid
// TODO ANIM4 Pallet avoidance
// TODO ANIM5 Flocking
};
function createMovementCircleControl() {
var label = document.createElement('label');
label.className = 'controls-checkbox';
var text = document.createElement('span');
text.innerHTML = 'Show movement circle';
text.className = 'controls-checkbox-text';
var checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.className = 'controls-checkbox-input';
label.appendChild(checkbox);
label.appendChild(text);
return label;
}
Animation1.prototype.subscriber = function (_ref) {
var key = _ref.key,
value = _ref.value;
@ -6305,6 +6338,8 @@ Animation1.prototype.subscriber = function (_ref) {
this.updateAnimating(value);break;
case _enums.CONTROLS.COUNT:
this.updateCount(value);break;
case _enums.CONTROLS.MOVEMENT_CIRCLE:
this.updateMovementCircle(value);break;
case _enums.CONTROLS.RADIUS:
this.updateRadius(value);break;
case _enums.CONTROLS.ROTATION:
@ -6346,6 +6381,14 @@ Animation1.prototype.updateCount = function (count) {
}
};
Animation1.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 });
});
};
Animation1.prototype.updateRadius = function (randomizeRadius) {
this.options.randomizeRadius = randomizeRadius;
this.particles.forEach(function (p) {
@ -6414,17 +6457,13 @@ var RAD = {
var CONTROLS = {
ANIMATING: 'animating',
COUNT: 'count',
MOVEMENT_CIRCLE: 'movementCircle',
RADIUS: 'radius',
ROTATION: 'rotation',
SPEED: 'speed'
};
var IMAGES = {
SEAHORSE: 'seahorse'
};
exports.CONTROLS = CONTROLS;
exports.IMAGES = IMAGES;
exports.RAD = RAD;
/***/ }),
@ -6480,35 +6519,35 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
// import DOM from './dom';
var random = {
bool: function bool() {
return Math.random() < 0.5;
bool: function bool(weight) {
return Math.random() < (weight || 0.5);
},
num: function num(min, max) {
return min + Math.round(Math.random() * max);
},
color: function color() {
return 'rgb(' + Math.floor(Math.random() * 255) + ', ' + Math.floor(Math.random() * 255) + ', ' + Math.floor(Math.random() * 255) + ')';
}
};
/* ===== Constructor ===== */
function Particle(container, bounds, options) {
var _this = this;
var color = random.color();
this.container = container;
this.bounds = bounds;
this.visionGridPoints = calculateVisionGridPoints();
// this.visionGridPoints = calculateVisionGridPoints();
this.node = document.createElement('div');
this.node.className = 'particle has-vision';
this.circle = document.createElement('div');
this.circle.className = 'particle-movement-circle';
this.node.style.backgroundColor = color;
this.container.appendChild(this.node);
this.container.appendChild(this.circle);
this.visionGridPoints.forEach(function (point) {
_this.container.appendChild(point.div);
});
// this.visionGridPoints.forEach(point => {
// this.container.appendChild(point.div);
// });
this.options = Object.assign({
randomizeRadius: false,
@ -6527,11 +6566,12 @@ function Particle(container, bounds, options) {
this.particle = {
clockwise: random.bool(),
color: color,
x: 0,
y: 0
};
this.interval = 0;
this.interval = random.num(_enums.RAD.t90, _enums.RAD.t360);
this.updateOptions(this.options);
this.nextFrame();
@ -6540,31 +6580,38 @@ function Particle(container, bounds, options) {
Particle.prototype.nextFrame = function () {
this.move();
repaintParticle(this.arc, this.node, this.particle);
repaintCircle(this.arc, this.circle, this.particle);
if (this.options.showMovementCircle) {
repaintCircle(this.arc, this.circle);
}
if (this.options.showVisionGrid) {
repaintVisionGrid(this.arc, this.particle, this.visionGridPoints);
}
// if (this.options.showVisionGrid === true) {
// repaintVisionGrid(this.arc, this.particle, this.visionGridPoints);
// }
};
Particle.prototype.updateOptions = function (options) {
Object.assign(this.options, options);
// this.particleImage = options.image || IMAGES.SEAHORSE;
if (options.showMovementCircle === true && this.circle === undefined) {
this.circle = document.createElement('div');
this.circle.className = 'particle-movement-circle';
this.circle.style.borderColor = this.particle.color;
this.node.appendChild(this.circle);
}
if (options.showMovementCircle === false && this.circle !== undefined) {
this.circle.parentNode.removeChild(this.circle);
delete this.circle;
}
};
Particle.prototype.move = function () {
// Randomly change radius and rotation direction.
this.interval -= 1;
if (this.interval <= 0) {
this.interval = random.num(50, 100);
this.interval = random.num(_enums.RAD.t90, _enums.RAD.t360);
if (this.options.randomizeRadius === true) {
this.arc = moveArc(this.arc, random.num(100, 200));
if (random.bool() && this.options.randomizeRotation === true) {
if (random.bool(0.8) && this.options.randomizeRotation === true) {
this.particle.clockwise = !this.particle.clockwise;
this.arc = changeDirection(this.arc);
}
@ -6573,6 +6620,8 @@ Particle.prototype.move = function () {
// Ensure constant velocity and theta between 0 and 2π.
var delta = this.options.speed / this.arc.r;
this.interval -= delta;
this.arc.t += this.particle.clockwise ? -delta : +delta;
this.arc.t = this.arc.t > 0 ? this.arc.t % _enums.RAD.t360 : _enums.RAD.t360 - this.arc.t;
@ -6668,14 +6717,18 @@ function repaintParticle(arc, node, particle) {
node.style.left = particle.x + 'px';
node.style.top = particle.y + 'px';
node.style.transform = 'rotate(' + rad + 'rad)';
}
function repaintCircle(arc, node) {
function repaintCircle(arc, node, particle) {
if (node === undefined) {
return;
}
node.style.width = 2 * arc.r + 'px';
node.style.height = 2 * arc.r + 'px';
node.style.left = arc.x - arc.r + 'px';
node.style.top = arc.y - arc.r + 'px';
node.style.left = -particle.x - arc.r + arc.x + 'px';
node.style.top = -particle.y - arc.r + arc.y + 'px';
node.style.borderRadius = arc.r + 'px';
}

42
js/controls.js vendored

@ -1,19 +1,24 @@
import Rx, { Observable } from 'rxjs';
import { CONTROLS } from './enums';
function Controls(container, { animating, count, randomizeRadius, randomizeRotation, speed }) {
function Controls(container, { animating, count, maxCount, randomizeRadius, randomizeRotation, speed }, customNodes) {
this.nodes = {
animating: createAnimatingControl(animating),
count: createCountControl(count),
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);
container.appendChild(this.nodes.speed);
if (customNodes !== undefined) {
customNodes.forEach(node => { container.appendChild(node); });
}
container.appendChild(this.nodes.animating);
this.updateOptions({ key: CONTROLS.ANIMATING, value: animating });
@ -38,7 +43,6 @@ Controls.prototype.updateOptions = function({ key, value}) {
this.nodes.animating.querySelector('span').innerHTML =
(value ? '&#9724; Stop' : '&#9654; Start');
}
}
Controls.prototype.mount = function(customNodes) {
@ -90,20 +94,20 @@ const createAnimatingControl = function(value) {
return label;
}
const createCountControl = function(value) {
const createCountControl = function(value, max) {
const label = document.createElement('label');
label.className = 'controls-label';
label.className = 'controls-range';
const text = document.createElement('span');
text.innerHTML = '...';
text.className = 'controls-label-text';
text.className = 'controls-range-text';
const slider = document.createElement('input');
slider.type = 'range';
slider.min = 1;
slider.max = 5;
slider.max = max;
slider.value = value;
slider.className = 'controls-slider';
slider.className = 'controls-range-input';
label.appendChild(text);
label.appendChild(slider);
@ -113,15 +117,15 @@ const createCountControl = function(value) {
const createRadiusControl = function(value) {
const label = document.createElement('label');
label.className = 'controls-label';
label.className = 'controls-checkbox';
const text = document.createElement('span');
text.innerHTML = 'Random radii';
text.className = 'controls-label-text';
text.className = 'controls-checkbox-text';
const checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.className = 'controls-label-checkbox';
checkbox.className = 'controls-checkbox-input';
checkbox.checked = value;
label.appendChild(checkbox);
@ -132,15 +136,15 @@ const createRadiusControl = function(value) {
const createRotationControl = function(value) {
const label = document.createElement('label');
label.className = 'controls-label';
label.className = 'controls-checkbox';
const text = document.createElement('span');
text.innerHTML = 'Random rotation';
text.className = 'controls-label-text';
text.className = 'controls-checkbox-text';
const checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.className = 'controls-label-checkbox';
checkbox.className = 'controls-checkbox-input';
checkbox.checked = value;
label.appendChild(checkbox);
@ -151,17 +155,17 @@ const createRotationControl = function(value) {
const createSpeedControl = function(value) {
const label = document.createElement('label');
label.className = 'controls-label';
label.className = 'controls-range';
const text = document.createElement('span');
text.className = 'controls-label-text';
text.className = 'controls-range-text';
const slider = document.createElement('input');
slider.type = 'range';
slider.min = 1;
slider.max = 10;
slider.max = 50;
slider.value = value;
slider.className = 'controls-slider';
slider.className = 'controls-range-input';
label.appendChild(text);
label.appendChild(slider);

@ -9,13 +9,10 @@ const RAD = {
const CONTROLS = {
ANIMATING: 'animating',
COUNT: 'count',
MOVEMENT_CIRCLE: 'movementCircle',
RADIUS: 'radius',
ROTATION: 'rotation',
SPEED: 'speed'
};
const IMAGES = {
SEAHORSE: 'seahorse'
};
export { CONTROLS, IMAGES, RAD };
export { CONTROLS, RAD };

@ -4,29 +4,29 @@ import { RAD } from './enums';
import Store from './store';
const random = {
bool: () => Math.random() < 0.5,
num: (min, max) => min + Math.round(Math.random() * max)
bool: (weight) => Math.random() < (weight || 0.5),
num: (min, max) => min + Math.round(Math.random() * max),
color: () => `rgb(${Math.floor(Math.random() * 255)}, ${Math.floor(Math.random() * 255)}, ${Math.floor(Math.random() * 255)})`
}
/* ===== Constructor ===== */
function Particle(container, bounds, options) {
const color = random.color();
this.container = container;
this.bounds = bounds;
this.visionGridPoints = calculateVisionGridPoints();
// this.visionGridPoints = calculateVisionGridPoints();
this.node = document.createElement('div');
this.node.className = 'particle has-vision';
this.circle = document.createElement('div');
this.circle.className = 'particle-movement-circle';
this.node.style.backgroundColor = color;
this.container.appendChild(this.node);
this.container.appendChild(this.circle);
this.visionGridPoints.forEach(point => {
this.container.appendChild(point.div);
});
// this.visionGridPoints.forEach(point => {
// this.container.appendChild(point.div);
// });
this.options = Object.assign({
randomizeRadius: false,
@ -46,11 +46,12 @@ function Particle(container, bounds, options) {
this.particle = {
clockwise: random.bool(),
color,
x: 0,
y: 0
}
this.interval = 0;
this.interval = random.num(RAD.t90, RAD.t360);
this.updateOptions(this.options);
this.nextFrame();
@ -59,31 +60,38 @@ function Particle(container, bounds, options) {
Particle.prototype.nextFrame = function() {
this.move();
repaintParticle(this.arc, this.node, this.particle);
repaintCircle(this.arc, this.circle, this.particle);
if (this.options.showMovementCircle) {
repaintCircle(this.arc, this.circle);
}
if (this.options.showVisionGrid) {
repaintVisionGrid(this.arc, this.particle, this.visionGridPoints);
}
// if (this.options.showVisionGrid === true) {
// repaintVisionGrid(this.arc, this.particle, this.visionGridPoints);
// }
}
Particle.prototype.updateOptions = function(options) {
Object.assign(this.options, options);
// this.particleImage = options.image || IMAGES.SEAHORSE;
if (options.showMovementCircle === true && this.circle === undefined) {
this.circle = document.createElement('div');
this.circle.className = 'particle-movement-circle';
this.circle.style.borderColor = this.particle.color;
this.node.appendChild(this.circle);
}
if (options.showMovementCircle === false && this.circle !== undefined) {
this.circle.parentNode.removeChild(this.circle);
delete this.circle;
}
}
Particle.prototype.move = function() {
// Randomly change radius and rotation direction.
this.interval -= 1;
if (this.interval <= 0) {
this.interval = random.num(50, 100);
this.interval = random.num(RAD.t90, RAD.t360);
if (this.options.randomizeRadius === true) {
this.arc = moveArc(this.arc, random.num(100, 200));
if (random.bool() && this.options.randomizeRotation === true) {
if (random.bool(0.8) && this.options.randomizeRotation === true) {
this.particle.clockwise = !this.particle.clockwise;
this.arc = changeDirection(this.arc);
}
@ -92,6 +100,8 @@ Particle.prototype.move = function() {
// Ensure constant velocity and theta between 0 and 2π.
const delta = this.options.speed / this.arc.r;
this.interval -= delta;
this.arc.t += (this.particle.clockwise ? -delta : +delta);
this.arc.t = (this.arc.t > 0 ? this.arc.t % RAD.t360 : RAD.t360 - this.arc.t);
@ -189,14 +199,18 @@ function repaintParticle(arc, node, particle) {
node.style.left = `${particle.x}px`;
node.style.top = `${particle.y}px`;
node.style.transform = `rotate(${rad}rad)`;
}
function repaintCircle(arc, node) {
function repaintCircle(arc, node, particle) {
if (node === undefined) {
return;
}
node.style.width = `${2 * arc.r}px`;
node.style.height = `${2 * arc.r}px`;
node.style.left = `${arc.x - arc.r}px`;
node.style.top = `${arc.y - arc.r}px`;
node.style.left = `${-particle.x - arc.r + arc.x}px`;
node.style.top = `${-particle.y - arc.r + arc.y}px`;
node.style.borderRadius = `${arc.r}px`;
}

Loading…
Cancel
Save