PageRenderTime 66ms CodeModel.GetById 34ms RepoModel.GetById 0ms app.codeStats 0ms

/index.html

https://gitlab.com/vschmidt94/CS494-HowTo-Leaflet-map
HTML | 236 lines | 218 code | 13 blank | 5 comment | 0 complexity | b92e76a4ac7088fb46efc49164d9489a MD5 | raw file
  1. <!DOCTYPE html>
  2. <!-- Name: C. Vaughan Schmidt
  3. email: schmicar@onid.oregonstate.edu
  4. course: CS494-400 Fall 2014
  5. Assignment: Week 5 - Intro to PHP
  6. -->
  7. <meta charset="utf-8">
  8. <meta name="viewport" content="width=device-width, initial-scale=1">
  9. <title>schmicar HowTo</title>
  10. <link rel="stylesheet" href="css/style.css">
  11. <link rel="stylesheet" href="css/bootstrap.css">
  12. <link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.css" />
  13. <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
  14. <script src="js/bootstrap.js"></script>
  15. <script src="http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.js"></script>
  16. <script src="js/Leaflet.MakiMarkers.js"></script>
  17. <script src="js/getLoc.js"></script>
  18. <script src="js/leaflet.GeometryUtil.js"></script>
  19. <script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/gist-embed/1.9/gist-embed.min.js"></script>
  20. </head>
  21. </head>
  22. <body data-spy="scroll" data-target="#myScollspy">
  23. <div class="container">
  24. <div class="jumbotron">
  25. <h2>HowTo: Web Scraping + Leaflet.js</h2>
  26. </div>
  27. <div class="row" >
  28. <div class="col-xs-3" id="myScrollspy">
  29. <ul class="nav nav-tabs nav-stacked" data-spy="affix" data-offset-top="150" data-offset-bottom="0">
  30. <li><a href="#section-1">Motivation</a></li>
  31. <li><a href="#section-2">Web Scraping</a></li>
  32. <li><a href="#section-3">Leaflet.js Intro</a></li>
  33. <li><a href="#section-4">Markers &amp; Popups</a></li>
  34. <li><a href="#section-5">Where You At?</a></li>
  35. <li><a href="#section-6">Nearest Neighbor</a></li>
  36. <li><a href="#section-7">Recap</a></li>
  37. </ul>
  38. </div>
  39. <div class="col-xs-9" id="content" style="background-color:white;">
  40. <h2 id="section-1">Motivation</h2>
  41. <h4 class="highlighted2">Note: This guide is not a deep dive into any one single library or technique, but rather the intent is to show how to utilize several libraries and techniques in concert to achieve the result of mapping landmarks on the OSU campus - starting from scratch.</h4>
  42. <p>
  43. This how-to guide was developed for my CS494 Web Development class requirements. My personal objective was to combine what was learned in CS494 Databases with the database project I am also working on.
  44. </p>
  45. <p>
  46. The database project is working towards producing a useful database of all the public artwork installed across the Oregon State University campus in Corvallis, OR. There is a substantial amount of uncatalogged artwork across campus that has been installed as student projects, or even as part of funded projects, but very few of these pieces are even identified or contain the artist's name or other details.
  47. </p>
  48. <p>
  49. Ultimately, it would be a nice to have a mash-up of picture handling, mapping &amp; GIS services so that the end user could locate nearby artwork from their mobile device. Additionally, in the case of user-submitted pictures as content, the pictures could be geographically located as well as possibly validated that the picture was indeed taken in the vicinity of Corvallis.
  50. </p>
  51. </p>
  52. The general steps shown in this HowTo document achieves much of this functionality.
  53. </p>
  54. <h3>Relevant XKCD</h3>
  55. <img src="http://imgs.xkcd.com/comics/tasks.png" class="img-responsive inline-block" alt="xkcd comic">
  56. <p style="text-align:center;">
  57. Image credit: http://xkcd.com/1425/
  58. <hr>
  59. <h2 id="section-2">Web Scraping the OSU Map</h2>
  60. <p>
  61. In discussing the database project for CS275, I immediately found myself using the
  62. <a href="http://oregonstate.edu/campusmap/">OSU Campus Map</a> to orient myself and try to get some idea of how the artwork data could be located and visualized.
  63. </p>
  64. <p>
  65. As soon as I began using the online campus map, it's quickly apparent there is already a LOT of data published to the web for all the major (and minor) campus landmarks. Exploring the OSU online map leads to
  66. several discoveries:
  67. </p>
  68. <ul><li>OSU has unique location codes for *everything*
  69. <ul><li>Parking lots</li>
  70. <li>Buildings</li>
  71. <li>WiFi Hotspots</li>
  72. </ul>
  73. </li>
  74. <li>OSU uses Google's map api's</li>
  75. <li><strong>Somewhere, there must also be a database with additional information, such as building accessibility details, as some buildings have additional information available.</strong>
  76. <ul><li>Example: Selecting the Women's Building on the online map</li></ul>
  77. </li>
  78. </ul>
  79. <p id='video1'>
  80. It's much easier to show in a video how I went about discovering / uncovering the AJAX requests and JSON responses that the OSU Campus Map uses.
  81. </p>
  82. <iframe width="420" height="315" src="//www.youtube.com/embed/QhdgAH7yw2A"
  83. allowfullscreen style="display: block; margin: 0 auto;"></iframe>
  84. <p>
  85. Once the AJAX URL request format &amp; JSON response has been discovered (example: <a href="http://oregonstate.edu/campusmap/map/element?locations=814">http://oregonstate.edu/campusmap/map/element?locations=814</a>), it is straightforward to build a little PHP script to iterate through successive calls to the URL, parse the returned JSON and then recombine just the portions I am interested in.
  86. </p>
  87. The results of the crawler script can be seen here:
  88. <a href="http://web.engr.oregonstate.edu/~schmicar/cs494/HowTo/bldgcrawler.php">
  89. http://web.engr.oregonstate.edu/~schmicar/cs494/HowTo/bldgcrawler.php
  90. </a>.
  91. <p>
  92. The PHP code for the web scraping is listed below.
  93. </p>
  94. <p>
  95. <em>
  96. Note that what I really am after here is a format that can just be appended to a MySQL
  97. </em>
  98. <pre>
  99. INSERT INTO ... VALUES ....
  100. </pre>
  101. <em>
  102. query statement, so that is why I've formatted the output a certain way. You could just as easily format it into JSON or something else. (Also it took a few initial attemps to determine I really was only interested in landmark id's 447-1038...)
  103. </em>
  104. </p>
  105. <h3>bldgcrawler.php Script Listing</h3>
  106. <code data-gist-id="bf53163182bfcbfab579"></code>
  107. <p>
  108. <strong>Disclaimer</strong>: I <em>really</em> should go about getting official OK to use the OSU campus map website in this manner. However, due to expediency of the class projects, and the fact this is education-based &amp; non-commercial, I believe it falls under fair-use provisions of applicable copyright laws. I mention this as a reminder that there might be potential legal issues when it comes to web-scraping and data harvesting.
  109. </p>
  110. <hr>
  111. <h2 id="section-3">Introducing Leaflet.js</h2>
  112. <p>
  113. <a href="http://leafletjs.com/">Leaflet.js</a> "is a modern open-source JavaScript library for mobile-friendly interactive maps." (and from the various mapping API's I checked into, Leaflet looks very user-friendly and understandable...)
  114. </p>
  115. <p>
  116. Before you can use Leaflet.js - you need to go sign up at <a href="http://www.mapbox.com">mapbox.com</a> for your unique Map ID, which Leaflet needs to have to produce maps for the web application. Grab your new Map ID, and you will be ready to go.
  117. </p>
  118. <div id="map1">
  119. </div>
  120. <script src="./js/tutMap1.js"></script>
  121. <p>
  122. Adding the above map to the web page was as simple as adding a div for the map and calling a .js script in the .html file:
  123. </p>
  124. <code data-gist-id="e51148f749953299375a"></code>
  125. <p>
  126. The javascript file contains:
  127. </p>
  128. <code data-gist-id="4f1e97dd1860bcdab14a"></code>
  129. Note that I plugged in some initial latitude / longitude based on the data I had scraped from the OSU online campus map.
  130. <hr>
  131. <h2 id="section-4">Markers &amp; Popups</h2>
  132. <p>
  133. At this point, I would like to add some of my harvested landmarks as
  134. pushpins to the map. Additionally, I am going to have the landmark
  135. open as a popup if a user clicks on the pushpin marker.
  136. </p>
  137. <div id="map2">
  138. </div>
  139. <div>
  140. <script src="./js/tutMap2.js"></script>
  141. </div>
  142. The Javascript code to accomplish this is very straightforward:
  143. <ul>
  144. <li>Add a few landmarks as array of objects (real application would
  145. be using a database for this, just a simple array for demo).
  146. </li>
  147. <li>Loop through the array:
  148. <ul>
  149. <li>Add a leaflet marker (L.marker) for every landmark object.
  150. </li>
  151. <li>Bind a popup to each of the markers.
  152. </li>
  153. </ul>
  154. </li>
  155. </ul>
  156. <code data-gist-id="5b4b82787cd94cbd48a3" data-gist-highlight-line="30-31"></code>
  157. <hr>
  158. <h2 id="section-5">Where You At?</h2>
  159. <p>
  160. Now, let's incorporate the user's position on the map. Most modern browsers are capable of geolocation using something along the lines of:
  161. </p>
  162. <code data-gist-id="d190ba0ec26097726683" data-gist-line="11-18" data-gist-highlight-line="14"></code>
  163. <p> Once we get the user's cordinates (lat, long), now we have everything we need to start putting all the parts together. I've attached the getLocation() to the button below, and when clicked, it will:
  164. </p>
  165. <ol>
  166. <li>Get user location using the navigator.geolocation interface (if available) </li>
  167. <li>Above will set a callback to my showPosition() function where:</li>
  168. <ol><li>Set the innerHTML to display the user's position in text form on web page</li>
  169. <li>Add a leaflet.js map to the page (map3)</li>
  170. <li>Add markers for all my destination landmarks to the map, using the MakiMarkers.js plug-in (gives more colors and glyphs than stock leaflet.js marker)</li>
  171. <li>Add a different MakiMarker (rocket glyph) to the map for the user's location.</li>
  172. <li>Set the map's boundaries such that the proper bounds are selected that will allow ALL markers to display on the map. </li>
  173. <ol><li> To do this, I add all markers to an array, and add the array of markers to a leaflet feature group.</li>
  174. <li>Then, I can call method .fitBounds(group.getBounds().pad(0.5)) to have the map calculate the approriate bounds to encompass the markers.</li>
  175. </ol>
  176. <li>As long as I am here, I go ahead and calculate the nearest neighbor (see below for more on nearest neighbor)</li>
  177. </ol>
  178. </ol>
  179. <h4 class="highlighted2">
  180. <strong>Note that the user should get a popup asking to allow location services, etc.</strong>
  181. </h4>
  182. <div id="getLoc">
  183. <button onclick="getLocation()" class="highlighted">Get My Location!</button>
  184. </div>
  185. <div id="map3">
  186. </div>
  187. <p>
  188. <br>
  189. If you noticed the more colorful markers in the new map, this was done with the Leaflet.MakiMarkers.js plugin. This JavaScript file is
  190. <a href="https://github.com/jseppi/Leaflet.MakiMarkers">available here on GitHub.</a> The bit of code that sets the MakiMarker user location icon (rocket) on the Leaflet map is here:
  191. </p>
  192. <code data-gist-id="d190ba0ec26097726683" data-gist-line="43-46" data-gist-highlight-line="44"></code>
  193. <hr>
  194. <h2 id="section-6">Nearest Neighbor</h2>
  195. <div id="nearestMarker">
  196. </div>
  197. <p>
  198. Finally, as long as I was working with the user's geo location, I went ahead and used another GeometryUtil.js method to return the closest marker to the user's location.
  199. </p>
  200. <p>
  201. It's worth noting that the closest() method returns a simple object just containing the latitude and longitude of the closest marker. I have to take that information, and loop back through my collection of points comparing the lat, long values of each point to the lat, long of the closest to determine which one of my points actually *was* the closest point. Due to the floating point calculations involved in the various manipulations, I test for similarities by allowing a delta variance of under 1E-14 degrees - which in terms of actually feet and inches would be much smaller than a gnat's ass... so I should not be accidently confusing marker points unless they are literally the exact same spot.
  202. </p>
  203. <code data-gist-id="d190ba0ec26097726683" data-gist-line="58-79" data-gist-highlight-line="59"></code>
  204. <hr>
  205. <h2 id="section-7">Recap</h2>
  206. The intent of this section is to provide a quick summary of all the various libraries, tools, etc that were employed to achieve the final result - a map of OSU campus landmarks + the current user geolocation, with the landmark closest to the user identified and distance computed.
  207. <ul>
  208. <li><strong>Chrome Dev Tools</strong> - used to uncover the AJAX calls and JSON responses the official campus map web page is using.</li>
  209. <li><strong>PHP Script</strong> - quick and dirty PHP script to replicate the AJAX calls discovered above. Scans the range of location id's and produces a dataset useable elsewhere.</li>
  210. <li><strong><a href="http://leafletjs.com/">leaflet.js</a></strong> - JavaScript library for easy to use mapping.</li>
  211. <li><strong><a href="https://www.mapbox.com/">mapbox.com</a></strong> - Have to register here to get a map id code. Supplies the map tiles to our leaflet map.</li>
  212. <li><strong><a href="https://developer.mozilla.org/en-US/docs/Web/API/Geolocation">HTML5 Geolocation API</a></strong> - A HTML5 API providing geolocation information ability when used with most modern browsers.</li>
  213. <li><strong><a href="https://github.com/jseppi/Leaflet.MakiMarkers">MakiMarkers.js</a></strong> - A plugin library for leaflet that enhances the markers (pushpins) on the map. Adds color and glyphs</li>
  214. <li><strong><a href="http://makinacorpus.github.io/Leaflet.GeometryUtil/">Leaflet.GeometryUtil.js</a></strong> - A plugin library for leaflet adds a lot of computational function. Used to find the nearest neighbor and distance between a pair of markers.</li>
  215. <li><strong><a href="https://github.com/blairvanderhoof/gist-embed">gist-embed.js</a></strong> - JavaScript Library used on this webpage to provide line highlighting, line slection on embedded GitHub Gist code listings.</li>
  216. <li><strong><a href="http://getbootstrap.com/">bootstrap.js</a></strong> - JavaScript Library used on this webpage to provide the basic webpage framework.</li>
  217. </ul>
  218. <hr>
  219. <h2 id="section-7">Code Listing</h2>
  220. <p>All code used in this project is available at <a href="https://github.com/vschmidt94/CS494-HowTo-Leaflet-map.git">this GitHub Repository</a>. Some GitHub Gists have been used for convenience in the body of this document.
  221. </div>
  222. </div>
  223. </body>