Interactive JavaScript snippets

Snippets I made in vanilla JavaScript/TypeScript to add fully keyboard accessible, interactive JavaScript decorations to a section of a website

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.