3d-carousel

Main·2023년 3월 24일
0

3d-carousel 만들기

  • carousel은 다양한 종류가 있음
  • 플러그인을 사용하면 쉽게 구현할 수 있다.
    (owl-carousel, bootstrap-carousel, swiper-carousel 등)
    회전목마

수업에서 배운 perspective 속성과 perserve-3d 속성을 응용하여 3d-carousel를 직접 구현해 보기

구현 포인트

  • prespective 속성과 preserve-3d 속성
  • transformZ 길이 적용
<div class="carousel">
        <div class="carousel-card">Card1</div>
        <div class="carousel-card">Card2</div>
        <div class="carousel-card">Card3</div>
        <div class="carousel-card">Card4</div>
        <div class="carousel-card">Card5</div>
        <div class="carousel-card">Card6</div>
        <div class="carousel-card">Card7</div>
        <div class="carousel-card">Card8</div>
        <div class="carousel-card">card9</div>
      </div>

2 ) 원근감 효과를 위해 carousel의 부모요소를 만들고 perspective 속성을 부여한다.

 <div class="scene">
      <div class="carousel">
        <div class="carousel-card">Card1</div>
        <div class="carousel-card">Card2</div>
        <div class="carousel-card">Card3</div>
        <div class="carousel-card">Card4</div>
        <div class="carousel-card">Card5</div>
        <div class="carousel-card">Card6</div>
        <div class="carousel-card">Card7</div>
        <div class="carousel-card">Card8</div>
        <div class="carousel-card">card9</div>
      </div>
 </div>
.scene {
  width: 210x;
  height: 140px;
  position: relative;
  /* 원근감을 위해 */
  perspective: 1800px;
  margin: 0 auto;
  margin-top: 100px;
}

3 ) carousel의 자식요소에 3d 효과를 주기위해 perserve-3d 속성을 부여한다.

.carousel {
  width: 100%;
  height: 100%;
  position: absolute;
  /* perspective가 적용된 자식 요소들에 3D 효과 원근감*/
  transform-style: preserve-3d; 
  transition: all .5s;
}
.carousel-card {
  position: absolute;
  /* 셀 배치를 약간씩 떨어뜨림*/
  width: 190px;
  height: 120px;
  left: 10px;
  top: 10px;
  transition: all .5s;
  font-size: 30px;
  color: #fff;
  font-weight: bold;
  display: flex;
  align-items: center;
  justify-content: center;
}

angle = 360 / carousel-card 개수

.carousel-card:nth-child(1) { transform: rotateY(  0deg); }
.carousel-card:nth-child(2) { transform: rotateY( 40deg); }
.carousel-card:nth-child(3) { transform: rotateY( 80deg); }
.carousel-card:nth-child(4) { transform: rotateY(120deg); }
.carousel-card:nth-child(5) { transform: rotateY(160deg); }
.carousel-card:nth-child(6) { transform: rotateY(200deg); }
.carousel-card:nth-child(7) { transform: rotateY(240deg); }
.carousel-card:nth-child(8) { transform: rotateY(280deg); }
.carousel-card:nth-child(9) { transform: rotateY(320deg); }

r 만큼의 길이를 transformZ 속성을 주어 carousel-card를 떨어뜨린다.

.carousel-card:nth-child(1) { transform: rotateY(  0deg) translateZ(288px); }
.carousel-card:nth-child(2) { transform: rotateY( 40deg) translateZ(288px); }
.carousel-card:nth-child(3) { transform: rotateY( 80deg) translateZ(288px); }
.carousel-card:nth-child(4) { transform: rotateY(120deg) translateZ(288px); }
.carousel-card:nth-child(5) { transform: rotateY(160deg) translateZ(288px); }
.carousel-card:nth-child(6) { transform: rotateY(200deg) translateZ(288px); }
.carousel-card:nth-child(7) { transform: rotateY(240deg) translateZ(288px); }
.carousel-card:nth-child(8) { transform: rotateY(280deg) translateZ(288px); }
.carousel-card:nth-child(9) { transform: rotateY(320deg) translateZ(288px); }

=> css 대신 javascript를 이용하여 carousel-card 배치를 동적으로 할당

const carouselCard = documnet.queryselector(".carousel-card");
const rataeAngle = 360 / carouselCard.length;
const radian = (ratateAngle / 2) * Math.PI / 180;
const tz = (210 / 2) / Math.tan(radin); 

carouselCard.forEach((el,idx)=>el.style.transform = `rotateY(${ratateAngle*idx}deg) translateZ(${tz}px)`);

deg

📌 r를 구하는 방법 => 삼각비를 이용한다.

  • r = (밑변의 길이) / tan(angle)
  • 여기서 구하려는 r = (card의 width / 2 ) / Math.tan(angle에 해당하는 radian)
    • radian = (angle / 2) * (Math.PI / 180)
      삼각비

r 구하기

7 ) carousel를 위에서 구한 각도 만큼 더하면서 Y축으로 회전 시키면 카드가 바뀌는 효과가 나타난다.

casrousel angle = angle * 현재 카드의 index

추가 ) x축, y축를 축 전환시켜 전환효과를 줄 수 있다.

  • carousel, carousel-card 들의 translate 축 변경
    • X축으로 회전시
      transform = translateY() => transform = translateX()로 변경
    • Y축으로 회전시
      transform = translateX() => transform = translateY()로 변경
  • r 길이가 바뀌어야함 => r = (card-height / 2) / Math.tan(Radin)
    • X축으로 회전 시
      card-width 값 대신 card-height 값 대입
    • Y축으로 회전 시
      card-height 값 대신 card-width 값 대입
  • classList row 확인을 통해 축을 구분해줌

최종 코드

출처 ( https://3dtransforms.desandro.com/carousel )

profile
함께 개선하는 개발자 / 현재 노션으로 이동하였습니다.

0개의 댓글