• jquery animation easing 제어 :: 마이구미
    수학을 활용한 예제 2017. 6. 25. 15:14
    반응형

    이번 글은 jquery를 통해 easing을 원하는 대로 제어하는 법에 대해 다뤄본다.

    x,y 좌표 그래프 및 연립 방정식에 대한 기본 지식을 요구한다.


    애니메이션을 구현해봤거나, 구현하기 위해서 대부분 jquery의 animate 메소드를 사용해봤을 것이다.


    $( "#book" ).animate({

    opacity: 0.25, left: "50px" }, 5000, () => { // Animation complete. });


    기본적인 목적으로, 위 코드는 5초동안 투명도가 서서히 0.25로 변화하고, 왼쪽방향으로 50px로 이동한다.


    그렇다면, easing은 무엇을 뜻하는 건가?

    Easing Functions 는 매개변수의 변화율을 시간이 지남에 따라 정한다.


    jquery의 animate의 easing의 디폴트 값은 swing으로써, 선형(Linear)이라고 하는 일정한 속도로 움직이게 된다.

    그래프로 나타내면 아래와 같다.


    선형 Linear


    실제로 애니메이션을 구현할 때, 선형과 같은 일정한 속도를 선호하지 않는다.

    보다 자연스럽게 모션을 구현하기 위해, 감속이나 가속과 같은 속도를 원한다.


    그렇기에, 많은 종류의 easing을 사용한다.

    easing은 기본적으로 css에서도 제공하고 있다. (아래는 그 중 일부이다)

    • ease-in
    • ease-out
    • ease-in-out

    원하는 모션을 위해서는 jquery를 사용할 수 있다.

    jquery의 플러그인을 이용하면 아래와 같은 다양한 easing을 간편하게 구현할 수 있다.



    easing functions



    관련 플러그인을 추가하는 방식도 있고, 직접 jquery를 통해 추가해도 된다.

    아래와 같이 추가할 수 있다.


    // x = null; t = currentTime; b = begin; c = end; d = distance;


    $.easing.easeOutBounce = function (x, t, b, c, d) {

        if ((t /= d) < (1 / 2.75)) {

            return c * (7.5625 * t * t) + b;

        } else if (t < (2 / 2.75)) {

            return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;

        } else if (t < (2.5 / 2.75)) {

            return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;

        } else {

            return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;

        }

    };


    $('#book').animate({

        left: '50px'

    }, 5000, 'easeOutBounce', () => {

        // Animation complete callback.

    });


    위 코드는, 특정 시점마다 총 3번 바운스가 일어나게 된다.

    데모 링크를 통해 비교해보자. https://matthewlein.com/experiments/easing.html


    하지만 본인의 경우에는 제공하고 있는 easing을 사용할 수 없었다.

    예를 들어, easeOutBounce와 같이 바운스가 필요했지만, 한번의 바운스만 필요했다.

    easeOutBounce는 그래프나 데모를 보다시피, 3번의 바운스가 일어난다.


    본인이 원하는 그래프는 easeOutBounce 그래프에서 2번의 바운스를 뺀 아래와 같다.


    easeOutBounce 커스텀


    바운스가 일어나기 전과 후로 나누어서 생각해보면 2가지 그래프가 필요하다.

    2가지 그래프는 아래와 같은 식으로 이용할 수 있다.



    y = x^2y = ax^2 + bx + c


    바운스 일어나기 전

    => y = ax^2

    바운스 일어난 후

    => y = ax^2 + bx + c


    코드로는 본인은 1번의 바운스만을 필요로 하기 때문에, 아래와 같이 구현할 수 있다.


    // BOUNCE_TIMING - 바운스가 일어날 시점, 전체 시간의 75%라고 가정한다.

    $.easing.customBounce = function (x, t, b, c, d) { if (t < 0.75 * d) { // y = ax^2 , 바운스가 일어나기 전까지의 시점 return ..... } else { // ax^2 + bx + c = 0, 바운스가 일어나는 시점 return ..... } };


    기울기 a는 바운스가 일어나는 지점인 (t0, x) 좌표를 이용해서 쉽게 구할 수 있다.

    (x는 0 ~ 1이기 때문에, 마지막 도착 지점은 1이 된다. 이것이 return 값이 된다.)


    a = y / x^2 =======> a = 1  / (t0)^2


    이로써, 바운스가 일어나기 전 그래프에 대한 값들을 구할 수 있다.


    그리고 편의를 위해 바운스가 일어난 그래프에서도 구한 기울기 a를 사용할 것이다.

    바운스가 일어난 그래프에서의 두 점의 좌표는 (t0, x) 와 (t, x0) 인 것을 알 수 있다.

    그것을 활용해 연립방정식을 통해 필요한 값을 구할 수 있다.


    a(t0)^2 + b(t0) + c -(a(t)^2 + b(t) + c) 

    ==> b 값 추출


    a와 b를 구했으니, 이를 활용해 c를 구할 수 있다.


    c = -(a(t)^2 + b(t))


    a, b, c 값을 모두 구했기에, 연립 방정식을 통해 두번째 그래프의 시간에 따른 값을 구할 수 있게 되었다.

    코드로는 아래와 같이 구현된다.

    지속시간은 320ms, 바운스가 일어난 시점은 시간의 75% 시점으로 가정한다.


    let BOUNCE_DURATION = 320

    let BOUNCE_TIMING = 0.75


    let A = parseFloat(1 / Math.pow(BOUNCE_TIMING * BOUNCE_DURATION, 2))

    let pointLeft = parseFloat(A * Math.pow(BOUNCE_TIMING * BOUNCE_DURATION, 2))

    let pointRight = parseFloat(A * Math.pow(BOUNCE_DURATION, 2))

    let result = -(pointRight - pointLeft)

    let B = result / parseFloat(BOUNCE_DURATION - (BOUNCE_TIMING * BOUNCE_DURATION))

    let C = 1 - (A * BOUNCE_DURATION * BOUNCE_DURATION + B * BOUNCE_DURATION)


    $.easing.customBounce = function (x, t, b, c, d) {

        if (t < BOUNCE_TIMING * d) {

            // y = ax^2

            return A * t * t

        } else {

            // ax^2 + bx + c = 0

            return A * t * t + B * t + C

        }

    };


    위는 기본적인 접근을 통해 구현한 방식이다.

    다소 최적화되지 않은 코드이지만, 이처럼 커스텀할 수 있다는 것을 보여주기 위함이다.



    jquery easing 제어 관련 링크


    플러그인 없이 jquery easing function 사용

    https://stackoverflow.com/questions/5207301/jquery-easing-functions-without-using-a-plugin

    애니메이션을 위한 easing 커스텀

    https://stackoverflow.com/questions/17471537/add-easing-to-custom-animation-function


    반응형

    댓글

Designed by Tistory.