웹아틀리에 - Web atelier

Jquery 애니메이션은 어떻게 작동하는가? -기본 편 본문

IT-웹 Front end/jQuery & Javascript

Jquery 애니메이션은 어떻게 작동하는가? -기본 편

네루펜 2016. 5. 30. 17:46

매번 방문할때마다 느끼는 거지만 네이버 D2 Hello world는 정말 좋은 곳 인것 같습니다.

평소에 별 의미를 느끼지 못하고 사용하던 것들이 알고보면 매우 복잡하고 다양한 로직을 수행하고 있더랍니다.

오늘도 후진 개발자를 위해서 지식을 나누어 주신 분들께 감사를 표하며 글을 읽습니다.



전문출처 - 손찬욱 | 네이버AU개발랩 ( http://d2.naver.com/helloworld/0265052 )


웹 개발에서 가장 많이 사용하는 JavaScript 프레임워크는 단연 jQuery일 것입니다. 2006년 6월 30일 존 레식(John Resig)이 jQuery 1.0a를 공개한 이후 jQuery는 꾸준히 발전해 지금은 업계의 현실적인 표준이라고 말해도 손색이 없을 만큼 성장했습니다. jQuery는 DOM을 제어하고 이벤트를 처리하는 일을 주로 담당하지만, 그 외에도 웹 개발을 쉽게 할 수 있게 도와주는 많은 기능을 제공합니다.

이 글에서는 jQuery가 제공하는 기능 가운데 jQuery.fn.animate() 함수에 관해 이야기하려 합니다.

"jQuery 애니메이션은 어떻게 작동하는가?"는 기본, 심화, 활용의 총 3편에 걸쳐 jQuery의 애니메이션을 다룰 예정입니다. 이 글은 첫 번째인 기본 편으로, jQuery로 애니메이션을 구현하는 방법과 jQuery 애니메이션의 작동 방식을 간략하게 설명합니다.

이 글에서 설명하는 내용은 jQuery 2.2.1이 기준입니다.

비동기 애니메이션 구현

비동기로 작동하는 애니메이션을 구현하려면 몇 가지 기능이 꼭 지원돼야 한다. 다음 배너를 예로 살펴보자.

그림 1 애니메이션으로 구현한 배너(원본 출처: http://sculove.github.io/slides/jQueryAnimate/example/banner.html)

위와 같은 배너를 만들기 위해서는 크게 다음과 같은 네 가지 기능을 구현할 수 있어야 한다.

  • 하나의 요소를 순서대로 움직이기
  • 여러 개의 요소를 순서대로 움직이기
  • 여러 개의 요소를 동시에 움직이기
  • 애니메이션을 반복하기

jQuery를 이용한 애니메이션 구현

jQuery는 그림 1의 배너와 같이 복잡한 애니메이션을 간단히 개발할 수 있게 jQuery.fn.animate() 함수를 제공한다. 이 함수는 slideDown()slideUp()slideToggle()fadeTo()fadeIn()fadeOut()fadeToggle() 등 애니메이션 관련 함수의 실제 구현체이며, 애니메이션을 구현할 때 사용할 수 있는 저수준(low level) API다.

jQuery.fn.animate() 함수로 그림 1의 배너에 필요한 애니메이션 기능을 어떻게 구현하는지 살펴보겠다.

하나의 요소를 순서대로 움직이기

공이 날아가는 궤적이 다르다면, 즉 공이 왼쪽으로 갔다가 다시 오른쪽으로 간다면, 하나의 공, 즉 하나의 요소에 두 개의 애니메이션을 차례로 적용해야 한다. jQuery.fn.animate() 함수를 체이닝으로 호출하면 차례로 애니메이션을 실행할 수 있다.

다음 예는 클래스 이름이 box인 박스 요소의 속성을 left:150px와 top:150pxleft:50pxtop:0px로 차례로 바꾸면서 요소가 이동하게 하는 코드다. 실제 작동하는 모습은 http://codepen.io/sculove/pen/BoXYwq에서 확인할 수 있다.

...
    $(".box").animate({ left : "150px" },1000)
      .animate({ top : "150px" },1000)
      .animate({ left : "50px" },1000)
      .animate({ top : "0px" },1000);
...

여러 개의 요소를 순서대로 움직이기

그림 1의 배너에서는 배가 움직인 다음 물음표가 서서히 나타나고 이후 문장이 나온다. 이런 배너를 구현하려면 배를 움직이는 애니메이션과 물음표가 표시되는 애니메이션, 문장이 표시되는 애니메이션이 차례로 실행돼야 한다. jQuery.fn.animate() 함수에서 콜백 함수를 호출하거나 Promise 객체를 이용하면 여러 개의 요소를 차례로 움직이는 애니메이션을 쉽게 구현할 수 있다.

콜백 함수를 사용하는 방법

jQuery.fn.animate() 함수의 파라미터에 애니메이션 종료 시점에 호출할 콜백 함수를 등록하면 다른 요소에 애니메이션을 적용할 수 있다.

다음 예는 클래스 이름이 box1인 박스 요소와 box2인 박스 요소가 차례로 이동하게 jQuery.fn.animate() 함수의 파라미터에 콜백 함수를 등록한 코드다. 실제 작동하는 모습은 http://codepen.io/sculove/pen/wKVypR에서 확인할 수 있다.

...
    $(".box1").animate({ left : "200px" },1000, function() {
      $(".box2").animate({ left : "50px" },1000, function() {
        $(".box1").animate({ top : "150px" },1000, function() {
          $(".box2").animate({ top : "0px" },1000, function() {
            alert("완료!");
          });
        });
      });
    });
...

box1 요소의 속성을 left:200px로 바꿔 요소를 이동한 다음 box2 요소의 속성을 left:50px로 바꾸는 함수를 호출한다. 그다음에는 다시 box1 요소의 속성을 top:150px로 바꾸는 함수를 호출한다. 마지막으로 box2 요소의 속성을 top:0으로 바꾸는 함수를 호출한다. 모든 애니메이션이 끝나면 브라우저의 메시지 상자에 "완료!"를 표시하는 alert() 메서드를 호출한다.

Promise 객체를 사용하는 방법

Promise 객체를 이용하면 콜백 함수를 사용할 때보다 코드를 더 간결하게 작성할 수 있다.

다음 예는 위의 예와 마찬가지로 클래스 이름이 box1인 박스 요소와 box2인 박스 요소를 차례로 이동한 다음 메시지 상자가 나타나게 하는 코드다. 콜백 함수 대신 Promise 객체로 애니메이션을 차례로 실행한다. 실제 작동하는 모습은http://codepen.io/sculove/pen/mPVOmR에서 확인할 수 있다.

...
    $(".box1").animate({ left : "200px" },1000).promise().then(function() {
      return $(".box2").animate({ left : "50px" },1000).promise();
    }).then(function() {
      return $(".box1").animate({ top : "150px" },1000).promise();
    }).then(function() {
      return $(".box2").animate({ top : "0px" },1000).promise();
    }).then(function() {
      alert("완료!");
    });
...

여러 개의 요소를 동시에 움직이기

그림 1의 배너에서는 배가 움직이는 동안 파도도 함께 출렁거린다. 이런 애니메이션을 구현하려면 배를 움직이는 애니메이션과 파도가 출렁이는 애니메이션이 동시에 진행돼야 한다.

배와 파도를 각각 jQuery 객체로 만들고, 각 객체에 애니메이션을 적용하면 여러 요소의 애니메이션을 동시에 실행할 수 있다. 그뿐만 아니라 jQuery.when() 메서드를 이용하면 각 애니메이션이 종료되는 시점도 제어할 수 있다.

다음 예는 두 개의 박스 요소를 동시에 이동하는 코드다. 요소의 이동이 완료되면 브라우저의 메시지 상자에 "완료!"를 표시하는 alert() 메서드를 호출한다. 실제 작동하는 모습은 http://codepen.io/sculove/pen/xwvYzq에서 확인할 수 있다.

...
    var $box1 = $(".box1");
    var $box2 = $(".box2");
    $box1.animate({ left : "200px" },1000);
    $box2.animate({ top : "0px" }, 1000);

    $.when($box1, $box2).then(function() {
        alert("완료!");
    });
...

애니메이션을 반복하기

그림 1의 배너에서는 모든 애니메이션이 진행되는 동안에 파도가 항상 출렁거린다. jQuery는 반복해서 애니메이션을 실행하는 인터페이스를 정식으로 지원하지는 않는다. 하지만 약간의 프로그래밍 기술을 이용하면 반복되는 애니메이션 또한 손쉽게 구현할 수 있다. 재귀 함수와 jQuery의 jQuery.fn.animate() 함수를 이용하는 방법이다. 즉, 차례로 실행되는 애니메이션이 모두 완료되면 애니메이션을 실행하는 첫 번째 함수를 다시 호출하도록 구현해 애니메이션이 반복되게 한다.

다음 예는 boat라는 jQuery 객체의 bottom 속성값을 15px에서 25px로 바꾸는 애니메이션을 반복해서 실행하는 코드다.

function loopBoat() {  
      $boat.animate({ 'bottom' : '15px'}, 500)
        .animate({ 'bottom' : '25px'}, 500, loopBoat);
    }

bottom 속성값을 15px에서 25px로 바꾸는 loopBoat() 함수를 만들었다. jQuery.fn.animate() 함수의 파라미터에 loopBoat() 함수를 콜백 함수로 넘겨주면 애니메이션이 반복해서 실행된다.

jQuery 애니메이션 구현 요소

앞에서 살펴본 것과 같이 jQuery 애니메이션을 이용하면 비동기 방식으로 작동하는 애니메이션을 동기 방식으로 손쉽게 구현할 수 있다. 동기 방식으로 구현한 애니메이션을 비동기 방식으로 실행하기 위해 jQuery 내부에서는 많은 작업이 이루어진다.

jQuery 애니메이션을 실행하는 작업에는 다음과 같이 많은 클래스와 객체, 메서드, 함수가 이용된다.

  • jQuery.fn.animate() 메서드: 사용자가 애니메이션을 구현할 때 사용할 수 있는 메서드
  • jQuery.Animation() 함수: 애니메이션 실행에 필요한 정보를 구성하고, 애니메이션의 상태를 관리하는 Promise 객체를 반환하는 팩토리 함수
  • jQuery.fx 객체: 실제 애니메이션을 작동시키는 객체. jQuery.Tween 클래스를 상속받았다.
  • jQuery.Tween 클래스: 속성별 애니메이션 클래스
  • jQuery.fn.queue, jQuery.fn.dequeue: Promise 객체를 생성하는 doAnimation() 함수를 저장하고 실행하는 큐(queue). DOM 요소마다 큐가 있다.
  • jQuery.Deferred() 함수: Promise 객체를 생성하는 팩토리 함수

이 글은 jQuery 애니메이션을 다루기 때문에 jQuery.fn.queue와 jQuery.fn.dequeue, jQuery.Deferred() 함수에 관한 자세한 설명은 생략한다. 그 외에 jQuery 애니메이션 내부에서 일어나는 일에 관한 더 자세한 내용은 이 글에 이어지는 다음 편에서 설명할 것이다.

jQuery 애니메이션 관련 파일

jQuery 애니메이션과 관련된 내용을 더 자세하게 살펴보려면 GitHub의 jQuery 저장소에서 관리하는 파일을 확인한다.

jQuery는 기능에 따라 파일을 분리해 저장소에서 관리한다. 일반적으로 jQuery 저장소에서 애니메이션과 관련된 파일은effects.js 파일과 effects 디렉터리에 있는 파일이다. jQuery를 빌드하면 이 파일의 코드가 하나로 합쳐져 다른 영역의 코드와 결합해 애니메이션을 처리한다.

effects.js 파일

effect.js 파일에는 jQuery 인스턴스 메서드가 정의돼 있으며, jQuery.Animation 객체와 jQuery.speed 객체, jQuery.fx 객체가 정의돼 있다.

애니메이션 관련 메서드

jQuery에서 애니메이션을 다룰 때 사용하는 인스턴스 메서드는 다음과 같다. jQuery 애니메이션의 인스턴스 메서드는 모두 jQuery.fn.animate() 메서드를 이용해 구현돼 있다. 사용자 편의성을 위해 jQuery.fn.animate() 메서드를 감싸서(wrapping) 구현한 메서드다.

jQuery.Animation() 함수

jQuery.Animation() 함수는 애니메이션 실행에 필요한 정보를 구성하고, Animation 객체의 상태를 관리하는 Promise 객체를 반환하는 팩토리 함수다. jQuery.Animation() 함수에 관한 자세한 내용은 "jQuery 애니메이션 처리 과정"에서 살펴보겠다.

jQuery.speed() 메서드

jQuery.speed() 메서드는 jQuery.fn.animate() 메서드에 입력된 값을 jQuery.Animation() 함수에서 처리할 수 있는 값으로 변경한다.

jQuery.fx 객체

jQuery.fx 객체는 jQuery.fn.animate() 메서드가 호출한 애니메이션을 관리하고 실행하는 객체다. jQuery.Animation() 함수가 생성한 Promise 객체와 tick() 메서드로 애니메이션을 실행한다.

effects/Tween.js 파일

Tween.js 파일에는 속성별 애니메이션 클래스인 Tween 클래스와 jQuery.easing 객체가 선언돼 있다.

jQuery 애니메이션 처리 과정

다음은 jQuery.fn.animate() 함수를 호출해 애니메이션을 실행할 때 jQuery 내부에서 일어나는 과정을 나타낸 그림이다.

그림 2 jQuery 애니메이션 처리 과정

그림 2 jQuery 애니메이션 처리 과정

jQuery 애니메이션을 실행하는 과정은 다음과 같다.

  1. jQuery.fn.animate() 메서드를 호출한다.
  2. jQuery.Animation() 함수를 호출하는 doAnimation() 함수를 큐에 등록한다.
  3. 큐에 등록된 doAnimation() 함수를 실행하고 큐에는 "inprogress" 문자열을 등록해 진행 여부를 표시한다.
  4. jQuery.Animation() 함수가 호출되면 다음과 같은 과정으로 Animation 객체를 생성한다. 
    a. 애니메이션의 상태를 관리하는 Promise 객체를 생성한다. 
    b. 애니메이션의 이동을 제어하는 tick() 함수를 생성한다. 
    c. 생성된 Promise 객체와 tick() 함수를 jQuery.timers 객체에 등록한다.
  5. jQuery.fx.tick() 함수가 다음과 같은 과정으로 애니메이션을 진행한다. 
    a. 애니메이션이 완료되면 Promise 객체의 상태를 'resolve'로 바꾼다. 
    b. 큐에서 "inprogress" 문자열을 제거하고 다시 큐를 확인한다.
  6. 큐에 등록된 애니메이션이 있다면 3번 과정부터 다시 진행한다.

jQuery 애니메이션은 Promise 객체를 큐에 저장하는 구조를 사용해 '순차적(sequence) 애니메이션'을 처리한다. 그뿐만 아니라 DOM 요소마다 있는 큐를 타이머 하나(jQuery.fx 객체)로 관리하면서 요소의 좌표를 이동하고 경과 시간을 기준으로 요소의 좌표를 계산하는 구조 덕분에 동시에 여러 대상에서 애니메이션을 실행할 수 있다.

마치며

jQuery는 비동기 방식으로 작동하는 애니메이션을 동기 방식으로 개발할 수 있는 인터페이스를 제공한다. 하나 이상의 요소에 차례로 애니메이션을 적용할 수 있으며, 동시에 여러 요소에 다른 애니메이션을 적용할 수 있다. 이렇게 할 수 있는 이유는 jQuery의 큐 구조와 Promise 객체, 경과 시간 기준의 좌표 계산 때문이다.

이번 글에서는 jQuery 애니메이션의 사용 방법과 작동 방식을 간략하게 살펴보았다. 다음 편에서는 jQuery 애니메이션의 작동 방식을 더 자세히 살펴보고, 이를 이용해 jQuery 애니메이션을 확장하는 방법을 설명하겠다.

공유하기 링크
Comments