간단한 삼각법을 사용하여 더 좋은 로더(Loader)를 만드는 방법 (How you can use simple Trigonometry to create better loaders)

이 글은 Nash Vail의 How you can use simple Trigonometry to create better loaders 을 번역하였습니다.

최근에 landing pages를 조사하면서 웹 사이트를 우연히 발견했습니다. 그것은 그 사이트를 이용하는 사람들에게 매우 유용했습니다. 사이트의 무언가가 시선을 사로잡았고 저를 조금 불안하게 만들었습니다.
presentation
Nooooo!
지저분하고 부자연스러운 움직임과 원들(circles)의 부드럽지 않은 움직임이 이 글을 쓰게 했습니다.
이 글에서 하려고 하는 것은 삼각법(trigonometry)의 기본 개념을 사용하여 위에서 보는 로더의 훨씬 더 부드러운 버전을 다시 만드는 것입니다. 이것이 이상하게 들리는 것을 알고 있습니다. 이것은 재미있을 것입니다. 모든 코드가 작동하려면 얼마나 적은 코드를 작성해야 하는지 놀라게 될 것입니다. 그리고 이 글을 이해하기 위해 삼각법을 알거나 수학의 천재가 될 필요는 없습니다. 모든 것을 설명할 것입니다.
여기에 우리가 만들 것입니다!
presentation
Smoooooth!

시작합니다.

