베지어곡선 / 애니메이션(CSS/JS)

woolee의 기록보관소·2022년 12월 5일
1

FE개념정리

목록 보기
23/35

베지어 곡선

베지어 곡선(Bezier Curve)은 컴퓨터 그래픽스에서 사용되는 특별한 형태의 곡선이다. CSS 애니메이션 등에서 도형을 그릴 때 사용한다.

베지어 곡선은 n개의 점으로부터 얻어지는 n-1차 곡선이다.

베지어 곡선은 조절점(control point)을 사용해 정의한다. 모양을 결정하는 context point and ending point와, 모양을 결정하는 control point들이 존재한다.

베지어 곡선은 아래와 같은 주요 특징을 지닌다.
1. 조절점은 항상 곡선 위에 있지는 않는다.
2. 곡선의 차수는 조절점의 개수에서 1을 뺀 값이다.
조절점이 2개면 직선이고, 3개면 2차 곡선, 4개면 3차 곡선이 된다.
3. 곡선은 항상 조절점의 convex hull 안에 존재한다.

베지어 곡선은 조절점을 움직여보면 알겠지만, 굉장히 직관적이므로 형태를 쉽게 예측할 수 있다.
(여기에서 직접 마우스로 움직여볼 수 있다.)

베지어 곡선을 이해하려면 카스텔조 알고리즘(De Casteljau's algorithm)을 알아야 한다.

베지어 곡선에서 애니메이션으로 확인해볼 수 있는데, 곡선 위를 지나는 점의 움직임을 따라가보면 된다.

조절점(control point)와 각 end point를 잇는 선이 되는 순간 매개변수 t값이 1이 된다(곡선 양 끝에서 매개변수 t가 1이 된다). control point를 어떻게 찍느냐에 따라서 형태가 달라진다. 카스텔조 알고리즘은 재귀성을 띤다.

이 알고리즘을 자세히 보면, 곡선 양 끝을 제외하고 조절점이 곡선 위에 있는 경우는 없다.

이때 조절점을 통과하는 곡선을 그려야 한다면,
보간(interpolation)을 참고해야 한다.

보통 베지어 곡선은 수학 공식을 알아야 하기 보다는 마우스로 점을 움직여가며 원하는 형태만 도출하면 되지만, 수학 공식은 아래와 같다. 재귀성을 띤다.

매개변수 t는 1과 0을 오고 간다. 각각의 P1, P2는 좌표를 의미한다.
조절점이 2개 일 때, P = (1-t)P1 + tP2
조절점이 3개 일 떄, P = (1−t)2P1 + 2(1−t)tP2 + t2P3
조절점이 4개 일 때, P = (1−t)3P1 + 3(1−t)2tP2 +3(1−t)t2P3 + t3P4
...

0부터 시작해서 1이 될 때까지 매개변수 t를 증가시켜서 무수히 많은 (x, y) 조합을 만들고, 이를 연결해서 곡선을 만드는 원리인 것이다.

CSS 애니메이션

CSS 애니메이션을 사용하면 자바스크립트가 없어도 간단한 애니메이션을 쉽게 구현할 수 있다. 하지만 분명 한계가 있고, CSS로 구현하지 못하는 애니메이션은 자바스크립트로 구현해야 한다.

CSS transition을 사용하면 쉽게 애니메이션을 구현할 수 있다. 개발자는 프로퍼티 값만 변경하면 되고, 변경되는 프로퍼티 값에 따른 자연스러운 transition은 브라우저가 알아서 처리해준다.

CSS transition에 사용되는 프로퍼티 4가지

transition: property name | duration | timing function | delay

3. transition-timing-function

transition-timing-function에는 조절점이 4개면서 아래 조건을 만족하는 베지어 곡선을 구현할 수 있다.
⇒ 첫번째 조절점 (0,0)
⇒ 두번째 조절점 (1,1)
⇒ 중간 조절점 2개 (x가 0에서 1 사이, y는 제약 없음)

CSS에서는 베지어 곡선을 cubic-bezier(x2, y2, x3, y3) 형태로 정의하며, 위 규칙에 따라 첫번째 조절점은 (0,0), 네번째 조절점은 (1,1)으로 고정되고 두번째, 세번째 조절점만 설정하면 된다.

주로 시간이 지남에 따라 애니메이션이 어느 정도 속도로 진행될지 결정하기 위해 사용한다.
x축은 시간이다. 0이면 애니메이션이 시작하는 시간, 1이면 끝나는 시간을 의미한다.
y축은 프로세스 완성 정도이다. 0은 프로퍼티 시작 값, 1은 최종값을 나타낸다.

ease, linear, ease-in, ease-out, ease-in-out, step-start, step-end 등의 키워드를 사용하면 자주 사용하는 베지어 곡선을 쉽게 사용할 수 있다.

혹은 원하는 형태가 따로 있다면 cubic-bezier(x2, y2, x3, y3)를 통해 직접 값을 조정할 수도 있다.

혹은 steps(number of steps[, start/end])을 사용해서 애니메이션을 여러 단계로 나눌 수도 있다.

약간 정리하자면,

  • 베지어 곡선은 형태를 그릴 때 사용할 수 있다.
  • CSS에서 애니메이션을 구현하는 방법 중 하나는 transition을 사용하는 것이다. 변화 전/후 코드를 짜고, transition 값을 부여하면 손쉽게 애니메이션을 구현할 수 있다. (특정 시점에 CSS 속성이 어떤 값을 가져야 하는지 브라우저에 지시하고 격차를 메꾸는 메커니즘)
  • CSS에서 애니메이션의 변화 속도를 설정할 때 키워드로 베지어 곡선을 쉽게 사용할 수 있다.

CSS 애니메이션이 끝나면 transitionend 이벤트가 자동으로 트리거 된다. 애니메이션이 끝났을 때 어떤 동작을 부여하고 싶으면 transitionend 이벤트를 사용하면 된다.

애니메이션을 여러 개 실행하고 싶을 때는 @keyframes를 사용하면 된다.

JS 애니메이션

자바스크립트로는 CSS로 처리할 수 없는 복잡한 애니메이션을 구현할 수 있다. 복잡한 애니메이션일 수록 엄격하게 제어해야 성능을 보장할 수 있으므로 이때는 CSS가 아니라 JS로 애니메이션을 구현해야 한다.

1. setInterval을 사용하는 방법

애니메이션은 일련의 프레임으로 구현될 수 있다. 이때 사용할 수 있는 게 setInterval이다.

setInterval() 함수는 특정 코드를 일정한 간격을 두고 반복 실행할 때 사용할 수 있다. 애니메이션이 아니더라도 웹페이지의 특정 부분을 주기적으로 업데이트하거나 API로부터 데이터를 주기적으로 받아와야 할 때 주로 사용하지만, setInterval로 애니메이션을 구현할 수도 있다.

주의할 점은, setInterval()이나 setTimeout() 같이 자바스크립트의 타이머를 사용하는 내장 함수들은 clearTimeout() 함수와 clearInterval() 함수를 사용해서 타이머를 주기적으로 청소해줘야 한다(메모리 누수 방지).

2. requestAnimationFrame을 사용하는 방법

setInterval은 일일이 구현해야 하므로 쉽지 않다. 예를 들어 브라우저마다 애니메이션 동작 시간이 다를 수 있다.

그리고 애니메이션을 여러 개 만들면 웹페이지가 느려질 수도 있다. 너무 자주 redraws를 할 수 있기 때문이다. (빈번한 geometry recalculation and repaint은 성능에 악영향을 끼친다)

requestAnimationFrame을 사용하면 이를 방지할 수 있다. requestAnimationFrame은 구조화된 애니메이션을 제공해준다.
requestAnimationFrame은 애니메이션을 수행하는 시간을 제어할 수 있다.

애니메이션이 여러 개라고 해서 geometry recalculation and repaint을 여러 번 수행하는 게 아니라, 하나의 geometry recalculation and repaint에 여러 애니메이션을 같이 수행할 수 있게 callback 함수를 예약해준다.

CSS 애니메이션과 JS 애니메이션 비교

CSS 애니메이션은 간단한 애니메이션(예를 들어, 간단한 UI 요소의 상태 전환)을 간단히 만들 수 있다. 빠르고 CPU를 많이 소모하지 않는다.

하지만 CSS 애니메이션은 JS 애니메이션보다 덜 유연하다. 특수한 애니메이션 로직을 구현하려면 JS로 구현해야 한다. JS를 사용하면 단순히 프로퍼티의 변화 뿐만 아니라, 애니메이션에 필요한 새로운 요소를 만들 수 있다. CSS로는 불가능할 수도 있다. 혹은 CSS로 구현하기에는 성능을 떨어트릴 수 있다.

자바스크립트로 애니메이션을 제작하려 한다면 Web Animations API나 관련 프레임워크들을 적극적으로 사용하는 것도 좋은 방법이 될 수 있다. (Web Animations API는 W3C의 비교적 새로운 표준에 가까우며 대부분 브라우저가 지원한다. 다만, 지원하지 않는 브라우저의 경우 polyfill을 사용할 수도 있다)

게다가 자바스크립트로 애니메이션을 구현하면 모든 단계에서 요소의 스타일을 제어할 수 있다. 즉, 동작을 적절하게 캡슐화할 수 있으므로 복잡한 객체 지향 어플리케이션을 구축할 때 특히 유용하다.


**
개인적으로 애니메이션 구현할 때 gsap도 사용하기 좋은 것 같다.
GreenSock - Easing 같은 곳이 애니메이션 구현할 때 참조하기 좋은 것 같다.

**
반복 애니메이션 구현할 때는
ease in out처럼 느렸다가-빨랐다가-느려지는 게 자연스럽다.

참고

위키피디아 - 베지에 곡선
Chapter 66: The Geometry of Design: Bézier Curves for digital Typography and CAGD
CSS transition-timing-function Property
CSS versus JavaScript animations

모던 JavaScript 튜토리얼__추가 주제 : 5.1 베지어 곡선
모던 JavaScript 튜토리얼__추가 주제 : 5.2 CSS 애니메이션
모던 JavaScript 튜토리얼__추가 주제 : 5.3 JS 애니메이션

profile
https://medium.com/@wooleejaan

0개의 댓글