이전 글 보기 (더보기 클릭)
저번 글에서 로드된 모델의 사용 가능한 애니메이션이 있는지 체크 후 있다면 model-veiwer에 animation-name 속성을 추가해주는 준비 단계에 이어서 이번 포스팅에서는
이런 버튼들을 만들어 각 버튼에 맞는 기능을 추가해 보겠습니다.
아래 모든 소스는 이전 포스팅을 이어갑니다.
버튼 만들기
<model-viewer id="model-ex" camera-controls>
<!-- new -->
<div class="model-nav">
<div class="model-control">
<button class="zoom-in-btn">+</button>
<button class="zoom-out-btn">-</button>
<button class="animation-btn">ani</button>
<button class="fullscreen-btn">full screen</button>
</div>
<div class="open-ar">
<button class="open-ar-btn">AR</button>
</div>
</div>
</model-viewer>
우선 <model-viewer> 안에 컨트롤 버튼이 들어갈 영역을 만들어줍니다.
줌 인/아웃 기능 구현
zoom in/out은 공식 문서에 있는 zoom methods를 사용합니다.
문서 설명에 보면
키보드 또는 마우스 휠 입력을 모방하여, 확대/축소 동작을 적용합니다.
라고 나와있습니다. (영어를 잘 못해서 이게 정확하게 맞나...? 싶지만.. 여하튼)
즉, zoom(10)의 경우 확대 zoom(-10)은 축소가 됩니다.
// new function
function modelController() {
const zoomInBtn = document.querySelector('.zoom-in-btn');
const zoomOutBtn = document.querySelector('.zoom-out-btn');
zoomInBtn.addEventListener('click', () => {
MODEL_VIEWER.zoom(5);
});
zoomInBtn.addEventListener('click', () => {
MODEL_VIEWER.zoom(-5);
});
}
해당 기능은 손쉽게 구현이 가능합니다.
애니메이션 토글 기능 구현
저번 포스팅에서 로드된 모델의 사용 가능한 애니메이션이 있는지 체크 후 있다면 model-veiwer에 animation-name 속성을 추가해주는 준비 단계까지 맞추어놓은 상태가 되어 있어야 합니다.
function modelController() {
const zoomInBtn = document.querySelector('.zoom-in-btn');
const zoomOutBtn = document.querySelector('.zoom-out-btn');
// new variable
const animationBtn = document.querySelector('.animation-btn');
zoomInBtn.addEventListener('click', () => {
MODEL_VIEWER.zoom(5);
});
zoomInBtn.addEventListener('click', () => {
MODEL_VIEWER.zoom(-5);
});
// new eventListener
animationBtn.addEventListener('click', () => {
if (animationArr.length > 0) {
MODEL_VIEWER.classList.toggle('activeAni');
toggleAnimation();
}
});
}
// new function
function toggleAnimation() {
const isActive = MODEL_VIEWER.classList.contains('activeAni');
if (isActive) {
MODEL_VIEWER.setAttribute('animation-name', animationArr[animationArr.length - 1]);
} else {
MODEL_VIEWER.setAttribute('animation-name', animationArr[0]);
}
}
애니메이션 토글 버튼을 클릭할 때마다 한번 더 animationArr가 존재하는지 확인 후
현재 애니메이션이 활성화되었는지 체크하기 위해 'activeAni' 클래스를 toggle 시켜줍니다.
'toggleAnimation' 함수에서 toggle 시켰던 'activeAni' 클래스를 가지고 있는지 확인하는 변수 'isActive'를 만들어 줍니다.
이제 isActive 변수를 통해 조건문으로 true라면 aniamtionArr의 마지막, false라면 첫 번째(기본)로 animation-name 속성을 설정해줍니다.
저는 저번 포스팅에서도 말했듯 제가 사용한 모든 model 파일은 사용 가능한 animation이 2개로 고정되어있는데 가끔 사용하지 않는 애니메이션이 중간에 포함돼서 3개가 들어있는 경우가 있어서 [0]으로 첫 번째는 고정, Array.length - 1로 배열의 length가 2이던 3이던 마지막 요소를 선택하도록 해놨습니다.
본인 프로젝트에 맞게 바꾸시면 될 거 같습니다.
풀 스크린 기능 구현하기
function modelController() {
const zoomInBtn = document.querySelector('.zoom-in-btn');
const zoomOutBtn = document.querySelector('.zoom-out-btn');
const animationBtn = document.querySelector('.animation-btn');
// new variable
const fullScreenBtn = document.querySelector('.fullscreen-btn');
zoomInBtn.addEventListener('click', () => {
MODEL_VIEWER.zoom(5);
});
zoomInBtn.addEventListener('click', () => {
MODEL_VIEWER.zoom(-5);
});
animationBtn.addEventListener('click', () => {
if (animationArr.length > 0) {
MODEL_VIEWER.classList.toggle('activeAni');
toggleAnimation();
}
});
// new eventListener
fullScreenBtn.addEventListener('click', () => {
toggleFullScreen(MODEL_VIEWER.parentElement);
});
}
// new function
function toggleFullScreen(element) {
const agent = navigator.userAgent.toLowerCase();
const target =
agent.indexOf('safari') > -1
? !document.webkitFullscreenElement
: !document.fullscreenElement;
if (target) {
if (element.requestFullscreen) return element.requestFullscreen();
if (element.webkitRequestFullscreen) return element.webkitRequestFullscreen();
if (element.mozRequestFullScreen) return element.mozRequestFullScreen();
if (element.msRequestFullscreen) return element.msRequestFullscreen();
} else {
if (document.exitFullscreen) return document.exitFullscreen();
if (document.webkitExitFullscreen) return document.webkitExitFullscreen();
if (document.mozCancelFullScreen) return document.mozCancelFullScreen();
if (document.msExitFullscreen) return document.msExitFullscreen();
}
}
풀 스크린은 엄청 많은 예제가 있기에 자세한 설명은 생략하겠습니다.
현재 최종 소스
<button class="open-model-btn" data-product-name="robot">3D - 01</button>
<button class="open-model-btn" data-product-name="phone">3D - 02</button>
<button class="open-model-btn" data-product-name="car">3D - 03</button>
<div class="mv-modal-box">
<button class="close-modal-btn">X</button>
<model-viewer id="model-ex" camera-controls>
<div class="model-nav">
<div class="model-control">
<button class="zoom-in-btn">+</button>
<button class="zoom-out-btn">-</button>
<button class="animation-btn">ani</button>
<button class="fullscreen-btn">full screen</button>
</div>
<div class="open-ar">
<button class="open-ar-btn">AR</button>
</div>
</div>
</model-viewer>
</div>
const MV_MODAL_BOX = document.querySelector('.mv-modal-box');
const MODAL_VIEWER = document.querySelector('#model-ex');
const modelOpenBtn = document.querySelector('.open-model-btn');
const modalCloseBtn = document.querySelector('.close-modal-btn');
let animationArr = [];
MODEL_VIEWER.addEventListener('progress', (e) => {
if (e.detail.totalProgress === 1) {
MODEL_VIEWER.cameraOrbit = '0deg 75deg 105%';
animationArr = MODEL_VIEWER.availableAnimations;
}
});
modelOpenBtn.addEventListener('click', (e) => {
const target = e.currentTarget;
const productName = target.getAttribute('data-product-name');
MV_MODAL_BOX.style.display = 'block';
loadModel(productName)
});
modalCloseBtn.addEventListener('click', () => {
MODEL_VIEWER.removeAttribute('src');
MODEL_VIEWER.removeAttribute('animation-name');
animationArr = [];
MV_MODAL_BOX.style.display = 'none';
});
function loadModel(name) {
const modelSrc = `./assets/model/${name}.glb`;
MODEL_VIEWER.setAttribute('src', modelSrc);
}
function setAnimation() {
if (animationArr.length > 0) {
MODEL_VIEWER.setAttribute('animation-name', animationArr[0]);
} else {
console.log("사용 가능한 애니메이션이 없습니다.")
}
}
function modelController() {
const zoomInBtn = document.querySelector('.zoom-in-btn');
const zoomOutBtn = document.querySelector('.zoom-out-btn');
const animationBtn = document.querySelector('.animation-btn');
const fullScreenBtn = document.querySelector('.fullscreen-btn');
zoomInBtn.addEventListener('click', () => {
MODEL_VIEWER.zoom(5);
});
zoomInBtn.addEventListener('click', () => {
MODEL_VIEWER.zoom(-5);
});
animationBtn.addEventListener('click', () => {
if (animationArr.length > 0) {
MODEL_VIEWER.classList.toggle('activeAni');
toggleAnimation();
}
});
fullScreenBtn.addEventListener('click', () => {
toggleFullScreen(MODEL_VIEWER.parentElement);
});
}
function toggleAnimation() {
const isActive = MODEL_VIEWER.classList.contains('activeAni');
if (isActive) {
MODEL_VIEWER.setAttribute('animation-name', animationArr[animationArr.length - 1]);
} else {
MODEL_VIEWER.setAttribute('animation-name', animationArr[0]);
}
}
function toggleFullScreen(element) {
const agent = navigator.userAgent.toLowerCase();
const target =
agent.indexOf('safari') > -1
? !document.webkitFullscreenElement
: !document.fullscreenElement;
if (target) {
if (element.requestFullscreen) return element.requestFullscreen();
if (element.webkitRequestFullscreen) return element.webkitRequestFullscreen();
if (element.mozRequestFullScreen) return element.mozRequestFullScreen();
if (element.msRequestFullscreen) return element.msRequestFullscreen();
} else {
if (document.exitFullscreen) return document.exitFullscreen();
if (document.webkitExitFullscreen) return document.webkitExitFullscreen();
if (document.mozCancelFullScreen) return document.mozCancelFullScreen();
if (document.msExitFullscreen) return document.msExitFullscreen();
}
}
modelController()
다음 포스팅에선 마지막으로 AR버튼을 추가해보겠습니다.
이전 포스팅들과 다르게 기능 추가시마다 계속 소스를 이어나가는 게 아닌, 해당 추가 기능의 소스만 적은 후 마지막에 최종 소스를 한번 보여주는 방식으로 포스팅을 해봤는데 어떤 게 더 보기 편하신가요?
보기 편한 방식에 대해서 조언 남겨주시면 정말 감사하겠습니다!!
util, ui등 평소 개발 스타일대로 포스팅 소스의 파일을 나눠서 export/import 해서 진행하는 것은 포스팅 가독성을 떨어뜨린다고 판단해서 해당 포스팅은 별도의 리팩토링 없이 한 파일에 진행됩니다.
피드백, 질문, 댓글 언제나 환영입니다!
감사합니다 :)
'개발 > js' 카테고리의 다른 글
[JS] Element의 CSS Style 값 가져오기 - getComputedStyle() (0) | 2022.09.15 |
---|---|
[JS] model-viewer 사용법 4 - model AR 활성화 및 커스텀 하기 (0) | 2022.09.15 |
[JS] model-viewer 사용법 2 - model animation 추가하기 (with. modal 닫기) (0) | 2022.09.13 |
[JS] model-viewer 사용법 1 - web에 3D 모델을 띄우자! (0) | 2022.09.13 |
JS - 실시간 시계 만들기 (requestAnimationFrame) (0) | 2022.09.06 |