<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;
}
}