본문 바로가기

UI 디자인 애니메이션 연구소

바탕화면 마우스 드래그 애니메이션

반응형

애니메이션 소개

문득 바탕화면의 마우스를 드래그 하면서 저 드래그 애니메이션은 어떻게 동작하는 거지? 라는 궁금증이 생겼습니다. 그래서 동작과정을 하나하나 살펴보고, 직관적이게도 위치좌표 사이의 거리에 따라 크기가 변경되는 것을 알 수 있었습니다. 단순한 애니메이션이었지만, 실제 구현을 할 때는 크기의 반전과 같은 생각지 못한 부분에서 예상과 다른 문제가 있었는데요. 이번 포스트는 그렇게 완성된 간단한 애니메이션인 바탕화면 마우스 드래그 애니메이션에 대해서 정리해보는 시간을 가져볼까 합니다.

 

아래는 시작전에 참고하시라고 준비된 완성된 코드 예시입니다. 

 

 

코드 자체만으로 보면 보완해야할 점이 많지만, 여기서 동작 흐름을 살펴보시고, 본인의 프로젝트에 맞게 응용해보시면 좋을 것 같습니다. 그럼 시작하겠습니다.

 

 

소스코드

우선 원리 설명에 앞서 기본적인 소스 코드를 HTML, CSS, JS 순으로 정리하겠습니다.

 

HTML

요소는 하나만 있으면 됩니다. 응용에 따라서는 자바스크립트를 통해 동적으로 요소를 생성, 삭제 해도 됩니다.

<div class="box"></div>

 

CSS

기존적인 CSS 초기화 작업과 box 요소에 대한 몇 가지 속성 설정을 진행합니다. 사용자가 화면에 마우스를 클릭 후 드래그 하기 전 까지는 box 요소가 보여지면 안 되므로 초기 상태는 display:none 으로 지정하였습니다. 이후 .open 클래스가 추가 되면서 동적으로 증가하는 box 가 화면에 보여지게 될 것입니다.

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

.box {
  display: none;
  background: #a9cdf2;
  position: absolute;
}
.open.box {
  display: block;
  position: absolute;
}

 

JS

아래는 사용된 자바스크립트 소스코드 전체입니다. 실제 적용하기에는 코드의 안정성이나 반복적인 부분이 많기 때문에, 여기서 알아보는 것은 어떤 동작원리를 기반으로 애니메이션이 진행되는지 이해하기 위한 초석으로 봐주면 좋을 것 같습니다. 

let startPoint = [0, 0]; // 드래그 시작 위치
let endPoint = [0, 0]; // 드래그 끝 위치
let pressState = false; // 마우스 눌림 상태
let box = document.querySelector(".box"); // 드래그할 요소

// 마우스 다운 (누를 때)
window.addEventListener("mousedown", (e) => {
  pressState = true;

  const x = (startPoint[0] = e.pageX);
  const y = (startPoint[1] = e.pageY);

  box.classList.add("open"); // 박스가 열린 상태로
  box.style.left = x + "px";
  box.style.top = y + "px";
});

// 마우스 업 (뗄 때)
window.addEventListener("mouseup", (e) => {
  pressState = false; // 마우스 업 상태 종료
  box.classList.remove("open");
  
  const x = (endPoint[0] = e.pageX);
  const y = (endPoint[1] = e.pageY);
  
  // 크기 초기화
  box.style.width = 0 + "px";
  box.style.height = 0 + "px";
});

// 마우스 움직임 (드래그 중일 때)
window.addEventListener("mousemove", (e) => {
  if (pressState) {
    const width = e.pageX - startPoint[0];
    const height = e.pageY - startPoint[1];

    // 크기나 위치가 0보다 작으면 반전 효과 적용
    if (width < 0 && height < 0) {
      box.style.transform = "scale(-1)"; // X, Y축 모두 뒤집기
      box.style.width = -width + "px";
      box.style.height = -height + "px";
      box.style.transformOrigin = "left top"; // 뒤집을 기준점을 왼쪽 상단으로
    } else {
      if (width >= 0) {
        box.style.width = width + "px"; // 정상적인 크기
        box.style.transformOrigin = "center"; // 중심을 기준으로 크기 확장
      } else {
        box.style.transform = "scaleX(-1)"; // X축 반전
        box.style.transformOrigin = "left"; // 왼쪽 기준으로 크기 확장
        box.style.width = -width + "px";
      }
      if (height >= 0) {
        box.style.height = height + "px";
      } else {
        box.style.transform = "scaleY(-1)"; // Y축 반전
        box.style.height = -height + "px";
        box.style.transformOrigin = "top"; // 위쪽 기준으로 크기 확장
      }
    }
  }
});

 

 

애니메이션 동작원리

