반응형
룰렛을 적용시킬 원판이미지와 배열을 준비한다.
이미지는 테스트로 첨부하니 테스트를 원하면 사용하도록.
/**
* # 스크립트 준비
*/
// 룰렛결과 배열
const itemList = [
{value: 0, label: "샌드위치"},
{value: 1, label: "핫도그"},
{value: 2, label: "도너츠"},
{value: 3, label: "마카롱"},
{value: 4, label: "아이스크림"},
{value: 5, label: "에그타르트"},
{value: 6, label: "크로와상"},
{value: 7, label: "케이크"},
{value: 8, label: "면세점 상품권"},
{value: 9, label: "우주패스"},
{value: 10, label: "영화관 콤보"},
{value: 11, label: "케이크"},
];
// 항목 개수
const itemLength = computed(() => itemList.length);
// 원판 div 접근 ref
const wacuRef = ref();
html 구성은 container와 원판영역, 버튼영역으로 구성한다. (필요에 따라 수정)
버튼은 img를 사용했으니 필요에 따라 수정.
<div class="roulette-container">
<div class="rouletter">
<div class="rouletter-bg">
<div class="rouletter-wacu" ref="wacuRef"></div>
</div>
<div class="rouletter-arrow"></div>
</div>
<div class="button-container">
<a
href="javascript:void(0)"
class="btn-start"
@click="onClickStart">
<img src="/images/step-two/btn_start.png" alt="start"/>
</a>
</div>
</div>
버튼에는 onClickStart 메서드가 있다.
roll 메서드에서는 api등을 통해서 값을 받아와도 되고, 랜덤으로 배열의 인덱스를 추출해도된다.
아래는 3번인덱스로 테스트 하드코딩.
roll메서드에서 3번인덱스로 위에서 정의해둔 12개의 배열에서 꺼내온 후 value값을 넘겨준다.
실제 회전은 onRotateStart 메서드에서 진행된다.
원판 div에 ref 접근하여, style transform 값의 roate값을 interval로 변경시킨다.
delay라는 메소드로 지연함수를 사용하여 원판이 진행되는동안을 기다리도록 처리한다.
최종 목표 rotate 값은 360/배열 수 * 파라메터로 받은 배열값(인덱스)로 하면 해당하는 타겟에 멈추게 된다.
num === 30 부분과 delay(2400) 부분을 적절히 조절하여 속도를 늦추고 당겨줄 수도 있겠다.
// 룰렛 진행중 여부
const isSpining = ref(false);
/**
* # 룰렛 start
*/
const onClickStart = async () => {
// business logic
// 진행중이면 클릭 무시
if (isSpining.value) return;
isSpining.value = true;
await roll();
// after logic
}
async function roll() {
try {
// TODO : 당첨 결과 값(상품 고유값) 룰렛 결과로 세팅
// TEST로 3번 인덱스 당첨
const idx: number = parseInt("3", 10);
const drawValue = itemList[idx].value;
// onRotateStart에는 당첨결과 번호를 넘겨주면 룰렛이 해당 인덱스에 멈춘다.
await onRotateStart(drawValue);
// after logic
} catch (err: any) {
Alert.error("에러");
} finally {
isSpining.value = false;
}
}
/**
* # 룰렛 시작
* @param targetValue: 당첨 결과값
*/
const onRotateStart = async (targetValue: number) => {
const panel = wacuRef.value;
const deg = [];
// 룰렛 각도 설정
for (let i = 1; i <= itemLength.value; i++) {
deg.push((360 / itemLength.value) * i);
}
let num = 0;
return new Promise((resolve) => {
// 애니설정
let ani = setInterval(async () => {
num++;
panel.style.transform = "rotate(" + 360 * num + "deg)";
// num이 몇까지 돌지 세팅(속도제한)(30)
if (num === 30) {
clearInterval(ani);
panel.style.transform = `rotate(${(360 / itemLength.value) * targetValue}deg)`;
await delay(2400);
resolve(true);
}
}, 50);
});
};
// 지연 함수 참고
function delay(ms = 1000) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
await을 걸어두었기때문에 이후 팝업같은 logic을 추가할 수 있겠다.
아래는 html에 해당하는 scss 예시이다.
.roulette-container {
.rouletter {
position: relative;
width: 690px;
height: 690px;
margin: 0 auto;
.rouletter-bg {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 690px;
height: 690px;
border-radius: 50%;
overflow: hidden;
}
.rouletter-wacu {
width: 100%;
height: 100%;
background-image: url(/images/step-two/wacu.png);
background-repeat: no-repeat;
background-size: 100%;
transform-origin: center;
transition-timing-function: ease-in-out;
transition: 2s;
}
.rouletter-arrow {
position: absolute;
top: -30px;
left: 50%;
width: 61px;
height: 82px;
transform: translateX(-50%);
background-image: url(/images/step-two/pin.png);
background-repeat: no-repeat;
background-size: 100%;
}
}
.button-container {
margin-top: 83px;
}
}
.on {
animation-name: ani;
animation-duration: 0.1s;
animation-fill-mode: forwards;
animation-iteration-count: infinite;
}
@keyframes ani {
0% {
transform: rotate(0deg);
transition-timing-function: ease-out;
}
100% {
transform: rotate(360deg);
}
}
// 반응형 참고
//@media only screen and (max-width: $mobile-max-width) {
// .roulette-container {
// .rouletter {
// width: vw(690);
// height: vw(690);
//
// .rouletter-bg {
// width: vw(690);
// height: vw(690);
// }
//
// .rouletter-arrow {
// top: vw(-30);
// width: vw(61);
// height: vw(82);
// }
// }
// .button-container {
// margin-top: vw(83);
// img {
// width: vw(500);
// height: vw(120);
// }
// }
// }
//}
.rouletter-wacu의 transition값을 2s에서 3s이상으로 늘리면 룰렛이 좀 더 천천히 멈추는느낌이고,
1s로 줄이게되면 확 멈추는 느낌이 되겠다.
반응형
'프로그래밍 > Vue.js' 카테고리의 다른 글
vuejs 반응형 sprite canvas 만들기 (1) | 2023.07.19 |
---|---|
vuejs 슬롯머신 만들기 (0) | 2023.05.22 |
vuejs 가상스크롤로 로딩지연 개선 (1) | 2023.02.27 |
vuejs 공공데이터 공적 마스크 판매 정보 api 사용해보기 (3) (0) | 2020.03.13 |
vuejs 공공데이터 공적 마스크 판매 정보 api 사용해보기 (2) (0) | 2020.03.12 |