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

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

@ -1,10 +1,12 @@
.particle { .particle {
$side: 20px; $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; background-size: $side $side;
border-radius: $side / 2; border-radius: $side / 2;
color: #fff; color: #fff;
font-size: 11px;
height: $side; height: $side;
line-height: $side; line-height: $side;
margin: #{-$side / 2} 0 0 #{-$side / 2}; margin: #{-$side / 2} 0 0 #{-$side / 2};
@ -13,40 +15,29 @@
width: $side; width: $side;
z-index: 1; z-index: 1;
&.has-vision::after { // &.has-vision::after {
border: 50px solid; // border: 50px solid;
border-color: lightgreen transparent transparent turquoise; // border-color: lightgreen transparent transparent turquoise;
border-radius: 50px; // border-radius: 50px;
content: ' '; // content: ' ';
height: 0; // height: 0;
left: -50px; // left: -50px;
margin: #{$side / 2} 0 0 #{$side / 2}; // margin: #{$side / 2} 0 0 #{$side / 2};
opacity: 0.5; // opacity: 0.5;
position: absolute; // position: absolute;
transform: rotate(45deg); // transform: rotate(45deg);
top: -50px; // top: -50px;
width: 0; // width: 0;
} // z-index: 0;
// }
} }
.particle-movement-circle { .particle-movement-circle {
border: 2px dotted darkturquoise; border: 3px dotted darkturquoise;
margin-left: 10px;
margin-top: 10px;
position: absolute; position: absolute;
transition: left 0.2s, top 0.2s, height 0.2s, width 0.2s;
z-index: 0; 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 { .particle-vision-grid {

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

@ -3,7 +3,7 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<link rel="stylesheet" href="css/style.css"> <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> </head>
<body> <body>
<h1>Dust</h1> <h1>Dust</h1>
@ -23,6 +23,10 @@
<hr> <hr>
<p>
<h4>Iteration 1: Organic movement at 32fps</h4>
</p>
<p> <p>
The trickiest portion of this iteration was animating the curved paths. Elliptical geometry was the initial goal, 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 but calculating arc length (to maintain a scalar speed) is quite difficult. Smoothstep cubic curves

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

42
js/controls.js vendored

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

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

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

Loading…
Cancel
Save