23/10/2019, 19:17

Vòng quay may mắn - JQUERY

Chả là đợt vừa rồi section mình có tổ chức 20/10 cho chị em, sau hàng loạt các đầu mục chương trình sẽ diễn ra thì mình có nẩy ra ý tưởng làm cái vòng quay may mắn này để tìm ra 3 chị em may mắn để kiếm về giải thưởng từ 50k cho đến 150k. Hôm nay mình xin chia sẻ với mọi người về cách làm nó. ...

Chả là đợt vừa rồi section mình có tổ chức 20/10 cho chị em, sau hàng loạt các đầu mục chương trình sẽ diễn ra thì mình có nẩy ra ý tưởng làm cái vòng quay may mắn này để tìm ra 3 chị em may mắn để kiếm về giải thưởng từ 50k cho đến 150k. Hôm nay mình xin chia sẻ với mọi người về cách làm nó.

1. Chuẩn bị giao diện

  • Mình có sử dụng thêm các package như sweetalert2 để hiển thị kết quả, jquery, bootstrap, font-awesome... các bạn nhớ chú ý thêm vào nhé
  • MÌnh sẽ trình bày source từ trên xuống dưới, chứ không trình bày theo logic bởi vì như vậy sẽ khá dài, chỗ nào cần note thì mình sẽ thêm message. HTML
<html lang="en"><head>
    <meta charset="UTF-8">
    <meta name="viewport" content="awidth=550, initial-scale=1">
    <title>Section Bar - Pes Club</title>
    <link rel="stylesheet" type="text/css" href="{{ asset('assets/bootstrap/css/bootstrap.css') }}" media="screen" />
    <link rel="stylesheet" type="text/css" href="{{ asset('assets/font-awesome/css/font-awesome.min.css') }}" media="screen" />
    <link rel="stylesheet" type="text/css" href="{{ asset('assets/sweetalert/sweetalert2.min.css') }}" media="screen" />
    <link rel="stylesheet" type="text/css" href="{{ asset('assets/custom/css/app.css') }}" media="screen" />
</head>
<body>
    <div class="container">
        <div class="container-fluid">
        <div class="col-md-6">
            <h2>Kết quả vòng quay may mắn</h2>           
              <table class="table" style="color: black;">
                <thead style="display: block">
                  <tr>
                    <th>Avatar</th>
                    <th>Họ tên</th>
                  </tr>
                </thead>
                <tbody id="results" style="display: block;">
                </tbody>
              </table>
        </div>
        <div class="col-md-6">
            <div id="wrapper" style="">
                <audio style="display: none;" controls src="{{ asset('assets/images/nhacchuong.mp3') }}" id="audio"></audio>
                // chỗ này là để có nhạc khi quay.
                <div id="wheel">
                    <div id="inner-wheel" style="transform: rotate(1802deg);">
                    //Jquery sẽ hiển thị list các thành viên ở đây
                    </div>
                    <div id="spin" class="showing">
                        <div id="inner-spin" style="background: rgba(0, 0, 0, 0) url('{{ asset('assets/images/2010/logo.jpg') }}') no-repeat scroll center center;"></div>
                    </div>
                    <div id="shine"></div>
                </div>
            </div>
        </div>
        
        <div class="text-center" style="color: black;">Made by <a href="https://www.facebook.com/son.hip.1" target="_blank">Bố Su</a> © 2019</div>
    </div>
    </div>
</body>
    <script src="{{ asset('assets/js/jquery.min.js') }}"></script>
    <script src="{{ asset('assets/sweetalert/sweetalert2.min.js') }}"></script>
    <script src="{{ asset('assets/custom/js/rotation.js') }}"></script>
</html>

CSS

