Edit in JSFiddle


              
<head>
    <title>Flying Tweets — Shiny Demos</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width">
    <link rel="stylesheet" href="styles/screen.css">
    <link rel="stylesheet" href="/styles/panel.css">
</head>
<body>
    <div id="container">
        <header>
            <form id="frm_search">
                <input type="text" id="txt_search">
                <button type="submit" id="btn_search">Get tweets</button>
            </form>
            <img src="images/resize.svg" alt="Resize icon" id="btn_resize" role="button" title="Resize">
            <!-- Icon source: http://iconmonstr.com/resize-5-icon/ -->
        </header>
        <div id="content" class="animate">
            <div id="tweet"></div>
        </div>
    </div>
    <script src="/scripts/modernizr.js"></script>
    <script src="/scripts/panel.js"></script>
    <script src="scripts/options.js"></script>
    <script src="scripts/script.js"></script>
<script>
window.addEventListener('DOMContentLoaded', function() {
    'use strict';
    
    /*
     * Configuration
     */
    var query = '#css3'; // The initial search term
    var updateTime = 2; // The time between updates in minutes
    
    /*
     * Main script
     */
    // Set some global variables
    var container = document.getElementById('container');
    var content = document.getElementById('content');
    var frm_search = document.getElementById('frm_search');
    var txt_search = document.getElementById('txt_search');
    var btn_search = document.getElementById('btn_search');
    var btn_resize = document.getElementById('btn_resize');
    var tweet = document.getElementById('tweet');
    var count = 0;
    var tweets = [];
    var img = document.createElement('img');
    
    // Add span element and classes to each letter
    function doCharify(tweetData) {
        var text = tweetData.text;
        var user = tweetData.user;
        var result = '';
        for (var i = 0, lenText = text.length; i < lenText; i++) {
            result += '<span class="char' + (i % 10) + '">' + text[i] + '</span>';
        }
        result += '<div id="user"><a href="http://twitter.com/' + user + '">';
        user = '@' + user;
        for (var j = 0, lenUser = user.length; j < lenUser; j++) {
            result += '<span class="char' + (j % 10) + '">' + user[j] + '</span>';
        }
        result += '</a></div>';
        return result;
    }
    
    // Submit search for tweets
    frm_search.onsubmit = function(event) {
        event.preventDefault();
        count = 0;
        query = txt_search.value;
        getTweets(query, 'setTweets');
        txt_search.blur();
        btn_search.blur();
        return false;
    };
    
    // Loop through and show individual tweets
    function doAnimationIteration() {        
        if (count >= (tweets.length - 1)) {
            count = 0;
        } else {
            count++;
        }
        showTweet(count);
    }
    
    // Listen for the end of each animation cycle
    img.addEventListener('webkitAnimationIteration', doAnimationIteration, false);
    img.addEventListener('MSAnimationIteration', doAnimationIteration, false);
    img.addEventListener('oanimationiteration', doAnimationIteration, false);
    img.addEventListener('animationiteration', doAnimationIteration, false);
    
    // Get tweets and append JSON result to body
    function getTweets(query, callback) {
        var url = 'http://search.twitter.com/search.json?q=' + encodeURIComponent(query) + '&callback=' + callback;
        // Remove any script tag we've used before
        var jsonScript = document.getElementById('jsonScript');
        if (jsonScript) {
            document.body.removeChild(jsonScript);
        }
        // Create new script tag with new query results
        jsonScript = document.createElement('script');
        jsonScript.id = 'jsonScript';
        jsonScript.src = url;
        document.body.appendChild(jsonScript);
    }
    
    // Update tweets array with latest data
    this.updateTweets = function(data) {
        tweets = [];
        var results = data.results;
        var result, tweetData;
        for (var i = 0, len = results.length; i < len; i++) {
            result = results[i];
            tweetData = {
                text: result.text,
                user: result.from_user,
                img: result.profile_image_url
            };
            tweets.push(tweetData);
        }
        count = 0;
    };
    
    // High-level function to update & show tweets
    this.setTweets = function(data) {
        updateTweets(data);
        showTweet(0);
    };
    
    // Do this at the end of every animation iteration
    function showTweet(num) {
        var tweetData = tweets[num];
        img.src = tweetData.img;
        img.onload = function() {
            tweet.innerHTML = doCharify(tweetData);
            tweet.appendChild(img);
        };
    }
    
    // Start the animation
    txt_search.value = query;
    getTweets(query, 'setTweets');
    
    // Update the tweets
    var timer = window.setInterval(function() {
        getTweets(query, 'updateTweets');
    }, 60000 * updateTime);
    
    // Page Visibility API: http://www.w3.org/TR/page-visibility/
    // Stop the animation when the tab is not visible
    document.addEventListener("visibilitychange", function(event) {
        if (document.hidden) {
            content.classList.remove('animate');
        } else {
            content.classList.add('animate');
        }
    }, false);
    
    // Fullscreen API: http://www.w3.org/TR/fullscreen/
    // Check for fullscreen API support
    if (document.fullscreenEnabled || document.mozFullScreenEnabled || document.webkitFullscreenEnabled) {
        // Resize the page
        btn_resize.onclick = function(event) {
            if (document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement) {
                if (document.exitFullscreen) {
                    document.exitFullscreen();
                } else if (document.mozCancelFullScreen) {
                    document.mozCancelFullScreen();
                } else if (document.webkitExitFullscreen) {
                    document.webkitExitFullscreen();
                }
            } else {
                if (container.requestFullscreen) {
                    container.requestFullscreen();
                } else if (container.mozRequestFullScreen) {
                    container.mozRequestFullScreen();
                } else if (container.webkitRequestFullscreen) {
                    container.webkitRequestFullscreen();
                }
            }
        };
    } else {
        btn_resize.style.display = 'none';
    }
}, false);
</script>





 
* {
    -webkit-box-sizing:border-box;
    -moz-box-sizing:border-box;
    box-sizing:border-box;
    margin:0;
    padding:0;
}

