PIP 구현

이인재·2022년 9월 2일
0

Javascript

목록 보기
18/28
post-thumbnail

결론 화면 먼저!!!


HTML

html은 정말 간단하다.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Picture in Picture</title>
    <link rel="icon" type="image/png" href="favicon.png">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.10.2/css/all.min.css"/>
    <link rel="stylesheet" href="style.css">
</head>
<body>

    <video id="video" controls height="360" width="640" hidden></video>

    <div class="button-container">
        <button id="button">시작</button>
    </div>
    
    <script src="script.js"></script>
</body>
</html>

단순하게 PIP를 위한 video태그를 하나 만들어주고 버튼을 하나 만들어준다.

CSS


CSS도 역시 어려울 만한 것이 없다.

그래도 첫번째 줄부터 차례차례 알아보자.

@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@300&family=Poor+Story&family=Yeon+Sung&display=swap');

자신이 원하는 폰트의 url을 import해주어 글자의 폰트를 바꾸어준다.

html {
  box-sizing: border-box;
}

나는 CSS에서 이 부분이 제일 중요하다고 생각한다.

쉽게 말하면, 자신이 원하는 치수대로 나오도록 box-sizing을 바꾸어주는 것이다.

이 부분의 자세한 설명은 밑에 링크를 통해 확인 바란다.

https://velog.io/@dldlswognqh/Box-Model

body {
  margin: 0;
  min-height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  background: rgb(37, 37, 37);
}

첫번째!!!

body부분 CSS에서 가장 기본적으로 해주는 것인데,

일단 body 자체에 있는 margin을 없애고 본다.

두번째!!!

body의 height가 화면 전체의 높이를 차지하도록 100vh라는 값을 준다.

세번째!!!

나중에 생성하는 버튼이 가운데로 정렬되도록

display: flex를 주고 가로 세로도 가운데로 정렬해준다.

네번째!!!

배경색은 내가 원하는 색깔로~~

.button-container {
  border: 2px solid black;
  padding: 10px;
  border-radius: 7px;
  box-shadow: inset 0 20px 4px -19px rgba(255, 255, 255, 0.7);
}

첫번째!!!

border 설정도 취향대로!! 하지만 보기 좋게 설정

두번째!!!

보기 좋게 안쪽 여백을 준다.

세번째!!!

버튼이 속해있는 container 박스가 보기 좋게 border-radius를 줌

네번째!!!

조금 더 입체감을 위해서 box-shadow를 주는데

box-shadow : inset(선택) | offset-x | offset-y | blur-radius | spread-radius | color

inset : 요소가 움푹 들어간 것처럼 그림자가 요소의 테두리 안, 배경색 위, 내부 콘텐츠 밑에 그려짐
(사진 속 박스 위에 하얀색 부분)

offset-x 즉 수평 부분에는 그림자를 설정하지 않음

offset-y 즉 수직 거리에는 밑에쪽으로 20px

blur-radius : 크면 클 수록 그림자 테두리가 흐려지고 크기는 더 커지고 색은 더 밝아짐

spread-radius를 -19px로 음수로 주어 그림자가 줄어들도록

color는 내가 원하는 색!!!

button {
  cursor: pointer;
  outline: none;
  width: 120px;
  height: 75px;
  font-family: 'Poor Story', cursive; 
  font-size: 25px;
  color: white;
  text-shadow: 0 2px 5px black;
  background: linear-gradient(to top, #696969, #575757);
  border: 2px solid black;
  border-radius: 7px;
  box-shadow: inset 0 20px 4px -19px rgba(255, 255, 255, 0.4), 0 12px 12px 0 rgba(0, 0, 0, 0.3);
}

첫번째!!!

cursor를 pointer로 설정하여 버튼에 가까이하면 손가락 모양으로!!

두번째!!!

outline: none으로 일반적으로 버튼 클릭하면 생기는 blue outline을 없애줌

세번째!!!

font-family로 아까 import했던 것을 사용하여준다.

네번째!!!

font-size는 내 기호에 따라 글자 크기를 설정한다.

다섯번째!!!

text-shadow: 0 2px 5px black;

글자에 형성되는 그림자를 수평으로는 0 아래로 2px blur는 5px로 설정

여섯번째!!!

linear-gradient로 선의 방향을 설정하고 두 가지 색을 설정해준다.

button:hover {
  background: linear-gradient(to bottom, #696969, #575757);
}

button 위에 마우스가 있으면 linear-gradient를 변경해준다.

button:active {
  transform: translateY(3px);
  box-shadow: 0 6px 6px 0 rgba(0, 0, 0, 0.3);
}

버튼을 누르고 뗄 때까지 버튼을 3px 아래로 이동하고 그림자의 설정이 변하게 한다.

JavaScript

const videoElement = document.getElementById('video');
const button = document.getElementById('button');

video라는 id를 가져와서 videoElement라는 변수에 넣어줌.
button이라는 id를 가져와서 button이라는 변수에 넣어줌.

async function selectMediaStream() {
    try {
        const mediaStream = await navigator.mediaDevices.getDisplayMedia();
        videoElement.srcObject = mediaStream;
        videoElement.onloadedmetadata = () => {
            videoElement.play();
        }
    } catch (error) {
        console.log(error)
    }
}

async/await을 통해 비동기 처리를 한다.

async/await을 사용하면 비동기 처리를 하지만 동기처럼 작성할 수 있어서 가독성이 좋아진다.

await 키워드를 사용하면 일반 비동기 처리처럼 바로 실행이 다음 라인으로 넘어가는 것이 아니라 결과값을 얻을 수 있을 때까지 기다려줌.

함수 선언부에서 function 앞에 async를 붙여서 작성해줌.

비동기/동기를 구분하지 않고 try/catch를 이용해 일관되게 예외 처리 가능.

navigator.mediaDevices.getDisplayMedia();를 통해 화면 기록을 할 수 있도록 해줌.

카메라의 mediaStream 은 videoElement 요소에 할당.

videoElement의 메타데이터가 로드될 때 videoElement가 실행되도록 함.

button.addEventListener('click', async () => {
    button.disabled = true;
    await videoElement.requestPictureInPicture();
    button.disabled = false;
});

button.disabled = true : button이 클릭되었을 때 비활성화시킴

await videoElement.requestPictureInPicture() : PIP 시작되도록

button.disabled = false : 다시 리셋시킴

selectMediaStream();

selectMediaStream() 함수가 로드 되도록

실행 화면

0개의 댓글