우리가 만들려고 하는 loader는 기본적으로 주기적인 위아래로 움직이는 세 개의 작은 원들로 구성되며, 각각은 다른 것들과 약간의 싱크가 맞지 않습니다.
파트로 분해해봅시다. 우선, 작은 원을 매끄럽게 주기적으로 위아래로 움직일 것이다. 나머지 부분은 나중에 이해할 것입니다.
항상 코드 작성을 환영합니다.
1. 원의 위치
presentation
위의 모든 코드는 <svg> 요소의 가운데에 작은 원을 그립니다.
presentation
그림 1 : SVG 출력의 실제 표현이 아닙니다.
어떻게 하는지 이해합시다.
widthheight 속성은 정확히 상상할 수 있는 속성입니다. 단순화를 위해 SVG 요소 또는 Box의 width와 height입니다.
presentation
그림 2 : SVG box의 Width와 height.
기본적으로 SVG box는 원점이 왼쪽 상단에 있고 x, y 값이 오른쪽과 아래쪽으로 각각 증가하는 전통적인 좌표계를 사용합니다. 또한 모든 단일 단위는 픽셀에 해당하므로 box의 네 모퉁이가 주어진 widthheight에 따라 적절한 좌표를 갖습니다.
presentation
그림 3 : SVG Box 코너의 좌표.
다음 단계는 초등학교 수학을 사용하여 매우 간단합니다. Box의 중심은 (150, 75)(width/2, height/2)로 계산할 수 있습니다. cxcy에 이 값을 할당하여 원을 가운데에 배치합니다.
presentation
그림 4 : 중심 계산.
2. 원을 움직이게 하기
이 섹션의 목표는 원을 움직이는 것입니다. 그러나 어떤 형태로든 움직이게 하는 것이 아닙니다. 원이 주기적인 상하 운동으로 움직이게 만들 것 입니다.
presentation
그림 5 : 예상되는 움직임.
2.1 주기성의 수학
주기적이란 일정한 간격으로 발생하는 모든 것입니다. 주기성의 가장 간단한 예는 매일 태양의 일출과 일몰입니다. 그리고 시간. 현재 시간은 언제든지, 오후 6시 30분, 24시간 후에 다시 오후 6시 30분이 되며 그 이후 24시간은 다시 오후 6시 30분이 됩니다. 이것은 규칙적입니다. 정확하게 24시간 간격으로 일어나는 일입니다.
정오가 되고 태양이 하늘에서 가장 높은 지점에 있다면 24시간 후에 다시 거기에 있게 됩니다. 저녁이 되고 태양이 지평선에 닿아서 준비가 되면 24시간 후에 다시 똑같이 할 것입니다.
presentation
그림 6 : 태양의 일출 및 일몰 주기.
이것은 매우 단순한 표현이며 심지어 일부 레벨에서 (과학적으로) 부정확하다고 말하지만, 여전히 태양의 위치를 반복하는 점을 이해합니다.
하루의 시간에 대비하여 하늘에서의 태양의 수직 위치를 플로팅 한다면, 우리는 주기성을 보다 분명하게 볼 수 있습니다.
임의의 2차원 곡선을 그리려면 두 개의 값 x , y가 필요합니다. 이 경우에는 [오늘의] timepositionOfTheSun를 정했습니다. 이러한 값의 집합을 수집하여 그래프에 표시하고 이것을 우리가 얻는 것입니다.
presentation
그림 7 : 그래프에 그려진 태양의 일출 및 일몰 주기.
수직축(vertical) 또는 y axis은 하늘에서 태양의 수직 위치이며, 수평축(horizontal) 또는 x axis은 시간을 나타냅니다. 시간이 진행됨에 따라 "position of the Sun"는 값을 변경하고 24시간 후에 동일한 값 세트를 반복합니다.
그래프를 알게 되었으므로, 할 수 있는 것은 동굴 안에 있을지라도 하늘에서 태양의 위치를 파악하는 것입니다. 어떻게 할 수 있는지 보려면 먼저 그래프에 sunsVerticalPositionAt라는 이름을 지정하겠습니다.
일단 우리가 방정식을 만들 수 있다면 ...
verticalPositionInTheSky = sunsVerticalPositionAt( [time] )
그래프 (또는 수학적으로 말해서 함수)에 시간을 들여 공급할 필요가 있습니다. 태양의 위치를 파악할 수 있습니다. 방법은 다음과 같습니다.
presentation
그림 8 : 그래프를 사용하여 태양의 위치를 파악.
태양의 위치 (t1)를 알고, 직선을 그리며, 곡선과 교차하는 곳에서 교차점에서 y축까지 직선을 그린다. 그 새로운 교차로는 그 특정 시간에 우리에게 하늘의 위치를 줍니다.
우리가 유추를 충분히 했다고 생각해 봅시다. 몇 가지 수학으로 바로 뛰어들어 봅시다. 그래프에서 태양과 다른 모든 장식물을 제거할 때, 이것이 우리가 얻는 것입니다.
presentation
그림 9 : 주기적 곡선.
이 그래프는 대담하게 주기성을 나타냅니다. 다른 엔티티 (이 예에서는 time)로 값을 반복하는 엔티티 (이 예에서는 the vertical position of the Sun)가 진행됩니다.
수학에는 몇 가지의 정기 함수가 있습니다, 우리는 가장 기본적인 함수와주기 함수의 특징을 고수할 것이며, 우리는 완벽한 loaders를 만드는 데 사용할 것입니다. y = sin (x) - 사인 함수.
다음은 y = sin(x)에 대한 그래프입니다.
presentation
그림 10 : 사인 곡선
이 방정식과 우리가 하늘에서의 태양의 위치를 알아내는 방정식 사이의 유사점을 보았습니까?
x를 전달하고 y의 값을 얻을 수 있습니다. 우리가 time을 두고 지나가고 하늘에서의 태양의 위치를 파악할 수 있었던 것처럼 ... 동굴을 떠나지 않고서, 지금 저는 동굴 농담을 죽이고 있습니다.
sin/Sine을 생각한다면? 함수에 주어진 이름입니다. sunsVerticalPositionAt의 이름을 지정하는 것과 같습니다. 우리의 graph/function.
여기서 초점을 맞추어야 할 것은 yx입니다. x가 진행됨에 따라 y의 값이 어떻게 변하는 지 보십시오.
또한 도달하는 최대값 y는 1이며 달성할 수 있는 최소값은 -1입니다. 원한다면 Sine 함수의 기능입니다. 값의 범위 y = sin (x)은 -1에서 +1까지 생성됩니다.
그러나 이 범위는 간단한 조작으로 변경할 수 있습니다. 그러나 그전에 지금까지 배웠던 모든 것을 가져와서 할 수 있는 한 많이 움직 이도록 하십시오.
2.2 수학에서 코드로
지금까지 우리는 <svg> ... </ svg> 안에 원을 가지고 있고 원은 c의 id를 가지고 있습니다. 이 원을 자바 스크립트로 타겟팅하고 춤을 추게 합시다!
let c = document.getElementbyId('c');