html {
    height: 100%;
}
body {
    font-family:georgia, 'Times New Roman', times, serif;
    height:100%;
}
a {
    color:#33c;
    text-decoration:none;
}

#container {
    background:#fcc;
    display:table;
    height:100%;
    width:100%;
    -webkit-animation: container 60s linear infinite;
    -moz-animation: container 60s linear infinite;
    -o-animation: container 60s linear infinite;
    animation: container 60s linear infinite;
}
@-webkit-keyframes container {
    25% {
        background:#ffc;
    }
    50% {
        background:#cfc;
    }
    75% {
        background:#ccf;
    }
    100% {
        background:#fcc;
    }
}
@-moz-keyframes container {
    25% {
        background:#ffc;
    }
    50% {
        background:#cfc;
    }
    75% {
        background:#ccf;
    }
    100% {
        background:#fcc;
    }
}
@-o-keyframes container {
    25% {
        background:#ffc;
    }
    50% {
        background:#cfc;
    }
    75% {
        background:#ccf;
    }
    100% {
        background:#fcc;
    }
}
@keyframes container {
    25% {
        background:#ffc;
    }
    50% {
        background:#cfc;
    }
    75% {
        background:#ccf;
    }
    100% {
        background:#fcc;
    }
}

header {
    text-align:right;
}
#frm_search {
    display:inline;
}
#btn_search {
    margin-right:0.5em;
}
#txt_search, #btn_search {
    margin-top:0.5em;
    opacity:0.5;
    padding:0.5em;
    -webkit-transition-duration:0.3s;
    -moz-transition-duration:0.3s;
    -o-transition-duration:0.3s;
    transition-duration:0.3s;
    -webkit-transition-property:opacity;
    -moz-transition-property:opacity;
    -o-transition-property:opacity;
    transition-property:opacity;
}
#txt_search:focus, #txt_search:hover, #btn_search:focus, #btn_search:hover, #btn_resize:focus, #btn_resize:hover {
    opacity:1;
}
#btn_resize {
    cursor:pointer;
    float:right;
    height:2em;
    margin:0.5em 0.5em 0 0;
    opacity:0.5;
    width:2em;
    -webkit-transition-duration:0.3s;
    -moz-transition-duration:0.3s;
    -o-transition-duration:0.3s;
    transition-duration:0.3s;
}

