· 9 years ago · Oct 04, 2016, 12:56 AM
1/** Set up object array to be used later by map, markers, and list
2 */
3var locations = [{
4 name: "Red Bull Arena",
5 address: "600 Cape May St, Harrison, NJ 07029",
6 lat: 40.737046,
7 long: -74.150361,
8 marker: '',
9 yelpWeb: "https://api.yelp.com/v2/business/red-bull-arena-harrison"
10}, {
11 name: "MetLife Stadium",
12 address: "1 MetLife Stadium Dr, East Rutherford, NJ 07073",
13 lat: 40.813091,
14 long: -74.074209,
15 marker: '',
16 yelpWeb: "https://api.yelp.com/v2/business/metlife-stadium-east-rutherford"
17}, {
18 name: "World Trade Center",
19 address: "1 World Trade Center, New York, NY 10007",
20 lat: 40.713175,
21 long: -74.013104,
22 marker: '',
23 yelpWeb: "https://api.yelp.com/v2/business/one-world-trade-center-new-york-4"
24}, {
25 name: "Zeppelin Hall Biergarten",
26 address: "88 Liberty View Dr, Jersey City, NJ 07302",
27 lat: 40.715120,
28 long: -74.046754,
29 marker: '',
30 yelpWeb: "https://api.yelp.com/v2/business/zeppelin-hall-biergarten-and-restaurant-jersey-city-2"
31}, {
32 name: "Prudential Center",
33 address: "25 Lafayette St, Newark, NJ 07102",
34 lat: 40.733617,
35 long: -74.171150,
36 marker: '',
37 yelpWeb: "https://api.yelp.com/v2/business/prudential-center-newark"
38}, {
39 name: "Madison Square Garden",
40 address: "7th Ave & 32nd St, New York, NY 10001",
41 lat: 40.750691,
42 long: -73.993476,
43 marker: '',
44 yelpWeb: "https://api.yelp.com/v2/business/madison-square-garden-new-york"
45}];
46
47
48
49
50/** Considering how 'this' changes in every scope, 'self' will preserve
51 * 'this' value throughout viewModel. Since we want our array of objects to be
52 * able to detect changes as well as respond to changes we use knockout's
53 * observableArray and pass our array of objects (locations) through it.
54 * It will now be referred to self.places.
55 */
56var viewModel = function() {
57 var self = this;
58
59 self.places = ko.observableArray(locations);
60
61 /** Set currentLocation to first object in object array.
62 * When particular object is clicked from list, change currentLocation
63 * value to the clicked location. Also trigger a click on the marker.
64 */
65 this.currentLocation = ko.observable(self.places()[0]);
66 this.setLocation = function(clickedLocation) {
67 self.currentLocation(clickedLocation);
68 google.maps.event.trigger(clickedLocation.marker, 'click');
69 };
70
71 /** Setting up search so it filters through object array or locations
72 * while allowing lowercase typing to bring back relevant results.
73 */
74 self.query = ko.observable('');
75
76 /** Display list of locations in a list view
77 */
78 self.search = ko.computed(function() {
79 for (var i = 0; i < locations.length; i++) {
80 locations[i].marker.setVisible(true);
81 }
82 /** If what's typed in input lowercase or not matches a location in object array
83 * display the results, however many there are. If there are objects that don't contain
84 * what's typed in the input then hide those objects.
85 */
86 return ko.utils.arrayFilter(locations, function(place) {
87 if (place.name.toLowerCase().indexOf(self.query().toLowerCase()) >= 0) {
88 return true;
89 }
90 infowindow.close();
91
92 place.marker.setVisible(false);
93 return false;
94 });
95 });
96
97 /** When width of page is > 600px hamburger menu
98 * is visible, and when clicked list menu slides in.
99 * Refactored jQuery hamburger menu code into knockout
100 * to prove ninja-worthiness.
101 */
102 this.isOpen = ko.observable(false);
103
104 this.toggle = function() {
105 self.isOpen(!self.isOpen());
106 };
107 this.close = function() {
108 self.isOpen(false);
109 };
110};
111
112function nonce_generate() {
113 return (Math.floor(Math.random() * 1e12).toString());
114}
115var yelpAPI = function(location) {
116 console.log(location);
117 var yelp_url = location.yelpWeb;
118
119 var parameters = {
120 oauth_consumer_key: 'AOsWUWqrkWd3Lx9RHt4ihA',
121 oauth_token: 'rqRj4BFQ1xVBEut_57pPedSonmLjkyde',
122 oauth_nonce: nonce_generate(),
123 oauth_timestamp: Math.floor(Date.now() / 1000),
124 oauth_signature_method: 'HMAC-SHA1',
125 oauth_version: '1.0',
126 callback: 'cb', // This is crucial to include for jsonp implementation in AJAX or else the oauth-signature will be wrong.
127 ll: '40.753011, -74.128069',
128 radius: 40000,
129 limit: 5
130 };
131
132 var encodedSignature = oauthSignature.generate('GET', yelp_url, parameters, 'bVxTwnXgkOCAg5Kfhrw7eWEthu8', 'cK98_xpt5iXoBJVyeysJzw5Ypxk');
133 parameters.oauth_signature = encodedSignature;
134
135 /** Configure Yelp API settings as well as provide some error handling
136 */
137 var settings = {
138 url: yelp_url,
139 data: parameters,
140 cache: true, // This is crucial to include as well to prevent jQuery from adding on a cache-buster parameter "_=23489489749837", invalidating our oauth-signature
141 dataType: 'jsonp',
142 success: function(results) {
143 /** Do stuff with results
144 */
145 location.url = results.url;
146 location.rating_img_small_url = results.rating_img_url_small;
147 location.snippet_text = results.snippet_text;
148 location.image_url = results.image_url;
149 },
150 error: function() {
151 /** Do stuff on fail
152 */
153 alert("You have encountered an error");
154 }
155 };
156
157 /** Send AJAX query via jQuery library.
158 */
159 $.ajax(settings);
160};
161/*for (var i = 0; i < locations.length; i++) {
162 yelpAPI(i);
163}*/
164var map, bounds, infowindow;
165/** Main map function that zooms in and centers it at specific location due to the given
166 * coordinates. Also displays the map in the respective div.
167 */
168function initMap() {
169 map = new google.maps.Map(document.getElementById('map'), {
170 zoom: 12,
171 center: new google.maps.LatLng(40.753011, -74.128069)
172 });
173 bounds = new google.maps.LatLngBounds();
174 infowindow = new google.maps.InfoWindow();
175
176
177
178 /** Marker gets created on map with a falling animation and positioned in respective coordinates from locations array up top.
179 */
180 function createMarker(location) {
181 latlng = new google.maps.LatLng(location.lat, location.long);
182 var marker = new google.maps.Marker({
183 map: map,
184 animation: google.maps.Animation.DROP,
185 position: latlng
186 });
187
188 bounds.extend(marker.position);
189
190 /** When marker gets clicked on, it toggles bouncing animation and info window pops up
191 */
192 google.maps.event.addListener(marker, 'click', function() {
193 html = '<h3>' + location.name + '</h3>';
194 html += '<br><img src=' + location.image_url + '><br>' + location.address;
195 html += '<br><img src=' + location.rating_img_small_url + '>';
196 html += '<p>' + location.snippet_text + '<a href="' + location.url + '">more...</a></p>';
197 yelpAPI(location);
198 infowindow.setContent(html);
199 infowindow.open(map, this);
200 toggleBounce(marker);
201 });
202
203 return marker;
204
205
206 }
207
208
209 /** Set's bounce animation to marker with a timer on it so it doesn't
210 * keep bouncing forever
211 */
212 function toggleBounce(marker) {
213 if (marker.getAnimation() !== null) {
214 marker.setAnimation(null);
215 } else {
216 marker.setAnimation(google.maps.Animation.BOUNCE);
217 setTimeout(function() { marker.setAnimation(null); }, 650);
218 }
219 }
220
221 /** Loop that iterates through each object in the locations array. Marker property stores coordinates
222 * for exact location for each object. Because createMarker function is called it will display each
223 * and every marker in locations on the map.
224 */
225 for (var i = 0; i < locations.length; i++) {
226 locations[i].marker = createMarker(locations[i]);
227 }
228 map.fitBounds(bounds);
229
230 /** Activate knockout bindings
231 */
232 ko.applyBindings(new viewModel());
233}