113일차(1)/CSS(12) : 3차원 컨텐츠 만들기(5)
*지난 예제 코드리뷰
- container 는 전체 브라우저 폭의 80%로 설정해 둠.
- wrapper의 크기는 이 container의 영향을 받는다.
- 웹페이지가 resize 되었을때 이 함수를 호출하도록 함!
- resize될 때마다 이 곳으로 실행 순서가 들어온다.
- 페이지 로딩시점에 init() 으로 한 번 배치하고, resize될 때마다 다시 배치하는 구조이다.
- init 안에서는 z축 평행이동값(tz)를 얻어내서 평행이동에 활용하고,
angle값은 페이지 로딩시점에 얻어온 값을 활용한다.
- rY값(회전량)을 변화시키고 함수를 호출해서 회전시킨다.
- 브라우저에서 돌려보면서 검사창에서 변화하는 rotateY 값을 확인할 수 있다.
- 위와 같이 일부러 carousel 개체들 간의 거리를 좀 띄우고 싶다면 ?
tz=getAngleNtz(n, width).tz+100;
- init() 안에서 이런 형태로 tz에 띄우고 싶은 만큼 값을 더해주면 된다.
- transition 은 개체가 이동, 전환되는 과정을 보여주는것
- 지금은 회전할때와 재배치할때 모두 transition이 들어가 있는데,
회전시킬 때만 적용하고 재배치할때는 transition 기능을 뺄 것이다.
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;
}
/*
class 선택자로 transition을 정의하고
필요할 때 이 class를 어떤 요소에 추가하면 transition이 적용되고
제거하면 transition이 적용되지 않도록 할 수 있다.
*/
.transition{
transition: transform 0.4s ease-out;
}
</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(){
//다시 배치할 때는 transition이 필요없다.
$(".carousel").removeClass("transition");
//배치할때 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(()=>{
$(".carousel").addClass("transition");
rY -= angle;
rotateY();
})
$("#nextBtn").on("click", ()=>{
$(".carousel").addClass("transition");
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;
}
//carousel 을 자동 회전시킬지 여부
let isRun=true;
$(".carousel").on("mouseover", ()=>{
isRun=false;
});
$(".carousel").on("mouseout", ()=>{
isRun=true;
});
//5초마다 carousel을 회전시키는 인터벌
let setIntervalId=setInterval(()=>{
if(!isRun){
return;
}
$(".carousel").addClass("transition");
rY -= angle;
rotateY();
}, 5000);
</script>
</body>
</html>
- 이전에 있던 trasition 은 빼고 transition을 클래스로 만들어줌!
- 클래스로 만들어 필요할 때에만 적용할 수 있다!
- .addClass(), .removeClass() 를 사용해 필요한 시점에 add, remove 할수있다. 콘솔창에서 테스트!
- addClass, removeClass 를 사용한 클래스 추가, 제거
(클릭시에 추가하고, init에서 배치할때 제거해준다)
* Carousel 자동 플레이 기능 추가
- 일정 시간 주기(5초) 마다 자동으로 돌아가게 만들기!
setInterval(function, 주기)
- 함수 자리에 ()=>{} 으로 원하는 함수를 넣어서 테스트해보기!
- 콘솔창에 5초 주기로 계속 출력되는 것을 볼 수 있다.
- rY값과 rotateY() 코드를 setInterval() 안에 넣어주면 5초마다 carousel이 자동 회전한다.
- 이 setInterval() 함수는 인터벌의 아이디값을 리턴해준다.
let setIntervalId=setInterval(()=>{});
- 리턴된 id값을 변수에 담아서 아래에서 사용할 수 있다.
- 웹페이지에서 뭔가 움직이는 컨텐츠를 만들었다면 정지하는 기능도 반드시 고려해야 한다.
(고려하지 않을 경우 웹 접근성에 어긋난다.)
- 이외에도 번쩍거리는 컨텐츠 등도 주의해야 한다..
- 이 인터벌을 특정 시점에 취소하거나, 더 이상 carousel이 돌아가지 않게 할 수 있는 방법도 고려해야 한다.
- clearInterval(인터벌 id); 로 인터벌을 취소할 수 있다.
- 아니면 isRun이라는 변수를 선언해두고, false 조건 하에서는 멈추도록 할 수도 있다.
- 멈추고 싶은 상황이나 지점에서 isRun 변수의 값을 제어해주면 된다.
- 움직이는 컨텐츠가 있다면 멈추는 방법도 반드시 고려해주기!
- carousel을 위아래로 회전하게 할 수도 있다. 다양하게 응용해보기.
* Touch Swipe 기능 사용해보기
* 구글에 검색: touch swipe js
- 링크: https://github.com/mattbryson/TouchSwipe-Jquery-Plugin
- jquery 로딩하기
- jquery 플러그인이므로 jquery에 의존하고 있다.
- jquery로 $().action() / .on() / .addClass() 등등을 써봤는데,
이 플러그인을 추가하면 이와 비슷하게 새 동작 .swipe() 를 사용할 수 있게 된다.
- swipe() 메소드를 사용하면 direction, distance, duration, fingerCount, fingerData 등
사용자가 화면에 어떤 동작을 했는지 데이터를 얻어낼 수 있다.
- 깃허브에서 ZIP 압축파일로 받아서 해제해두기
- jquery.touchSwipe javascript 파일을 복사해서
- 현재 VS code에서 사용하는 폴더 위치에 넣어준다.
touchSwipe.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>touchSwipe.html</title>
<style>
#touchPad{
width: 300px;
height: 300px;
background-color: antiquewhite;
border: 1px solid palevioletred;
border-radius: 10px;
}
</style>
</head>
<body>
<div class="container">
<h3>touch 이벤트 처리</h3>
<div id="touchPad">
</div>
phase : <span id="phase"></span><br/>
direction : <span id="direction"></span><br/>
distance : <span id="distance"></span><br/>
coord : <span id="coord"></span>
</div>
<!-- jquery 로딩 -->
<script src="https://code.jquery.com/jquery-3.6.4.js"
integrity="sha256-a9jBBRygX1Bh5lt8GZjXDzyOB+bWve9EiO7tROUtj/E="
crossorigin="anonymous"></script>
<!-- jquery plugin javascript 로딩 -->
<script src="js/jquery.touchSwipe.js"></script>
<script>
$("#touchPad").swipe({
swipeStatus:function(event, phase, direction, distance){
/*
event 는 발생항 이벤트에 대한 정보를 담고 있는 event object 이다.
phase는 위상값
direction은 방향값
distance는 거리이다.
*/
console.log(event);
console.log(phase);
$("#phase").text(phase);
$("#direction").text(direction);
$("#distance").text(distance);
$("#coord").text(event.x+"|"+event.y);
if(phase=="start"){
//터치 시작일때
}else if(phase=="move"){
//터치 후 움직이는 상태
}else if(phase=="end"){
//터치하고 조금만 움직이고 뗀 상태
}else if(phase=="cancel"){
//터치하고 일정 역치 이상 움직이고 뗀 상태
}
}
});
</script>
</body>
</html>
- 이 swipe() 는 이 jquery 플러그인이 있어서 사용가능한 함수!
- 깃허브 문서를 보고 사용하는 법을 익히면 된다.
- touch 이벤트를 사용하기 위해 4개의 값을 조사해볼 것이다. touchSwipe로 4가지 값을 얻어낼 수 있다.
1) phase : 위상
2) direction : 방향
3) distance : 거리
4) coord : 좌표
- swipe() 안에는 { } object 를 전달한다.
- 이 함수를 호출하면서 div안의 정보에서 필요한 값을 함수에 전달해준다.
- 이벤트, 위상, 방향, 거리 4개의 인자를 넣어준다.
- 이 안에서 필요한 값을 특정 시점에 사용해주면 된다.
- event phase 콘솔창에 출력해보기
- #touchPad 개체를 클릭하면 pointerEvent 가 발생한다.
- pointer down : 마우스를 클릭한 것을 말한다.
- 클릭하고 드래그하고 떼면 이런 위상이 발생하는 것을 볼 수 있다!
1) start : 시작하는 상태
2) move : 움직이는 상태
3) cancel : 드래그하고 멈춘 상태. 단, 드래그를 거의 안했을 때
4) end : 드래그하고 멈춘 상태. 드래그를 일정량 이상 했을 때
- 개체 아래에 뽑아내는 값을 출력해보았다.
- distance는 start와 end 사이의 거리이다.
- direction : 이동한 방향
- distance : 이동 거리인데, 거리 그 자체가 아니라 그 방향으로 이동한 절대값을 말한다.
- phase 의 end와 cancel 을 구분하는 데에는 기준점이 있다.
(드래그해서 75이상 움직여야 end가 뜬다. 그 이하로 움직인것은 취소된 것으로 본다. 75이상 움직여야 의도를 갖고 움직인 것으로 판정하겠다는 뜻!)
- 이렇게 phase 값에 따라 분기하도록 작성해볼 수 있다.
- right, left 값이 필요하다. 이것을 회전값에 반영한다.
- 좌우로 움직일때는 transition 없이, 움직였다가 뗐을 때(회전시킬 때)는 transition이 있도록 설정해보기
test_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>test_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;
}
/*
class 선택자로 transition을 정의하고
필요할 때 이 class를 어떤 요소에 추가하면 transition이 적용되고
제거하면 transition이 적용되지 않도록 할 수 있다.
*/
.transition{
transition: transform 0.4s ease-out;
}
</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>
<!-- jquery plugin javascript 로딩 -->
<script src="js/jquery.touchSwipe.js"></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(){
//다시 배치할 때는 transition이 필요없다.
$(".carousel").removeClass("transition");
//배치할때 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(()=>{
$(".carousel").addClass("transition");
rY -= angle;
rotateY();
})
$("#nextBtn").on("click", ()=>{
$(".carousel").addClass("transition");
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;
}
//carousel 을 자동 회전시킬지 여부
let isRun=true;
$(".carousel").on("mouseover", ()=>{
isRun=false;
});
$(".carousel").on("mouseout", ()=>{
isRun=true;
});
//5초마다 carousel을 회전시키는 인터벌
// let setIntervalId=setInterval(()=>{
// if(!isRun){
// return;
// }
// $(".carousel").addClass("transition");
// rY -= angle;
// rotateY();
// }, 5000);
//터치가 시작된 지점의 rY값을 저장할 변수
let startRY=0;
$(".carousel").swipe({
swipeStatus:function(event, phase, direction, distance){
switch(phase){
case "start":
$(".carousel").removeClass("transition");
//터치가 시작된 지점의 현재 rY값을 변수에 저장한다.
startRY=rY;
break;
case "move":
if(direction=="left"){
//스와이프한 거리에 비례해서 rY 에 반영해서 회전시킨다.
rY = startRY - distance/8;
}else if(direction=="right"){
rY = startRY + distance/8;
}
break;
case "cancel":
$(".carousel").addClass("transition");
//취소되었을 때는 원상복구
rY=startRY;
rotateY();
break;
case "end":
$(".carousel").addClass("transition");
if(direction=="left"){
rY = startRY - angle;
rotateY();
}else if(direction=="right"){
rY = startRY + angle;
rotateY();
}
break;
}
}
});
</script>
</body>
</html>
- jquery 플러그인 추가
- 이벤트 발생시 읽어들이는 4개의 인자를 넣어주기
- 위상값 활용하기. switch문으로 위상의 4가지 경우를 분기해준다!
- Y축을 중심으로 회전시켜야 한다.(반시계 방향)
- swipe한 방향으로 이동 거리를 읽어내서 반응할 수 있도록
- 각각 반시계 방향, 시계 방향으로 돌리는 것
- 이제 마우스 움직임에 따라 조정된다.
- rY값을 변화시키므로, 터치가 시작될 때 원상복구할 rY값을 어딘가에 저장해주어야 한다.
- 변수 startRY 를 만들어주고, 터치가 시작된 시점의 rY 값을 해당 변수에 저장한다.
(direction이 아니라 distance이다.)
- 여기서 계산한 값을 각도로 사용하는데, direction의 단위는 px이다.
그런데 100px 움직인 것을 100도로 사용하면 너무 많다.
- 대략 /8 정도로 나눠보기 (100px 움직이면 1/8만큼 이동하도록)
- 터치가 시작된 지점의 rY값(startRY)과 지금의 rY값을 계산해서 움직이게 한다.
- 취소 cancel 시 rY값은 원상복구되도록 한다.
- end일때는 이동한 방향 좌우를 파악해서 이동하기!
- 최초값에서 angle을 더해서 돌릴 것인지 빼서 돌릴 것인지 파악하고 움직이기
- 원래 최초의 rY값을 저장해놓고 기본값으로 활용하는 것이 중요하다!!
- 이렇게 마우스 클릭-드래그로 이동할수있는 Carousel을 만들어보았다.
'국비교육(22-23)' 카테고리의 다른 글
115일차(1)/CSS(14) : CSS3 Flex 활용(2) (0) | 2023.03.26 |
---|---|
114일차(1)/CSS(13) : CSS3 Flex 활용(1) (1) | 2023.03.24 |
112일차(1)/CSS(11) : 3차원 컨텐츠 만들기(4) (1) | 2023.03.22 |
111일차(1)/CSS(10) : 3차원 컨텐츠 만들기(3) (0) | 2023.03.21 |
110일차(1)/CSS(9) : 3차원 컨텐츠 만들기(2) (1) | 2023.03.20 |