animate(); function animate() { requestAnimationFrame(animate); }
위의 코드에서 일어나는 일은 간단합니다. 먼저 원을 타겟팅 하여 변수 c에 저장합니다.
다음으로, animate라는 이름의 함수와 함께 requestAnimationFrame을 사용합니다. animaterequestAnimationFrame을 사용하여 재귀 적으로 자신을 호출하여 60FPS (가능한 경우)에서 모든 애니메이션 코드를 실행합니다. requestAnimationFrame에 대한 자세한 내용은 여기를 참조하십시오.
모든 호출에서 animate되는 코드는 전체 애니메이션에서 단일 프레임을 설명한다는 점만 알면 됩니다. 다음에 호출될 때, 재귀 적으로 프레임의 약간의 변경이 이루어집니다. 이것은 매우 빠른 속도 (60 FPS)로 반복해서 수행되며 애니메이션으로 나타납니다.
코드를 자세히 살펴보면 더 이해가 됩니다.
let c = document.getElementById('c');

let currentAnimationTime = 0; const centreY = 75;

animate(); function animate() { c.setAttribute('cy', centreY + (Math.sin(currentAnimationTime)));
currentAnimationTime += 0.15; requestAnimationFrame(animate); }
4줄의 새로운 코드를 추가했습니다. 이것을 실행하면 서클이 서서히 천천히 움직이는 것을 볼 수 있습니다.
presentation
여기 무슨 일이 일어나고 있는 거죠?
원의 중심인 cxcy의 좌표를 얻었으면 50% 정도 완성입니다. 우리가 해야 할 일은 우선 원의 horizontal 위치를 바꾸고 싶지 않기 때문에 cx 만 남겨 둡니다. 동그라미를 오르락 내리락하게 만들기 위해 cy에서 주기적으로 동일한 수를 더하거나 빼야 합니다. 이것이 바로 코드에서 우리가 하는 일입니다.
presentation
그림 11 : 원 중심의 y 좌표 변경.
centreY는 원의 중심 (75)값을 저장하여 이미 언급 한 것처럼 원의 vertical 위치를 변경하기 위해 숫자를 추가하거나 뺄 수 있습니다.
currentAnimationTime은 애니메이션의 속도를 나타내는 0으로 초기화되는 숫자입니다. 호출할 때마다 이를 증가시키면 애니메이션이 더 빠르게 발생합니다. 충분한 속도처럼 보이기 때문에 시행착오를 거쳐 0.15의 값을 선택했습니다.
currentAnimationTime은 사인 그래프 / 함수의 x입니다. currentAnimationTime의 값이 증가하면 Math.sin (Sine의 내장 JavaScript 함수)에 전달하고 생성되는 숫자를 centreY에 추가합니다.
presentation
... 그리고 cysetAttribute를 사용하여 그 숫자를 할당하십시오.
presentation
이미 알고 있는 것처럼 사인은 x의 어떤 값에 대해서도 1-1 사이의 수를 생성할 수 있습니다. 따라서 cy에 할당되는 값의 최소값은 centreY - 1에서 최대값은 centreY + 1입니다. 그러면 원이 해당 위치에서 1픽셀의 margin 만큼 수직으로 흔들립니다.
presentation
그림. 12
그 margin을 증가시키고 자합니다. 1보다 큰 숫자를 필요로 한다는 것을 의미합니다.
2.2에서 시작 직전에 작업을 하려고 했던 것을 기억합니까? 그것은 매우 간단합니다. 우리가 해야 할 일은 Sine에 우리가 원하는 margin을 곱하는 것입니다.
함수에 상수를 곱하는 연산을 스케일링이라고 합니다. 그래프의 모양이 어떻게 바뀌는 지 확인하고, Sine의 최대값과 최소값에 대한 곱셈의 효과를 확인하십시오.
presentation
그림 13 : 그래프 크기 조정
이제는 이를 알았으므로 코드를 수정하십시오.
let c = document.getElementById('c');

let currentAnimationTime = 0; const centreY = 75;

animate(); function animate() { c.setAttribute('cy', centreY + (20 *(Math.sin(currentAnimationTime))));
currentAnimationTime += 0.15; requestAnimationFrame(animate); }

