Bruno Joystick Demo
by Cody Bennett
HTML
<div class="joystick">
<div class="joystick__cursor"></div>
<div class="joystick__ring"></div>
</div>
CSS
body {
background: #F88B3E;
}
.joystick {
position: fixed;
bottom: 10px;
left: 10px;
width: 170px;
height: 170px;
border-radius: 50%;
}
.joystick__cursor {
width: 60px;
height: 60px;
position: absolute;
top: calc(50% - 30px);
left: calc(50% - 30px);
opacity: 0.6;
border: 2px solid #FFFFFF;
border-radius: 50%;
}
.joystick__ring {
position: absolute;
width: 150px;
height: 150px;
top: calc(50% - 77px);
left: calc(50% - 77px);
border-radius: 50%;
border: 2px solid #FFFFFF;
opacity: 0.3;
transform: opacity 0.3 0;
}
JavaScript
const LIMIT = 43;
let active;
const angle = {
center: {
x: 0,
y: 0,
},
current: {
x: 0,
y: 0,
},
};
const joystick = document.querySelector('.joystick');
const cursor = document.querySelector('.joystick__cursor');
const ring = document.querySelector('.joystick__ring');
const boundings = joystick.getBoundingClientRect();
angle.center.x = boundings.left + boundings.width * 0.5;
angle.center.y = boundings.top + boundings.height * 0.5;
const render = () => {
if (active) {
angle.value = Math.atan2(
(angle.current.y - angle.center.y),
(angle.current.x - angle.center.x),
);
const distance = Math.hypot(
angle.current.y - angle.center.y,
angle.current.x - angle.center.x,
);
const radius = distance > LIMIT ? LIMIT : distance;
const cursorX = radius * Math.cos(angle.value);
const cursorY = radius * Math.sin(angle.value);
cursor.style.transform = `translateX(${cursorX}px) translateY(${cursorY}px)`;
}
requestAnimationFrame(render);
};
render();
const touchstart = (event) => {
const [touch] = event.changedTouches;
if (touch) {
active = true;
ring.style.opacity = '0.5';
angle.current.x = touch.clientX;
angle.current.y = touch.clientY;
document.addEventListener('touchend', touchend);
document.addEventListener('touchmove', touchmove, {
passive: false
});
}
};
const touchmove = (event) => {
const [touch] = event.changedTouches;
if (touch) {
active = true;
angle.current.x = touch.clientX;
angle.current.y = touch.clientY;
}
};
const touchend = (event) => {
const [touch] = event.changedTouches;
ring.style.opacity = '0.3';
if (touch) {
active = false;
cursor.style.transform = 'translateX(0px) translateY(0px)';
document.removeEventListener('touchend', touchend);
}
};
joystick.addEventListener('touchstart', touchstart, {
passive: false
});