Kim-aide / frontend

https://kim-aide.github.io/frontend/
0 stars 0 forks source link

[FEAT] 모든 사용자의 회의 참여 화면 신규 생성 #23

Closed wzrabbit closed 1 month ago

wzrabbit commented 1 month ago

이슈 번호

close #3

작업 요약

본 PR에서는 모든 참가자에 해당하는 회의 화면을 나타내는 컴포넌트를 신규 생성 및 구현했습니다. -- <UserVideoGrid>

1️⃣ <UserVideoGrid> 신규 생성 및 구현

2️⃣ <UserVideo> 관련 작업 진행

참고/인용 자료

1️⃣ 작동 화면

https://github.com/user-attachments/assets/55cc7a1b-cfb9-4b5b-b513-3a46618bd9e1

2️⃣ 원리 설명

필요한 정보를 사용해 작동 화면처럼 유동적으로 자연스럽게, 밸런스 있게 구성된 레이아웃을 표시하는 알고리즘을 설명하겠습니다. 이 알고리즘은 calculateUserVideoGridLayout.ts에 구현되어 있습니다.

엄밀하게 설명해야 되서 내용이 많이 깁니다! 적당히 훑으면서 보셔도 되며, 그림도 넣어두겠습니다. 이건 도메인 지식은 아니니 이해를 원치 않으시면 "아, 어쨌든 최적의 레이아웃을 뽑아서 보여주겠군" 이라고 생각하셔도 좋습니다.

0. 요구하는 정보 / 반환하는 정보

알고리즘이 구현된 도메인 함수가 요구하는 정보는 아래와 같습니다.

알고리즘이 구현된 도메인 함수가 반환하는 정보는 아래와 같습니다.

1. 최적의 그리드 찾기 (Line 10 ~ 39)

image

참가자 수가 같더라도, 이를 활용해 만들 수 있는 레이아웃은 다양할 것입니다. 우리는 이 중에서 가장 자연스러운 레이아웃 하나만을 골라야 합니다. 가장 자연스러운 레이아웃이 "가로 $a$칸, 세로 $b$칸의 격자"라 할 때, $(a, b)$의 값을 구하는 것이 이번 단계의 목표입니다.

이를 실현시키기 위해서 가로 칸의 개수가 $1$개일 경우의 레이아웃, 가로 칸의 개수가 $2$개일 경우의 레이아웃, ..., 가로 칸의 개수가 $1\,000$개일 때의 레이아웃모두 따져줄 것입니다. (가로 칸의 개수가 $1$, $2$, $3$개인 경우의 레이아웃이 위 그림과 같은 경우입니다.)

아래의 절차를 가로 칸의 개수가 $1, 2, 3, ..., 1\,000$인 경우에 대해 모두 진행합니다.

1️⃣ 세로 칸의 개수를 계산합니다. 참가자 수가 정해져 있으므로, 참가자를 꽉 차게 담을 수 있는 세로 칸의 개수는 유일할 것입니다. 너무 세로 칸의 개수가 적다면 칸 수가 모자랄 것이고, 세로 칸의 개수가 너무 많다면 아예 비는 가로줄이 하나 이상 생길 것입니다. 세로 칸의 개수는 아래와 같이 계산합니다.

$$\lceil (\frac{참가자\;수}{가로\;칸의\;개수}) \rceil$$

예를 들어, 참가자가 $5$명이고, 가로 칸이 $3$칸이라고 해 봅시다. 이 경우 $\frac{참가자\,수}{가로\,칸의\,개수}$는 $\frac{5}{3} = 1.666...$이고, 이를 올림하면 $2$이므로 $3 \times 2$의 격자로 결정되는 것입니다. $3 \times 1$이면 참가자를 모두 넣기에 칸 수가 모자랄 것이고, $3 \times 3$이면 아예 빈 줄이 하나 남게 됩니다. 그렇죠?

2️⃣ 단일 비디오 화면의 가로, 세로 크기를 계산합니다. 참가자를 담을 그릇인 격자가 결정되었기 때문에 각 참가자의 비디오 화면의 가로/세로 크기가 특정됩니다. 주의해야 할 점은 격자에는 간격이 있으므로, 먼저 간격을 뺀 후 계산해야 정확한 수치를 구할 수 있습니다.

단일 비디오 화면의 가로 크기는 아래와 같이 계산합니다. 세로 크기도 동일한 형식으로 구할 수 있습니다.

$$\frac{레이아웃의\;가로\;길이 - (간격의\;길이 \times (가로\;칸의\;개수 - 1))}{가로\;칸의\;개수}$$

이 과정에서 단일 비디오 화면의 가로 크기, 세로 크기 중 어느 하나라도 $0$ 이하일 경우 이 과정을 중단하고 다른 가로 칸의 개수로 처음부터 다시 시작합니다. (즉, continue)

3️⃣ 비율을 구하고, 최적의 비율로 갱신하기. 단일 비디오의 가로/세로 크기가 모두 구해졌습니다. 그럼 이제 해야 할 것은 가로/세로의 비율을 정해주는 것이죠.

비율은 가로 크기세로 크기를 나눈 값입니다. 가로가 $300$px, 세로가 $200$px이면 비율은 $1.5$가 되는 것이죠.

그리고, 저는 이미 최고의 비율이라고 생각하는 값을 미리 상수화 해 두었습니다. 그 값은 $\frac{1920}{1080} = 1.777...$입니다. 우리는 이번에 구한 비율을 최고의 비율과 가능한 한 비슷하게 하고 싶고, 얼마나 최고의 비율과 비슷한지는 비율의 오차를 구해 판단할 것입니다.