presentation
이것은 원의 매우 부드러운 위아래 애니메이션을 생성합니다.
우리가 한 것은 숫자에 곱셈을 적용하여 사인 함수의 진폭을 증가시킨 것입니다.
그다음으로 할 일은 원본 서클의 양쪽에 두 개의 새로운 서클을 추가하고 같은 방식으로 움직 이도록 하는 것입니다.
<svg width="300" height="150"> <circle id="cLeft" cx="120" cy="75" r="10" /> <circle id="cCentre" cx="150" cy="75" r="10" /> <circle id="cRight" cx="180" cy="75" r="10" /> </svg>
여기에 몇 가지 변경 사항을 적용했으며 코드를 체계화했습니다. 먼저 두 개의 새 줄이 굵게 표시됩니다. 이들은 두 개의 새로운 원으로, 하나는 왼쪽으로 30 픽셀 (150 -30 = 120)이고 다른 하나는 오른쪽으로 (150 + 30 = 180) 위치합니다.
이전에, 우리는 유일한 원에 c의 id를 주었습니다. 그것이 유일한 원이었기 때문에 효과가 있었습니다. 하지만 이제 총 3개의 서클이 있으므로 설명적인 ID를 제공하는 것이 좋습니다. 왼쪽에서 오른쪽으로 원은 cLeft, cCentrecRight의 ID를 갖습니다. ID가 c 인 원래 원이 이제 cCentre입니다.
위의 코드를 실행하면 다음 내용이 표시됩니다.
presentation
좋습니다. 하지만 새로운 서클은 전혀 움직이지 않습니다!
let cLeft= document.getElementById('cLeft'), cCenter = document.getElementById('cCenter'), cRight = document.getElementById('cRight');

let currentAnimationTime = 0; const centreY = 75; const amplitude = 20;

animate();
function animate() {

cLeft.setAttribute('cy', centreY + (amplitude *(Math.sin(currentAnimationTime))));

cCenter.setAttribute('cy',
centreY + (amplitude * (Math.sin(currentAnimationTime))));

cRight.setAttribute('cy', centreY + (amplitude * (Math.sin(currentAnimationTime))));

currentAnimationTime += 0.15; requestAnimationFrame(animate); }
새로운 서클을 대상으로 하고 동일한 애니메이션 코드를 cCentre로 적용하는 몇 가지 추가 코드를 사용하면 이것이 우리가 얻는 것입니다.
presentation
우와! 새로운 원이 움직이고 있습니다! 그러나 우리가 현재 가지고 있는 것은 가능한 한 결코 우리가 구축하기 위해 준비한 loader와 다릅니다.
원이 주기적으로 움직이고 있지만 문제는 3 개의 원이 모두 동기적으로 움직이고 있다는 것입니다. 그건 우리가 원하는 것이 아닙니다. 연속적인 각 원이 약간의 움직임을 지연시키기를 원합니다. 그래서 처음에는 원이 아닌 원이 원의 움직임을 따라가는 것처럼 보입니다. 아래처럼.
presentation
첫 번째 서클 이후의 각 서클은 하나에서 왼쪽으로 약간 동기화되지 않음을 알 수 있습니다. 손바닥으로 다른 두 개의 원을 숨기면 보이는 원이 여전히 2.2에서 코딩 한 것과 동일한 상하 동작을 수행함을 알 수 있습니다.
이제 동그라미를 동기화하지 못하게 하려면, 코드를 약간만 변경하면 됩니다. 그러나 소소한 변화가 어떻게 작용하는지 이해하는 것이 중요합니다.
앞의 그림과 같이 각 원의 움직임을 그래프로 표시하면 그래프가 보입니다.
presentation

