Below is the process and code that I used to create this map showing Instagram pictures from a road trip I took starting in Nashville, TN and ending in Portland, OR. This exercise demonstrates:
- API Development
- Consumption of JSON Data
- Object-Oriented Principles
The Process
- First, I gathered the Instagram pictures I wanted to show on my map. Because I didn’t properly tagged the original Instagram posts with any location info, or anything that would distinguish the posts from my other posts, I had to build my own custom results set using the results set from Instagram as a foundation. I employed Instafeed.js to help build my results set. Here is the final JSON object.
- Next, I got my App Key from Google and built a “Hello, World!” test to make sure everything worked.
- Finally, I created two javascript classes, MyList and MyMap. MyList is a glorified array of Map Markers, with an internal pointer that tracks the “current” index. MyMaps is a wrapper class for the google.maps.Map object, adding UI controls.
The Code
Class: MyList
/***************** CLASS: MyList **********************/ /* * Stores a list of pbjects, and a a reference pointing to a selected list item Functions: add - Adds item to the list saveAll - Adds an array of items to the list count - returns number of items in list getAll - returns entire list get - gets the item at a specified index indexOf - returns index number of specified object, making that object the new selection next - returns the next object in the list previous - returns the previous object in the list triggerMarkerIcon - toggles marker icon of the selected index; Parameter toggle - boolean. False for default red flag; true for green flag */ function MyList() { this.list = []; this.pointer = -1; } MyList.prototype.add = function(obj) { return this.list.push(obj); }; MyList.prototype.saveAll = function(array) { if(array.constructor === Array) this.list = array; }; MyList.prototype.count = function() { return this.list.length; }; MyList.prototype.getAll = function() { return this.list; }; MyList.prototype.get = function(i) { if(i > -1 && i < this.list.length) { this.triggerMarkerIcon(); this.pointer = i; this.triggerMarkerIcon(true); return this.list[i]; } }; MyList.prototype.indexOf = function(marker) { this.triggerMarkerIcon(); for(var i = 0; i < this.list.length; i++) { if(this.list[i] === marker) { this.pointer = i; this.triggerMarkerIcon(true); return i; } } return -1; }; MyList.prototype.next = function() { this.triggerMarkerIcon(); this.pointer++; if(this.pointer == this.list.length) this.pointer = 0; this.triggerMarkerIcon(true); return this.list[this.pointer]; }; MyList.prototype.previous = function() { this.triggerMarkerIcon(); this.pointer--; if(this.pointer < 0) this.pointer = this.list.length - 1; this.triggerMarkerIcon(true); return this.list[this.pointer]; }; MyList.prototype.triggerMarkerIcon = function(toggle) { var icon = red_icon; if(toggle) icon = green_icon; if(this.pointer > -1 && this.list[this.pointer]) { this.list[this.pointer].setIcon(icon); } };
Class: MyMaps
/***************** CLASS: MyMap **********************/ /* * Wrapper class for Google Maps Object. customized to show a list of Instagram images, each marked on a map Functions: changeMarker: activates the marker chosen by the user. Displays infoWindow addMarker: creates a custom marker object, including the content for the marker, extrracted from the data object. Expands the bounds of the map. initControls: Adds the 'Next' and 'Previous' click event handlers allowing the user to go back and forth between markers initMap: initializes Map, stores the markers in a list */ function MyMap() { this.map = undefined; this.el = undefined; this.infoWindow = new google.maps.InfoWindow(); this.bounds = new google.maps.LatLngBounds(); this.markers = new MyList(); } MyMap.prototype.changeMarker = function(marker, origin) { if(!origin) this.markers.indexOf(marker); this.infoWindow.setContent(marker.content); this.infoWindow.open(this.map, marker); }; MyMap.prototype.addMarker = function(mark) { var self = this, date, date_string, latlng, gMarker; if (mark.location.lat != undefined && mark.location.long != undefined) { date = new Date(mark.created_time * 1000); date_string = monthnames[date.getMonth()] + ' ' + date.getDate(); latlng = new google.maps.LatLng(mark.location.lat, mark.location.long); gMarker = new google.maps.Marker({ position: latlng, map: self.map, title: date_string }); gMarker.content = ""; google.maps.event.addListener(gMarker, 'click', function() { self.changeMarker(gMarker); }); this.markers.add(gMarker); this.bounds.extend(latlng); } } MyMap.prototype.initControls = function() { var self = this; $('.next-marker').click(function(e) { e.preventDefault(); self.changeMarker(self.markers.next(), this); }); $('.previous-marker').click(function(e) { e.preventDefault(); self.changeMarker(self.markers.previous(), this); }); }; MyMap.prototype.initMap = function(id, data) { this.el = $(id)[0]; this.map = new google.maps.Map(this.el, {zoom: 8}); var self = this; for(var i = 0; i < data.length; i++) { this.addMarker(data[i]); } this.map.fitBounds(self.bounds); this.changeMarker(this.markers.next()); };
$(document).ready()
map_to_pdx = new MyMap(); $(function() { if(!pdx_trip_data_uri) { console.log("ERROR. No input."); } else { //#map-container is hidden on small screens if($('#map-container').is(':visible')) { //Get Data from JSON Object var jqxhr = $.getJSON(pdx_trip_data_uri.path); jqxhr.done(function(data) { if(data.length > 0) { map_to_pdx.initMap('#map-canvas', data); map_to_pdx.initControls(); } }); } } });
Links
Special Thanks To:
- This link for helping me understand how to attech a click event handler to a Map Marker
- Design Patterns - TutsPlus.com, addyosmani.com, and carlsanley.com