2014
05.03

Plotting Seaports in Google Map

In my recent project, one of its important feature was to be able to display all seaports that currently have ISO Tanks in the world map. To do that, first I need to have a database of seaports complete with the longitude & latitude position. Below is the data-entry form I created.

edit-port

You can slowly insert the data one-by-one, or you can just scrape the web 🙂

Since Google Map is using decimal Latitude/Longitude value, we need to create a method to convert from degree (e.g. 103° 50′ N) to decimal value (e.g. 103.833) . Here’s my code in C#:

// ---- Code SNIP -------
//Declare the Regex as part of the class member
private Regex rgxLatLon = new Regex("((?<degree>[0-9]+)°)((\\ )(?<minute>[0-9]+)')?((\\ )(?<second>[0-9]+)\")?((\\ )(?<dir>(E|S|N|W)))");
// ---- Code SNIP -------
private bool convDegDec(String raw, out double result)
{
	result = 0;
	var mLat = rgxLatLon.Match(raw);
	if (mLat.Success)
	{
		foreach (var g in mLat.Groups)
		{
			var deg = mLat.Groups["degree"].Value;
			if (!String.IsNullOrEmpty(deg))
				result = double.Parse(deg);
			var min = mLat.Groups["minute"].Value;
			if (!String.IsNullOrEmpty(min))
				result += (double.Parse(min) / 60);
			var sec = mLat.Groups["second"].Value;
			if (!String.IsNullOrEmpty(sec))
				result += (double.Parse(sec) / 3600);
			var dir = mLat.Groups["dir"].Value;
			if (dir == "S" || dir == "W")
				result = result * (-1);
		}
	}
	return mLat.Success;
}
// ---- Code SNIP -------

Final step is to actually render Google Maps, add the markers according to Seaports’ position, and display the necessary information when the marker is clicked. I won’t explain on how to use the Google Maps API because they already have a very good official guide.

Anyway, here’s how I render the map, markers and information window:

var map, info = {};
function initialize() {
	// Centralize the map to Singapore	
	var mapOptions = {
		center : new google.maps.LatLng(1.2666666666666666, 103.83333333333333),
		zoom : 6
	};

	// I have a div with id='map-canvas' as the map's placeholder
	map = new google.maps.Map(document.getElementById("map-canvas"),
			mapOptions);

	//get the Seaports and its Tanks count
	$.ajax({
		// the JSON webservice, add tick to prevent caching
		url : '/Tank/MapData?_tick=' + Math.random(),
		dataType : 'json'
	}).always(function (resp) {
		var obj = {};
		eval("obj = " + resp.responseText);

		/* Sample JSON object returned by /Tank/MapData: 
		{
			data : [{
					"CurPort" : "PKL",
					"CurrentPort" : "Port Klang",
					"decLat" : 3.0,
					"decLon" : 101.4,
					"TankCount" : 41
				}, {
					"CurPort" : "SIN",
					"CurrentPort" : "Singapore",
					"decLat" : 1.2666666666666666,
					"decLon" : 103.83333333333333,
					"TankCount" : 44
				}, {
					"CurPort" : "JKT",
					"CurrentPort" : "Jakarta",
					"decLat" : -6.1,
					"decLon" : 106.86666666666666,
					"TankCount" : 18
				},  {
					"CurPort" : "KUA",
					"CurrentPort" : "Kuantan ",
					"decLat" : 3.9666666666666668,
					"decLon" : 103.43333333333334,
					"TankCount" : 47
				}
			],
			total : 4
		}
		*/
		if (obj.data) {
			$.each(obj.data, function (i, p) {
				// set marker's position
				var myLatlng = new google.maps.LatLng(p.decLat, p.decLon);
				
				// the info window to show if the marker is clicked
				// the info window contains a hyperlink to SeaPort's details
				var infowindow = new google.maps.InfoWindow({
						content : "<div class='winInfo'><strong><a href='#' class='liPort' data-port='" + p.CurPort + "'>" + p.CurrentPort.toUpperCase() + "</a></strong><div>Tanks : " + p.TankCount + "</div></div>",
						disableAutoPan : true
					});
				
				// create the marker
				var marker = new google.maps.Marker({
						position : myLatlng,
						map : map,
						title : p.CurPort
					});

				// add the info window to global collection
				info[p.CurPort] = infowindow;

				// if marker is clicked, show the info window
				google.maps.event.addListener(marker, 'click', function () {
					info[marker.title].open(map, marker);
				});

				// by default, show the info window
				infowindow.open(map, marker);
			});

			// bind the click event on the document and use selector 
			// to ensure any new info window's hyperlink is clickable
			$(document).on('click', '.liPort', {}, function () {
				var port = $(this).attr('data-port');
				var title = $(this).text();
				top.Northwind.addTab({
					url : '/Tank/Overview?port=' + port,
					title : title,
					icon : 'icon-database'
				});
			});

			// refresh the map data every 30 seconds
			setInterval(function () {
				$.ajax({
					url : '/Tank/MapData?_tick=' + Math.random(),
					dataType : 'json'
				}).always(function (resp) {
					var obj = {};
					eval("obj = " + resp.responseText);
					if (obj.data) {
						$.each(obj.data, function (ii, pp) {
							var dPort = $(".liPort[data-port='" + pp.CurPort + "']");
							if (dPort.length > 0) {
								dPort.parent().next().html("<div>Tanks : " + pp.TankCount + "</div>");
							}
						});
					}
				});
			}, 30000);
		}
	});
}

// call initialize() when map is fully loaded
google.maps.event.addDomListener(window, 'load', initialize);

Here’s how the map will look like:

google-map-sea

Good luck on your implementation. I hope it helps, cheers!

GD Star Rating
a WordPress rating system
Plotting Seaports in Google Map, 5.0 out of 5 based on 2 ratings

Incoming Search Term

Advertise Here

No Comment

Add Your Comment