그림 14 : 구성 원의 모션 그래프.
각 원이 같은 방식으로 움직이고 있다는 것을 알고 있기 때문에 놀랄 일이 아닙니다. 이 애니메이션을 만들기 위해 Sine 함수를 사용하고 있기 때문에 위의 모든 곡선은 사인 함수의 그래프 일뿐입니다. 이제 이러한 그래프를 동기화하지 않으려면 그래프를 이동 / 변환하는 수학 개념을 이해해야 합니다.
시프트는 함수 그래프의 모양이나 크기를 변경하지 않는다는 점에서 엄격한 변환입니다. 변화는 그래프의 위치를 변경하는 것입니다. 시프트는 수평 또는 수직이 될 수 있습니다. 의도와 목적에 따라 수평 시프트에 관심이 있습니다.
아래의 Gif에서 a의 값을 변경하면 y = sin (x) 그래프가 수평으로 이동하는 것을 볼 수 있습니다.
presentation
그림 15 : 그래프 번화 (Desmos)
이것이 어떻게 작동하는지 이해하기 위해, 태양의 일출과 일몰의 비유로 돌아가 봅시다.
기능은 무엇이었습니까? sunsVerticalPositionAt (t). 맞습니다! 자, 이제 이 함수에 언제든지 전달할 수 있고 그 특정 시간에 하늘에서 태양의 수직 위치를 얻을 수 있습니다. 그러므로 오전 9시에 하늘에서 태양의 위치를 얻으려한다면 sunsVerticalPositionAt (9)를 쓸 수 있습니다.
이제 함수 sunsVerticalPositionAt (t - 3). 우리가 이 새로운 함수 (t 대신에 t-3을 취함)로 전달하는 시간 (t)에 관계없이 여기서 세심한 주의를 기울여야 합니다. 우리는 t보다 3 시간 일찍 태양의 위치 값을 구할 것입니다.
presentation
그림. 16
t = 9 일 때 t = 12에서 6시에 값을 구할 것입니다. 9시에 얻는 등등. 우리는 그 방법으로 함수를 연결했거나, t가 전달되는 것보다 이전 값을 반환합니다.
함수의 그래프를 x 축에서 오른쪽으로 이동했다고 말할 수 있습니다. 아래 그림에서 t = 6에있는 이전 그래프는 값 B를 제공합니다. 그래프가 이동되면 t = 9에서 동일한 값 B가 이동된 그래프에 의해 반환됩니다.
presentation
그림 17 : 그래프 이동.
마찬가지로, sunsVerticalPosition (t + 3) 대신에 3을 더하면 그래프는 왼쪽으로 이동합니다. 즉, 하루 후 3시간 동안 값을 제공합니다.
지금 할 수 있는 일은 머리속에 있는 이 개념에 대한 지식으로 마지막 두 동그라미의 애니메이션을 지시하는 그래프를 이동시키는 것입니다.
presentation
그림. 18
이렇게 하려면 코드를 아주 조금만 변경해야 합니다.
let cLeft= document.getElementById('cLeft'), cCenter = document.getElementById('cCenter'), cRight = document.getElementById('cRight');

let currentAnimationTime = 0; const centreY = 75; const amplitude = 20;

animate(); function animate() {

cLeft.setAttribute('cy', centreY + (amplitude *(Math.sin(currentAnimationTime))));

cCenter.setAttribute('cy', centreY + (amplitude * (Math.sin(currentAnimationTime - 1))));

cRight.setAttribute('cy', centreY + (amplitude * (Math.sin(currentAnimationTime - 2))));

currentAnimationTime += 0.15; requestAnimationFrame(animate); }
cCentercRight를 만드는 그래프를 이동시켰습니다.
presentation
Loader 서클은 절대적인 수학적 정확도로 움직입니다. currentAnimationFrame으로 증가하는 것과 같이 오프셋에 대한 제어 속도 나 amplitude을 제어하고 원하는 방식으로 loader를 애니메이션화하는 등 다른 값으로 언제든지 재생할 수 있습니다.

Skitshare 에서 Git와 GitHub을 가르치는 나의 최초의 온라인 수업을 가지고있다! 이 링크를 사용하면 무료 2 개월 Skillshare 회원 자격을 얻거나 (신용 카드가 필요하고 저를 지원할 수 있습니다.) 또는 이 링크를 사용하여 수업을 무료로 볼 수 있습니다.
스케치를 사용합니까? 그렇다면 와이어 프레이밍에 도움이되도록 만든이 라이브러리를 찾을 수 있습니다!
presentation
Check out Wireframe.sketch.

이 글은 번역 글입니다. 원본 링크입니다.



presentation
안녕하세요! Early adopter입니다.
페이스북 [DTF] 디자인 번역 공장 - Design Translation Factory 그룹도 많이 가입해주시길 바랍니다.
"보버"에서 "디자인 번역 공장" 연재를 저와 함께 해주실 분을 찾습니다. 하단 "리뷰" 또는 "페이스북"으로 편하게 메시지 주세요!
PS. 제가 사용하는 블로그 "보버"에 "함께 쓰는 블로그"라는 기능이 요번에 추가됐네요 ㅋ (미디엄에 퍼블리케이션 같은 기능..)
하단 링크 글을 보시면 "디자인 번역 공장"에 어떻게 함께 연재할 수 있는지 자세히 설명되어있습니다. 또는 쉽게 FB 메시지 주세요!
https://bit.ly/2L6WsZp