UNPKG

vue-wheel-spinner

Version:

A Vue.js component that provides wheel spinner

242 lines (204 loc) 7.81 kB
# Wheel Spinner Component A customizable wheel spinner component built with Vue.js. ![image](https://github.com/ilyasozkurt/vue-wheel-spinner/assets/4955440/08cb6195-60eb-4ac4-82cb-2a4b5296dc5e) ## Table of Contents - [Installation](#installation) - [Usage](#usage) - [Props](#props) - [Slots](#slots) - [Events](#events) - [License](#license) - [Demo](https://vue-wheel-spinner-demo.vercel.app/) - [Demo Project Source](https://stackblitz.com/~/github.com/ilyasozkurt/vue-wheel-spinner) ## Installation To use this component, you need to have a Vue.js project set up. If you don't have one, you can create a new Vue.js project using Vue CLI: ```sh npm install -g @vue/cli vue create my-project cd my-project ``` Install the component ```sh npm install vue-wheel-spinner ``` ## Usage Import and register the component in your Vue component: ```vue <template> <VueWheelSpinner ref="spinner" :slices="slices" :slice-font-style="sliceFontStyle" :slice-text-position="sliceTextPosition" :winner-index="defaultWinner" :sounds="sounds" :cursor-angle="cursorAngle" :cursor-position="cursorPosition" :cursor-distance="cursorDistance" @spin-start="onSpinStart" @spin-end="onSpinEnd"> <template #cursor> <img class="cursor-img" :src="cursorImage" alt="Cursor"> </template> <template #default> <button class="spin-button" :disabled="isSpinning" @click="handleSpinButtonClick" @mouseover="handleSpinButtonHover" @mouseleave="handleSpinButtonLeave"> Spin </button> </template> </VueWheelSpinner> </template> <script> import VueWheelSpinner from 'vue-wheel-spinner'; import cursorImage from './assets/cursor.svg'; import wonSound from './sounds/won.mp3'; import clickSound from './sounds/click.mp3'; import hoverSound from './sounds/hover.mp3'; import leaveSound from './sounds/leave.mp3'; import spinningSound from './sounds/spinning.mp3'; export default { components: { VueWheelSpinner }, data() { return { winnerResult: null, slices: [ {color: '#eb4d4b', text: 'Slice 1', textColor: '#000000'}, {color: '#f0932b', text: 'Slice 2', textColor: '#ffffff'}, {color: '#f9ca24', text: 'Slice 3', textColor: '#000000'}, {color: '#badc58', text: 'Slice 4', textColor: '#ffffff'}, {color: '#7ed6df', text: 'Slice 5', textColor: '#000000'}, {color: '#e056fd', text: 'Slice 6', textColor: '#ffffff'}, ], sliceFontStyle: 'bold 16px Arial', sliceTextPosition: 'edge', isSpinning: false, defaultWinner: 0, sounds: { won: wonSound, spinButtonClick: clickSound, spinButtonHover: hoverSound, spinButtonLeave: leaveSound, spinning: spinningSound }, cursorImage, cursorAngle: 0, cursorPosition: 'edge', cursorDistance: 0 }; }, methods: { playAudio(audio) { if (audio) { audio.volume = 0.5 audio.play(); } }, handleSpinButtonClick() { if (this.buttonClickAudio) { this.playAudio(this.buttonClickAudio) } this.$refs.spinner.spinWheel(this.defaultWinner); }, handleSpinButtonHover() { if (this.buttonHoverAudio) { this.playAudio(this.buttonHoverAudio) } }, handleSpinButtonLeave() { if (this.buttonLeaveAudio) { this.playAudio(this.buttonLeaveAudio) } }, spinFor(index) { this.defaultWinner = index; this.$refs.spinner.spinWheel(index); }, onSpinStart() { this.winnerResult = null; this.isSpinning = true; }, onSpinEnd(winnerIndex) { this.isSpinning = false; this.winnerResult = this.slices[winnerIndex]; } }, mounted() { this.buttonHoverAudio = new Audio(hoverSound); this.buttonLeaveAudio = new Audio(leaveSound); this.buttonClickAudio = new Audio(clickSound); } }; </script> <style> .cursor-img { width: 50px; aspect-ratio: 1 / 1; filter: drop-shadow(3px 3px 2px rgba(0, 0, 0, 0.19)); } .spin-button { width: 100px; height: 100px; margin: 0 auto; aspect-ratio: 1 / 1; font-size: 20px; cursor: pointer; background: #eb4d4b; border-radius: 50%; transition: all 150ms; border: 10px solid white; display: flex; align-items: center; justify-content: center; font-weight: 600; color: white !important; box-shadow: inset -3px -3px 2px 2px rgba(0, 0, 0, 0.19), 3px 3px 2px 2px rgba(0, 0, 0, 0.19); z-index: 11; position: relative; user-select: none; &:hover { box-shadow: inset -5px -5px 2px 2px rgba(0, 0, 0, 0.19), 3px 3px 2px 2px rgba(0, 0, 0, 0.19); } &:active { box-shadow: inset 3px 3px 2px 2px rgba(0, 0, 0, 0.19), 3px 3px 2px 2px rgba(0, 0, 0, 0.19); } &:disabled { background: #ccc; cursor: not-allowed; pointer-events: none; } } </style> ``` ## Props | Prop | Type | Default | Description | |-----------------------------|--------|------------|--------------------------------------------------------------------------------------| | `slices` | Array | required | Array of slice objects. Each slice object should have `color` and `text` properties. | | `sliceFontStyle` | String | 'bold 16px Arial' | Font style for the slice text. | | `sliceTextPosition` | String | 'edge' | Position of the slice text. Can be 'edge', 'center' or 'middle'. | | `winnerIndex` | Number | 0 | Index of the slice that will be the winner. | | `spinDuration` | Number | 4000 | Duration of the spin animation in milliseconds. | | `cursorAngle` | Number | 0 | Angle of the cursor. | | `cursorPosition` | String | 'edge' | Position of the cursor. Can be 'edge' or 'center'. | | `cursorDistance` | Number | 0 | Distance of the cursor from the center or edge. It's depending to cursorPosition | | `sounds` | Object | {} | Object of sound files. | | `sounds.won` | String | null | Sound file for the winning event. | | `sounds.spinning` | String | null | Sound file for the spinning event. | ## Slots | Slot | Description | |--------------|------------------------------------------------------------| | `cursor` | Slot for the cursor element. Mostly an image like a cursor | | `default` | Slot for centered content. Mostly a circle spin button | ## Events | Event | Description | |---------------|---------------------------------------------------------------------| | `spin-start` | Emitted when the spin starts. | | `spin-end` | Emitted when the spin ends. Passes the `winnerIndex` as a parameter.| ## License This project is licensed under the MIT License.