Interactive Google Map using the Twitter API

Hey! In today’s tutorial we will create an interactive Google map using the geocoding service. Using the Twitter API we will retrieve the user’s location, and then display the profile […]

Hey! In today’s tutorial we will create an interactive Google map using the geocoding service. Using the Twitter API we will retrieve the user’s location, and then display the profile picture on the map. We will also add the click action, after which we will retrieve the user’s 5 latest tweets.

So, let’s start!

Tiny break: 📬 Want to stay up to date with frontend and trends in web design? Subscribe and get our Collective newsletter twice a tweek.

The Markup

At the beginning let’s write some simple HTML code.

<div id="map"></div>
<div class="twitter">
	<div class="inside"></div>
</div>
<div class="posts"></div>
<div class="get">
	<input type="hidden" value="marcinmobily" />
	<input type="hidden" value="codrops" />
	<input type="hidden" value="onextrapixel" />	
	<input type="hidden" value="smashingmag" />			
	<input type="hidden" value="umutm" />
	<input type="hidden" value="1stwebdesigner" />	
	<input type="hidden" value="chriscoyier" />	
	<input type="hidden" value="marcofolio" />			
</div>	

Let’s examine the code line-by-line. The first “div” will display a Google map. Another “div” is the place where we store the description, name and profile picture of the Twitter users. Next, we create a “div” which will display the last 5 tweets.

At the end of the block, we store the Twitter user name, which will be used to download the location. If this is already done, we can proceed to write the JavaScript code.

The JavaScript

At the beginning we should define the global variables.

var map, geocoder, marker, ey, my, mouseDown = false;

Then we create the main object that will incorporate all functions used by us. The most important function in this object is the ‘init’ function.

