Skip to content

기술공유 06. 이모지가 날아간다🤭

DHKIM edited this page Dec 22, 2019 · 4 revisions

드로피 기술공유 날아가는 이모지🤭

왜 필요한가요? 🤔

저희는 프레젠테이션에서 스피커가 발표를 하다보면 리스너들을 신경 못쓰는 경우들이 종종 있다고 생각했어요.

그래서 첫 번째로 생각한게 채팅이었고, 그 다음으로 또 다른 것으로 소통을 도와줄 수 없을지를 고민했어요.

그리고 채팅 다음으로 나온 생각이 이모지였죠!😎

그렇다고 채팅에는 이모지를 사용할 수있고 조금더 자극적인게 필요했어요😏

결국 저희는 슬라이드 위로 날아다니는 이모지를 만들기로 했습니다!!

스피커와 리스너가 감정을 쉬운 방법으로 공유할 수 있는 방법이죠!

날아가는 방법 찾아보기😥

좋았어! 기획은 성공적. 결과도 좋을거라고 생각했는데... 어떻게 구현할지에 대해서 고민을 안해봤어요.

그래서 팀원들과 함께 어떤식으로 구현할지 생각을 해봤어요.

생각보다 많은 방법들이 있더라구요.

CSS VS JS

먼저 큰 단위로 CSS로 구현하는 방법이 있고, 자바스크립트로 구현하는 방법이 있습니다. 그럼 어떤 경우에 이렇게 나뉘어 지는걸까요?🤔

구글에서 이렇게 이야기 했어요👇

UI 요소에 대해 작고 자체적으로 포함된 상태가 있는 경우 CSS를 사용합니다. CSS 전환 및 애니메이션은 측면에 탐색 메뉴를 나타내거나 도움말을 표시하는 데 적합합니다. 자바스크립트를 사용하여 상태를 제어할 수 있지만 애니메이션 자체는 CSS에 있게 됩니다.

애니메이션을 세밀하게 제어해야 하는 경우 자바스크립트를 사용합니다. Web Animations API는 표준 기반의 접근방식이며, 현재 Chrome 및 Opera에서 사용할 수 있습니다. 이 접근방식은 실제 객체를 제공하며, 복잡한 객체 지향 애플리케이션에 이상적입니다. 자바스크립트는 중지, 일시 중지, 감속 또는 되감기해야 하는 경우에도 유용합니다.

전체 장면을 손으로 조정하려는 경우에는 requestAnimationFrame을 직접 사용합니다. 이것은 고급 자바스크립트 접근방식이지만, 게임을 빌드하거나 HTML 캔버스에 그리는 경우에 유용할 수 있습니다.

🤔조금 더 자세히 알아보고 결정해야겠어요. 저희조의 상황에 맞는게 무엇일까요??

CSS 로 애니메이션 구현해보기👩🏻‍🎨

CSS로 애니메이션을 만드는 것이 화면에서 움직임을 표현하는 가장 간단한 방법입니다. 이 접근방식을 선언적이라고 하는 이유는, 일어나기 원하는 동작을 지정하기 때문입니다.

첫 번째로 알아야 할 CSS 속성은 바로 transform 이에요.

transform 속성을 사용하면, CSS의 시각적 서식 모델(visual formatting model)의 좌표공간을 변형시킬 수 있어요! 해당 속성에 지정된 값에 따라 엘리먼트(element)에 이동(translate), 회전(rotate), 크기변경(scale), 기울임(skew)등의 효과를 줄 수있는거죠.

transform: scaleX(2); /* X가 두배 */
transform: scaleY(2); /* Y가 두배 */

위처럼 쓰면 아래것밖에 적용이 안돼요!! 왜 그럴까요?

하나만 인식하기 때문에 그래요!

transform: scale(2, 2);

이런식으로 하면 됩니당😁

transform: scaleX(2) scaleY(2);

혹은 한칸을 띄워서 계속 써내려가면 됩니당!

transform의 원점의 위치를 정하고 싶다면, transform-origin 속성을 이용하시면 됩니다!!

