HTML/CSS
JavaScript

Spin the Wheel

It is commonly used in promotions, giveaways, decision-making tools, and gamified experiences.

 
								<!DOCTYPE HTML>
<html>
<head>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta charset="utf-8">
    <title>Wheel of Fortune Bingo</title>
    <style type="text/css">
        body {
            font-family: Helvetica, Arial, sans-serif;
        }
        text {
            font-family: Helvetica, Arial, sans-serif;
            font-size: 10px;
            pointer-events: none;
        }
        #chart {
            background-image: url("https://experiencenetcorecloud.com/assets/images/spinbg.png");
            background-repeat: no-repeat;
            background-size: 130px;
    background-position: center 185px;
        }
        .close {
            position: absolute;
    color: red;
    right: 2px;
    top: 2px;
    font-family: Arial;
    font-size: 18px;
    line-height: 14px;
    cursor: pointer;
    border: 1px solid red;
    border-radius: 14px;
    padding: 3px;
        }
        .spinner-wappers {
    width: 100%;
    height: 100%;
    display: block;
    background: #f2f2f2;
}
        .spinner {
            margin: 0 auto;
            display: block;
            position: relative;
            width: 400px;
            height: 365px;
        }
        #formContainer {
            display: none;
            position: fixed;
            left: 0;
            top: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0, 0, 0, 0.7);
            z-index: 1000;
        }
        .form-wrapper {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            background-color: white;
            padding: 15px;
            border-radius: 5px;
            width: 300px;
            max-width: 90%;
        }
        .form-title {
            text-align: left;
    margin-bottom: 15px;
    font-size: 12px;
    font-weight: bold;
        }
        .form-group {
            margin-bottom: 10px;
        }
        .form-group label {
            display: block;
            margin-bottom: 5px;
            font-weight: bold;
            text-align: left;
            font-size: 10px;
        }
        .success-message h2 {
    font-size: 14px;
    font-weight: bold;
    margin-bottom: 10px;
    text-align: center;
}
        .form-group input {
            width: 100%;
            padding: 8px;
            box-sizing: border-box;
            border: 1px solid #ccc;
            border-radius: 4px;
            text-align: left;
            font-size: 10px;
        }
        .form-group .error {
            color: red;
            font-size: 8px;
            margin-top: 5px;
            display: none;
        }
        .spin-submit-btn {
            background-color: #BF2526!Important;
            color: white!Important;
            border: none!Important;
            padding: 10px 20px!Important;
            width: 100%!Important;
            border-radius: 4px!Important;
            cursor: pointer!Important;
            font-size: 14px!Important;
            font-weight: bold!Important;
        }
        .spin-submit-btn:hover {
            background-color: #9E1E1F!Important;
        }
        .success-message {
            display: none;
            text-align: center;
        }
        .prize-title {
            font-size: 18px;
            color: #BF2526;
            margin-bottom: 10px;
        }
        .prize-info p {
    font-size: 10px;
    color: #000;
}
        .coupon-code {
            background-color: #f5f5f5;
            border: 2px dashed #BF2526;
            padding: 10px 15px;
            font-size: 20px;
            font-weight: bold;
            letter-spacing: 1px;
            margin: 15px auto;
            max-width: 200px;
            border-radius: 4px;
        }
        .spinner {
    animation: none ! Important;
}
.spinner *:focus-visible {
    outline: none !important;
    box-shadow: none !important;
}
        .coupon-instructions {
            font-size: 14px;
            color: #555;
            margin-top: 10px;
        }
        .disabled {
            opacity: 0.5;
            cursor: not-allowed !important;
        }
        #spinButton {
            cursor: pointer;
        }
    </style>
</head>
<body>
<div class="spinner-wappers">
    <div class="spinner">
        <div id="chart"></div>
    </div>
     </div>

    <div id="formContainer">
        <div class="form-wrapper">
            <div class="form-content">
                <div class="close" id="close-form">X</div>
                <div class="form-title">Congratulations! You've won: <span id="prizeText"></span></div>
                <div class="form-group">
                    <label for="name">Name:</label>
                    <input type="text" id="name" placeholder="Enter your name">
                    <div class="error" id="nameError">Please enter your name</div>
                </div>
                <div class="form-group">
                    <label for="email">Email: <span style="color: red;">*</span></label>
                    <input type="email" id="email" placeholder="Enter your email">
                    <div class="error" id="emailError">Please enter a valid email address</div>
                </div>
                <div class="form-group">
                    <label for="phone">Phone: <span style="color: red;">*</span></label>
                    <input type="tel" id="phone" placeholder="Enter your phone number">
                    <div class="error" id="phoneError">Please enter a valid phone number</div>
                </div>
                <button type="button" class="spin-submit-btn" id="claimBtn">Claim Offer Now</button>
            </div>
            <div class="success-message" id="successMessage">
                <div class="close" id="close-success">X</div>
                <h2>Thank You!</h2>
                <div class="prize-info">
                    <p>Your prize: <span class="prize-title" id="finalPrize"></span></p>
                    <div class="coupon-code" id="couponCode"></div>
                    <p class="coupon-instructions">Use this code during checkout to redeem your offer.</p>
                </div>
            </div>
        </div>
    </div>
    </body>
    </html>

							
