Custom infowindow with jQuery UI Tabs using infobox, Google Maps API v3

Recently, I started using Google Maps API v3 and one of the things I wanted to achieve is to customize the default infowindow, re-skin it and add some tabbed content into it.

After some R&D I found infobox JS which allows you to customize the default infowindow. You can add styles and any HTML content. In a way it actually replaces the default infowindow functionality.

So in this tutorial I’m going to explain how I’ve used Google Maps API v3, jQuery UI Tabs and Infobox JS to achieve the below:

Prerequisites: Knowledge on XHTML / HTML5, CSS, JSON, Good understanding of JS and jQuery is required.

More Tutorials on Google Maps API V3: I’ve recently put up a tutorial on Get Directions and Custom Directions Panel.

HTML5 Mark-up:

<!DOCTYPE html>
<html>
  <head>

    <title>Google Maps API V3: Custom Infowindow using Infobox</title>
    <meta name="viewport" content="initial-scale=1.0, user-scalable=no" />

    <link rel="stylesheet" href="jquery-ui-1.9.0.custom/css/ui-lightness/jquery-ui-1.9.0.custom.min.css" type="text/css" media="all" />

    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>    
    <script type="text/javascript" src="jquery-ui-1.9.0.custom/js/jquery-ui-1.9.0.custom.min.js"></script>

    <script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?key=&sensor=false"></script>
    <script type="text/javascript" src="infobox.js"></script>

    <style type="text/css">
    	body {margin: 0; padding: 0; width:100%; height: 1000px; overflow: hidden}
    	#map_canvas {margin:0 auto; width: 100%; height: 90%}
		#tabs {font-size: x-small; width: 255px; height: 150px}
		#tabs .ui-tabs-nav {height: 25px}
		p {font-size: x-small; marign: 0; padding: 0}
    </style>

  </head>
  <body>
    <div id="map_canvas"> </div>
    <script type="text/javascript" src="sample.js"></script> 
  </body>
</html>

Google Maps API v3 Basics:

Reference Javascript script:

You need to add the below reference Javascript script to your page. There is no need of API key to use Google Maps API v3. Sensor parameter is false by default. If your device have a GPS sensor make the sensor parameter true(sensor=true).

<script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?key=&sensor=false"></script>

Creating a Map:

To initialize the Map, we need to call constructor of Map class. It takes 2 arguments one is reference of HTML element to insert map (<div id=”map_canvas”> </div>) and two is Map options object.

map = new google.maps.Map(mapCanvas, {
	zoom: 10,
	center: new google.maps.LatLng(-33.950198, 151.259302),
	mapTypeId: google.maps.MapTypeId.ROADMAP 
});

zoom: It is a number to set initial zoom level of the map
center: It sets center of the map by taking coordinates of latitude and longitude.
mapTypeId: It specifies initial type of map. It is an identifier of google.maps.MapTypeId class.

Before continuing further please go through the Google MAPS API v3 Tutorials and get familiarized with the default options and functionalities.

Customizing infowindow using infobox JS:

The objective of this JS is to access the JSON Data and setup the markers using the latitude and longitude on the Google Map and add the custom infobox with jQuery UI Tabs for each of the markers.

For this tutorial I’ve used a JSON file which contains the location data(latitude and longitude). I’ve used a Singleton JS pattern coding standard for the JS. You can read more about this pattern here: The Singleton Pattern – Addy Osmani

Below is the JS code:

var myCustomMaps = (function (jQuery) {
	var instance, 
		map,
		mapCanvas = jQuery('#map_canvas')[0], 
		init = function () {
			return {
				pageLoad: function () {
					this.invokeMyMaps();										
				},	
				invokeMyMaps: function() {	

					var	markers = [], infoBubbles = [], infoBubble, 
						contentString=['<div id="tabs">','<ul>','<li><a href="#tab-1"><span>Tab1</span></a></li>','<li><a href="#tab-2"><span>Tab2</span></a></li>','<li><a href="#tab-3"><span>Tab3</span></a></li>','</ul>','<div id="tab-1">','<p>Tab 1 content. You can customize it further and make this dynamic / JS Object</p>','</div>','<div id="tab-2">','<p>Tab 2 content</p>','</div>','<div id="tab-3">','<p>Tab 3 content</p>','</div>','</div>'].join('');

					map = new google.maps.Map(mapCanvas, {
						zoom: 10,
						center: new google.maps.LatLng(-33.950198, 151.259302),
						mapTypeId: google.maps.MapTypeId.ROADMAP
					});				

					jQuery.ajax({
						url: 'Beach.json', 
						type: 'GET',
						dataType: 'json', 
						success: function(D) {

							beachSpecs = D.beaches;
							jQuery.each(beachSpecs, function(k, v) {
								//console.log(v.beachName, v.latitude, v.longitude);

								// Creating / Initiating Markers:
								var marker = new google.maps.Marker({
									position: new google.maps.LatLng(v.latitude, v.longitude),
									map: map, 
									title: jQuery.trim(v.beachName)
								});								

								// Creating / Initiating Infobox					
								infoBubble = new InfoBox({
									 content: contentString, // Tab content gets appended here.
									 disableAutoPan: false, 
									 maxWidth: 0, 
									 pixelOffset: new google.maps.Size(-140, 0), 
									 zIndex: null, 
									 boxStyle: { 
										//background: "url('tipbox.gif') no-repeat", 
										opacity: 1, 
										width: "280px"
									 }, 
									 closeBoxMargin: "0px", 
									 closeBoxURL: "http://www.google.com/intl/en_us/mapfiles/close.gif", 
									 infoBoxClearance: new google.maps.Size(1, 1), 
									 isHidden: false, 
									 pane: "floatPane", 
									 enableEventPropagation: true									
								});

								markers[k] = marker;
								infoBubbles[k] = infoBubble;							

								// Binding Tab Functionality to infowindow
								google.maps.event.addListener(infoBubble, 'domready', function() {
								  jQuery("#tabs").tabs();
								});	

								// Marker Mouse events
								google.maps.event.addListener(marker, 'mouseup', function() {
									$.each(infoBubbles, function(ix, vx) {
										if(ix >; 0) {
											infoBubbles[ix].close();											
										}
									});
									infoBubble.open(map, marker);
								});																						

							});

						}, // success
						error: function (xhr, textStatus, errorThrown) {
							alert("Error: " + (errorThrown ? errorThrown : xhr.status));
						} // error
					}); //ajax																

				} //invokeMyMaps
			};
		};		
	return {
		load: function () {
			if (!instance) {
				instance = init();
			}
			return instance;
		}
	};
})(jQuery);

(function (jQuery) {
	var myMaps = myCustomMaps.load();
	myMaps.pageLoad();
})(jQuery);

All the Map related functionality is wrapped in the invokeMyMaps function. The below code is required to initialize the Google Map API.

map = new google.maps.Map(mapCanvas, {
	zoom: 10,
	center: new google.maps.LatLng(-33.950198, 151.259302),
	mapTypeId: google.maps.MapTypeId.ROADMAP
});

My next steps are to access the JSON File using the jQuery Ajax Call. On Success I’m accessing the JSON data and doing the following:

Setting up the Markers:

The below JS code is for setting up the Markers on the map with the latitude and longitude data from the JSON Object.

// Creating / Initiating Markers:
var marker = new google.maps.Marker({
	position: new google.maps.LatLng(v.latitude, v.longitude),
	map: map, 
	title: jQuery.trim(v.beachName)
});

Read more about markers.

Creating the Infobox:

Infobox is basically an enhanced version of an Infowindow. The below code is for setting up the infobox with options.

// Creating / Initiating Infobox					
infoBubble = new InfoBox({
	content: contentString, // Tab content gets appended here.
	disableAutoPan: false, 
	maxWidth: 0, 
	pixelOffset: new google.maps.Size(-140, 0), 
	zIndex: null, 
	boxStyle: { 
		//background: "url('tipbox.gif') no-repeat", 
		opacity: 1, 
		width: "280px"
	}, 
	closeBoxMargin: "0px", 
	closeBoxURL: "http://www.google.com/intl/en_us/mapfiles/close.gif", 
	infoBoxClearance: new google.maps.Size(1, 1), 
	isHidden: false, 
	pane: "floatPane", 
	enableEventPropagation: true									
});

The content option is where you need to pass your custom HTML Content. I’m passing the jQuery UI Tads code using contentString variable and Infobox gives you a lot of options to play around and do maximum customization.

Read the detailed documentation on Infobox.

Since I have more than one location data I’m storing the marker details and the infobox details in the arrays:

markers[k] = marker;
infoBubbles[k] = infoBubble;

The Below functions are required to put everything together. The jQuery Tab event needs to be attached to the infobox on domready and infobox .open function is responsible for opening up the infowindow.

// Binding Tab Functionality to infowindow
google.maps.event.addListener(infoBubble, 'domready', function() {
	jQuery("#tabs").tabs();
});	

// Marker Mouse events
google.maps.event.addListener(marker, 'mouseup', function() {
	$.each(infoBubbles, function(ix, vx) {
		if(ix >; 0) {
			infoBubbles[ix].close();											
		}
	});
	infoBubble.open(map, marker);
});

This tutorial is still a work in progress. My intention is to just give a basic idea on how we can put things together. Any feedback is welcome. Please comment or email me for any questions.

Click Here to download the complete code.

More Tutorials on Google Maps API V3: I’ve recently put up a tutorial on Get Directions and Custom Directions Panel.

Good Luck!