{"id":1068,"date":"2016-08-06T12:35:21","date_gmt":"2016-08-06T19:35:21","guid":{"rendered":"http:\/\/www.certainly-strange.com\/?p=1068"},"modified":"2016-08-22T20:47:27","modified_gmt":"2016-08-23T03:47:27","slug":"using-the-google-maps-javascript-api","status":"publish","type":"post","link":"http:\/\/www.certainly-strange.com\/?p=1068","title":{"rendered":"Using the Google Maps Javascript API"},"content":{"rendered":"<p>I&#8217;ve recently been playing around with the <a href=\"https:\/\/developers.google.com\/maps\/documentation\/javascript\/\">Google Maps Javascript API<\/a>\u00a0in my Rails web \u00a0apps to make some simple maps. Google&#8217;s documentation on this is very very good, so in most cases I&#8217;d recommend you start there to figure out how to make the map you want. Nonetheless, I thought I&#8217;d write up a quick tutorial for making a very simple map, making\/displaying markers, and automatically re-positioning the map based on multiple location markers (from the perspective of using it in a Rails app).<\/p>\n<p>I&#8217;ll start with <a href=\"https:\/\/developers.google.com\/maps\/documentation\/javascript\/examples\/map-simple\">Google&#8217;s Simple Map<\/a> example.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"html\" data-enlighter-theme=\"twilight\">\u00a0 &lt;div id=\"map\"&gt;&lt;\/div&gt;\r\n &lt;script&gt;\r\n var map;\r\n function initMap() {\r\n map = new google.maps.Map(document.getElementById('map'), {\r\n center: {lat: -34.397, lng: 150.644},\r\n zoom: 8\r\n });\r\n }\r\n &lt;\/script&gt;\r\n &lt;script src=\"https:\/\/maps.googleapis.com\/maps\/api\/js?key=YOUR_API_KEY&amp;callback=initMap\"\r\n async defer&gt;&lt;\/script&gt;<\/pre>\n<p>Remember to set the styling for #map to be whatever size you want the div to be in your stylesheet, because this is what will determine the size of your map.<\/p>\n<p>The first obvious place to make this map dynamic is the lat, lng. Presumably you will have a variable declared in the controller that has a latitude and longitude associated with it, or perhaps you even have latitude and longitude variables available. In my case, I have @contact defined in the show action of my contacts controller as an instance of the contact class. Each contact instance has a latitude and longitude associated with it, based on the address input by the user (using Geocoder to look them up); from the create action:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-theme=\"twilight\" data-enlighter-language=\"ruby\">city = Geocoder.search(params[:address])\r\ncontact.latitude = city[0].latitude\r\ncontact.longitude = city[0].longitude<\/pre>\n<p>So on the show view, the latitude and longitude would be accessible via @contact.latitude and @contact.longitude (respectively). <a href=\"https:\/\/github.com\/laserlemon\/figaro\">And be sure to define your Google API key in the environmental variable hash<\/a>, so you don&#8217;t go pushing that key up anywhere you wouldn&#8217;t want it to go. Actually, better go do that first.<\/p>\n<p>Now you can put in your environmental variable for your API key, as well as embedded Ruby for your latitude and longitude:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-theme=\"twilight\" data-enlighter-language=\"js\">&lt;script&gt;\r\n      var map;\r\n      function initMap() {\r\n        var myLatLng = {lat: &lt;%= @contact.latitude %&gt;, lng: &lt;%= @contact.longitude %&gt;};\r\n\r\n        map = new google.maps.Map(document.getElementById('map'), {\r\n          center: myLatLng,\r\n          zoom: 12\r\n        });\r\n      }\r\n    &lt;\/script&gt;\r\n    &lt;script src=\"https:\/\/maps.googleapis.com\/maps\/api\/js?key=&lt;%= ENV[\"google_key\"] %&gt;&amp;callback=initMap\"\r\n    async defer&gt;&lt;\/script&gt;<\/pre>\n<p>That will make a simple map centered on your latitude and longitude. But obviously, what we all really want is a marker. So, let us put in a marker!<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-theme=\"twilight\" data-enlighter-language=\"js\">&lt;script&gt;\r\n  var map;\r\n  function initMap() {\r\n    var myLatLng = {lat: &lt;%= @contact.latitude %&gt;, lng: &lt;%= @contact.longitude %&gt;};\r\n\r\n    map = new google.maps.Map(document.getElementById('map'), {\r\n      center: myLatLng,\r\n      zoom: 12\r\n    });\r\n\r\n    \/\/ makes a marker\r\n    var marker = new google.maps.Marker({\r\n      position: myLatLng, \/\/at your latitude and longitude\r\n      map: map, \/\/on the map called map\r\n    });\r\n  }\r\n&lt;\/script&gt;\r\n&lt;script src=\"https:\/\/maps.googleapis.com\/maps\/api\/js?key=&lt;%= ENV[\"google_key\"] %&gt;&amp;callback=initMap\"\r\nasync defer&gt;&lt;\/script&gt;<\/pre>\n<p>Feel free to play around with the zoom until you get it to where you like it. I find that 12 is pretty good for a single marker, but your tastes\/needs may vary. The higher the number, the higher the zoom. So zoom: 1 will basically give you a map of the whole world. Which, maybe you want!<\/p>\n<p>But now, what if you have a bunch of markers, and you want to adjust the center\/zoom based on them? Obviously you wouldn&#8217;t be able to just use one marker&#8217;s latitude and longitude to determine the center anymore. Well, there is a simple way to do this, too! All you need to do is define a LatLngBounds variable, and then use the extend and fitBounds methods. For this example, I put the map in the contacts index, so there would be multiple lat, long coordinates to play with:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-theme=\"twilight\" data-enlighter-language=\"js\">&lt;script&gt;\r\n   var map;\r\n   function initMap() {\r\n     var contacts = &lt;%= raw @script_contacts %&gt;;\r\n \r\n     var bounds = new google.maps.LatLngBounds(); \/\/these will define the bounds of your map\r\n     map = new google.maps.Map(document.getElementById('map'), {}); \/\/this makes your map caled map\r\n\r\n     for (var i = 0; i &lt; contacts.length; i++) { \/\/Iterate over all the contacts\r\n       var contact = JSON.parse(contacts[i]);\r\n       var marker = new google.maps.Marker({ \/\/Make a marker for each contact as you iterate\r\n         position: {lat: contact.latitude, lng: contact.longitude},\r\n         map: map,\r\n       });\r\n       bounds.extend(marker.position); \/\/will extend your bounds each time a contact is added\r\n     } \r\n \r\n     \/\/refit the map to the bounds as defined in your each loop\r\n     map.fitBounds(bounds);\r\n    }\r\n &lt;\/script&gt;<\/pre>\n<p>Et voila! It really is that easy. And now you have a map that will re-center\/re-zoom to fit\/show all the markers on it. If you want to force the zoom to a certain level, and only let the centering change, all you have to do is define the zoom anywhere after you use the fitBounds method on your map. I don&#8217;t really like forcing the zoom, though, I find I like it best when the map finds it own zoom.<\/p>\n<p>Oh, yea, and this is what happens when you use the Faker gem to randomly generate a bunch of latitudes and longitudes for a bunch of randomly generated contacts&#8230; you get contacts\u00a0in the middle of the ocean, lol:<\/p>\n<figure id=\"attachment_1071\" aria-describedby=\"caption-attachment-1071\" style=\"width: 640px\" class=\"wp-caption alignnone\"><a href=\"http:\/\/www.certainly-strange.com\/wp-content\/uploads\/2016\/08\/Screen-Shot-2016-08-06-at-12.28.10-PM.png\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-1071 size-large\" src=\"http:\/\/www.certainly-strange.com\/wp-content\/uploads\/2016\/08\/Screen-Shot-2016-08-06-at-12.28.10-PM-1024x639.png\" alt=\"map of randomly generated locations\" width=\"640\" height=\"399\" srcset=\"http:\/\/www.certainly-strange.com\/wp-content\/uploads\/2016\/08\/Screen-Shot-2016-08-06-at-12.28.10-PM-1024x639.png 1024w, http:\/\/www.certainly-strange.com\/wp-content\/uploads\/2016\/08\/Screen-Shot-2016-08-06-at-12.28.10-PM-300x187.png 300w, http:\/\/www.certainly-strange.com\/wp-content\/uploads\/2016\/08\/Screen-Shot-2016-08-06-at-12.28.10-PM-768x479.png 768w, http:\/\/www.certainly-strange.com\/wp-content\/uploads\/2016\/08\/Screen-Shot-2016-08-06-at-12.28.10-PM.png 2020w\" sizes=\"auto, (max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 984px) 61vw, (max-width: 1362px) 45vw, 600px\" \/><\/a><figcaption id=\"caption-attachment-1071\" class=\"wp-caption-text\">You&#8217;d be surprised at how many people live in the middle of the ocean these days<\/figcaption><\/figure>\n<p>But I got sick of manually entering actual addresses,\u00a0so now I have ocean contacts. This is the generally-accepted tradeoff.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I&#8217;ve recently been playing around with the Google Maps Javascript API\u00a0in my Rails web \u00a0apps to make some simple maps. Google&#8217;s documentation on this is very very good, so in most cases I&#8217;d recommend you start there to figure out how to make the map you want. Nonetheless, I thought I&#8217;d write up a quick &hellip; <a href=\"http:\/\/www.certainly-strange.com\/?p=1068\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Using the Google Maps Javascript API&#8221;<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_crdt_document":"","footnotes":""},"categories":[373,361,374,362],"tags":[],"class_list":["post-1068","post","type-post","status-publish","format-standard","hentry","category-javascript","category-programming","category-rails","category-ruby"],"_links":{"self":[{"href":"http:\/\/www.certainly-strange.com\/index.php?rest_route=\/wp\/v2\/posts\/1068","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.certainly-strange.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.certainly-strange.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.certainly-strange.com\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/www.certainly-strange.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1068"}],"version-history":[{"count":8,"href":"http:\/\/www.certainly-strange.com\/index.php?rest_route=\/wp\/v2\/posts\/1068\/revisions"}],"predecessor-version":[{"id":1089,"href":"http:\/\/www.certainly-strange.com\/index.php?rest_route=\/wp\/v2\/posts\/1068\/revisions\/1089"}],"wp:attachment":[{"href":"http:\/\/www.certainly-strange.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1068"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.certainly-strange.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1068"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.certainly-strange.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1068"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}