Introduction
In today's digital age, engaging your community with interactive tools is essential for fostering participation and excitement. Whether you're hosting a giveaway, conducting a poll, or organizing a competition, having a visually appealing and interactive raffle wheel can significantly enhance user experience. In this article, I'll walk you through the process of creating Modern Raffle 2024, an interactive raffle wheel built with HTML, CSS, and JavaScript. We'll cover everything from setting up the structure to adding animations and integrating social sharing features.
To bring this project to life, I leveraged the following technologies:
The project is organized into three main files:
Additionally, a footer section is incorporated to promote my website, LinkedIn, Twitter, and include a Buy Me a Coffee button for support.
The HTML structure sets up the main components of the raffle application, including input sections for participants and prizes, the raffle wheel, a modal for announcing winners, and a footer for promotions.
html
<div class="input-section"> <h2>Add Participants</h2> <div class="input-group"> <input type="text"> <pre class="brush:php;toolbar:false"> ? CSS (styles.css) The CSS file is meticulously crafted to ensure a modern and premium look, incorporating glassmorphism, smooth animations, responsive design, and accessibility features. Below is the complete CSS with detailed explanations of enhancements and fixes.
/* Reset and Base Styles */
body {
background: linear-gradient(135deg, #1e3c72, #2a5298);
color: #ffffff;
display: flex;
flex-direction: column; /* Stack children vertically /
justify-content: flex-start; / Start from the top /
align-items: center;
min-height: 100vh;
/ Remove overflow hidden to allow footer visibility */
overflow-x: hidden;
}
/* Container Styles /
.container {
background: rgba(255, 255, 255, 0.05);
backdrop-filter: blur(10px);
padding: 40px;
border-radius: 20px;
text-align: center;
width: 90%;
max-width: 900px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.37);
border: 1px solid rgba(255, 255, 255, 0.18);
animation: fadeIn 1s ease-in-out;
flex: 1; / Allow container to grow and push footer down */
display: flex;
flex-direction: column;
align-items: center;
}
/* Fade-in Animation */
@keyframes fadeIn {
from { opacity: 0; transform: translateY(-20px); }
to { opacity: 1; transform: translateY(0); }
}
/* Heading Styles */
h1 {
margin-bottom: 30px;
font-size: 3rem;
font-weight: 700;
text-shadow: 3px 3px 6px rgba(0,0,0,0.3);
}
/* Input Sections */
.input-section {
margin-bottom: 40px;
width: 100%;
}
.input-section h2 {
margin-bottom: 15px;
font-size: 1.75rem;
font-weight: 600;
}
/* Input Groups */
.input-group {
display: flex;
justify-content: center;
align-items: center;
gap: 10px;
margin-bottom: 15px;
}
.input-group input {
padding: 12px 20px;
width: 60%;
border: none;
border-radius: 30px;
background: rgba(255, 255, 255, 0.1);
color: #ffffff;
font-size: 1rem;
outline: none;
transition: background 0.3s ease, box-shadow 0.3s ease;
}
.input-group input::placeholder {
color: #dddddd;
}
.input-group input:focus {
background: rgba(255, 255, 255, 0.2);
box-shadow: 0 0 10px rgba(255, 127, 80, 0.5);
}
.input-group button {
padding: 12px 25px;
border: none;
border-radius: 30px;
background-color: #ff7f50;
color: #fff;
font-size: 1rem;
font-weight: 600;
cursor: pointer;
display: flex;
align-items: center;
gap: 8px;
transition: background-color 0.3s ease, transform 0.2s ease, box-shadow 0.3s ease;
}
.input-group button:hover {
background-color: #ff5722;
transform: translateY(-2px);
box-shadow: 0 4px 10px rgba(0,0,0,0.3);
}
/* User List */
}
<div class="input-section"> <h2>Add Participants</h2> <div class="input-group"> <input type="text"> <pre class="brush:php;toolbar:false"> ? CSS (styles.css) The CSS file is meticulously crafted to ensure a modern and premium look, incorporating glassmorphism, smooth animations, responsive design, and accessibility features. Below is the complete CSS with detailed explanations of enhancements and fixes.
}
/* Selected Prize */
list-style: none; max-height: 120px; overflow-y: auto; text-align: left; padding: 0 20%; width: 100%;
}
/* Wheel Container */
.wheel-container {
position: relative;
margin-bottom: 40px;
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
}
.wheel-wrapper {
position: relative;
width: 100%;
max-width: 500px;
margin: 0 auto 20px;
}
/* Canvas Styles */
canvas {
width: 100%;
height: auto;
border-radius: 50%;
box-shadow: 0 0 20px rgba(0,0,0,0.5);
background: #000;
transition: transform 4s cubic-bezier(0.33, 1, 0.68, 1);
}
/* Pointer Styles */
.pointer {
position: absolute;
top: -20px;
left: 50%;
transform: translateX(-50%);
font-size: 2rem;
color: #ffeb3b;
animation: bounce 2s infinite;
}
@keyframes bounce {
0%, 100% { transform: translateX(-50%) translateY(0); }
50% { transform: translateX(-50%) translateY(-10px); }
}
/* Spin Button */
padding: 8px 0; border-bottom: 1px solid rgba(255, 255, 255, 0.2); font-size: 1rem;
}
font-size: 1.2rem; font-weight: 500; margin-top: 10px;
}
padding: 15px 35px; border: none; border-radius: 50px; background-color: #32cd32; color: #fff; font-size: 1.25rem; font-weight: 600; cursor: pointer; box-shadow: 0 6px 20px rgba(0,0,0,0.3); transition: background-color 0.3s ease, transform 0.2s ease, box-shadow 0.3s ease; display: flex; align-items: center; gap: 10px; margin: 0 auto;
}
/* Modal Styles */
.modal {
display: none;
position: fixed;
z-index: 100;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: rgba(0,0,0,0.8);
animation: fadeInModal 0.5s ease;
}
@keyframes fadeInModal {
from { opacity: 0; }
to { opacity: 1; }
}
.modal-content {
background-color: rgba(30, 30, 30, 0.95);
margin: 10% auto;
padding: 30px;
border-radius: 15px;
width: 90%;
max-width: 600px;
text-align: center;
box-shadow: 0 8px 25px rgba(0,0,0,0.5);
position: relative;
animation: slideDown 0.5s ease;
}
@keyframes slideDown {
from { transform: translateY(-50px); opacity: 0; }
to { transform: translateY(0); opacity: 1; }
}
.close-button {
color: #bbb;
position: absolute;
top: 15px;
right: 20px;
font-size: 28px;
font-weight: bold;
cursor: pointer;
transition: color 0.3s ease;
}
.close-button:hover,
.close-button:focus {
color: #fff;
}
.modal-content h2 {
margin-bottom: 20px;
font-size: 2rem;
font-weight: 700;
}
.modal-content p {
font-size: 1.25rem;
margin-bottom: 25px;
}
background-color: #28a428; transform: translateY(-3px); box-shadow: 0 8px 25px rgba(0,0,0,0.4);
}
transform: translateY(0); box-shadow: 0 4px 15px rgba(0,0,0,0.2);
}
/* Footer Styles /
.footer {
background: rgba(255, 255, 255, 0.05);
backdrop-filter: blur(10px);
padding: 20px 0;
border-top: 1px solid rgba(255, 255, 255, 0.2);
width: 100%;
/ Ensure footer stays below content */
flex-shrink: 0;
}
.footer-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
max-width: 900px;
margin: 0 auto;
padding: 0 20px;
}
.footer-links {
display: flex;
gap: 20px;
margin-bottom: 15px;
}
.footer-links a {
color: #ffffff;
font-size: 1rem;
text-decoration: none;
display: flex;
align-items: center;
gap: 8px;
transition: color 0.3s ease, transform 0.2s ease;
}
.footer-links a:hover {
color: #ff7f50;
transform: translateY(-2px);
}
.footer-links a i {
font-size: 1.2rem;
}
.footer-donate {
margin-top: 10px;
}
/* Responsive Design for Footer */
@media (min-width: 600px) {
.footer-container {
flex-direction: row;
justify-content: space-between;
}
}
/* Scrollbar Styles for User List */
<div class="input-section"> <h2>Add Participants</h2> <div class="input-group"> <input type="text"> <pre class="brush:php;toolbar:false"> ? CSS (styles.css) The CSS file is meticulously crafted to ensure a modern and premium look, incorporating glassmorphism, smooth animations, responsive design, and accessibility features. Below is the complete CSS with detailed explanations of enhancements and fixes.
}
list-style: none; max-height: 120px; overflow-y: auto; text-align: left; padding: 0 20%; width: 100%;
}
padding: 8px 0; border-bottom: 1px solid rgba(255, 255, 255, 0.2); font-size: 1rem;
}
font-size: 1.2rem; font-weight: 500; margin-top: 10px;
}
/* Button Focus States for Accessibility */
.input-group button:focus,
padding: 15px 35px; border: none; border-radius: 50px; background-color: #32cd32; color: #fff; font-size: 1.25rem; font-weight: 600; cursor: pointer; box-shadow: 0 6px 20px rgba(0,0,0,0.3); transition: background-color 0.3s ease, transform 0.2s ease, box-shadow 0.3s ease; display: flex; align-items: center; gap: 10px; margin: 0 auto;
}
background-color: #28a428; transform: translateY(-3px); box-shadow: 0 8px 25px rgba(0,0,0,0.4);
// Selecting DOM Elements
const addUserBtn = document.getElementById('addUserBtn');
const usernameInput = document.getElementById('username');
const userList = document.getElementById('userList');
const setPrizeBtn = document.getElementById('setPrizeBtn');
const prizeInput = document.getElementById('prize');
const selectedPrize = document.getElementById('selectedPrize');
const spinBtn = document.getElementById('spinBtn');
const winnerModal = document.getElementById('winnerModal');
const closeBtn = document.querySelector('.close-button');
const winnerText = document.getElementById('winnerText');
const shareBtn = document.getElementById('shareBtn');
// State Variables
let users = [];
let prize = "None";
let isSpinning = false;
// Wheel Configuration
const canvas = document.getElementById('raffleWheel');
const ctx = canvas.getContext('2d');
const wheelRadius = canvas.width / 2;
const colors = ['#FF5733', '#33FF57', '#3357FF', '#F333FF', '#FF33A8', '#33FFF6', '#FFC300', '#DAF7A6'];
let startAngle = 0;
let arc = 0;
// Initialize Wheel
function initializeWheel() {
if (users.length === 0) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
return;
}
arc = (2 * Math.PI) / users.length;
drawWheel();
}
// Draw the Raffle Wheel
function drawWheel() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (let i = 0; i < users.length; i ) {
const angle = startAngle i * arc;
ctx.fillStyle = colors[i % colors.length];
ctx.beginPath();
ctx.moveTo(wheelRadius, wheelRadius);
ctx.arc(wheelRadius, wheelRadius, wheelRadius, angle, angle arc, false);
ctx.closePath();
ctx.fill();
}
// Draw the Pointer Arrow
function drawPointer() {
const pointerSize = 20;
ctx.fillStyle = '#FFEB3B';
ctx.beginPath();
ctx.moveTo(wheelRadius - pointerSize, 0);
ctx.lineTo(wheelRadius pointerSize, 0);
ctx.lineTo(wheelRadius, -pointerSize * 1.5);
ctx.closePath();
ctx.fill();
}
// Add User Event
addUserBtn.addEventListener('click', addUser);
usernameInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') addUser();
});
// Function to Add a User
function addUser() {
const username = usernameInput.value.trim();
if (username === "") {
showAlert("Please enter a valid username.");
return;
}
if (users.includes(username)) {
showAlert("This username is already added.");
return;
}
users.push(username);
updateUserList();
usernameInput.value = '';
initializeWheel();
}
// Update the User List UI
function updateUserList() {
userList.innerHTML = '';
users.forEach(user => {
const li = document.createElement('li');
li.textContent = user;
userList.appendChild(li);
});
}
// Set Prize Event
setPrizeBtn.addEventListener('click', setPrize);
prizeInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') setPrize();
});
// Function to Set the Prize
function setPrize() {
const prizeInputValue = prizeInput.value.trim();
if (prizeInputValue === "") {
showAlert("Please enter a valid prize.");
return;
}
prize = prizeInputValue;
selectedPrize.textContent = Selected Prize: ${prize};
prizeInput.value = '';
}
// Spin Button Event
spinBtn.addEventListener('click', spinWheel);
// Function to Spin the Wheel
function spinWheel() {
if (isSpinning) return;
if (users.length === 0) {
showAlert("Please add at least one user.");
return;
}
if (prize === "None") {
showAlert("Please set a prize.");
return;
}
}
// Function to Stop the Wheel and Announce Winner
function stopRotateWheel() {
const degrees = startAngle * 180 / Math.PI 90;
const arcd = arc * 180 / Math.PI;
const index = Math.floor((360 - (degrees % 360)) / arcd) % users.length;
const winner = users[index];
showWinner(winner);
isSpinning = false;
spinBtn.disabled = false;
}
// Easing Function for Smooth Animation
function easeOut(t, b, c, d) {
t /= d;
t--;
return c * (t * t * t 1) b;
}
// Function to Display Alerts
function showAlert(message) {
alert(message);
}
// Function to Show Winner in Modal
function showWinner(winner) {
winnerText.textContent = ${winner} has won ${prize}! ?;
winnerModal.style.display = "block";
}
// Close Modal Events
closeBtn.addEventListener('click', () => {
winnerModal.style.display = "none";
});
window.addEventListener('click', (event) => {
if (event.target === winnerModal) {
winnerModal.style.display = "none";
}
});
// Share on Twitter
shareBtn.addEventListener('click', shareOnTwitter);
// Function to Share Winner on Twitter
function shareOnTwitter() {
const text = encodeURIComponent(? Congratulations to ${winnerText.textContent}! They have won ${prize}! ? #Giveaway #Community);
const url = encodeURIComponent('https://gladiatorsbattle.com');
const twitterUrl = https://twitter.com/intent/tweet?text=${text}&url=${url};
window.open(twitterUrl, '_blank');
}
// Initial Wheel Setup
initializeWheel();
<div class="input-section"> <h2>Add Participants</h2> <div class="input-group"> <input type="text"> <pre class="brush:php;toolbar:false"> ? CSS (styles.css) The CSS file is meticulously crafted to ensure a modern and premium look, incorporating glassmorphism, smooth animations, responsive design, and accessibility features. Below is the complete CSS with detailed explanations of enhancements and fixes.
The above is the detailed content of Building a Modern Interactive Raffle Wheel with HTML, CSS, and JavaScript. For more information, please follow other related articles on the PHP Chinese website!