어디를 기점으로 transform의 효과를 줄지 정할 수 있어요!

두 번째로 알아야 할 CSS 속성은 바로 transition 이에요.

전환이라는 뜻을 가진 transition은 css의 값이 변경 되었을 때, 변경을 부드럽게 해주는 속성이에요!

여기서부터 애니메이션이 본격적으로 나오는 것이죠!!😎

  • transition-duration
  • transition-property
  • transition-delay
  • transition-timing-function
  • transition

위와 같은 속성들이 대표적입니다~!

마지막으로 @keyframes 입니다!

@keyframes는 애니메이션을 재생할 각 프레임의 스타일을 정의하는 것으로 from 속성이나 0% 속성에 설정한 스타일에서 출발해 to 속성이나 100% 속성에 설정한 스타일로 점차 바뀌면서 애니메이션이 재생을 해주는 거에요!

그렇다면??

dropy에서 채널을 생성할 때, 손가락이 드랍하라고 안내를 해주잖아요?? 이건 어떻게 만든걸까요?🤔

  .dropEmoji
    {
      position: relative;
      display:block;
      max-width:400px;
      margin:0px auto;
      animation:fingerAnimation 2s infinite;
    }
    @keyframes fingerAnimation

    {
      0%{transform:translateY(10px);}
      50%{transform:translateY(-20px);}
      100%{transform:translateY(10px);}
    }

바로 @keyframes를 이용해서 이동을 정해 준거예요!

다음은 X축과 Y축 모두에서 요소를 100px 이동하는 CSS입니다. 이 과정은 500ms가 걸리도록 설정된 CSS 전환을 사용하여 수행됩니다. move 클래스가 추가되면 transform 값이 변경되고 전환이 시작됩니다.

Javascript 로 애니메이션 구현해보기 🔨

이제 본격적으로 날아가는 이모지를 구현할거에요! 저희는 자바스크립트로 단조롭지 않은 rand값을 이용하고 requestAnimationFrame을 이용해서 구현을 해보기로 했어요.

날아가는 이모지 공장이라는 이름을 가진 class가 이모지를 찍어낼거에요!

requestAnimationFrame의 장점을 똑똑한 아이라는 것입니다.

가령 사람들이 보지 못할까봐 다른 모니터를 사용하게 된다면, 날아가는 이모지가 클릭 된 만큼 출발하지 않고 옹기종기 모여있게 됩니다.

그랬다가 사용자가 해당 브라우저를 보는순간 같이 신나게 날아가는것이에요!

이것은 자원을 아끼기 위한 requestAnimationFrame의 특징이라고 할 수 있어요!

하지만 이런 똑똑한 장점 때문에 저희는 고생을 했답니다..😥 이따가 함께 보시죠!!

날아가는 이모지 구현하기😍

인스타그램을 자주 사용하시는 분은 인스타그램 라이브 방송 혹은 facebook을 보신 적 있을 거에요!

flyingEmoji

거기서 실시간으로 하트 혹은 이모지를 날릴 수 있어요.

우리도 그런 비슷한걸 생각했어요. 사실 더 많이 움직이는 이모지를 원했지만, 스피커와 슬라이드에 집중을 할 수 없다는 이유가 있어서 빈 공간으로 보내졌어요 😥

  const startAnimation = () => {
    jobQueue = jobQueue.filter((job) => job.flying());
    if (isAchieve()) {
      cancelAnimationFrame(requestId);
      return;
    }
    requestId = requestAnimationFrame(startAnimation.bind(this));
  };

위의 코드가 바로 requestAnimationFrame 을 이용하는 방식이에요!

시작하면 해당 startAnimation 함수를 재귀로 계속 부르며, 애니메이션을 동작합니다. 모든 애니메이션을 실행했다면, cancelAnimationFrame 을 통해 종료를 하는 방식이에요.

jobQueue.push(
      new Factory(
        emojiType,
        startPosition,
        GET_FLYING_EMOJI_SPEED(),
        isFullScreen,
      ),
    );