이 애니메이션은 마우스의 위치를 실시간으로 추적하여 box 요소의 크기와 위치를 동적으로 변경하는 방식으로 동작합니다. 전체적인 흐름은 마우스를 눌렀을 때, 마우스를 움직일 때, 마우스를 떼었을 때에 따라 달라집니다. 아래에서 각 단계의 동작 원리를 설명하겠습니다.

 

마우스 다운 (mousedown 이벤트)

// 마우스를 눌렀을 때
window.addEventListener("mousedown", (e) => {
  pressState = true;  // 마우스가 눌린 상태

  // 마우스 위치 기록
  const x = (startPoint[0] = e.pageX);
  const y = (startPoint[1] = e.pageY);

  // 박스를 화면에 표시
  box.classList.add("open");
  box.style.left = x + "px";
  box.style.top = y + "px";
});

사용자가 마우스를 누르면 드래그가 시작됩니다. startPoint 배열에 마우스의 초기 위치(pageX, pageY)가 저장되며, box 요소의 left와 top 스타일을 초기 마우스 위치로 설정하여 box가 그 위치에서 나타나게 만듭니다.
box 클래스에 open을 추가하여, transition 속성에 의해 박스가 크기가 변할 때 부드러운 애니메이션 효과를 제공합니다.

 

마우스 움직임 (mousemove 이벤트)

// 마우스가 움직일 때
window.addEventListener("mousemove", (e) => {
  if (pressState) {  // 마우스 눌린 상태일 때만 작동
    const width = e.pageX - startPoint[0];
    const height = e.pageY - startPoint[1];

    // 마우스를 왼쪽 또는 위로 드래그하면 반전
    if (width < 0 && height < 0) {
      box.style.transform = "scale(-1)";
      box.style.width = -width + "px";
      box.style.height = -height + "px";
      box.style.transformOrigin = "left top";  // 반전 기준점
    } else {
      // 정상적인 크기 확장
      if (width >= 0) {
        box.style.width = width + "px";
        box.style.transformOrigin = "center";
      } else {
        box.style.transform = "scaleX(-1)";
        box.style.transformOrigin = "left";
        box.style.width = -width + "px";
      }
      if (height >= 0) {
        box.style.height = height + "px";
      } else {
        box.style.transform = "scaleY(-1)";
        box.style.height = -height + "px";
        box.style.transformOrigin = "top"; // 반전 기준점
      }
    }
  }
});

 

마우스를 누른 상태에서 이동할 때마다 mousemove 이벤트가 발생합니다. 마우스의 현재 위치(pageX, pageY)와 드래그 시작 위치(startPoint)를 비교하여, box의 너비(width)와 높이(height)를 실시간으로 업데이트합니다.

 

만약 마우스가 왼쪽 또는 위로 드래그되면, box가 뒤집히는 효과가 나타나도록 transform을 적용합니다. 이때 scaleX, scaleY, transformOrigin을 사용하여 반전된 상태로 박스를 그립니다.

 

여기서 중요한 점은 width 나 height 가 마이너스가 될 때 크기 변화와 반전이 필요합니다. 
width와 height가 0보다 작으면 scale(-1)을 사용해 박스를 뒤집고, transformOrigin을 통해 박스의 기준점을 설정하여 반전된 위치에서 크기를 확장합니다. 반면, width와 height가 양수일 경우에는 정상적인 크기 변화를 적용합니다.

 

마우스 업 (mouseup 이벤트)

// 마우스를 뗄 때
window.addEventListener("mouseup", (e) => {
  pressState = false;  // 마우스가 떼어진 상태
  box.classList.remove("open");  // 애니메이션 효과 제거
  
  // 크기 초기화
  box.style.width = 0 + "px";
  box.style.height = 0 + "px";
});

 

사용자가 마우스를 떼면 드래그가 종료됩니다. 이때 pressState를 false로 설정하여 더 이상 크기나 위치가 변경되지 않도록 합니다. box 클래스에서 open을 제거하여, 드래그가 끝난 후에는 부드러운 애니메이션 효과가 적용되지 않게 됩니다.
box의 width와 height를 0으로 설정하여 크기를 초기화합니다.

 

정리

애니메이션이 실제 바탕화면의 마우스처럼 드래그된 박스가 반전되어 확장될 수 있는 키 포인트는 transform 의 scale 과 transformOrigin 입니다. 따라서 이에 대해서 다시 정리하고 마무리할까 합니다.

 

- transform 속성: scaleX(-1), scaleY(-1) 등을 사용하여 요소를 반전시킬 수 있습니다. 이 속성은 박스가 드래그되면서 반전되는 효과를 제공하며, 크기를 변형할 때 원점을 설정하는 transformOrigin 속성과 함께 사용합니더.

반응형