*{margin:0;padding:0}body{color:#fff;font-size:18px;font-family:sans-serif;overflow:hidden}a{color:#34495e}#wrapper{margin:20px auto;awidth:516px;position:relative}#txt{margin:20px;font-size:11px;text-align:center;user-select:none}#wheel{awidth:500px;height:500px;border-radius:50%;position:relative;overflow:hidden;border:8px solid #fff;box-shadow:rgba(0,0,0,.2) 0 0 10px,rgba(0,0,0,.05) 0 3px 0;transform:rotate(0)}#wheel:before{content:';position:absolute;border:4px solid rgba(0,0,0,.1);awidth:492px;height:492px;border-radius:50%;z-index:1000}#inner-wheel{awidth:100%;height:100%;-webkit-transition:all 6s cubic-bezier(0,.99,.44,.99);-moz-transition:all 6 cubic-bezier(0,.99,.44,.99);-o-transition:all 6s cubic-bezier(0,.99,.44,.99);-ms-transition:all 6s cubic-bezier(0,.99,.44,.99);transition:all 6s cubic-bezier(0,.99,.44,.99)}#wheel div.sec{position:absolute;awidth:0;height:0;border-style:solid;border-awidth:280px 25px 0;border-color:transparent;transform-origin:25px 280px;left:225px;top:-30px;opacity:1}#wheel div.sec:nth-child(2){transform:rotate(20deg);-webkit-transform:rotate(20deg);-moz-transform:rotate(20deg);-o-transform:rotate(20deg);-ms-transform:rotate(20deg)}#wheel div.sec:nth-child(4){transform:rotate(40deg);-webkit-transform:rotate(40deg);-moz-transform:rotate(40deg);-o-transform:rotate(40deg);-ms-transform:rotate(40deg)}#wheel div.sec:nth-child(6){transform:rotate(60deg);-webkit-transform:rotate(60deg);-moz-transform:rotate(60deg);-o-transform:rotate(60deg);-ms-transform:rotate(60deg)}#wheel div.sec:nth-child(8){transform:rotate(80deg);-webkit-transform:rotate(80deg);-moz-transform:rotate(80deg);-o-transform:rotate(80deg);-ms-transform:rotate(80deg)}#wheel div.sec:nth-child(10){transform:rotate(100deg);-webkit-transform:rotate(100deg);-moz-transform:rotate(100deg);-o-transform:rotate(100deg);-ms-transform:rotate(100deg)}#wheel div.sec:nth-child(12){transform:rotate(120deg);-webkit-transform:rotate(120deg);-moz-transform:rotate(120deg);-o-transform:rotate(120deg);-ms-transform:rotate(120deg)}#wheel div.sec:nth-child(14){transform:rotate(140deg);-webkit-transform:rotate(140deg);-moz-transform:rotate(140deg);-o-transform:rotate(140deg);-ms-transform:rotate(140deg)}#wheel div.sec:nth-child(16){transform:rotate(160deg);-webkit-transform:rotate(160deg);-moz-transform:rotate(160deg);-o-transform:rotate(160deg);-ms-transform:rotate(160deg)}#wheel div.sec:nth-child(18){transform:rotate(180deg);-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-o-transform:rotate(180deg);-ms-transform:rotate(180deg)}#wheel div.sec:nth-child(20){transform:rotate(200deg);-webkit-transform:rotate(200deg);-moz-transform:rotate(200deg);-o-transform:rotate(200deg);-ms-transform:rotate(200deg)}#wheel div.sec:nth-child(22){transform:rotate(220deg);-webkit-transform:rotate(220deg);-moz-transform:rotate(220deg);-o-transform:rotate(220deg);-ms-transform:rotate(220deg)}#wheel div.sec:nth-child(24){transform:rotate(240deg);-webkit-transform:rotate(240deg);-moz-transform:rotate(240deg);-o-transform:rotate(240deg);-ms-transform:rotate(240deg)}#wheel div.sec:nth-child(26){transform:rotate(260deg);-webkit-transform:rotate(260deg);-moz-transform:rotate(260deg);-o-transform:rotate(260deg);-ms-transform:rotate(260deg)}#wheel div.sec:nth-child(28){transform:rotate(280deg);-webkit-transform:rotate(280deg);-moz-transform:rotate(280deg);-o-transform:rotate(280deg);-ms-transform:rotate(280deg)}#wheel div.sec:nth-child(30){transform:rotate(300deg);-webkit-transform:rotate(300deg);-moz-transform:rotate(300deg);-o-transform:rotate(300deg);-ms-transform:rotate(300deg)}#wheel div.sec:nth-child(32){transform:rotate(320deg);-webkit-transform:rotate(320deg);-moz-transform:rotate(320deg);-o-transform:rotate(320deg);-ms-transform:rotate(320deg)}#wheel div.sec:nth-child(34){transform:rotate(340deg);-webkit-transform:rotate(340deg);-moz-transform:rotate(340deg);-o-transform:rotate(340deg);-ms-transform:rotate(340deg)}#wheel div.sec:nth-child(36){transform:rotate(360deg);-webkit-transform:rotate(360deg);-moz-transform:rotate(360deg);-o-transform:rotate(360deg);-ms-transform:rotate(360deg)}#wheel div.sec:nth-child(1){transform:rotate(10deg);-webkit-transform:rotate(10deg);-moz-transform:rotate(10deg);-o-transform:rotate(10deg);-ms-transform:rotate(10deg)}#wheel div.sec:nth-child(3){transform:rotate(30deg);-webkit-transform:rotate(30deg);-moz-transform:rotate(30deg);-o-transform:rotate(30deg);-ms-transform:rotate(30deg)}#wheel div.sec:nth-child(5){transform:rotate(50deg);-webkit-transform:rotate(50deg);-moz-transform:rotate(50deg);-o-transform:rotate(50deg);-ms-transform:rotate(50deg)}#wheel div.sec:nth-child(7){transform:rotate(70deg);-webkit-transform:rotate(70deg);-moz-transform:rotate(70deg);-o-transform:rotate(70deg);-ms-transform:rotate(70deg)}#wheel div.sec:nth-child(9){transform:rotate(90deg);-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-o-transform:rotate(90deg);-ms-transform:rotate(90deg)}#wheel div.sec:nth-child(11){transform:rotate(110deg);-webkit-transform:rotate(110deg);-moz-transform:rotate(110deg);-o-transform:rotate(110deg);-ms-transform:rotate(110deg)}#wheel div.sec:nth-child(13){transform:rotate(130deg);-webkit-transform:rotate(130deg);-moz-transform:rotate(130deg);-o-transform:rotate(130deg);-ms-transform:rotate(130deg)}#wheel div.sec:nth-child(15){transform:rotate(150deg);-webkit-transform:rotate(150deg);-moz-transform:rotate(150deg);-o-transform:rotate(150deg);-ms-transform:rotate(150deg)}#wheel div.sec:nth-child(17){transform:rotate(170deg);-webkit-transform:rotate(170deg);-moz-transform:rotate(170deg);-o-transform:rotate(170deg);-ms-transform:rotate(170deg)}#wheel div.sec:nth-child(19){transform:rotate(190deg);-webkit-transform:rotate(190deg);-moz-transform:rotate(190deg);-o-transform:rotate(190deg);-ms-transform:rotate(190deg)}#wheel div.sec:nth-child(21){transform:rotate(210deg);-webkit-transform:rotate(210deg);-moz-transform:rotate(210deg);-o-transform:rotate(210deg);-ms-transform:rotate(210deg)}#wheel div.sec:nth-child(23){transform:rotate(230deg);-webkit-transform:rotate(230deg);-moz-transform:rotate(230deg);-o-transform:rotate(230deg);-ms-transform:rotate(230deg)}#wheel div.sec:nth-child(25){transform:rotate(250deg);-webkit-transform:rotate(250deg);-moz-transform:rotate(250deg);-o-transform:rotate(250deg);-ms-transform:rotate(250deg)}#wheel div.sec:nth-child(27){transform:rotate(270deg);-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-o-transform:rotate(270deg);-ms-transform:rotate(270deg)}#wheel div.sec:nth-child(29){transform:rotate(290deg);-webkit-transform:rotate(290deg);-moz-transform:rotate(290deg);-o-transform:rotate(290deg);-ms-transform:rotate(290deg)}#wheel div.sec:nth-child(31){transform:rotate(310deg);-webkit-transform:rotate(310deg);-moz-transform:rotate(310deg);-o-transform:rotate(310deg);-ms-transform:rotate(310deg)}#wheel div.sec:nth-child(33){transform:rotate(330deg);-webkit-transform:rotate(330deg);-moz-transform:rotate(330deg);-o-transform:rotate(330deg);-ms-transform:rotate(330deg)}#wheel div.sec:nth-child(35){transform:rotate(350deg);-webkit-transform:rotate(350deg);-moz-transform:rotate(350deg);-o-transform:rotate(350deg);-ms-transform:rotate(350deg)}#wheel div.sec:nth-child(odd){border-color:#e0e0e0 transparent}#wheel div.sec:nth-child(even){border-color:#ccc transparent}#wheel div.sec img{margin-top:-240px;z-index:10000000;display:block;margin-left:-18px;height:35px}#spin{awidth:168px;height:168px;position:absolute;top:50%;left:50%;margin:-84px 0 0 -84px;border-radius:50%;box-shadow:rgba(0,0,0,.1) 0 3px 0;z-index:1000;background:#fff;cursor:pointer;font-family:sans-serif;font-size:24px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none}#spin:after{content:"CLICK";text-align:center;line-height:168px;color:rgba(0,0,0,.4);position:relative;z-index:100000;awidth:168px;height:168px;display:block}#spin.showing:after{content:""}#spin:before{content:"";position:absolute;awidth:0;height:0;border-style:solid;border-awidth:0 25px 50px 25px;border-color:transparent transparent #fff transparent;top:-39px;left:59px}#inner-spin{awidth:144px;height:144px;position:absolute;top:50%;left:50%;margin:-73px 0 0 -73px;border-radius:50%;background:#fff;z-index:999;box-shadow:rgba(255,255,255,1) 0 -2px 0 inset,rgba(255,255,255,1) 0 2px 0 inset,rgba(0,0,0,.4) 0 0 5px;background:#fff;background:-moz-radial-gradient(center,ellipse cover,rgba(255,255,255,1) 0,rgba(234,234,234,1) 100%);background:-webkit-gradient(radial,center center,0,center center,100%,color-stop(0,rgba(255,255,255,1)),color-stop(100%,rgba(234,234,234,1)));background:-webkit-radial-gradient(center,ellipse cover,rgba(255,255,255,1) 0,rgba(234,234,234,1) 100%);background:-o-radial-gradient(center,ellipse cover,rgba(255,255,255,1) 0,rgba(234,234,234,1) 100%);background:-ms-radial-gradient(center,ellipse cover,rgba(255,255,255,1) 0,rgba(234,234,234,1) 100%);background:radial-gradient(ellipse at center,rgba(255,255,255,1) 0,rgba(234,234,234,1) 100%)}#spin:active #inner-spin{box-shadow:rgba(0,0,0,.4) 0 0 5px inset}#spin:active:after{font-size:15px}#shine{awidth:250px;height:250px;position:absolute;top:0;left:0;background:-moz-radial-gradient(center,ellipse cover,rgba(255,255,255,1) 0,rgba(255,255,255,.99) 1%,rgba(255,255,255,.91) 9%,rgba(255,255,255,0) 100%);background:-webkit-gradient(radial,center center,0,center center,100%,color-stop(0,rgba(255,255,255,1)),color-stop(1%,rgba(255,255,255,.99)),color-stop(9%,rgba(255,255,255,.91)),color-stop(100%,rgba(255,255,255,0)));background:-webkit-radial-gradient(center,ellipse cover,rgba(255,255,255,1) 0,rgba(255,255,255,.99) 1%,rgba(255,255,255,.91) 9%,rgba(255,255,255,0) 100%);background:-o-radial-gradient(center,ellipse cover,rgba(255,255,255,1) 0,rgba(255,255,255,.99) 1%,rgba(255,255,255,.91) 9%,rgba(255,255,255,0) 100%);background:-ms-radial-gradient(center,ellipse cover,rgba(255,255,255,1) 0,rgba(255,255,255,.99) 1%,rgba(255,255,255,.91) 9%,rgba(255,255,255,0) 100%);background:radial-gradient(ellipse at center,rgba(255,255,255,1) 0,rgba(255,255,255,.99) 1%,rgba(255,255,255,.91) 9%,rgba(255,255,255,0) 100%);opacity:.1}@-webkit-keyframes hh{0%,100%{transform:rotate(0);-webkit-transform:rotate(0)}50%{transform:rotate(7deg);-webkit-transform:rotate(7deg)}}@keyframes hh{0%,100%{transform:rotate(0);-webkit-transform:rotate(0)}50%{transform:rotate(7deg);-webkit-transform:rotate(7deg)}}.spin{-webkit-animation:hh .1s;animation:hh .1s}

JQuery

  • Setup
var degree = 18000,
    clicks = 10000;

function getRotationDegrees(e) {
    var r = e.css("-webkit-transform") || e.css("-moz-transform") || e.css("-ms-transform") || e.css("-o-transform") || e.css("transform");
    if ("none" !== r) var s = r.split("(")[1].split(")")[0].split(","),
        n = s[0],
        t = s[1],
        a = Math.round(Math.atan2(t, n) * (180 / Math.PI));
    else a = 0;
    return a < 0 ? a + 360 : a
}
$(document).ready(function() {
    var data = {
        'name': 'image-in-rotation.jpg',
    };

    var resultImages = {
        'name': 'image-in-result.jpg',
    }
  • Ở đây giao diện giành cho 36 vị trí, vậy nên bạn có gắng sắp xếp cho đủ vị trí nhé ví dụ hôm section mình tổ chức thì có 18 chị em nên mình có làm 2 vòng for ở dưới ????
    for (let i in data) {
        $('#inner-wheel').append(`
            <div class="sec">
                <img data-name="${i}" src="/assets/images/2010/${data[i]}">
            </div>
        `);
    }

    for (let i in data) {
        $('#inner-wheel').append(`
            <div class="sec">
                <img data-name="${i}" src="/assets/images/2010/${data[i]}">
            </div>
        `);
    }
// tất nhiền rồi, để có thể lọc được người đã được chọn thì mình sẽ lưu những người đã trúng vào localStorage
// Hiên thị tất cả chị em đã được quay trúng vào bên bảng và hiển thị người trúng cuối cùng trên nút click quay.
    let allItems = JSON.parse(localStorage.getItem('allItems')) ? JSON.parse(localStorage.getItem('allItems')) : [];
    if (allItems.length > 0) {
        for (let i in allItems) {
            $('#results').append(`
                  <tr>
                    <td><img style="awidth: 100%; height: 250px;" data-name="${allItems[i].key}" src="/assets/images/2010/main/${allItems[i].image}"></td>
                    <td>${allItems[i].key} <button class="delete" data-image="${allItems[i]}" data-key="${allItems[i].key}"><i class="fa fa-trash"></i></button></td>
                  </tr>
            `);
        }

        $("#inner-spin").css("background", "url(/assets/images/2010/" + allItems[allItems.length - 1].image + ") center center no-repeat"), $("#spin").addClass("showing"), !1
    }
  • Thực hiện quay
    $("#spin").click(function() {
        play();
        var e = degree * ++clicks + (Math.floor(360 * Math.random()) + 1),
            r = 360 - e % 360;
        $("#spin").removeClass("showing"), $("#inner-spin").css("background", ""), $("#inner-wheel").css({
            transform: "rotate(" + e + "deg)"
        }), setTimeout(function() {
            $("#wheel div.sec").each(function(e, s) {
                var n = getRotationDegrees($(s));
                if (0 === n && (n = 360), n - 5 < r && r <= n + 5) {
                    var t = $(s).children("img").attr("src");
                    let items = JSON.parse(localStorage.getItem('allItems')) ? JSON.parse(localStorage.getItem('allItems')) : []; // lấy ra list chị em đã trúng
                    for (let i in data) {
                        if (data[i] == t.split('/')[4] && JSON.stringify(allItems).indexOf(JSON.stringify({ // đoạn if này sẽ check những người đã trúng thì đảm bảo sẽ không được trúng nữa.
                            key: i,
                            image: data[i]
                        })) < 0) {
                            items.push({
                                key: i,
                                image: data[i]
                            });
                            Swal.fire({
                                title: `<strong>${i}! </strong>`,
                                imageUrl: `/assets/images/2010/main/${data[i]}`,
                                imageHeight: 550,
                                imageWidth: 500,
                                animation: false
                            });
                            localStorage.setItem('allItems', JSON.stringify(items))
                        }
                    }

                    volume();
                    $("#inner-spin").css("background", "url(" + t + ") center center no-repeat"), $("#spin").addClass("showing"), !1
                }
            })

            let allItemsAfter = JSON.parse(localStorage.getItem('allItems')) ? JSON.parse(localStorage.getItem('allItems')) : [];
            if (allItemsAfter.length > 0) {
                $('#results').html(');
                for (let i in allItemsAfter) {
                    $('#results').append(`
                          <tr>
                            <td><img style="awidth: 100%; height: 250px;" data-name="${allItemsAfter[i].key}" src="/assets/images/2010/main/${allItemsAfter[i].image}"></td>
                            <td>${allItemsAfter[i].key} <button class="delete" data-key="${allItemsAfter[i].key}" data-image="${allItemsAfter[i]}"><i class="fa fa-trash"></i></button></td>
                          </tr>
                    `);
                }

                $("#inner-spin").css("background", "url(/assets/images/2010/" + allItemsAfter[allItemsAfter.length - 1].image + ") center center no-repeat"), $("#spin").addClass("showing"), !1
            }
        }, 6000)
    }), $("#wrapper").css("margin-top", Math.max((parseFloat($(document).height()) - 500) / 2), 10)

    $('#results').on('click', '.delete', function () {
        if (confirm('Are you sure?')) {
            let key = $(this).data('key');
            let image = $(this).data('image');
            let allItems = JSON.parse(localStorage.getItem('allItems')) ? JSON.parse(localStorage.getItem('allItems')) : [];

            $.each(allItems, function (i, val) {
                if (val && val.key == key) {
                    allItems.splice(i, 1);
                }
            })

            $('#results').html(');
            for (let i in allItems) {
                $('#results').append(`
                      <tr>
                        <td><img style="awidth: 100%; height: 250px;" data-name="${allItems[i].key}" src="/assets/images/2010/main/${allItems[i].image}"></td>
                        <td>${allItems[i].key} <button class="delete" data-key="${allItems[i].key}" data-image="${allItems[i]}"><i class="fa fa-trash"></i></button></td>
                      </tr>
                `);
            }

            localStorage.setItem('allItems', JSON.stringify(allItems))

            location.reload();
        }
    })

    function play(){
       var audio = document.getElementById("audio");
       audio.currentTime=0;
       audio.volume = 1;
       audio.play();
    }

    function volume() {
       var audio = document.getElementById("audio");
       audio.volume = 0.2;
    }
});

0