x
<script type="text/template" id="visual-template">
<div class="size{{visualSize}}" id="tweet{{tweetId}}">
<div class="visual-container">
<div class="visual">
<div class="visual-inlay">
<div class="visual-img" style="background-image:url({{avatarImage}})"></div>
<div class="visual-overlay-container">
<div class="visual-text">{{retweetCount}}</div>
<div class="visual-overlay" style="background-image:url({{avatarImage}})"></div>
</div>
</div>
<div class="visual-text-2">{{tweetTime}}</div>
</div>
<div class="handle">
{{twitterHandle}}
</div>
</div>
</div>
</script>
<div id="twtcontainer"></div>
<script class="cssdeck" src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.8.0/jquery.min.js"></script>
<script class="cssdeck" src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.2.2/underscore-min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.8.3/moment.js"></script>
x
@import url("https://fonts.googleapis.com/css?family=Lato:100,400,700,700italic,900,400italic,300,300italic");
@import url("https://fonts.googleapis.com/css?family=Source+Code+Pro:300,300italic,400");
body {
background: #f6f6f6;
font-family: Lato, sans-serif;
overflow: hidden;
}
.first {opacity: 1!important}
* {
box-sizing: border-box;
}
$margin: 20px;
.flip-side {
.visual-text-2 {
display: block;
transform: rotateY(180deg);
opacity: 1!important;
}
transform: rotateY(180deg);
.handle, .visual-inlay {
opacity: 0;
}
}
.visual-inlay {
position: absolute;
width: 100%;
height: 100%;
}
.visual-overlay-container {
border-radius: 50%;
width: 70%;
height: 70%;
margin-left: 15%;
margin-top: 15%;
overflow: hidden;
position: absolute;
}
.visual-overlay-container:before {
content: '';
width: 100%;
height: 100%;
background: rgba(255, 255, 255, 0.2);
display:block;
position:absolute;
z-index: 10;
}
.visual-img {
border-radius: 50%;
width: 100%;
height: 100%;
position: absolute;
background: url(https://secure.gravatar.com/avatar/fdce3ad4c57f9ca651c168a8cf1f9416?s=180&d=identicon) center center no-repeat;
background-size: 100%;
box-shadow: 1px 1px 6px 0px rgba(255,255,255,1), inset 2px 2px 6px 0px rgba(0,0,0,0.3);
}
.visual {
width: 100%;
height: 100%;
position: relative;
border-radius: 50%;
//clip-path: polygon(0% 0%, 0% 100%, 45% 100%, 50% 91.3333333333%, 55% 100%, 100% 100%, 100% 0%);
}
.visual-overlay {
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 1) url(https://secure.gravatar.com/avatar/fdce3ad4c57f9ca651c168a8cf1f9416?s=180&d=identicon) center center no-repeat;
background-size: 140%;
//filter: blur(2px); filter: blur(2px); filter: blur(2px); filter: blur(2px); filter: blur(2px);
border-radius: 50%;
position:absolute;
}
.handle {
height: 100%;
width: 100%;
position: relative;
top: -100%;
float: left;
}
.visual-container {
border-radius: 50%;
background: white;
box-shadow: 0px 0px 6px 0px rgba(0,0,0,0.2);
border: $margin white solid;
transition: 0.5s;
transition: 0.5s;
.visual-text-2 {
opacity: 0;
}
}
.handle, .visual-inlay, .visual-text-2 {
transition: 0.25s;
transition: 0.25s;
}
.visual-text {font-weight: 400}
.visual-text, .visual-text-2 {
width: 100%;
height: 100%;
color: white;
text-align: center;
vertical-align: middle;
position: absolute;
line-height: 1em;
z-index: 11;
font-weight: 400;
text-shadow: 0px 0px 8px black;
}
.visual-text-2 {
color: #888;
text-shadow: none;
line-height: 1.2em;
font-weight: 300;
}
.handle span {
height: 100%;
position: absolute;
top: 0;
left: 0;
width: 100%;
transform-origin: center center;
text-transform: uppercase;
text-align: center;
font-size: $margin / 2;
line-height: 1.9em;
font-weight: 100;
font-family: 'Source Code Pro', typewriter;
}
@for $s from 0 through 4 {
$size: 100px + 20 * $s;
.size#{$s} {
opacity: 0.5;
transition: 0.5s;
transition: 0.5s;
position: absolute;
margin-left: -80px;
margin-top: -80px;
.visual-container {
width: $size + $margin * 2;
height: $size + $margin * 2;
}
.visual-text {
font-size: $size / 3;
margin-top: $size / 6;
}
.visual-text-2 {
font-size: $size / 6;
margin-top: $size / 4;
}
.handle span {
font-size: $margin / 2;
}
}
}
$rotation: 8;
@for $i from 1 through 16 {
.char#{$i} {
font-weight: 400;
transform: rotate(180 - $i * $rotation + deg);
span {
transform-origin: top center;
transform: rotate(180deg);
}
}
.length#{$i} {
transform: rotate($i * $rotation / 2 + deg);
}
}
var hash = {};
var hash = {};
var r = [];
function fromUTCDate(date) {
if (!(date instanceof Date)) {
date = new Date(date);
}
return new Date(Date.UTC(
date.getFullYear(),
date.getMonth(),
date.getDate(),
date.getHours(),
date.getMinutes(),
date.getSeconds(),
date.getMilliseconds()
));
};
function pt(x, y) {
return {
x: x,
y: y,
toString: function() { return [this.x, this.y].join(','); }
};
}
function adj(a) {
return [
pt(a.x + 1, a.y),
pt(a.x, a.y + 1),
pt(a.x - 1, a.y),
pt(a.x, a.y - 1)
]
}
function adjcreate(a, m) {
m = Math.abs(a.x) + Math.abs(a.y);
if (hash[a] || m > 10) return;
(r[m] = r[m] || []).push(a);
hash[a] = true;
adj(a).map(adjcreate);
}
function flat(a) {
var b = [];
for (var i = 0; i < a.length; i++) {
for (var j = 0; j < a[i].length; j++) {
b.push(a[i][j]);
}
}
return b;
}
adjcreate(pt(0, 0));
r = flat(r);
function rand(a, b) {
return a + Math.floor(Math.random() * (b - a));
}
/*********************************************************************
* #### Twitter Post Fetcher v12.0 ####
* Coded by Jason Mayes 2013. A present to all the developers out there.
* www.jasonmayes.com
* Please keep this disclaimer with my code if you use it. Thanks. :-)
* Got feedback or questions, ask here:
* http://www.jasonmayes.com/projects/twitterApi/
* Github: https://github.com/jasonmayes/Twitter-Post-Fetcher
* Updates will be posted to this site.
*********************************************************************/
var twitterFetcher = function() {
var domNode = '';
var maxTweets = 20;
var parseLinks = true;
var queue = [];
var inProgress = false;
var printTime = true;
var printUser = true;
var formatterFunction = null;
var supportsClassName = true;
var showRts = true;
var customCallbackFunction = null;
var showInteractionLinks = true;
var showImages = false;
var lang = 'en';
function strip(data) {
return data.replace(/<b[^>]*>(.*?)<\/b>/gi, function(a,s){return s;})
.replace(/class=".*?"|data-query-source=".*?"|dir=".*?"|rel=".*?"/gi,
'');
}
function getElementsByClassName (node, classname) {
var a = [];
var regex = new RegExp('(^| )' + classname + '( |$)');
var elems = node.getElementsByTagName('*');
for (var i = 0, j = elems.length; i < j; i++) {
if(regex.test(elems[i].className)){
a.push(elems[i]);
}
}
return a;
}
function extractImageUrl(image_data) {
if (image_data !== undefined) {
var data_src = image_data.innerHTML.match(/data-srcset="([A-z0-9%_\.-]+)/i)[0];
return decodeURIComponent(data_src).split('"')[1];
}
}
var div;
var first = 0;
return {
fetch: function(config) {
if (config.maxTweets === undefined) {
config.maxTweets = 20;
}
if (config.enableLinks === undefined) {
config.enableLinks = true;
}
if (config.showUser === undefined) {
config.showUser = true;
}
if (config.showTime === undefined) {
config.showTime = true;
}
if (config.dateFunction === undefined) {
config.dateFunction = 'default';
}
if (config.showRetweet === undefined) {
config.showRetweet = true;
}
if (config.customCallback === undefined) {
config.customCallback = null;
}
if (config.showInteraction === undefined) {
config.showInteraction = true;
}
if (config.showImages === undefined) {
config.showImages = false;
}
// if (inProgress) {
queue.push(config);
// } else {
inProgress = true;
domNode = config.domId;
parseLinks = config.enableLinks;
printUser = config.showUser;
printTime = config.showTime;
showRts = config.showRetweet;
formatterFunction = config.dateFunction;
customCallbackFunction = config.customCallback;
showInteractionLinks = config.showInteraction;
showImages = config.showImages;
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = '//cdn.syndication.twimg.com/widgets/timelines/' +(config.sinceId ?'paged/':'')+
config.id + '?&lang=' + (config.lang || lang) + '&callback=twitterFetcher.callback&' +
(config.sinceId ? 'max_id=' + config.sinceId + '&' : '')
'suppress_response_codes=true&rnd=' + Math.random();
document.getElementsByTagName('head')[0].appendChild(script);
this.config = config;
// }
},
callback: function(data) {
var self = this;
function handleTweets(tweets){
console.log(tweets);
if (customCallbackFunction) {
customCallbackFunction(tweets);
if (first < 2) {
self.fetch(config);
first++;
}
}
}
var config = this.config;
delete this.config;
div = div || document.createElement('div');
if (data.body.indexOf('<li') === 0) {
console.log($(data.body));
if ($(data.body).length > 1) {
div.querySelector('.stream .h-feed').innerHTML += data.body;
} else {
return;
}
} else {
div.innerHTML = data.body;
}
if (typeof(div.getElementsByClassName) === 'undefined') {
supportsClassName = false;
}
var tweets = [];
var authors = [];
var times = [];
var images = [];
var rts = [];
var tids = [];
var retweetCount = [];
var favCount = [];
var x = 0;
console.log(div);
var tmp = div.getElementsByClassName('tweet');
console.log([].slice.call(tmp), tmp.length);
while (x < tmp.length) {
if (tmp[x].getElementsByClassName('retweet-credit').length > 0) {
rts.push(true);
} else {
rts.push(false);
}
if (!rts[x] || rts[x] && showRts) {
tweets.push(tmp[x].getElementsByClassName('e-entry-title')[0]);
tids.push(tmp[x].getAttribute('data-tweet-id'));
var author = tmp[x].getElementsByClassName('p-author')[0];
authors.push({
avatar: author.querySelector('[data-scribe="element:avatar"').getAttribute('data-src-2x'),
name: author.querySelector('[data-scribe="element:name"').textContent,
screenName: author.querySelector('[data-scribe="element:screen_name"').textContent
});
times.push(tmp[x].getElementsByClassName('dt-updated')[0]);
if (tmp[x].getElementsByClassName('inline-media')[0] !== undefined) {
images.push(tmp[x].getElementsByClassName('inline-media')[0]);
} else {
images.push(undefined);
}
if (tmp[x].getElementsByClassName('stats-retweets')[0] !== undefined) {
retweetCount.push(tmp[x].getElementsByClassName('stats-retweets')[0].getElementsByTagName('strong')[0].textContent);
} else {
retweetCount.push(0);
}
if (tmp[x].getElementsByClassName('stats-favorites')[0] !== undefined) {
favCount.push(tmp[x].getElementsByClassName('stats-favorites')[0].getElementsByTagName('strong')[0].textContent);
} else {
favCount.push(0);
}
}
x++;
}
var arrayTweets = [];
var x = tweets.length;
var n = 0;
while(n < x) {
if (typeof(formatterFunction) !== 'string') {
var newDate = new Date(times[n].getAttribute('datetime')
.replace(/-/g,'/').replace('T', ' ').split('+')[0]);
var dateString = formatterFunction(newDate);
times[n].setAttribute('aria-label', dateString);
if (tweets[n].innerText) {
// IE hack.
if (supportsClassName) {
times[n].innerText = dateString;
} else {
var h = document.createElement('p');
var t = document.createTextNode(dateString);
h.appendChild(t);
h.setAttribute('aria-label', dateString);
times[n] = h;
}
} else {
times[n].textContent = dateString;
}
}
var op = '';
var retval = {};
if (printUser) {
retval.author = authors[n];
}
if (parseLinks) {
retval.tweet = strip(tweets[n].innerHTML);
if (printTime) {
retval.time = times[n].getAttribute('aria-label');
}
} else {
if (tweets[n].innerText) {
retval.tweet = tweets[n].textContent;
if (printTime) {
retval.time = times[n].textContent;
}
}
}
retval.id = tids[n];
if (showImages && images[n] !== undefined) {
retval.image = extractImageUrl(images[n]);
}
retval.isRetweet = rts[n];
retval.stats = {retweets: parseInt(retweetCount[n], 10), favorites: parseInt(favCount[n], 10)};
arrayTweets.push(retval);
n++;
}
handleTweets(arrayTweets);
inProgress = false;
if (queue.length > 0) {
twitterFetcher.fetch(queue[0]);
queue.splice(0,1);
}
}
}
}();
_.templateSettings = {
interpolate: /\{\{(.+?)\}\}/g
};
var visualTemplate;
$(function () {
visualTemplate = $('#visual-template').text();
visualTemplate = _.template(visualTemplate);
});
function createVisual(tweet) {
var element = document.createElement('div');
element.innerHTML = visualTemplate({
twitterHandle: tweet.author.screenName,
retweetCount: tweet.stats.retweets,
visualSize: 1,
tweetId: tweet.id,
avatarImage: tweet.author.avatar,
tweetTime: tweet.time
});
var handle = $('.handle', element).text().trim();
var text = '';
for (var i = 1; i < handle.length + 1; i++)
text += '<span class="char' + i + '"><span>' + handle[i - 1] + '</span></span>';
$('.handle', element).html(text).addClass('length' + handle.length);
return element;
}
var config = {
"id": '512112985221775360',
"domId": '',
"enableLinks": true,
"showUser": true,
"showRetweet": true,
"showTime": true,
"dateFunction": function (date) {
return moment(fromUTCDate(date)).format('MMM D<br>h:mma');
},
"showInteraction": true,
"customCallback": handleTweets
};
function handleTweets(tweets) {
config.sinceId = tweets[tweets.length-1].id;
tweets = tweets.filter(function(t) {
return !t.isRetweet;
});
tweets.sort(function(t1, t2){
if (t1.stats.retweets < t2.stats.retweets) {
return 1;
} else return -1;
});
console.log(tweets);
for (var i = 0; i < tweets.length; i++) {
var visual = $('#tweet' + tweets[i].id);
var directions = [
{left: '-50%', top: '-50%'},
{left: '50%', top: '-50%'},
{left: '150%', top: '-50%'},
{left: '-50%', top: '50%'},
{left: '150%', top: '50%'},
{left: '-50%', top: '150%'},
{left: '50%', top: '150%'},
{left: '150%', top: '150%'}
];
var random = rand(0, directions.length - 1);
if (visual.length) {
updateVisual(tweets[i], !i);
} else {
visual = createVisual(tweets[i]);
visual = $('#tweet' + tweets[i].id, visual);
visual.css({
position: 'absolute',
marginLeft: '-80px',
marginTop: '-80px'
})//.css(directions[random]);
if (!i) {
visual.addClass('first');
}
visual.css({'transform': 'translate(' + [r[i].x * 180 + 'px', r[i].y * 180 + 'px'] + ')'}, 400);
$('#twtcontainer').append(visual);
}
visual.css({'transform': 'translate(' + [r[i].x * 180 + 'px', r[i].y * 180 + 'px'] + ')'}, 400);
visual.css({
top: '50%',
left: '50%'
});
}
}
function updateVisual(tweet, first) {
console.log('updating tweet', tweet.stats.retweets);
var div = $('#tweet' + tweet.id);
if (first) {
$('.first').removeClass('first');
div.addClass('first');
}
div.find('.visual-img, .visual-overlay').css('background-image', "url('" + tweet.author.avatar + "')")
div.find('.visual-text').text(tweet.stats.retweets);
}
var truth = true;
setInterval(function () {
delete config.sinceId;
twitterFetcher.fetch(config);
if (truth) {
$('.visual-container').removeClass('flip-side');
} else {
$('.visual-container').addClass('flip-side');
}
truth = !truth;
}, 4000);