by Maxime Des Roches | 2013-10-09

In a recent project, we had to build a website where employees would get information about their workplace moving. We had to implement a Google Maps showing nearby amenities like restaurants and gyms, near their new address.

There are multiple ways to approach this, I could have written a simple and fast program that would work as is, but the map needed to be customizable and reusable so we could reuse it in other projects.

At first, I had to think forward and list features I wanted to implement in my plugin:

Basic features

The basic functions need to be called within a single line of code

The map must be centred around a certain point

Optional features

You can change the zoom level

You can specify the dimensions of the map

You can change the rendering of the map (roadmap, satellite or hybrid)

You can filter by places types (eg. only show cafes)

You can exclude certain types (eg. don't show night clubs)

You can exclude places by keywords (eg. don't show your competitor)

Diving into the code

Following Martin's footsteps, I wrote the basis of my plugin.

;(function($){ var WhatsNearby = { init: function(options, elem){ return this; } } $.fn.whatsnearby = function(options) { if(this.length) { return this.each(function(){ var wn = Object.create(WhatsNearby); wn.init(options, this); $.data(this, 'whatsnearby', wn); }) } } })(jQuery);

Here, $.fn.whatsnearby registers WhatsNearby into the jQuery plugins list. This function contains code that initialize our plugin.

With this simple code, we can now call the whatsnearby function on any DOM element like such : $('#somediv').whatsnearby() .

We can now implement our basic features into our plugin. We're going to modify the init function and add the options property :

var WhatsNearby = { init: function(options, elem){ this.options = $.extend({},this.options,options); this.elem = elem; this.$elem = $(elem); this._build(); return this; }, options: { } }

The options property will store the parameters that can change the behavior of our plugin (eg. change the zoom, change the dimension). Let's start by simply storing the address / position, zoom level, dimension and type of the map.

options: { "address": "", "lat": 45.509234, "lng": -73.559067, "width": 500, "height": 500, "zoom":8, "mapType": google.maps.MapTypeId.ROADMAP, }

Our plugin will look for an address, or fall back to longitude and latitude coordinates to center itself. In this example, the default location is Montreal (because, why not ?).

Let's drill down further by adding the _build function to our WhatsNearby object :

var WhatsNearby = { [...] _build: function(){ var o = this.options; $(this.elem).width(o.width).height(o.height); google.maps.visualRefresh = true; if($(this.elem).attr("data-address")) { o.address = $(this.elem).attr("data-address"); } if(o.address == "") { this._setupMap(o.lat,o.lng); } else { this._geocodeAddress(o.address); } } }

We first start by resizing our container this.elem . We then make sure Google uses its latest visuals (because it's prettier!). I decided that there were 2 ways to pass an address to WhatsNearby, by setting the options.address parameter or by setting the data-address attribute directly on the DOM element:

$('#somediv').whatsnearby({address:"32 St-Charles Ouest, Longueuil"});

or

<div id="somediv" data-address="32 St-Charles Ouest, Longueuil"></div>

Finally, if an address is found, we geocode it with Google Geocoder API or else, we fallback to lat/lng coordinates and setup the map.

Lets look at the _geocodeAddress function :

var WhatsNearby = { [...] _geocodeAddress: function(address){ var geocoder = new google.maps.Geocoder(); geocoder.geocode({ "address": address}, this._locationFound.bind(this) ); }, _locationFound: function(results, status){ if(status == "OK") { if(results[0].geometry.location.nb) this._setupMap(results[0].geometry.location.nb, results[0].geometry.location.ob); if(results[0].geometry.location.lb) this._setupMap(results[0].geometry.location.lb, results[0].geometry.location.mb); } else { console.log("An error occured while geocoding the address."); } } }

The Google Geocoder API allows us to transform a physical address to lat/lng coordinates. the _locationFound function is a callback from the API. We check for the status and setup the map with the correct coordinates passed by Google. If you notice, there are 2 different sets of coordinates ( location.nb, location.ob and location.lbm location.mb ). This is the result of a recent update in Google's API and solves a lot of problems.

Now that our plugin knows about the starting position of our map, we can setup the Map using the _setupMap function :

var WhatsNearby = { [...] _setupMap: function(lat, lng){ var o = this.options; var mapOptions = { zoom:o.zoom, mapTypeId: this.options.mapType, center: new google.maps.LatLng(lat, lng) } this.map = new google.maps.Map(this.elem, mapOptions); } }

At this point, our plugin can show a simple map, centered at an address or at lat/lng coordinates.

In the next part, we'll add the Places API to our plugin to show nearby amenities around a point.

View the source on the following page to see the complete code for this part.