#content {
    display:table-row;
    height:100%;
    text-align:center;
}
#tweet {
    color:#333;
    display:table-cell;
    font-size:3em;
    line-height:1.2;
    overflow:hidden;
    padding:0 8%;
    vertical-align:middle;
    white-space:pre-wrap; /* Needed to keep space in empty spans */
}
#tweet span, #tweet img {
    display:inline-block;
    position:relative;
}
.animate #tweet span, .animate #tweet img {
    -webkit-animation:char 10s infinite;
    -moz-animation:char 10s infinite;
    -o-animation:char 10s infinite;
    animation:char 10s infinite;
}
.animate #tweet .char9 {
    -webkit-animation-timing-function:cubic-bezier(0.25, 0, 0.25, 1);
    -moz-animation-timing-function:cubic-bezier(0.25, 0, 0.25, 1);
    -o-animation-timing-function:cubic-bezier(0.25, 0, 0.25, 1);
    animation-timing-function:cubic-bezier(0.25, 0, 0.25, 1);
}
.animate #tweet .char1 {
    -webkit-animation-timing-function:cubic-bezier(0.30, 0, 0.30, 1);
    -moz-animation-timing-function:cubic-bezier(0.30, 0, 0.30, 1);
    -o-animation-timing-function:cubic-bezier(0.30, 0, 0.30, 1);
    animation-timing-function:cubic-bezier(0.30, 0, 0.30, 1);
}
.animate #tweet .char7 {
    -webkit-animation-timing-function:cubic-bezier(0.35, 0, 0.35, 1);
    -moz-animation-timing-function:cubic-bezier(0.35, 0, 0.35, 1);
    -o-animation-timing-function:cubic-bezier(0.35, 0, 0.35, 1);
    animation-timing-function:cubic-bezier(0.35, 0, 0.35, 1);
}
.animate #tweet .char3 {
    -webkit-animation-timing-function:cubic-bezier(0.40, 0, 0.40, 1);
    -moz-animation-timing-function:cubic-bezier(0.40, 0, 0.40, 1);
    -o-animation-timing-function:cubic-bezier(0.40, 0, 0.40, 1);
    animation-timing-function:cubic-bezier(0.40, 0, 0.40, 1);
}
.animate #tweet .char5 {
    -webkit-animation-timing-function:cubic-bezier(0.45, 0, 0.45, 1);
    -moz-animation-timing-function:cubic-bezier(0.45, 0, 0.45, 1);
    -o-animation-timing-function:cubic-bezier(0.45, 0, 0.45, 1);
    animation-timing-function:cubic-bezier(0.45, 0, 0.45, 1);
}
.animate #tweet .char4 {
    -webkit-animation-timing-function:cubic-bezier(0.50, 0, 0.50, 1);
    -moz-animation-timing-function:cubic-bezier(0.50, 0, 0.50, 1);
    -o-animation-timing-function:cubic-bezier(0.50, 0, 0.50, 1);
    animation-timing-function:cubic-bezier(0.50, 0, 0.50, 1);
}
.animate #tweet .char6 {
    -webkit-animation-timing-function:cubic-bezier(0.55, 0, 0.55, 1);
    -moz-animation-timing-function:cubic-bezier(0.55, 0, 0.55, 1);
    -o-animation-timing-function:cubic-bezier(0.55, 0, 0.55, 1);
    animation-timing-function:cubic-bezier(0.55, 0, 0.55, 1);
}
.animate #tweet .char2 {
    -webkit-animation-timing-function:cubic-bezier(0.60, 0, 0.60, 1);
    -moz-animation-timing-function:cubic-bezier(0.60, 0, 0.60, 1);
    -o-animation-timing-function:cubic-bezier(0.60, 0, 0.60, 1);
    animation-timing-function:cubic-bezier(0.60, 0, 0.60, 1);
}
.animate #tweet .char8 {
    -webkit-animation-timing-function:cubic-bezier(0.65, 0, 0.65, 1);
    -moz-animation-timing-function:cubic-bezier(0.65, 0, 0.65, 1);
    -o-animation-timing-function:cubic-bezier(0.65, 0, 0.65, 1);
    animation-timing-function:cubic-bezier(0.65, 0, 0.65, 1);
}
.animate #tweet .char0 {
    -webkit-animation-timing-function:cubic-bezier(0.70, 0, 0.70, 1);
    -moz-animation-timing-function:cubic-bezier(0.70, 0, 0.70, 1);
    -o-animation-timing-function:cubic-bezier(0.70, 0, 0.70, 1);
    animation-timing-function:cubic-bezier(0.70, 0, 0.70, 1);
}
#user {
    font-family:'Helvetica Neue', 'Free Sans', 'Deja Vu Sans', Arial, Helvetica, sans-serif;
    font-size:0.7em;
    margin:1em 0 0.5em 0;
}

@-webkit-keyframes char {
    0% {
        left:-110%;
        -webkit-transform:rotate(-360deg);
    }
    25% {
        left:0;
        -webkit-transform:rotate(0);
    }
    80% {
        left:0;
        -webkit-transform:rotate(0);
    }
    100% {
        left:110%;
        -webkit-transform:rotate(360deg);
    }
}
@-moz-keyframes char {
    0% {
        left:-110%;
        -moz-transform:rotate(-360deg);
    }
    25% {
        left:0;
        -moz-transform:rotate(0);
    }
    80% {
        left:0;
        -moz-transform:rotate(0);
    }
    100% {
        left:110%;
        -moz-transform:rotate(360deg);
    }
}
@-o-keyframes char {
    0% {
        left:-110%;
        -o-transform:rotate(-360deg);
    }
    25% {
        left:0;
        -o-transform:rotate(0);
    }
    80% {
        left:0;
        -o-transform:rotate(0);
    }
    100% {
        left:110%;
        -o-transform:rotate(360deg);
    }
}
@keyframes char {
    0% {
        left:-110%;
        transform:rotate(-360deg);
    }
    25% {
        left:0;
        transform:rotate(0);
    }
    80% {
        left:0;
        transform:rotate(0);
    }
    100% {
        left:110%;
        transform:rotate(360deg);
    }
}

@media screen and (max-width:60em) {
    #tweet {
        font-size:2em;
    }
}
@media screen and (max-width:30em) {
    #tweet {
        font-size:1.5em;
    }
}