112일차(1)/CSS(11) : 3차원 컨텐츠 만들기(4)
- 3d공간을 정의하고, 그 안에 들어 있는 div들을 큐브 형태로 배치함
- 특정 UI를 페이지 로딩 시점에 3차원 transform을 이용해서 3차원적으로 배치해둔 다음,
특정 시점에 부모 요소를 3차원 transform 시키면 배치시켜둔 대로 움직인다.
- 마우스를 올렸을 때(특정 시점) 부모 div가 통째로 움직이도록 할 수 있다.
- 부모 div에 마우스 hover되었을 때 애니메이션이 적용되도록 한 상태!
- 원래는 겹쳐져 있었는데, 200px만큼 z축 방향으로 밀어버린 것이다.
- 2번째 div도 90도를 돌리고 200px 을 밀어버린 상태.
- 이렇게 겹쳐있던 div를 회전, 평행 이동시켜 정육면체 모양을 만들 수 있다.
- 처음에 1 div를 z축으로 밀었기 때문에 확대되어 커진다. 그래서 처음에 큐브를 -200px 만큼 밀어둔 것!
- div 크기의 절반만큼 밀어주어야 모서리가 딱 맞아 떨어진다.
- 사각형이기 때문에 90도 단위로 변화시키는 것이다. 우측상단 이미지는 위에서 본 것
- 만약 6각형을 만들고 싶다면? 가운데에 div가 6개 겹쳐져 있다고 하자
- 앞으로 미는 길이를 구하려면 200*tan60 만큼 곱해야 한다.
- div를 60도씩 돌리면서 200*tan60 만큼 평행이동시켜야 한다.
- 이렇게 함수를 만들어서 적용할 수도 있다. 4각형이고 폭이 400인 도형이라면 안에 숫자를 전달해주면 된다.
- 그러면 angle, tz에 알아서 값이 들어간다.
- 이 함수가 있으면 몇 도씩 돌리면서 얼마만큼 평행이동시켜야 하는지 알아내기 쉽다.
- 이 함수에서 리턴하는 object 를 사용하면 된다.
- div를 직접 배치하는 것이 아니라 원하는 시점에 javascript 로 배치할 수 있도록 할 예정!
- 이 도형을 화면 크기에 따라 다르게 보여주고 싶다면? (너비는 디바이스의 크기에 의존하도록 하면 된다.)
- 같은 코드인데 폭이 넓은 디바이스에서는 우측과 같이 보이도록 하려고 한다.
- 화면의 크기가 동적이라면 3d transform을 다르게 배치해야 한다. javascript로 배치하는 것이 필요한 이유!
- 화면 크기에따라 tz의 양이 달라진다(translateZ) 이것을 javascript로 할 수 있다.
- 터치(마우스 드래그)도 가능하게 할 수 있다. 마우스 터치에 반응해 박스를 돌아가게 하는 것!
- perspective-origin 을 설정해 시선을 바꾸어 볼 수 있다.
- javascript로 인라인 css를 추가하는 방법도 기억하기!
* 6각형 도형 배치하기
Step06_3dHexagon.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Step06_3dHexagon.html</title>
<style>
.wrapper{
perspective: 500px;
perspective-origin: 50% 50%;
}
.hexa{
width: 400px;
height: 400px;
margin: 0 auto;
transform-style: preserve-3d;
transform-origin: 50% 50%;
transform: translateZ(-346px);
}
.hexa > div{
border: 2px solid palevioletred;
position: absolute;
top:0;
left:0;
width: 400px;
height: 400px;
background-color: antiquewhite;
display: flex;
justify-content: center;
align-items: center;
font-size: 100px;
font-weight: bold;
opacity: 0.5;
}
.hexa > div:nth-child(1){
transform: translateZ(346px);
}
.hexa > div:nth-child(2){
transform: rotateY(60deg) translateZ(346px);
}
.hexa > div:nth-child(3){
transform: rotateY(120deg) translateZ(346px);
}
.hexa > div:nth-child(4){
transform: rotateY(180deg) translateZ(346px);
}
.hexa > div:nth-child(5){
transform: rotateY(240deg) translateZ(346px);
}
.hexa > div:nth-child(6){
transform: rotateY(300deg) translateZ(346px);
}
/* .cube{
transition: transform 0.4s ease-out;
}
.cube:hover{
transform: translateZ(-200px) rotateX(45deg) rotateY(90deg);
} */
@keyframes rotateAni{
0%{
transform: translateZ(-346px) rotateX(0deg) rotateY(0deg);
}
100%{
transform: translateZ(-346px) rotateX(360deg) rotateY(360deg);
}
}
.hexa:hover{
animation: rotateAni 5s infinite linear alternate;
}
</style>
</head>
<body>
<div class="container">
<h3>3d Hexagon 테스트</h3>
<div class="wrapper">
<div class="hexa">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
</div>
</div>
</div>
<script>
//n 각형의 폭을 함수에 전달하면 div 를 배치할때 rotateY 값과 translateZ 가 Object 로 리턴되는 함수
function getAngleNtz(n, width) {
var angle = Math.round(360 / n);
var tz = Math.round((width / 2) / Math.tan((angle * Math.PI) / (2 * 180)));
var obj = {
angle: angle,
tz: tz
};
return obj;
}
</script>
</body>
</html>
- 기본 정육면체 상태로 만들고 javascript 함수 가져오기
- 콘솔창에서 만들고자 하는 n, width 값을 넣어 함수로 계산해보면 정확한 값이 계산되어 나온다.
- 6각형은 60도씩 돌면서 346px 이동하면 된다.
- 클래스명은 hexa로 수정!
- 60도씩 회전시키고, Z이동은 346px씩 이동시킨다.
- 이런 형태로 만들어진다.
- 60도 회전시켜서 밀고, 120도 회전시켜서 밀고 ... 이런 과정으로 만들어진 것
Step06_3dHexagon2.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Step06_3dHexagon2.html</title>
<style>
.container{
width: 80%;
margin: 0 auto;
}
.wrapper{
perspective: 500px;
perspective-origin: 50% 50%;
}
.hexa{
width: 100%;
height: 400px;
margin: 0 auto;
transform-style: preserve-3d;
transform-origin: 50% 50%;
}
.hexa > div{
border: 2px solid palevioletred;
position: absolute;
top:0;
left:0;
width: 100%;
height: 400px;
background-color: antiquewhite;
display: flex;
justify-content: center;
align-items: center;
font-size: 100px;
font-weight: bold;
opacity: 0.5;
}
</style>
</head>
<body>
<div class="container">
<h3>3d Hexagon 테스트</h3>
<div class="wrapper">
<div class="hexa">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
</div>
</div>
</div>
<!-- jquery 로딩 -->
<script src="https://code.jquery.com/jquery-3.6.4.js"
integrity="sha256-a9jBBRygX1Bh5lt8GZjXDzyOB+bWve9EiO7tROUtj/E="
crossorigin="anonymous"></script>
<script>
//몇각형인지
const n=6;
//페이지 로딩 시점에 한 변의 길이가 몇인지
let width=$(".wrapper").width();
//배치할 때 회전할 각도 얻어내기
const angle=getAngleNtz(n, width).angle;
function init(){
//배치할때 z 축 평행이동 값 얻어내기
let tz=getAngleNtz(n, width).tz;
$(".hexa").css("transform", `translateZ(${-tz}px)`);
for(let i=0; i<n; i++){
let nth=i+1;
$(`.hexa > div:nth-child(${nth})`)
.css("transform",`rotateY(${angle*i}deg) translateZ(${tz}px)`);
}
}
//init() 함수를 호출해서 다각형 배치하기
init();
//화면이 리사이즈되었을 때 다시 배치하기
$(window).resize(()=>{
//폭을 새로 얻어와서
width=$(".wrapper").width();
//다각형 배치하기
init();
});
//n 각형의 폭을 함수에 전달하면 div 를 배치할때 rotateY 값과 translateZ 가 Object 로 리턴되는 함수
function getAngleNtz(n, width) {
var angle = Math.round(360 / n);
var tz = Math.round((width / 2) / Math.tan((angle * Math.PI) / (2 * 180)));
var obj = {
angle: angle,
tz: tz
};
return obj;
}
</script>
</body>
</html>
- div에 css를 적요한 이 작업을 javascript로 대체해볼 예정
- 반복문을 돌면서 숫자 값만 바꿔줄 수 있으면 된다.
- 초기화 함수 init() 만들기.
- 순서대로 다 돌면서 hexa안의 div에 각각 css를 적용해준다.
- 백틱을 사용하면 문자열을 이어붙이기가 편리하다. ${ } 로 사용가능
- n, width, angle, tz 값을 변수로 정의해주고 변수를 사용하는 구조로 바꿔 준다.(하드코딩 대신)
- 다양한 다각형에 적용할 수 있도록!
- width 변의 길이를 wrapper를 사용해 동적으로 적용한다.
- 반복문을 돌리기 전에 init 안에서 hexa를 -tz px만큼 밀어놓고 시작하기
$(window).resize()
- 화면의 폭이 달라졌을 때 다시 init을 하도록 설정해준다.
- 폭이 달라지면 tz 값도 달라져야 하므로, let함수를 정의하고 폭에 맞게 새로 배치되도록 한다.
- 윈도우 창의 폭에 따라 너비가 다르게 보인다.
Step07_Carousel.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Step07_Carousel.html</title>
<style>
.container{
width: 80%;
margin: 0 auto;
}
.wrapper{
perspective: 500px;
perspective-origin: 50% 50%;
}
.carousel{
width: 100%;
height: 400px;
margin: 0 auto;
transform-style: preserve-3d;
transform-origin: 50% 50%;
transition: transform 0.4s ease-out;
}
.carousel > div{
border: 2px solid palevioletred;
position: absolute;
top:0;
left:0;
width: 100%;
height: 400px;
background-color: antiquewhite;
display: flex;
justify-content: center;
align-items: center;
font-size: 100px;
font-weight: bold;
opacity: 0.5;
}
nav{
text-align: center;
}
nav button{
font-size: 40px;
}
</style>
</head>
<body>
<div class="container">
<h3>3d Carousel 테스트</h3>
<div class="wrapper">
<div class="carousel">
</div>
</div>
<nav>
<button id="prevBtn">«</button>
<button id="nextBtn">»</button>
</nav>
</div>
<!-- jquery 로딩 -->
<script src="https://code.jquery.com/jquery-3.6.4.js"
integrity="sha256-a9jBBRygX1Bh5lt8GZjXDzyOB+bWve9EiO7tROUtj/E="
crossorigin="anonymous"></script>
<script>
//몇각형인지
const n=8;
//n각형 만큼 div를 동적으로 만들어서 .carousel 안에 넣기
for(let i=0; i<n; i++){
//div를 만들어서 innerText를 출력하고 .carousel 에 추가하기
$("<div>").text(i+1).appendTo(".carousel");
}
//페이지 로딩 시점에 한 변의 길이가 몇인지
let width=$(".wrapper").width();
//배치할 때 회전할 각도 얻어내기
const angle=getAngleNtz(n, width).angle;
//tz값을 전역변수로 설정
let tz;
// .carousel의 회전값
let rY=0;
function init(){
//배치할때 z 축 평행이동 값 얻어내기
tz=getAngleNtz(n, width).tz;
$(".carousel").css("transform", `translateZ(${-tz}px)`);
for(let i=0; i<n; i++){
let nth=i+1;
$(`.carousel > div:nth-child(${nth})`)
.css("transform",`rotateY(${angle*i}deg) translateZ(${tz}px)`);
}
//현재 carousel 의 회전값 반영해주기
rotateY();
}
//init() 함수를 호출해서 다각형 배치하기
init();
//화면이 리사이즈되었을 때 다시 배치하기
$(window).resize(()=>{
//폭을 새로 얻어와서
width=$(".wrapper").width();
//다각형 배치하기
init();
});
//위의 버튼을 눌렀을때 .cube를 90도씩 y축 기준으로 회전하도록 해보세요
$("#prevBtn").click(()=>{
rY -= angle;
rotateY();
})
$("#nextBtn").on("click", ()=>{
rY += angle;
rotateY();
});
function rotateY(){
$(".carousel").css("transform", "translateZ(-"+tz+"px) rotateY("+rY+"deg)");
}
//n 각형의 폭을 함수에 전달하면 div 를 배치할때 rotateY 값과 translateZ 가 Object 로 리턴되는 함수
function getAngleNtz(n, width) {
var angle = Math.round(360 / n);
var tz = Math.round((width / 2) / Math.tan((angle * Math.PI) / (2 * 180)));
var obj = {
angle: angle,
tz: tz
};
return obj;
}
</script>
</body>
</html>
- 이전 예제를 복사해와서 ctrl+f 로 hexa를 carousel로 모두 바꾸어주기
- html 요소로 있는 div를 모두 삭제하고 javascript로 넣어주기
- div를 만들어서 innerText를 출력하고 .carousel 에 추가하기!
- <div> 요소를 jquery 로 만들어준 것이다.
- 자바스크립트 코드로 바꾸면 document.createElement("div") 가 된다.
- 이제 모두 변수를 사용해 일반화시켜 두었으므로 해당 위치에 숫자만 들어오면 된다.
- 변수 n 에다가 원하는 숫자를 넣어주면 알아서 n각형으로 만들어진다.
- 12각형으로 만들어본 모습!
- 하단에 화살표버튼 nav 요소를 추가하고 css를 추가
- 화살표 버튼의 클릭 이벤트에 함수를 적용
- rY에 들어갈 회전할 값이 angle 이고, translateZ() 에 들어갈 값이 tz이다.
- tz값을 여러 함수에서 사용할 수 있도록 전역변수로 설정
- angle, tz값을 함수에 적용
- 단, 이렇게 하면 회전하던 중에 창의 크기가 달라지면 다시 1로 돌아온다는 문제가 있다.
- 새로 배치할 때 이 값도 활용해야 한다!
- rY값도 전역변수로 설정해준다.
- 회전 함수(rotateY)를하나 만들어놓고 함수를 호출하는 구조로 바꿔주기
- 그리고 이 함수를 init()안에서도 적용한다.
- 새로 배치할 때 같이 배치해 주어야 값이 초기화되는 것을 방지할 수 있다.
- transition도 추가해주면 이동할 때 뿐만 아니라 배치할때도 변화과정이 천천히 보인다.
- 이제 이 div 안에다가 어떤 컨텐츠를 배치하고 싶으면 높이만 결정해서 배치하면 된다.
- 이렇게 div 안에 각각의 번호 대신 원하는 컨텐츠를 넣을 수 있다.
backface-visibility: hidden;
- hidden 으로 설정하면 뒤에 있는 것들이 보이지 않도록 할 수 있다. 원하는 이미지를 넣을 수 있다.
- Bootstrap의 carousel 처럼 갤러리 이미지를 하나씩 배치해서 돌아가면서 보여줄 수도 있다.
- 이제 이 예제를 마우스 터치로 회전시킬 수 있도록 설정할 예정!
'국비교육(22-23)' 카테고리의 다른 글
114일차(1)/CSS(13) : CSS3 Flex 활용(1) (1) | 2023.03.24 |
---|---|
113일차(1)/CSS(12) : 3차원 컨텐츠 만들기(5) / TouchSwipe 활용 (0) | 2023.03.23 |
111일차(1)/CSS(10) : 3차원 컨텐츠 만들기(3) (0) | 2023.03.21 |
110일차(1)/CSS(9) : 3차원 컨텐츠 만들기(2) (1) | 2023.03.20 |
109일차(2)/CSS(8) : 3차원 컨텐츠 만들기(1) (0) | 2023.03.17 |