Juggling
by Grzegorz Matyszewski
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.9/dat.gui.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.10.3/gsap.min.js"></script>
<li class="circle"></li>
<li class="circle"></li>
<li class="circle"></li>
<li class="circle"></li>
<li class="circle"></li>
<li class="circle"></li>
<li class="circle"></li>
<li class="circle"></li>
<li class="circle"></li>
<li class="circle"></li>
<li class="circle"></li>
<li class="circle"></li>
<li class="circle"></li>
<li class="circle"></li>
<li class="circle"></li>
<li class="circle"></li>
<li class="circle"></li>
<li class="circle"></li>
<li class="circle"></li>
<li class="circle"></li>
CSS
li.circle {
position: absolute;
list-style: none;
width: 40px;
height: 40px;
border-radius: 50%;
border: 1px solid currentcolor;
text-align: center;
line-height: 40px;
counter-increment: li;
margin: -20px;
font-family: monospace;
color: white;
}
li.circle::before { content: counter(li); }
body { margin: 0; padding: 0; background: #fff; }
JavaScript
const options = {
amount: 8,
offset: 125,
radius: 100,
shift: 100,
}
const items = [...document.querySelectorAll('li')];
function draw() {
const step = 360 / options.amount;
const {radius, offset, amount, shift} = options;
const center = { x: window.innerWidth * 0.5, y: window.innerHeight * 0.5 };
items.forEach((el, i) => {
let angle = (offset + i * step);
angle -= Math.sin((90 + angle) / 180 * Math.PI) * shift * step / 150;
const x = center.x + radius * Math.cos(angle * Math.PI / 180);
const y = center.y + radius * Math.sin(angle * Math.PI / 180);
el.style.left = x + 'px';
el.style.top = y + 'px';
el.style.display = i >= amount ? 'none': '';
});
}
/* draw(); */
const gui = new dat.GUI();
gui.add(options, 'radius').min(0).max(200).onChange(draw);
gui.add(options, 'amount').min(3).max(20).step(1).onChange(() => {
draw(); setColors(); });
gui.add(options, 'offset').min(0).max(360).onChange(draw).listen();
gui.add(options, 'shift').min(0).max(100).onChange(draw).name('distortion');
const timeline = gsap.timeline({ onUpdate: draw, repeat: -1 });
timeline.fromTo(options, {
offset: 0,
}, {
offset: 359,
ease: 'none',
duration: 3,
});
gui.add(timeline, 'play');
gui.add(timeline, 'pause');
gui.close();
function setColors() {
items.forEach((el, i) => {
const hue = 360 / options.amount * i;
el.style.backgroundColor = `hsl(${hue}deg, 90%, 60%)`;
});
}
setColors();