Interactive JavaScript Snippets
Snippets I made in vanilla JavaScript/TypeScript to add fully keyboard accessible, interactive JavaScript decorations to a section of a website. Refactored from the designs in my React sub-site hero sections. Quantity, position and colors are randomized with JavaScript, appearance is set with CSS. For the sake of accessibility, I made the elements into unordered list elements that are labelled eye 1, eye 2 etc.
Alien/Jelly Eyes
Features
- Remove with click/tap, or with Enter when focused
- Runs exit animation before removal
- Rotate to face cursor
- Hover/focus animation
- Pointer-enter direction aware movement
- Deployed by giving a container the id “snippet-eyes” and the class “snippet-container”
Geometric
Features
- Remove with click/tap, or with Enter when focused
- Runs exit animation before removal
- Hover/focus animation
- Pointer-enter direction aware movement
- Deployed by giving a container the id “snippet-geometric” and the class “snippet-container”
Bubbles
Features
- Remove with click/tap, or with Enter when focused
- Runs exit animation before removal
- Hover/focus animation jiggle and filter
- Pointer-enter direction aware movement
- Deployed by giving a container the id “snippet-bubbles” and the class “snippet-container”
Some of the Code
Moving the target
Making the target move up, down, left or right, depending on the direction that the pointer enters the target area.
Movement Code
//Move items up, down, left or right, depending on the direction they're approached from:
const movingItem = (e: PointerEvent) => {
const target = e.target as HTMLElement
const targetRight = window.getComputedStyle(target).getPropertyValue("right");
const targetTop = window.getComputedStyle(target).getPropertyValue("top");
const containerRect = target.closest(".snippet-container")?.getBoundingClientRect();
const from = getEnterDirection(e)
switch (from) {
case 'top':
setTimeout(() => {
if (containerRect) target.style.top = `${(parseFloat(targetTop) / containerRect.height) * 100 + 1}%`
else target.style.top = `${parseFloat(targetTop) + 10}px`
}, 100);
break;
case 'right':
setTimeout(() => {
if (containerRect) target.style.right = `${(parseFloat(targetRight) / containerRect.width) * 100 + 1}%`
else target.style.right = `${parseFloat(targetRight) + 10}px`
}, 100);
break;
case 'bottom':
setTimeout(() => {
if (containerRect) target.style.top = `${(parseFloat(targetTop) / containerRect.height) * 100 - 1}%`
else target.style.top = `${parseFloat(targetTop) - 10}px`
}, 100);
break;
case 'left':
setTimeout(() => {
if (containerRect) target.style.right = `${(parseFloat(targetRight) / containerRect.width) * 100 - 1}%`
else target.style.right = `${parseFloat(targetRight) - 10}px`
}, 100);
}
}
//Determine the pointer enter direction:
function getEnterDirection(e: PointerEvent) {
const ref = e.target as HTMLElement
const { width, height, top, left } = ref.getBoundingClientRect();
const l = e.pageX - (left + window.pageXOffset),
t = e.pageY - (top + window.pageYOffset),
xx = width > height ? (height / width) : 1,
x = (l - (width / 2) * xx),
yy = height > width ? (width / height) : 1,
y = (t - (height / 2) * yy),
d = Math.round(Math.atan2(y, x) / 1.57079633 + 5) % 4;
switch (d) {
case 0: return 'top';
case 1: return 'right';
case 2: return 'bottom';
case 3: return 'left';
default: return ''
}
};
Rotate Eyes
Making the eyes rotate to follow the pointer
Rotation code
//Making the eyes rotate to follow the pointer:
const follow = (e: PointerEvent) => {
const eyes = [...document.querySelectorAll<HTMLSpanElement>('.js-eye .inner')]
if (eyes) {
eyes.forEach(eye => {
const rect = eye.getBoundingClientRect()
const x = rect.left + rect.width / 2
const y = rect.top + rect.height / 2
const rotation = radianToAngle(e.clientX, e.clientY, x, y)
eye.style.transform = `rotate(${rotation}deg)`
})
}
}
function radianToAngle(cx: number, cy: number, ex: number, ey: number) {
const dy = ey - cy,
dx = ex - cx,
rad = Math.atan2(dy, dx),
deg = rad * 180 / Math.PI
return deg
}
window.addEventListener('pointermove', follow)
See also other interactive JavaScript examples at my accessible draggable blobs app and pong javascript game.