var map, geocoder, marker, ey, my, mouseDown = false;
var o = {
	init: function(){
		// in this place we will call all needed functions
	}
}
$(function(){ o.init(); }	

Let’s create a new object called “map” in the main “o” object. It is an object, where the function initiating a Google Map will be placed. The first function in this object is the “size” function, where we draw the current window size. This is what we need in order to display the map in full screen. Then we create the object entitled “data” with the parameters: “zoom”, “center” and “mapTypeId”. When the DOM is ready we call the init function.

var map, geocoder, marker, ey, my, mouseDown = false;
var o = {
	init: function(){
		this.map.init();
	},
	map: {
		size: function(){
			var w = $(window).width(),
				h = $(window).height();
			return { width: w, height: h }
		},
		data: {
			zoom: 3,
			center: new google.maps.LatLng(52, 23),
			mapTypeId: google.maps.MapTypeId.ROADMAP
		},
		init: function(){
			var size = o.map.size();
			$('#map').css({ width: size.width, height: size.height });
			map = new google.maps.Map(document.getElementById('map'), o.map.data),
			geocoder = new google.maps.Geocoder();
			google.maps.event.addListener(map, 'dragstart', function(){
				$('.posts').hide();
			}); 
		}
	}
}
$(function(){ o.init(); }	

The next step is to create an object, where we will retrieve the Twitter user data such as name, description, location and the path to the profile picture. First, we create a function where we will retrieve the value of the ‘input’ fields and we will store it in the array. The next stage is another function where every element of previously created tables is looped. Thus, by using the Twitter API, we can extract the user’s location and using a geocoding service we can convert it to geographic coordinates. At the end, we show the user in the right place on the map and put the name, description and user picture to a blank ‘div’ just called ‘twitter’ 😉

var map, geocoder, marker, ey, my, mouseDown = false;
var o = {
	init: function(){
		this.map.init();
		this.twitter.show();
		this.twitter.click();
	},
	twitter: {
		get: function(){
			var arr = new Array;
			$('.get').find('input').each(function(i){
				var t = $(this), 
					val = t.val();
				arr[i] = val;				
			});
			return arr;
		},
		show: function(){
			var users = o.twitter.get(),
				arr = new Array;
			for (i in users){
				var user = users[i];
				$.getJSON('http://twitter.com/users/show/'+user+'.json?callback=?', function(data) {
					var img = data.profile_image_url, 
						screen_name = data.screen_name;
					geocoder.geocode({ address: data.location }, function(response, status){
						if (status == google.maps.GeocoderStatus.OK) {
							var x = response[0].geometry.location.lat(), 
								y = response[0].geometry.location.lng();
							marker = new google.maps.Marker({
								icon: img,
								map: map,
								title: screen_name,
								position: new google.maps.LatLng(x, y)
							});
							arr.push('<div class="item">');
							arr.push('<p class="img"><a href="#" class="open" rel="'+screen_name+'"><img src="'+img+'" alt="" /></a></p>');
							arr.push('<div class="entry">');
							arr.push('<a href="#" class="open title" rel="'+screen_name+'">'+data.name+'</a>');
							arr.push('<p class="description">'+data.description+'</p>');
							arr.push('<p class="url"><a href="'+data.url+'" target="_blank">'+data.url+'</a></p>');
							arr.push('<p class="count">Followers: '+data.followers_count+', Following: '+data.friends_count+'</p>');
							arr.push('</div>');
							arr.push('</div>');
							var html = arr.join('');
							arr = [];
							$('.twitter').find('.inside').append(html);
							google.maps.event.addListener(marker, 'click', function(){
								o.twitter.open(this.title);
							}); 
						}
					});
				});
			}
		},
		click: function(){
			$('.twitter').find('.open').live('click', function(){
				var t = $(this), rel = t.attr('rel');
				o.twitter.open(rel);
			});
		},
		open: function(user){
			var posts = $('.posts'), arr = new Array;
			$.getJSON('http://twitter.com/status/user_timeline/'+user+'.json?count=5&callback=?', function(data) {
				$.each(data, function(i, post){
					arr.push('<div class="post">');
					arr.push(post.text);
					arr.push('</div>');
				});
				var html = arr.join('');
				posts.html(html).fadeIn();
			});
		}
	},
	map: {
		size: function(){
			var w = $(window).width(),
				h = $(window).height();
			return { width: w, height: h }
		},
		data: {
			zoom: 3,
			center: new google.maps.LatLng(52, 23),
			mapTypeId: google.maps.MapTypeId.ROADMAP
		},
		init: function(){
			var size = o.map.size();
			$('#map').css({ width: size.width, height: size.height });
			map = new google.maps.Map(document.getElementById('map'), o.map.data),
			geocoder = new google.maps.Geocoder();
			google.maps.event.addListener(map, 'dragstart', function(){
				$('.posts').hide();
			}); 
		}
	}
}
$(function(){ o.init(); }	

Lastly, we will add a ‘scroll’ object that has a function called ‘init’ which is responsible for scrolling the ‘.twitter’ div vertically.

var map, geocoder, marker, ey, my, mouseDown = false;
var o = {
	init: function(){
		this.map.init();
		this.twitter.show();
		this.twitter.click();
	},
	twitter: {
		get: function(){
			var arr = new Array;
			$('.get').find('input').each(function(i){
				var t = $(this), 
					val = t.val();
				arr[i] = val;				
			});
			return arr;
		},
		show: function(){
			var users = o.twitter.get(), // retrieve all users which are stored in html
				arr = new Array;
			for (i in users){
				var user = users[i];
				$.getJSON('http://twitter.com/users/show/'+user+'.json?callback=?', function(data) {
					var img = data.profile_image_url, 
						screen_name = data.screen_name;
					geocoder.geocode({ address: data.location }, function(response, status){
						if (status == google.maps.GeocoderStatus.OK) {
							var x = response[0].geometry.location.lat(), 
								y = response[0].geometry.location.lng();
							marker = new google.maps.Marker({
								icon: img,
								map: map,
								title: screen_name,
								position: new google.maps.LatLng(x, y)
							});
							arr.push('<div class="item">');
							arr.push('<p class="img"><a href="#" class="open" rel="'+screen_name+'"><img src="'+img+'" alt="" /></a></p>');
							arr.push('<div class="entry">');
							arr.push('<a href="#" class="open title" rel="'+screen_name+'">'+data.name+'</a>');
							arr.push('<p class="description">'+data.description+'</p>');
							arr.push('<p class="url"><a href="'+data.url+'" target="_blank">'+data.url+'</a></p>');
							arr.push('<p class="count">Followers: '+data.followers_count+', Following: '+data.friends_count+'</p>');
							arr.push('</div>');
							arr.push('</div>');
							var html = arr.join('');
							arr = [];
							$('.twitter').find('.inside').append(html);
							google.maps.event.addListener(marker, 'click', function(){
								o.twitter.open(this.title);
							}); 
						}
					});
				});
			}
		},
		click: function(){
			$('.twitter').find('.open').live('click', function(){
				var t = $(this), rel = t.attr('rel');
				o.twitter.open(rel);
			});
		},
		open: function(user){
			var posts = $('.posts'), arr = new Array;
			$.getJSON('http://twitter.com/status/user_timeline/'+user+'.json?count=5&callback=?', function(data) {
				$.each(data, function(i, post){
					arr.push('<div class="post">');
					arr.push(post.text);
					arr.push('</div>');
				});
				var html = arr.join('');
				posts.html(html).fadeIn();
			});
		}
	},
	map: {
		size: function(){
			var w = $(window).width(),
				h = $(window).height();
			return { width: w, height: h }
		},
		data: {
			zoom: 3,
			center: new google.maps.LatLng(52, 23),
			mapTypeId: google.maps.MapTypeId.ROADMAP
		},
		init: function(){
			var size = o.map.size();
			$('#map').css({ width: size.width, height: size.height });
			map = new google.maps.Map(document.getElementById('map'), o.map.data),
			geocoder = new google.maps.Geocoder();
			google.maps.event.addListener(map, 'dragstart', function(){
				$('.posts').hide();
			}); 
		}
	},
	scroll: {
		mouse: function(e){
			var y = e.pageY; 
			return y;
		},
		check: function(y){
			var all = $('.twitter').height(),
				inside = $('.twitter').find('.inside').height();
			if (y < (all - inside)) {
				y = all - inside;
			} else if (y > 0) {
				y = 0;
			}
			return y;
		},
		update: function(e){
			var y = o.scroll.mouse(e),
				movey = y-my,
				top = ey+movey;
				check = o.scroll.check(top);
			$('.twitter').find('.inside').css({ top: check+'px' });
		},
		init: function(){
			$('.twitter').find('.inside').bind({
				mousedown: function(e){
					e.preventDefault();
					mouseDown = true;
					var mouse = o.scroll.mouse(e);
						my = mouse;
					var element = $(this).position();
						ey = element.top;
					o.scroll.update(e);
				},
				mousemove: function(e){
					if (mouseDown)
						o.scroll.update(e);
					return false;
				},
				mouseup: function(){
					if (mouseDown)
						mouseDown = false;
					return false;
				},
				mouseleave: function(){
					if (mouseDown)
						mouseDown = false;
					return false;
				}
			});
		}
	}
}
$(function(){ o.init(); }	

The CSS

First, we will embed our reset.css that will reset all the basic styles, and we’ll define some main properties:

@import url("reset.css");

html, body {
	margin:0;
	padding:0;
}

body {
	font-family:Arial, Helvetica, sans-serif;
	font-size:12px;
	color:#333;
	line-height:18px;
}

a {
	text-decoration:none;
	color:#fff;
}

Next, we will define the styles for the map, Twitter posts and descriptions.

.twitter {
	position:fixed;
	left:0;
	bottom:0;
	background:#000;
	background:rgba(0, 0, 0, .7);
	width:100%;
	height:180px;
	color:#fff;
	overflow:hidden;
}

.twitter .inside {
	position:absolute;
	top:0;
	left:0;
	cursor:n-resize;
}

.twitter .item {
	float:left;
	width:280px;
	padding:20px;
}

.twitter .item .img {
	float:left;
	width:48px;
}

.twitter .img img {
	-moz-box-shadow:0 0 5px #000;
	-webkit-box-shadow:0 0 5px #000;
	box-shadow:0 0 5px #000;
}

.twitter .item .entry {
	float:right;
	width:215px;
	height:140px;
	color:#eee;
	font-size:11px;
	position:relative;
}

.twitter .item .count {
	position:absolute;
	left:0;
	bottom:-10px;
	font-size:10px;
	text-transform:uppercase;
}

.twitter .item .title {
	font-size:13px;
	font-weight:bold;
	color:#fff;
}

.twitter .item .url a {
	text-decoration:underline;
}

.twitter .item p {
	margin-bottom:5px;
}

.posts {
	display:none;
	position:absolute;
	left:50%;
	margin-left:-310px;
	width:580px;
	bottom:180px;
	background:#fff;
	color:#fff;
	background:#000;
	background:rgba(0, 0, 0, .7);
	padding:20px;
}

.posts .post {
	float:left;
	clear:both;
	width:100%;
	margin-bottom:20px;
	font-size:12px;
	font-weight:bold;
}

Conclusion

In today’s tutorial you learned how to use a geocoding service and how to use the Twitter API. An important fact to remember is that Google has imposed some limits to its geocoding service. Maximum number of requests in one day from a single IP address is 2500. Also, Twitter will rate limit the IP address from which the request was made.

Stay tuned for the next tutorial!

Marcin Dziewulski

Marcin is an experienced and creative web developer from Poland. He loves putting new ideas into practice and is addicted to jQuery and CSS. Read his blog about web development here: http://www.jscraft.net.

Stay in the loop: Get your dose of frontend twice a week

Fresh news, inspo, code demos, and UI animations—zero fluff, all quality. Make your Mondays and Thursdays creative!

Feedback 34

Comments are closed.
  1. Whoah, that’s pretty nifty! Looks great too. Thanks for sharing this wonderful piece of code.

    Also, neat to see that my twitter is included in this demo – thanks!

  2. Not that I cannot imagine this in use, but it would be great if you share 5 or more ways in which this is useful? Thanks.

  3. I agree with Dave and would also love to know a few ways to put this beautiful code to good use.

  4. nice & impressive tutorial. It shows the possibility of enhancing google map with custom functionality…

  5. Great tutorial, one thing only, the street view feature is available on it, but it wont let you zoom out back to the map

  6. I was wondering if it’s possible to reuse this code and instead of using Twitter API use a SQL DB with Clubs/Groups that have cities on its record.

    I just want to create a big map of all the Clubs/Groups around the world we have in our SQL DB.

    Might take couple days of rewriting and adjusting the code.

    Thanks for the tutorial, amazing work!

  7. Won’t work with my twitter, with those of my friend it does. I wasn’t using location information, so i turned it on (on my iphone) and posted 5 tweets with location information. But still no result.

    Anyone?

  8. Hi,

    nice idea. I am trying it out for a few friends that are all in one city…

    I can change the zoom and the location of the map. But it seems that only one image is being showed…

    If i zoom in to have more space between the locations there is also only one (thought they would disappear beneath each other…

    Any ideas?

  9. Thank you for that awesome script. I have built a Webcam, Twitter, Google Maps mashup. The idea is to offer a personalized but very simple voting site to display the wisdom of the crowd. Your script helped me with the Google Maps part, of course.

    If you want to have a look go to http://yourheadfor.com and click on “SEE WORLDMAP”. Thanks again. You rock!

  10. The tutorial is excellent, but I have some doubts, it would be possible to publish them here or you recommend any tutorial, I’m new to programming

  11. i found some things, the problem of show more of 12 twett profiles its only whit firefox, but IE 8 i dont have problems,

  12. Another problem is that if I update the website often ceases to show me profiles, suggestions??

  13. Excellent. Thank you for posting example. Two requests:

    1. Possible you add hashtag support? (searching on hashtag instead of user accounts).

    2. Auto-refresh every 20-30 seconds?

  14. This is incredible! Thanks so much!
    One question- how do I incorporate zindex. I am building a map for local food trucks, many of them set up close to each other and the problem is that only 1 twitter icon shows up on the map. The rest of the food trucks img icons that are in same location on map are are all hidden below the first img icon. PLEASE HELP. Ive been working on this for 36 hours straight, I’m a noob and its kicking my butt. Thanks a million!

  15. thanks for the item, wonderful.
    i hide your twitter accounts on the map but how can show my followers?
    can you tell us?
    thanks a lot.