Note: In the console, type 'allow pasting,' and then you can paste the code below.
 
								var script = document.createElement('script');
								script.src = "https://d3js.org/d3.v3.min.js";
								script.type = "text/javascript";
								document.head.appendChild(script);
								script.onload = function() {
									console.log("D3.js v" + d3.version + " loaded successfully!");
								};
								var padding = {top: 20, right:10, bottom: 100, left: 10},
            w = 400 - padding.left - padding.right,
            h = 365 - padding.top  - padding.bottom,
            r = Math.min(w, h)/2,
            rotation = 0,
            oldrotation = 0,
            picked = 100000,
            oldpick = [],
            isSpinning = false,
            color = d3.scale.ordinal()
                    .range([
                        "#8BC53E",
                        "#0A9343",
                        "#24A9E0",
                        "#652C90",
                        "#9E1E62",
                        "#BE1D2D",
                    ]);
        var data = [
            {"label":"100 points", "value": 1, "coupon": "SORRY2025"},
            {"label":"Buy 1 get 1 free", "value": 2, "coupon": "BOGO2025"},
            {"label":"Buy 3 get 1 free", "value": 3, "coupon": "B3G1FREE"},
            {"label":"Flat 50% Off", "value": 4, "coupon": "HALF2025"},
            {"label":"Extra 10% Off", "value": 5, "coupon": "EXTRA10"},
            {"label":"Extra 5% Off", "value": 6, "coupon": "EXTRA05"},
        ];
        
        var currentPrize = "";
        var currentCoupon = "";
        
        var svg = d3.select('#chart')
            .append("svg")
            .data([data])
            .attr("width",  w + padding.left + padding.right)
            .attr("height", h + padding.top + padding.bottom);
            
        var container = svg.append("g")
            .attr("class", "chartholder")
            .attr("transform", "translate(" + (w/2 + padding.left) + "," + (h/2 + padding.top) + ")");
            
        var vis = container
            .append("g");
            
        var finalVal = 'test';
        var pie = d3.layout.pie().sort(null).value(function(d){return 1;});
        
        // declare an arc generator function
        var arc = d3.svg.arc().outerRadius(r);
        
        // select paths, use arc generator to draw
        var arcs = vis.selectAll("g.slice")
            .data(pie)
            .enter()
            .append("g")
            .attr("class", "slice");
            
        arcs.append("path")
            .attr("fill", function(d, i){ return color(i); })
            .attr("d", function (d) { return arc(d); });
            
        // add the text
        arcs.append("text").attr("transform", function(d){
                d.innerRadius = 0;
                d.outerRadius = r;
                d.angle = (d.startAngle + d.endAngle)/2;
                return "rotate(" + (d.angle * 180 / Math.PI - 90) + ")translate(" + (d.outerRadius -10) +")";
            })
            .attr("fill", "#fff")
            .style({"font-weight":"bold"})
            .attr("text-anchor", "end")
            .text(function(d, i) {
                return data[i].label;
            });
            
        // Define the spin button group
        var spinButtonGroup = container.append("g")
            .attr("id", "spinButton");
            
        // Draw spin rectangle button
        spinButtonGroup.append("rect")
            .attr("x", -50)
            .attr("y", 165)
            .attr("rx", 5)
            .attr("width", 100)
            .attr("height", 40)
            .style({"fill":"#000"});
            
        // Spin text
        spinButtonGroup.append("text")
            .attr("x", 0)
            .attr("y", 193)
            .attr("text-anchor", "middle")
            .text("SPIN")
            .style({"font-weight":"bold","font-size":"20px","fill":"#fff"});
            
        // Add click event to spin button
        spinButtonGroup.style("cursor", "pointer")
            .on("click", function() {
                if (!isSpinning) {
                    spin();
                }
            });
            
        function spin(){
            // Set spinning state to true
            isSpinning = true;
            
            // Disable the button
            spinButtonGroup.classed("disabled", true)
                .style("pointer-events", "none");
                
            // Check if all slices have been seen
            console.log("OldPick: " + oldpick.length, "Data length: " + data.length);
            if(oldpick.length == data.length){
                console.log("done");
                return;
            }
            
            var ps = 360/data.length,
                pieslice = Math.round(1440/data.length),
                rng = Math.floor((Math.random() * 1440) + 360);
                
            rotation = (Math.round(rng / ps) * ps);
            picked = Math.round(data.length - (rotation % 360)/ps);
            picked = picked >= data.length ? (picked % data.length) : picked;
            
            if(oldpick.indexOf(picked) !== -1){
                d3.select(this).call(spin);
                return;
            } else {
                oldpick.push(picked);
            }
            
            rotation += 90 - Math.round(ps/2);
            
            vis.transition()
                .duration(3000)
                .attrTween("transform", rotTween)
                .each("end", function(){
                    // Mark question as seen
                    d3.select(".slice:nth-child(" + (picked + 1) + ") path")
                        .attr("stroke-width", "3px")
                        .attr("stroke", "#fff");
                    
                    oldrotation = rotation;
                    
                    // Get the value of the selected segment
                    var prizeWon = data[picked];
                    currentPrize = prizeWon.label;
                    currentCoupon = prizeWon.coupon;
                    finalVal = JSON.stringify(prizeWon);
                    console.log("You won: " + currentPrize + " with coupon: " + currentCoupon);
                    
                    // Show the form after 3 seconds
                    setTimeout(function() {
                        document.getElementById('prizeText').textContent = currentPrize;
                        document.getElementById('formContainer').style.display = 'block';
                    }, 1000);
                    
                    // Reset the spinning state
                    isSpinning = false;
                    
                    // Don't re-enable the button after spinning to prevent multiple spins
                    // We'll keep it disabled
                });
        }
        
        // Make arrow
        svg.append("g")
            .attr("transform", "translate(" + (w - padding.left) + "," + ((h/2)+padding.top) + ")")
            .append("path")
            .attr("d", "M-" + (r*.15) + ",0L0," + (r*.08) + "L0,-" + (r*.08) + "Z")
            .style({"fill":"#000"});
            
        // Draw spin circle
        container.append("circle")
            .attr("cx", 0)
            .attr("cy", 0)
            .attr("r", 10)
            .attr("stroke", "#fff")
            .attr("stroke-width", 2)
            .style({"fill":"#BF2526"});
            
        function rotTween(to) {
            var i = d3.interpolate(oldrotation % 360, rotation);
            return function(t) {
                return "rotate(" + i(t) + ")";
            };
        }
        
        function getRandomNumbers(){
            var array = new Uint16Array(1000);
            var scale = d3.scale.linear().range([360, 1440]).domain([0, 100000]);
            if(window.hasOwnProperty("crypto") && typeof window.crypto.getRandomValues === "function"){
                window.crypto.getRandomValues(array);
                console.log("works");
            } else {
                // No support for crypto, get crappy random numbers
                for(var i=0; i < 1000; i++){
                    array[i] = Math.floor(Math.random() * 100000) + 1;
                }
            }
            return array;
        }

        // close validation and submission
        document.getElementById('close-form').addEventListener('click', function() {
    let elements = document.querySelectorAll('#formContainer');
    elements.forEach(element => {
        element.style.display = 'none';
    });

    // Reset spinning state
    isSpinning = false;

    // Re-enable the spin button
    d3.select("#spinButton").classed("disabled", false).style("pointer-events", "auto");
});