비율의 오차를 구하는 공식은 아래와 같으며, 수가 작을수록 최고의 비율에 더 가까운 비율이라는 것이죠. 비율의 오차가 $1$이면 최고의 비율과 동일한 비율이라는 의미입니다.

$$\frac{max(현재\,비율, 최고의\,비율)}{min(현재\,비율, 최고의\,비율)}$$

이렇게 비율의 오차를 구한 이후에는, 이전에 구했던 가장 최선이었던 비율의 오차와 비교하고, 더 오차가 낮은 경우에만 현재 구한 정보를 갱신해 줄 겁니다. 이렇게 모든 가로 개수에 대해 비율의 오차를 구한 후 갱신해주면, 마지막에는 가장 비율의 오차가 작은 가로 개수가 정해지겠죠!

2. 비율 조정하기 (Line 41 ~ 42)

이전 단계에서, 최적의 레이아웃을 만들 수 있는 격자를 만들었습니다. 하지만 우리는 근사치를 구했을 뿐 레이아웃에 있는 각각의 비디오 화면은 의외로 꽤 우리가 원하는 비율과 많이 벗어나 찌그러져 있을 수도 있습니다. 이게 마음에 안 들어서, 해결 방법을 생각해 보았어요.

생각해 보면, 비율이 찌그러져 있다면 단일 비디오 화면의 가로/세로 크기 중 어느 한쪽을 줄여서 최적의 비율로 만들 수 있지 않을까요? 그림과 같이요! 레이아웃의 크기는 괜찮아요, 그림과 같이 남는 길이는 여백처럼 만들면 그만이에요. 컴포넌트에서 이렇게 여백이 생길 경우 알아서 정가운데에 배치하도록 css flex 설정은 다 해두었답니다. 이 알고리즘에서 신경쓸 필요가 없어요.

그래서 41 ~ 42번째 줄의 코드에서는 이러한 작업을 해 준 것입니다. 코드가 간단한 편이므로 설명은 이 정도로 마칠게요.

3. 레이아웃 평탄화시키기 (Line 44 ~ 53)

다 된 것 같지만, 악마같은 몇몇 케이스가 있었습니다. 그림과 같이요. 참가자가 $7$명이고, $5 \times 2$ 크기의 격자인 경우, 이런 상황이 발생할 수 있겠죠? 레이아웃에 빈 공간이 생긴 경우 그 빈 공간이 한쪽으로 쏠려 있기에 생길 수 있는 불균형한 레이아웃이에요.

우리는 이 비게 되는 비디오 공간가능한 한 많은 행에 분할해야 자연스러운 레이아웃을 만들 수 있을 거에요. 그림의 경우에는 $[5, 2]$에서 두 번째 행에 있는 빈 공간을 하나 첫 번째 행으로 옮겨 $[4, 3]$을 만든 모습이에요. 더 자연스럽죠?

이렇게 레이아웃을 평탄화시키기 위해, 우리는 먼저

  1. 빈 공간의 개수를 구하고
  2. 각 행에 몇 개의 화면이 배치될 것인지를 의미하는 배열을 만들고 값을 초기화한 뒤
  3. 빈 공간들을 배열의 끝에서부터 앞쪽 방향으로 분배해 줄 거에요.

빈 공간의 개수의 경우 아래의 공식을 이용하여 구할 수 있어요.

$$가로\;칸의\;개수 \times 세로\;칸의\;개수 - 참가자\;수$$

배열의 크기는 세로 칸의 개수로 하면 되고, 각 값은 가로 칸의 개수로 채우면 돼요. 여기까지 한다면 격자가 꽉 찼을 때의 모습이 되죠.

분배하는 방법은, 먼저 각 행에 나눠줄 빈 공간이 더 이상 없을 때까지, 배열의 끝에서부터 앞으로 계속해서 그 행의 참가자 수를 $1$ 빼는 과정을 반복할 거에요. 행의 크기가 $n$이면 $n - 1$ 인덱스에 있는 값을 $1$ 빼고, $n - 2$ 인덱스에 있는 값을 $1$ 빼고, ... 이런 식으로요. $0$번 인덱스에 있는 값을 뺐는데도 빈 공간이 남았다면, 다시 $n - 1$번째 인덱스에 있는 값부터 다시 빼기 시작해요.

끝입니다! 이 과정을 거쳐, 참여자의 수가 변동되고, 화면의 크기가 변동되더라도 항상 자연스럽고 밸런스 있는 레이아웃을 제공해 줄 수 있을 것이라고 생각해요.

wzrabbit commented 1 month ago

<UserVideoGrid>에 대한 스토리북 문서화 및 컴포넌트 설명이 제대로 안 되어 있는 점을 확인했습니다. 리뷰해 주시면 이후 반영해 두도록 하겠습니다. 혹시 컴포넌트에 대해 궁금하신 점이 있거나 이해가 안 되는 점이 있으면 부디 말씀해 주세요.

baesee0806 commented 1 month ago

계산 식부터 조금 헷갈리네요...

세로칸의 공식이 ⌈(참가자수 가로칸의개수)⌉인데 곱셈을 하게 되는건가요? ⌈(참가자수 X 가로칸의개수)⌉ 근데 이걸보면 53= 1.666...이값은 나눗셈인거 같은데 같이 적어두신 이유가 있으실까요?

wzrabbit commented 1 month ago

@baesee0806 해당 부분은 분수로 적혀 있습니다. 나눗셈입니다.

image