1 00:00:00,000 --> 00:00:04,000 [Jim Hoskins] So now that we've taken a look at the API for the Google Static Maps, 2 00:00:04,000 --> 00:00:08,000 let's go ahead and try to implement it in our code. 3 00:00:08,000 --> 00:00:12,000 So like I said before, we're going to implement this as a method 4 00:00:12,000 --> 00:00:19,000 on our Note model and encapsulate all of the maps data inside of that method. 5 00:00:19,000 --> 00:00:22,000 So inside of our note model, down at the bottom here, 6 00:00:22,000 --> 00:00:27,000 we're going to add another method right under isGeoTagged, 7 00:00:27,000 --> 00:00:35,000 and we'll call this method mapImageUrl. 8 00:00:35,000 --> 00:00:41,000 And let's take in some options so we can modify the kind of map we're going to create 9 00:00:41,000 --> 00:00:44,000 based on the function call 10 00:00:44,000 --> 00:00:49,000 and let's add a comment describing exactly what this does. 11 00:00:49,000 --> 00:01:08,000 There's // Creates a url for a map pinned with this Note's location. 12 00:01:08,000 --> 00:01:12,000 Now what I'd like to do anytime I'm using a URL like this 13 00:01:12,000 --> 00:01:16,000 where there's documentation available, is I like to create a nice comment 14 00:01:16,000 --> 00:01:21,000 with a link to the API that I'm using and the documentation we'll be using. 15 00:01:21,000 --> 00:01:25,000 So I'll just say we're going to be using the Google Static Maps API 16 00:01:25,000 --> 00:01:29,000 and pass a string in here, so anytime we're working on it, 17 00:01:29,000 --> 00:01:34,000 we can quickly jump into the docs and figure out exactly how this should all work. 18 00:01:34,000 --> 00:01:38,000 So the first thing I'm going to do is create a variable for the base URL 19 00:01:38,000 --> 00:01:43,000 that we're going to be creating; call this var base 20 00:01:43,000 --> 00:01:47,000 and I'm going to paste in the URL that we're always going to use 21 00:01:47,000 --> 00:01:50,000 and that we're going to be appending options to: 22 00:01:50,000 --> 00:01:59,000 and that URL is "http://maps.google.com/maps/api/staticmap?" 23 00:01:59,000 --> 00:02:05,000 and I've added a ? so we can begin adding our parameters. 24 00:02:05,000 --> 00:02:12,000 Now, one function we can use as a convenience here to create a URL-encoded parameter list 25 00:02:12,000 --> 00:02:22,000 where we have key=value&key2=val2... 26 00:02:22,000 --> 00:02:30,000 is jQuery actually has a method called $.param which takes an object of key 27 00:02:30,000 --> 00:02:35,000 and values and creates a string in this URL format. 28 00:02:35,000 --> 00:02:39,000 So what we want to do is create an object with the keys and values we want to use 29 00:02:39,000 --> 00:02:44,000 and then in the end, we'll use that convenience method to actually create the URL string 30 00:02:44,000 --> 00:02:46,000 of those options. 31 00:02:46,000 --> 00:02:50,000 Now, any time we take in options, we want to have defaults, 32 00:02:50,000 --> 00:02:55,000 so what I'm going to do is create a defaults object which will define the default zoom, 33 00:02:55,000 --> 00:02:58,000 default width and height, and type, 34 00:02:58,000 --> 00:03:02,000 and we'll build off of this object to actually create the parameters 35 00:03:02,000 --> 00:03:07,000 we'll ultimately use to generate the URL. 36 00:03:07,000 --> 00:03:11,000 So I'm going to create a variable defaults 37 00:03:11,000 --> 00:03:17,000 and we'll make it an object, and let's set the default that we're going to use. 38 00:03:17,000 --> 00:03:22,000 So one parameter we discussed we needed to use is zoom 39 00:03:22,000 --> 00:03:26,000 and this tells the map how far in to zoom. 40 00:03:26,000 --> 00:03:31,000 Now, playing around with it, I determined zoom level 14 is actually a pretty good zoom level 41 00:03:31,000 --> 00:03:34,000 for what I'm looking for; kind of a neighborhood level, 42 00:03:34,000 --> 00:03:37,000 but it gives you enough context to figure out where your pins are. 43 00:03:37,000 --> 00:03:40,000 So I'll set the zoom to 14. 44 00:03:40,000 --> 00:03:43,000 So let's also set the height and width for our maps, 45 00:03:43,000 --> 00:03:48,000 so let's say height: 500, 46 00:03:48,000 --> 00:03:54,000 and we'll say width: 500, so we'll make a nice square map. 47 00:03:54,000 --> 00:03:56,000 We want to set the default map type to the road map 48 00:03:56,000 --> 00:04:00,000 which is the normal street map that we're used to seeing. 49 00:04:00,000 --> 00:04:02,000 We could do a satellite map if we wanted to, 50 00:04:02,000 --> 00:04:04,000 but let's just set the default to road map 51 00:04:04,000 --> 00:04:06,000 so we can override it later. 52 00:04:06,000 --> 00:04:08,000 maptype: "roadmap", 53 00:04:08,000 --> 00:04:14,000 And we want to set sensor: "false", and this is a Google parameter 54 00:04:14,000 --> 00:04:17,000 that we don't want to use because we're already giving it all the information. 55 00:04:17,000 --> 00:04:23,000 We don't need Google using its sensor to figure out where the request is coming from. 56 00:04:23,000 --> 00:04:26,000 So those are all the defaults that we need to set right now. 57 00:04:26,000 --> 00:04:30,000 If we were to just call mapImageUrl without passing any options in, 58 00:04:30,000 --> 00:04:35,000 we should be able to generate a map based on the notes location 59 00:04:35,000 --> 00:04:38,000 and these default values. 60 00:04:38,000 --> 00:04:41,000 And now what we're going to do is take the options argument, 61 00:04:41,000 --> 00:04:46,000 combine it with the defaults, and extend the defaults with those options. 62 00:04:46,000 --> 00:04:51,000 So basically, we're going to take the defaults and take the options 63 00:04:51,000 --> 00:04:57,000 and any values defined in options are going to be sort of transplanted on top of default. 64 00:04:57,000 --> 00:05:03,000 So if we define options zoom, when we finally use our options variable 65 00:05:03,000 --> 00:05:08,000 if it wasn't defined in the options argument that was passed in, we'll use the default. 66 00:05:08,000 --> 00:05:11,000 However, if it is defined, we'll use the value that was passed in. 67 00:05:11,000 --> 00:05:18,000 And to do this, we can do options = 68 00:05:18,000 --> 00:05:21,000 and we'll use the underscore library 69 00:05:21,000 --> 00:05:24,000 and use this _.extend method 70 00:05:24,000 --> 00:05:28,000 and what this takes is two objects--we'll take the defaults and options. 71 00:05:28,000 --> 00:05:31,000 (defaults, options) 72 00:05:31,000 --> 00:05:34,000 So this will return the defaults, objects, 73 00:05:34,000 --> 00:05:38,000 but any keys that are in the options value will also be in that object that is returned 74 00:05:38,000 --> 00:05:42,000 with options overwriting anything that is in defaults. 75 00:05:42,000 --> 00:05:45,000 So if we don't pass in any options at all, 76 00:05:45,000 --> 00:05:56,000 options will now be set to the defaults. 77 00:05:56,000 --> 00:06:01,000 So now that we have some options that we can use to generate our parameters, 78 00:06:01,000 --> 00:06:09,000 we need to actually go around and update some of these to match the API's expectation. 79 00:06:09,000 --> 00:06:12,000 One thing is it doesn't take a width and a height attribute. 80 00:06:12,000 --> 00:06:18,000 Instead, it takes a single size attribute which takes the form of 500x500. 81 00:06:18,000 --> 00:06:25,000 So what we want to do is // Convert {width:400, as an example 82 00:06:25,000 --> 00:06:37,000 and height: 300}. 83 00:06:37,000 --> 00:06:40,000 We want to instead convert this to {size: 84 00:06:40,000 --> 00:06:46,000 being "400x300"}. 85 00:06:46,000 --> 00:06:50,000 So we need to take this width and height attribute, 86 00:06:50,000 --> 00:06:52,000 convert them into a size attribute, 87 00:06:52,000 --> 00:06:57,000 and remove the width and height from our options. 88 00:06:57,000 --> 00:07:01,000 So first, let's set the options.size , 89 00:07:01,000 --> 00:07:07,000 and we'll construct a string based on options.width, 90 00:07:07,000 --> 00:07:10,000 concatenate the "x" that will separate them, 91 00:07:10,000 --> 00:07:18,000 and then concatenate options.height;. 92 00:07:18,000 --> 00:07:21,000 So now we have a size in the correct format 93 00:07:21,000 --> 00:07:25,000 and we actually want to delete width and height from our options 94 00:07:25,000 --> 00:07:31,000 because the jQuery convenience method is going to add those extra paremeters in 95 00:07:31,000 --> 00:07:34,000 which we don't need. 96 00:07:34,000 --> 00:07:42,000 So let's do delete options.height; 97 00:07:42,000 --> 00:07:45,000 and delete options.width;. 98 00:07:45,000 --> 00:07:48,000 So now, let's define our markers, 99 00:07:48,000 --> 00:07:51,000 which will actually tell the map where we want to put our markers 100 00:07:51,000 --> 00:07:55,000 and what we want our markers to look like. 101 00:07:55,000 --> 00:08:00,000 Now, you'll remember from the API that markers have a pretty interesting syntax 102 00:08:00,000 --> 00:08:03,000 where the different properties are separated by pipes 103 00:08:03,000 --> 00:08:06,000 with the keys and values separated by colons 104 00:08:06,000 --> 00:08:12,000 and it's a little bit tough to parse, but let's get through it in our code here. 105 00:08:12,000 --> 00:08:16,000 So let's set options.markers 106 00:08:16,000 --> 00:08:19,000 and let's construct the string. 107 00:08:19,000 --> 00:08:24,000 So let's go ahead and say our pin is going to be blue, 108 00:08:24,000 --> 00:08:27,000 so we'll say "color:blue|". 109 00:08:27,000 --> 00:08:32,000 Now, our next property, we want to define what the label on that pin is, 110 00:08:32,000 --> 00:08:35,000 I'm just going to call it "X" so like "X marks the spot." 111 00:08:35,000 --> 00:08:41,000 So we'll put our pipe in and we'll say |label:X" 112 00:08:41,000 --> 00:08:44,000 so our marker will be blue with the label X. 113 00:08:44,000 --> 00:08:49,000 Now, to put another pipe in, basically what we're going to do 114 00:08:49,000 --> 00:08:53,000 is put in |lat,lon". 115 00:08:53,000 --> 00:09:01,000 Now, this lat and lon are going to be coming from this Note's latitude and longitude. 116 00:09:01,000 --> 00:09:05,000 Now, since we're going to be using the lat,lon string in two different places-- 117 00:09:05,000 --> 00:09:08,000 one for our marker and one for our center-- 118 00:09:08,000 --> 00:09:14,000 let's go ahead and create a variable that will hold the string lat,lon with a comma in it. 119 00:09:14,000 --> 00:09:28,000 So up here, I'm going to say var latlon = this.get("latitude") 120 00:09:28,000 --> 00:09:31,000 and we'll concatenate the comma + "," 121 00:09:31,000 --> 00:09:43,000 and then we'll concatenate + this.get("longitude");. 122 00:09:43,000 --> 00:09:48,000 So now, we have this latlon here and we can replace this 123 00:09:48,000 --> 00:09:51,000 with our latlon variable. 124 00:09:51,000 --> 00:09:56,000 We'll close out the string and concatenate latlon. 125 00:09:56,000 --> 00:10:03,000 So now, this should accurately describe our marker over our Note, 126 00:10:03,000 --> 00:10:06,000 so let's add a comment describing what we were doing here. 127 00:10:06,000 --> 00:10:23,000 We'll // Add markers to parameters to add a blue pin to the map. 128 00:10:23,000 --> 00:10:28,000 Now, the last option we need to set is where the center of the map is going to be, 129 00:10:28,000 --> 00:10:32,000 and that's going to be the same location as our pin, so it's centered on the pin 130 00:10:32,000 --> 00:10:39,000 so let's // Center on this Note's location. 131 00:10:39,000 --> 00:10:50,000 And we'll set options.center = latlon; 132 00:10:50,000 --> 00:10:52,000 the comma-separated latitude and longitude. 133 00:10:52,000 --> 00:10:55,000 Now finally, we want to construct the URL 134 00:10:55,000 --> 00:10:59,000 and to do that, we're going to take our base 135 00:10:59,000 --> 00:11:06,000 and we're going to concatenate all of our options parsed together as a URL. 136 00:11:06,000 --> 00:11:08,000 So to do that, we'll use jQuery 137 00:11:08,000 --> 00:11:11,000 $.param method 138 00:11:11,000 --> 00:11:15,000 and pass in (options) and this should now create a full URL, 139 00:11:15,000 --> 00:11:19,000 properly encoded,based on the options we have. 140 00:11:19,000 --> 00:11:26,000 All we need to do is return url;. 141 00:11:26,000 --> 00:11:30,000 So now that we have our mapImageUrl method, 142 00:11:30,000 --> 00:11:34,000 we can try to insert it into our view. 143 00:11:34,000 --> 00:11:38,000 So I'm going to go back to index.html 144 00:11:38,000 --> 00:11:42,000 and inside of this clause here where we have isGeoTagged, 145 00:11:42,000 --> 00:11:48,000 I'm going to insert an image tag <img> 146 00:11:48,000 --> 00:11:51,000 and we're going to add a source, 147 00:11:51,000 --> 00:11:56,000 and the source is actually going to be dynamically generated using the template, 148 00:11:56,000 --> 00:12:03,000 and we'll do <% note.mapImageUrl() 149 00:12:03,000 --> 00:12:06,000 and I'm not going to pass in any options; 150 00:12:06,000 --> 00:12:09,000 we're going to use the defaults. 151 00:12:09,000 --> 00:12:13,000 So let's go back to our browser on our Note with location data 152 00:12:13,000 --> 00:12:16,000 and refresh and see what happens. 153 00:12:16,000 --> 00:12:19,000 So we got a syntax error: unexpected token, 154 00:12:19,000 --> 00:12:22,000 and it's being brought up in _.js 155 00:12:22,000 --> 00:12:26,000 and underscore is what handles our templates, 156 00:12:26,000 --> 00:12:29,000 and if we expand this out, we can see that the actual error 157 00:12:29,000 --> 00:12:31,000 happened in the template method. 158 00:12:31,000 --> 00:12:35,000 So the actual source of our error is probably in our template code, 159 00:12:35,000 --> 00:12:41,000 so if you go to index.html and take a look here, 160 00:12:41,000 --> 00:12:44,000 I may not need the semicolon there. 161 00:12:44,000 --> 00:12:49,000 Let's just see see what happens if we leave that off and save it. 162 00:12:49,000 --> 00:12:52,000 All right, that looks like it worked. 163 00:12:52,000 --> 00:12:54,000 So when we refresh it and that error seems to have gone away, 164 00:12:54,000 --> 00:12:56,000 so we won't use the semicolon there, 165 00:12:56,000 --> 00:12:58,000 it looks like we have a map. 166 00:12:58,000 --> 00:13:03,000 It looks like it's in the right part of downtown Orlando. 167 00:13:03,000 --> 00:13:07,000 We have a blue pin right over our current offices 168 00:13:07,000 --> 00:13:15,000 and it looks like it worked, so this shows our map is working. 169 00:13:15,000 --> 00:13:20,000 And right after it, we have our latitude and longitude. 170 00:13:20,000 --> 00:13:23,000 So let's check this out in our mobile browser. 171 00:13:23,000 --> 00:13:26,000 I'm going to create a New Note, 172 00:13:26,000 --> 00:13:36,000 and we'll say from the Office, we are Recording a Master Class. 173 00:13:36,000 --> 00:13:42,000 We definitely want to tag this with our location and save it out, 174 00:13:42,000 --> 00:13:45,000 and it's going to confirm that we can use our current location. 175 00:13:45,000 --> 00:13:49,000 We will accept that, check All Notes, 176 00:13:49,000 --> 00:13:55,000 go into this Office one here. 177 00:13:55,000 --> 00:13:57,000 Now, it doesn't look like it's working; let me go ahead and refresh 178 00:13:57,000 --> 00:14:00,000 to make sure that we have the code--there we go. 179 00:14:00,000 --> 00:14:05,000 And now it looks like it is showing up; however, on the mobile device, 180 00:14:05,000 --> 00:14:07,000 it seems to be getting cut off. 181 00:14:07,000 --> 00:14:13,000 That's because the image is 500pxx500px, but what we really want to do 182 00:14:13,000 --> 00:14:19,000 is scale it to the width of the device, so we're going to do this using CSS. 183 00:14:19,000 --> 00:14:24,000 So let's go into our index.html here 184 00:14:24,000 --> 00:14:34,000 and let's link to another style sheet. 185 00:14:34,000 --> 00:14:43,000 We'll call this "css/main.css" 186 00:14:43,000 --> 00:14:47,000 and this is where we'll put our own styles for our application. 187 00:14:47,000 --> 00:14:51,000 So far, we haven't had to define any of our own styles in the application 188 00:14:51,000 --> 00:14:55,000 since jQuery Mobile has done all of that for us, 189 00:14:55,000 --> 00:14:58,000 but now let's go ahead and create our main.css file. 190 00:14:58,000 --> 00:15:04,000 So I saved the link here in our CSS folder. 191 00:15:04,000 --> 00:15:10,000 I'm going to create a new file we'll call main.css. 192 00:15:10,000 --> 00:15:14,000 We'll go ahead and add a class to our image tag, 193 00:15:14,000 --> 00:15:17,000 so we'll say img.map { 194 00:15:17,000 --> 00:15:21,000 and we'll just say width: 100%; 195 00:15:21,000 --> 00:15:26,000 and the height will be determined by the aspect ratio of the actual image, 196 00:15:26,000 --> 00:15:34,000 so let's go back to our index.html where we define our image. 197 00:15:34,000 --> 00:15:42,000 We'll add a class="map" and save it out 198 00:15:42,000 --> 00:15:47,000 and if we go back here and refresh, 199 00:15:47,000 --> 00:15:51,000 you can see it now has been resized to fit the width of the device 200 00:15:51,000 --> 00:15:57,000 so we can see all of our map here. 201 00:15:57,000 --> 00:16:01,000 And if we flip it back to portrait mode, you can see it resizes so we can always see 202 00:16:01,000 --> 00:16:04,000 all of the map and determine where our note was created.