document.getElementById('close-success').addEventListener('click', function() {
    let elements = document.querySelectorAll('#formContainer');
    elements.forEach(element => {
        element.style.display = 'none';
    });

    // Reset spinning state
    isSpinning = false;

    // Re-enable the spin button
    d3.select("#spinButton").classed("disabled", false).style("pointer-events", "auto");
});
        // Form validation and submission
        document.getElementById('claimBtn').addEventListener('click', function() {
            var name = document.getElementById('name').value;
            var email = document.getElementById('email').value;
            var phone = document.getElementById('phone').value;
            var isValid = true;
            
            // Validate name (optional)
            if (name.trim() === '') {
                document.getElementById('nameError').style.display = 'none';
            }
            
            // Validate email (required)
            if (email.trim() === '' || !isValidEmail(email)) {
                document.getElementById('emailError').style.display = 'block';
                isValid = false;
            } else {
                document.getElementById('emailError').style.display = 'none';
            }
            
            // Validate phone (required)
            if (phone.trim() === '' || !isValidPhone(phone)) {
                document.getElementById('phoneError').style.display = 'block';
                isValid = false;
            } else {
                document.getElementById('phoneError').style.display = 'none';
            }
            
            if (isValid) {
                // Collect and process form data
                var formData = {
                    name: name,
                    email: email,
                    phone: phone,
                    prize: currentPrize,
                    coupon: currentCoupon
                };
                
                console.log("Form submitted with data:", formData);
                
                // Show success message
                document.querySelector('.form-content').style.display = 'none';
                document.getElementById('finalPrize').textContent = currentPrize;
                document.getElementById('couponCode').textContent = currentCoupon;
                document.getElementById('successMessage').style.display = 'block';
          
            }
        });
        
        function isValidEmail(email) {
            var emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
            return emailRegex.test(email);
        }
        
        function isValidPhone(phone) {
            var phoneRegex = /^\+?[0-9]{10,15}$/;
            return phoneRegex.test(phone);
        }