doc-fui-ds
Version:
Doc
534 lines (461 loc) • 21.2 kB
HTML
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Random Spin Wheel</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js"></script>
<!-- Include SweetAlert2 from CDN -->
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<style>
body {
font-family: Arial, sans-serif;
background: #f4f4f4;
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
.container {
display: flex;
max-width: 800px;
background: white;
box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.1);
border-radius: 10px;
padding: 20px;
}
.left-section {
width: 60%;
text-align: center;
}
.right-section {
width: 40%;
padding-left: 20px;
text-align: left;
border-left: 2px solid #ddd;
}
h1 {
font-size: 24px;
color: #333;
}
textarea {
width: 100%;
height: 100px;
border: 1px solid #ccc;
padding: 10px;
font-size: 16px;
border-radius: 5px;
direction: auto;
}
button {
margin-top: 10px;
padding: 10px 20px;
font-size: 18px;
border: none;
background: #007bff;
color: white;
cursor: pointer;
border-radius: 5px;
}
button:hover {
background: #0056b3;
}
.wheel-container {
position: relative;
width: 300px;
height: 300px;
margin: 20px auto;
}
#wheel {
width: 100%;
height: 100%;
border-radius: 50%;
transition: transform 4s cubic-bezier(0.17, 0.67, 0.83, 0.67);
}
.arrow {
position: absolute;
top: -10px;
left: 50%;
transform: translateX(-50%);
width: 0;
height: 0;
border-left: 15px solid transparent;
border-right: 15px solid transparent;
border-bottom: 30px solid red;
}
.winner-list {
font-size: 18px;
font-weight: bold;
color: #28a745;
}
.winner-item {
background: #f8f9fa;
padding: 5px 10px;
margin: 5px 0;
border-radius: 5px;
border-left: 5px solid #28a745;
}
</style>
</head>
<body>
<div class="container">
<!-- Left Section: Wheel -->
<div class="left-section">
<h1>🎡 Random User Draw Wheel 🎡</h1>
<input type="file" id="fileInput" accept=".xls, .xlsx">
<br><br>
<textarea id="nameInput" placeholder="Enter names (one per line)..."></textarea>
<button id="drawButton">Spin the Wheel</button>
<button id="resetButton" style="margin-top: 10px; padding: 10px 20px; font-size: 18px; border: none; background: #dc3545; color: white; cursor: pointer; border-radius: 5px;">Reset Game</button>
<div class="wheel-container">
<div class="arrow"></div>
<svg id="wheel" width="300" height="300" viewBox="0 0 300 300"></svg>
</div>
</div>
<!-- Right Section: Winner List -->
<div class="right-section">
<h2>🏆 Winners</h2>
<div id="winnerList" class="winner-list"></div>
<!-- Download Winner List Buttons -->
<button id="downloadTxtButton" style="margin-top: 10px; padding: 10px 20px; font-size: 16px; background: #28a745; color: white; border: none; cursor: pointer; border-radius: 5px;">Download Winner List (.txt)</button>
<button id="downloadExcelButton" style="margin-top: 10px; padding: 10px 20px; font-size: 16px; background: #007bff; color: white; border: none; cursor: pointer; border-radius: 5px;">Download Winner List (.xlsx)</button>
</div>
</div>
<script>
let namesArray = [];
let rotation = 0;
document.getElementById('fileInput').addEventListener('change', function (event) {
const file = event.target.files[0];
if (!file) return;
const fileType = file.name.split('.').pop().toLowerCase();
const reader = new FileReader();
if (fileType === 'txt') {
// Handle .txt file
reader.onload = function (e) {
document.getElementById('nameInput').value = e.target.result;
};
reader.readAsText(file);
} else if (fileType === 'xls' || fileType === 'xlsx') {
// Handle Excel file
reader.onload = function (e) {
const data = new Uint8Array(e.target.result);
const workbook = XLSX.read(data, { type: 'array' });
// Extract data from the first sheet and first column
const sheet = workbook.Sheets[workbook.SheetNames[0]];
const rows = XLSX.utils.sheet_to_json(sheet, { header: 1 });
// Extract names from the first column
const names = rows.map(row => row[0]).filter(name => name); // Remove empty values
// Insert names into textarea
document.getElementById('nameInput').value = names.join('\n');
};
reader.readAsArrayBuffer(file);
} else {
// alert('Unsupported file type. Please upload a .txt, .xls, or .xlsx file.');
// ✅ Show SweetAlert2 warning when no names are available
Swal.fire({
title: "Unsupported file type.😕",
text: "lease upload a .txt, .xls, or .xlsx file.",
icon: "warning",
confirmButtonText: "OK",
confirmButtonColor: "#007bff"
});
return;
}
});
document.getElementById("drawButton").addEventListener("click", function () {
if (namesArray.length === 0) {
let namesText = document.getElementById("nameInput").value;
namesArray = namesText.split("\n").map(name => name.trim()).filter(name => name !== "");
}
if (namesArray.length === 0) {
// ✅ Show SweetAlert2 warning when no names are available
Swal.fire({
title: "Oops! No Names Found 😕",
text: "Please enter names before spinning the wheel.",
icon: "warning",
confirmButtonText: "OK",
confirmButtonColor: "#007bff"
});
return;
}
generateWheel();
spinWheel();
});
// ✅ Reset Button Click Event
document.getElementById("resetButton").addEventListener("click", function () {
Swal.fire({
title: "Are you sure?",
text: "This will clear the entire wheel, names, and winners.",
icon: "warning",
showCancelButton: true,
confirmButtonColor: "#dc3545",
cancelButtonColor: "#6c757d",
confirmButtonText: "Yes, Reset"
}).then((result) => {
if (result.isConfirmed) {
// ✅ Clear the text area & winners list
document.getElementById("nameInput").value = "";
document.getElementById("winnerList").innerHTML = "";
// ✅ Reset the names array
namesArray = [];
// ✅ Clear the entire spin wheel
let wheel = document.getElementById("wheel");
wheel.innerHTML = ""; // Clears all wheel segments
// ✅ Reset the rotation to default
wheel.style.transform = "rotate(0deg)";
rotation = 0;
// ✅ Reset file input so users can re-upload Excel after reset
let fileInput = document.getElementById("fileInput");
fileInput.value = ""; // Clears selected file
Swal.fire({
title: "Game Reset!",
text: "The spin wheel, names, and winners have been cleared. You can now re-import Excel data.",
icon: "success",
confirmButtonText: "OK",
confirmButtonColor: "#007bff"
});
}
});
});
function generateWheel() {
let wheel = document.getElementById("wheel");
wheel.innerHTML = ""; // Clear previous segments
let totalSegments = namesArray.length;
let sliceAngle = 360 / totalSegments;
for (let i = 0; i < totalSegments; i++) {
let angle = i * sliceAngle;
let color = `hsl(${(i * 360) / totalSegments}, 80%, 60%)`;
let path = document.createElementNS("http://www.w3.org/2000/svg", "path");
path.setAttribute("d", describeArc(150, 150, 150, angle, angle + sliceAngle));
path.setAttribute("fill", color);
path.setAttribute("stroke", "#fff");
path.setAttribute("stroke-width", "2");
wheel.appendChild(path);
// Text positioning
let text = document.createElementNS("http://www.w3.org/2000/svg", "text");
let textAngle = angle + sliceAngle / 2; // Center of the slice
let textX = 150 + Math.cos((textAngle - 90) * Math.PI / 180) * 100; // Adjusted for diagonal alignment
let textY = 150 + Math.sin((textAngle - 90) * Math.PI / 180) * 100;
text.setAttribute("x", textX);
text.setAttribute("y", textY);
text.setAttribute("transform", `rotate(${textAngle + 90}, ${textX}, ${textY})`); // Rotates text diagonally
text.setAttribute("text-anchor", "middle");
text.setAttribute("font-size", "14px");
text.setAttribute("fill", "#fff");
text.setAttribute("dominant-baseline", "middle"); // Center align text vertically
text.textContent = namesArray[i];
wheel.appendChild(text);
}
}
function spinWheel() {
let totalSegments = namesArray.length;
let sliceAngle = 360 / totalSegments;
let randomIndex = Math.floor(Math.random() * totalSegments);
let finalRotation = 360 * 5 + (randomIndex * sliceAngle) + (sliceAngle / 2);
let wheel = document.getElementById("wheel");
rotation += finalRotation;
wheel.style.transform = `rotate(${rotation}deg)`;
setTimeout(() => {
let actualRotation = rotation % 360;
let winningIndex = Math.floor((360 - actualRotation) / sliceAngle) % totalSegments;
let winner = namesArray[winningIndex];
// ✅ Show SweetAlert2 pop-up with the winner
Swal.fire({
title: "🎉 Winner Selected! 🎉",
text: `${winner} is the lucky winner! 🏆`,
icon: "success",
confirmButtonText: "OK",
confirmButtonColor: "#007bff"
});
// ✅ Display the winner in the list
let winnerList = document.getElementById("winnerList");
let winnerItem = document.createElement("div");
winnerItem.classList.add("winner-item");
winnerItem.textContent = `🏆 ${winner}`;
winnerList.appendChild(winnerItem);
// ✅ Remove the winner from the names list
namesArray.splice(winningIndex, 1);
if (namesArray.length === 0) {
setTimeout(() => {
Swal.fire({
title: "Game Over! 🎊",
text: "All winners have been selected! Resetting the game.",
icon: "info",
confirmButtonText: "Restart"
}).then(() => {
document.getElementById("nameInput").value = "";
document.getElementById("winnerList").innerHTML = "";
});
}, 2000);
}
}, 5000);
}
function describeArc(x, y, radius, startAngle, endAngle) {
let start = polarToCartesian(x, y, radius, endAngle);
let end = polarToCartesian(x, y, radius, startAngle);
let largeArcFlag = endAngle - startAngle <= 180 ? "0" : "1";
return [
"M", x, y,
"L", start.x, start.y,
"A", radius, radius, 0, largeArcFlag, 0, end.x, end.y,
"Z"
].join(" ");
}
function polarToCartesian(centerX, centerY, radius, angleInDegrees) {
let angleInRadians = (angleInDegrees - 90) * Math.PI / 180;
return {
x: centerX + (radius * Math.cos(angleInRadians)),
y: centerY + (radius * Math.sin(angleInRadians))
};
}
// ✅ Function to download winner list as a .txt file
document.getElementById("downloadTxtButton").addEventListener("click", function () {
let winnerList = document.getElementById("winnerList").children;
if (winnerList.length === 0) {
Swal.fire({
title: "No Winners Yet!",
text: "There are no winners to download.",
icon: "warning",
confirmButtonText: "OK",
confirmButtonColor: "#dc3545"
});
return;
}
let winners = Array.from(winnerList).map(item => item.textContent).join("\n");
let blob = new Blob([winners], { type: "text/plain" });
let link = document.createElement("a");
link.href = URL.createObjectURL(blob);
link.download = "WinnerList.txt";
link.click();
});
// ✅ Function to download winner list as an .xlsx (Excel) file
document.getElementById("downloadExcelButton").addEventListener("click", function () {
let winnerList = document.getElementById("winnerList").children;
if (winnerList.length === 0) {
Swal.fire({
title: "No Winners Yet!",
text: "There are no winners to download.",
icon: "warning",
confirmButtonText: "OK",
confirmButtonColor: "#dc3545"
});
return;
}
let winners = Array.from(winnerList).map(item => [item.textContent]);
let worksheet = XLSX.utils.aoa_to_sheet([["Winner List"], ...winners]);
let workbook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(workbook, worksheet, "Winners");
// ✅ Create and trigger download
let excelBuffer = XLSX.write(workbook, { bookType: "xlsx", type: "array" });
let blob = new Blob([excelBuffer], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" });
let link = document.createElement("a");
link.href = URL.createObjectURL(blob);
link.download = "WinnerList.xlsx";
link.click();
});
// ✅ Prevent Page Reload with Confirmation
window.addEventListener("beforeunload", function (event) {
event.preventDefault();
Swal.fire({
title: "Are you sure?",
text: "Refreshing will reset the game and clear all data.",
icon: "warning",
showCancelButton: true,
confirmButtonColor: "#dc3545",
cancelButtonColor: "#6c757d",
confirmButtonText: "Yes, Refresh"
}).then((result) => {
if (result.isConfirmed) {
window.removeEventListener("beforeunload", () => {}); // Allow reload if confirmed
location.reload();
}
});
return ""; // Blocks default browser refresh alert
});
// ✅ Block Page Refresh (F5, Ctrl+R, Cmd+R)
document.addEventListener("keydown", function (event) {
if (event.key === "F5" ||
(event.ctrlKey && event.key === "r") ||
(event.metaKey && event.key === "r")) {
event.preventDefault();
Swal.fire({
title: "Action Blocked 🚫",
text: "Page refresh is disabled!",
icon: "error",
confirmButtonText: "OK",
confirmButtonColor: "#dc3545"
});
}
});
// ✅ Block Right Click Context Menu
document.addEventListener("contextmenu", function (event) {
event.preventDefault();
Swal.fire({
title: "Action Blocked 🚫",
text: "Right Click is disabled!",
icon: "error",
confirmButtonText: "OK",
confirmButtonColor: "#dc3545"
});
});
// ✅ Block Inspect Element (F12, Ctrl+Shift+I, Cmd+Opt+I)
document.addEventListener("keydown", function (event) {
if (event.key === "F12" ||
(event.ctrlKey && event.shiftKey && event.key === "I") ||
(event.metaKey && event.altKey && event.key === "I")) {
event.preventDefault();
Swal.fire({
title: "Action Blocked 🚫",
text: "Inspect Element is disabled!",
icon: "error",
confirmButtonText: "OK",
confirmButtonColor: "#dc3545"
});
}
});
// ✅ Block View Source (Ctrl+U, Cmd+U)
document.addEventListener("keydown", function (event) {
if ((event.ctrlKey && event.key === "u") ||
(event.metaKey && event.key === "u")) {
event.preventDefault();
Swal.fire({
title: "Action Blocked 🚫",
text: "View Source is disabled!",
icon: "error",
confirmButtonText: "OK",
confirmButtonColor: "#dc3545"
});
}
});
// ✅ Detect Developer Tools (DevTools) and Block Access
let devtoolsOpen = false;
setInterval(function () {
let widthThreshold = window.outerWidth - window.innerWidth > 160;
let heightThreshold = window.outerHeight - window.innerHeight > 160;
if (widthThreshold || heightThreshold) {
if (!devtoolsOpen) {
devtoolsOpen = true;
document.body.innerHTML = ""; // Clear the page content
alert("Developer Tools Detected! Access Denied. 🔒");
}
} else {
devtoolsOpen = false;
}
}, 1000);
// ✅ Block Back/Forward Button Navigation
history.pushState(null, null, location.href);
window.addEventListener("popstate", function () {
history.pushState(null, null, location.href);
Swal.fire({
title: "Navigation Blocked 🚫",
text: "Back and forward navigation is disabled!",
icon: "error",
confirmButtonText: "OK",
confirmButtonColor: "#dc3545"
});
});
</script>
</body>
</html>