PalmGround

Annoying Button

Markup

<div>
  <button id="annoying">Click me!</button>
</div>

Styles

div {
  display: grid;
  place-items: center;
  min-height: 50vh;
  border: 1px solid var(--color-accent);
}

button {
  transition: transform 0.1s ease-in-out;
}

Script

const button = document.querySelector('#annoying')
const parent = button.parentElement

button.addEventListener('pointerenter', mouseOver)
button.addEventListener('click', handleClick)

const currentPos = {
  left: 0,
  top: 0,
}

const minDistance = 50
const maxDistance = 80
let moving = false

async function mouseOver() {
  if (button.matches(':hover') && !moving) {
    moving = true
    await moveButton()
    moving = false
  }
}

async function moveButton() {
  return new Promise((res) => {
    const prevLeft = currentPos.left
    const prevTop = currentPos.top

    const parentRect = parent.getBoundingClientRect()
    const buttonRect = button.getBoundingClientRect()
    const buttonWidth = buttonRect.width
    const buttonHeight = buttonRect.height

    const distanceLeft = buttonRect.left - parentRect.left
    const distanceTop = buttonRect.top - parentRect.top
    const distanceRight = parentRect.right - buttonRect.right
    const distanceBottom = parentRect.bottom - buttonRect.bottom

    const xDistance = getRandomDistance()
    const yDistance = getRandomDistance()
    const xDirection = getRandomDirection()
    const yDirection = getRandomDirection()

    const isNearLeft = distanceLeft < xDistance
    const isNearRight = distanceRight < xDistance
    const isNearTop = distanceTop < yDistance
    const isNearBottom = distanceBottom < yDistance

    if (isNearLeft) {
      currentPos.left += xDistance
    } else if (isNearRight) {
      currentPos.left -= xDistance
    } else {
      currentPos.left += xDistance * xDirection
    }

    if (isNearTop) {
      currentPos.top += yDistance
    } else if (isNearBottom) {
      currentPos.top -= yDistance
    } else {
      currentPos.top += yDistance * yDirection
    }

    const keyframes = [
      { transform: `translate(${prevLeft}px, ${prevTop}px)` },
      { transform: `translate(${currentPos.left}px, ${currentPos.top}px)` },
    ]

    const animation = button.animate(keyframes, {
      duration: 150,
      easing: 'ease-in-out',
      fill: 'forwards',
    })

    animation.onfinish = () => {
      res()
    }
  })
}

function getRandomDistance() {
  return Math.floor(Math.random() * (maxDistance - minDistance) + minDistance)
}

function getRandomDirection() {
  return Math.random() < 0.5 ? -1 : 1
}

function handleClick() {
  button.innerText = 'Clicked!'
}