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