이제 이모지가 날아갈 시간입니다!🐤

jobQueue에 이모지를 삽입 시키고, jobQueue배열이 결국 날아가는 이모지 하나에 해당됩니다!

어떤 종류의 이모지인지, 시작좌표, 날아가는 스피드 그리고 전체화면인지 일반화면인지 파라미터를 가지고 출발합니다.

constructor(emoji, coordinates, friction, isFullScreen) {
    this.emoji = this.setEmoji(emoji);
    this.steps = document.querySelector('body').offsetHeight;
    this.item = null;
    this.friction = friction;
    this.coordinates = coordinates;
    this.position = -(this.coordinates.y);
    this.isFullScreen = isFullScreen;
    this.scale = isFullScreen ? FULL_SCREEN_SCALE() : NORMAL_SCREEN_SCALE();
    this.rotation = ROTATION();
    this.siner = SINER();
    this.opacity = OPACITY;
    this.appHeight = document.querySelector('body').offsetHeight;
    this.dimensions = this.render();
  }

🤭 constructor가 엄청나요... 날아가기 위해 준비해야 할게 정말 많았어요.. 욕심은 나고.. 시간은 부족하지만 포기할 수 없었습니다!! 너무 매력적인 기능이니까요!!

this.emoji로 div 를 생성했습니다! 🤭 <- 이런이모지 모형을 갖는 div가 생성이 됩니다!

return this.coordinates.x + Math.sin((this.position * Math.PI) / this.steps) * this.siner;

다음은 x좌표를 실시간으로 구하는 코드인데요. 저런식으로 Math.sin 함수와 추가 변수들을 통해 부드럽게 좌우로 흔들흔들 하면서 올라가는 애니메이션을 완성해 줍니다.

목표에 도달한 이모지는 높이를 실시간으로 계산해서

destroyEmoji() {
  this.item.parentNode.removeChild(this.item);
}

위의 함수를 이용해 바로바로 제거를 해줬습니다.

결국 요약을 하자면, jobQueue에 호출 된 만큼의 이모지를 담아두고 requestAnimationFrame를 이용해서 class 객체 (이모지) 를 애니메이션 화 하는 방식입니다. 하지만 예상보다 비용이 있었어요.

왜냐하면, requestAnimationFrame 의 특성상 안보는 곳에 있다가 다시 돌아오면, 한방에 빵~~ 터지면서 이모지들이 올라오는 현상이었어요! 이 현상 때문에 브라우저가 거의 멈출뻔한 적도 있었죠!

그래서 고민을 했어요. 이 상황에서 CSS의 keyframe으로 하면 비용이 적어지겠지만, 처음부터 다시 설계해야 하는 상황이었거든요. 그리고 styled를 이용하면, 쉽게 랜덤으로 움직이는 것도 구현 가능할 것이라 판단을 했었어요.

아무튼... 확실한 예정을 못정하고, 곧 네트워킹 데이를 앞두고 있는 상황이라 추후에 수정하기로 했습니다.

그리고 이모지가 한방에 빵 터지는(한번에 올라오는) 현상은

window.onfocus = () => { setIsFocused(true); };
window.onblur = () => { setIsFocused(false); };

위의 코드를 추가해서 방지를 했습니다.

onblur인 상황에서는 이모지들이 못모이게 강제로 막아버린 것입니다.😕

스피커와 리스너간 날아가는 이모지 동기화시키기🐤

이제 날아가는 이모지를 모두가 볼 수 있어야 해요.

하지만 좌표를 완벽하게 공유하기에는 비용이 너무 크다고 판단했어요.

그래서 이벤트를 공유하기로 결정했습니다. 아쉽게도 모든 이모지의 좌표마저 똑같진 않다는 이야기에요.

기존의 슬라이드 채팅과 마찬가지로 pub/sub 의 방식을 이용했어요.

여기에 대해 자세한 사항은 저희 기술공유 기술공유03.-graphQL과-Apollo-이용하여-리액트에서-상태관리하기 를 참고해주세요!

감사합니다.

Clone this wiki locally