JSFiddle - React, Tailwind, and code Playground

by mackry

HTML

<script src="https://raw.github.com/weepy/jquery.path/master/jquery.path.js"></script>
<div id="zoom-pts">
    <h3>Nice!</h3>
    <div class="pts">
        <span>+50</span> pts
    </div>
</div>

<div id="profile-pts"><span class="counter-pts">256</span> pts</div>

<button>Track</button>

<div id="coords"></div>

CSS

body {
    font-family: "Helvetica Neue", Arial, sans-serif;
    background-color: #eee;
}

#zoom-pts {
    background-image: -webkit-radial-gradient(center, circle contain, white 60%, rgba(255,255,255,0) 100%);  
    font-size: 22px;
    margin: -100px 0 0 -125px;
    padding: 50px;
    position: absolute;
    top: 50%;
    left: 50%;
    text-align: center;
    height: 100px;
    width: 150px;
    
    -webkit-transform: translateZ(0) scale(0);
    -webkit-transition: all .3s cubic-bezier(0.26,0.67,0.27,1);
}

h3 {
    color: #555;
    font-weight: bold;
}

body > .pts {
    width: 150px;
    -webkit-transition: -webkit-transform .3s linear .2s, opacity .8s linear;
}

.disappear {
    -webkit-transform: scale(0);
    opacity: .2;
}

.pts {
    position: absolute;
    color: #8bc347;
}

.pts span {
    font-size: 60px;
    font-weight: bold;
}

#zoom-pts.launch .pts {
    -webkit-animation: bounceInReverse .3s 1 cubic-bezier(0.26, 0.67, 0.27, 1);
    -webkit-animation-delay: .3s;
    -webkit-animation-fill-mode: both;
}


#zoom-pts.launch {
   -webkit-transform: translateZ(0) scale(1);
}

#profile-pts {    
    color: #8bc347;
    font-size: 22px;
    font-weight: bold;
    position: absolute;
    top: 50px;
    right: 50px;
}

button {
    position: absolute;
    top: 140px;
    left: 100px;
}

@-webkit-keyframes bounceInReverse {
    0% {
        opacity: 0;
        -webkit-transform: scale(2);
    }
    
    50% {
        opacity: 1;
        -webkit-transform: scale(0.9);
    }
    
    70% {
        -webkit-transform: scale(1.05);
    }
    
    100% {
        -webkit-transform: scale(1);
    }
}

@-webkit-keyframes bounceIn {
    0% {
        opacity: 0;
        -webkit-transform: translateZ(0) scale(0.3);
    }
    
    50% {
        opacity: 1;
        -webkit-transform: translateZ(0) scale(1.05);
    }
    
    70% {
        -webkit-transform: translateZ(0) scale(0.9);
    }
    
    100% {
        -webkit-transform: translateZ(0) scale(1);
    }
}

JavaScript

$('button').click(function() {
    $('#zoom-pts').toggleClass('launch');

    setTimeout(function() {

        var clone = $('#zoom-pts .pts').clone(),
            position = $('#zoom-pts .pts').offset(),

            bezier_params = {
                start: {
                    x: position.left,
                    y: position.top,
                    angle: -90
                },
                end: {
                    x: $('#profile-pts').offset().left,
                    y: $('#profile-pts').offset().top,
                    angle: 100,
                    length: .3
                }
            };
        
        clone.css({ left: position.left + 'px', top: position.top + 'px' });
        
        clone.appendTo('body');
        
        clone.animate({
            path: new $.path.bezier(bezier_params)
        }, 600, function() {
            $('#profile-pts .counter-pts').stop().countTo({ from: 256, to: 306 });
        });

        clone.addClass('disappear');
        
       
    }, 1000);
});


$(window).mousemove(function(e){
      var pageCoords = "( " + e.pageX + ", " + e.pageY + " )";
      $("#coords").text(pageCoords);
});


(function($) {
    $.fn.countTo = function(options) {
        // merge the default plugin settings with the custom options
        options = $.extend({}, $.fn.countTo.defaults, options || {});

        // how many times to update the value, and how much to increment the value on each update
        var loops = Math.ceil(options.speed / options.refreshInterval),
            increment = (options.to - options.from) / loops;

        return $(this).each(function() {
            var self = this,
                loopCount = 0,
                value = options.from, //parseInt($(this).text());
                interval = setInterval(updateTimer, options.refreshInterval);
            
            function updateTimer() {
                value += increment;
                loopCount++;
               ...