├── js ├── search.js ├── html5shiv.min.js └── map.js ├── README.md ├── css ├── reset.css └── style.css └── index.html /js/search.js: -------------------------------------------------------------------------------- 1 | $(function() { 2 | $( "#searchZip" ).click(function() { 3 | $("#searchZip").hide(); 4 | $( ".zipSearch" ).show(); 5 | }); 6 | }); -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | SeedTip 2 | ======= 3 | 4 | Find your local farmers markets (U.S. only) 5 | 6 | I threw this together to learn the Google Map API. The script will pull data from the USDA API and use 7 | the Google Maps API to display the closest locations. 8 | 9 | A basic, responsive front end is included. 10 | 11 | See a live working sample at www.seedtip.com 12 | 13 | View the 4 part tutorial on YouTube
14 | Part 1 - https://www.youtube.com/watch?v=lVhDux1vmIU
15 | Part 2 - https://www.youtube.com/watch?v=ygNn7P-Fas4
16 | Part 3 - https://www.youtube.com/watch?v=vImMDfaqA2A
17 | Part 4 - https://www.youtube.com/watch?v=Hv76o8PEKwk
18 | -------------------------------------------------------------------------------- /css/reset.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Eric Meyer's Reset CSS v2.0 (http://meyerweb.com/eric/tools/css/reset/) 3 | * http://cssreset.com 4 | */ 5 | html, body, div, span, applet, object, iframe, 6 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, 7 | a, abbr, acronym, address, big, cite, code, 8 | del, dfn, em, img, ins, kbd, q, s, samp, 9 | small, strike, strong, sub, sup, tt, var, 10 | b, u, center, 11 | dl, dt, dd, ol, ul, li, 12 | fieldset, form, label, legend, 13 | table, caption, tbody, tfoot, thead, tr, th, td, 14 | article, aside, canvas, details, embed, 15 | figure, figcaption, footer, header, hgroup, 16 | menu, nav, output, ruby, section, summary, 17 | time, mark, audio, video { 18 | margin: 0; 19 | padding: 0; 20 | border: 0; 21 | font-size: 100%; 22 | font: inherit; 23 | vertical-align: baseline; 24 | } 25 | /* HTML5 display-role reset for older browsers */ 26 | article, aside, details, figcaption, figure, 27 | footer, header, hgroup, menu, nav, section { 28 | display: block; 29 | } 30 | body { 31 | line-height: 1; 32 | } 33 | ol, ul { 34 | list-style: none; 35 | } 36 | blockquote, q { 37 | quotes: none; 38 | } 39 | blockquote:before, blockquote:after, 40 | q:before, q:after { 41 | content: ''; 42 | content: none; 43 | } 44 | table { 45 | border-collapse: collapse; 46 | border-spacing: 0; 47 | } -------------------------------------------------------------------------------- /js/html5shiv.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @preserve HTML5 Shiv 3.7.2 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed 3 | */ 4 | !function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.2",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML="",k="hidden"in a,l=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){k=!0,l=!0}}();var t={elements:n.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:n.shivCSS!==!1,supportsUnknownElements:l,shivMethods:n.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=t,j(b)}(this,document); -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Find Local Farmers Markets 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 |

Find Local Farmers Markets

31 |

We'll help you locate your closest farmers markets. Simply choose an option below to begin...

32 |
33 | 34 | 35 |
36 |
37 | 38 | 39 |
40 |
41 |
42 | 43 |

If you've found SeedTip helpful, please help spread the word!

44 | 45 |
46 | 47 | 51 | 52 | 55 | 56 | 57 |
58 |
59 |
60 |

A project by Paul Dessert.

61 |
62 | 63 | 64 |
65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /css/style.css: -------------------------------------------------------------------------------- 1 | 2 | /* Global styles */ 3 | html, body { 4 | height: 100%; 5 | margin: 0px; 6 | padding: 0px 7 | } 8 | 9 | 10 | body { 11 | font-family: "Open Sans", sans-serif; 12 | /* font-family: 'Libre Baskerville', serif; */ 13 | color: #686868; 14 | font-size: 15px; 15 | background-color: #6B7283; 16 | } 17 | 18 | 19 | .clearfix:after { 20 | content: " "; 21 | display: block; 22 | height: 0; 23 | clear: both; 24 | } 25 | 26 | .clear{ 27 | clear: both; 28 | } 29 | 30 | a { 31 | text-decoration: none; 32 | color: #79accd; 33 | } 34 | 35 | a:hover { 36 | color: #79accd; 37 | text-decoration: underline; 38 | } 39 | 40 | h1, h2, h3, h4, h5, h6 { 41 | margin-bottom: 17px; 42 | font-weight: 300; 43 | /* color: #ff5400; */ 44 | } 45 | 46 | h1 { 47 | font-size: 28px; 48 | } 49 | 50 | h2 { 51 | font-size: 26px; 52 | } 53 | 54 | h3 { 55 | font-size: 24px; 56 | margin-bottom: 15px; 57 | } 58 | 59 | ul{ 60 | list-style-type: square; 61 | margin-left: 60px; 62 | margin-bottom: 30px; 63 | } 64 | 65 | ul li{ 66 | line-height: 1.9; 67 | } 68 | 69 | 70 | .zipSearch{ 71 | display: none; 72 | } 73 | 74 | /* Popup */ 75 | .markerPop{ 76 | 77 | } 78 | 79 | 80 | .twitter{ 81 | float: left; 82 | } 83 | 84 | .facebook{ 85 | float: left; 86 | width: 150px !important; 87 | height: 35px !important; 88 | } 89 | 90 | /* tablets and desktop */ 91 | @media only screen and (min-width: 361px) { 92 | 93 | p { 94 | margin-bottom: 15px; 95 | line-height: 20px; 96 | } 97 | 98 | #map-canvas{ 99 | height: 100%; 100 | } 101 | #control{ 102 | float: left; 103 | color: #D8D8DD; 104 | width: 15%; 105 | padding: 50px 30px 10px 30px; 106 | border-right: 1px solid black; 107 | } 108 | 109 | #control input[type=text]{ 110 | width: 100%; 111 | height: 40px; 112 | font-size: 24px; 113 | background-color: #6B7283; 114 | border: 1px solid #BE757E; 115 | } 116 | 117 | .learnButton { 118 | margin-top: 10px; 119 | margin-bottom: 20px; 120 | background: #BE757E; 121 | border: 0; 122 | color: #D8D8DD; 123 | height: 37px; 124 | line-height: 37px; 125 | width: 100%; 126 | text-align: center; 127 | cursor: pointer; 128 | } 129 | 130 | #mc_embed_signup{ 131 | margin-top: 30px; 132 | float: left; 133 | width: 300px; 134 | } 135 | 136 | #mc_embed_signup form label{ 137 | margin-bottom: 30px; 138 | line-height: 20px; 139 | clear: right; 140 | } 141 | 142 | #mc_embed_signup form input.email{ 143 | width: 100%; 144 | height: 40px; 145 | font-size: 24px; 146 | background-color: #6B7283; 147 | border: 1px solid #BE757E; 148 | } 149 | } 150 | 151 | /* phones */ 152 | @media only screen and (max-width: 360px) { 153 | 154 | p { 155 | margin-bottom: 10px; 156 | line-height: 26px; 157 | } 158 | 159 | #map-canvas{ 160 | height: 100%; 161 | } 162 | 163 | #control{ 164 | color: #D8D8DD; 165 | padding: 20px 30px 10px 30px; 166 | } 167 | 168 | #control input[type=text]{ 169 | width: 100%; 170 | height: 40px; 171 | font-size: 24px; 172 | background-color: #6B7283; 173 | border: 1px solid #BE757E; 174 | } 175 | 176 | .learnButton { 177 | float: left; 178 | margin: 0px 10px 0px 10px; 179 | margin-top: 20px; 180 | margin-bottom: 20px; 181 | background: #BE757E; 182 | border: 0; 183 | color: #D8D8DD; 184 | height: 37px; 185 | line-height: 37px; 186 | width: 40%; 187 | text-align: center; 188 | } 189 | 190 | #mc_embed_signup{ 191 | display: none; 192 | } 193 | 194 | #mc_embed_signup form label{ 195 | margin-bottom: 30px; 196 | line-height: 20px; 197 | clear: right; 198 | } 199 | 200 | #mc_embed_signup form input.email{ 201 | width: 100%; 202 | height: 40px; 203 | font-size: 24px; 204 | background-color: #6B7283; 205 | border: 1px solid #BE757E; 206 | } 207 | } 208 | 209 | 210 | -------------------------------------------------------------------------------- /js/map.js: -------------------------------------------------------------------------------- 1 | /* Pull local Farers market data from the USDA API and display on 2 | ** Google Maps using GeoLocation or user input zip code. By Paul Dessert 3 | ** www.pauldessert.com | www.seedtip.com 4 | */ 5 | 6 | $(function() { 7 | 8 | var marketId = []; //returned from the API 9 | var allLatlng = []; //returned from the API 10 | var allMarkers = []; //returned from the API 11 | var marketName = []; //returned from the API 12 | var infowindow = null; 13 | var pos; 14 | var userCords; 15 | var tempMarkerHolder = []; 16 | 17 | //Start geolocation 18 | 19 | if (navigator.geolocation) { 20 | 21 | function error(err) { 22 | console.warn('ERROR(' + err.code + '): ' + err.message); 23 | } 24 | 25 | function success(pos){ 26 | userCords = pos.coords; 27 | 28 | //return userCords; 29 | } 30 | 31 | // Get the user's current position 32 | navigator.geolocation.getCurrentPosition(success, error); 33 | //console.log(pos.latitude + " " + pos.longitude); 34 | } else { 35 | alert('Geolocation is not supported in your browser'); 36 | } 37 | 38 | //End Geo location 39 | 40 | //map options 41 | var mapOptions = { 42 | zoom: 5, 43 | center: new google.maps.LatLng(37.09024, -100.712891), 44 | panControl: false, 45 | panControlOptions: { 46 | position: google.maps.ControlPosition.BOTTOM_LEFT 47 | }, 48 | zoomControl: true, 49 | zoomControlOptions: { 50 | style: google.maps.ZoomControlStyle.LARGE, 51 | position: google.maps.ControlPosition.RIGHT_CENTER 52 | }, 53 | scaleControl: false 54 | 55 | }; 56 | 57 | //Adding infowindow option 58 | infowindow = new google.maps.InfoWindow({ 59 | content: "holding..." 60 | }); 61 | 62 | //Fire up Google maps and place inside the map-canvas div 63 | map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions); 64 | 65 | //grab form data 66 | $('#chooseZip').submit(function() { // bind function to submit event of form 67 | 68 | //define and set variables 69 | var userZip = $("#textZip").val(); 70 | //console.log("This-> " + userCords.latitude); 71 | 72 | var accessURL; 73 | 74 | if(userZip){ 75 | accessURL = "http://search.ams.usda.gov/farmersmarkets/v1/data.svc/zipSearch?zip=" + userZip; 76 | } else { 77 | accessURL = "http://search.ams.usda.gov/farmersmarkets/v1/data.svc/locSearch?lat=" + userCords.latitude + "&lng=" + userCords.longitude; 78 | } 79 | 80 | 81 | //Use the zip code and return all market ids in area. 82 | $.ajax({ 83 | type: "GET", 84 | contentType: "application/json; charset=utf-8", 85 | url: accessURL, 86 | dataType: 'jsonp', 87 | success: function (data) { 88 | 89 | $.each(data.results, function (i, val) { 90 | marketId.push(val.id); 91 | marketName.push(val.marketname); 92 | }); 93 | 94 | //console.log(marketName); 95 | 96 | var counter = 0; 97 | //Now, use the id to get detailed info 98 | $.each(marketId, function (k, v){ 99 | $.ajax({ 100 | type: "GET", 101 | contentType: "application/json; charset=utf-8", 102 | // submit a get request to the restful service mktDetail. 103 | url: "http://search.ams.usda.gov/farmersmarkets/v1/data.svc/mktDetail?id=" + v, 104 | dataType: 'jsonp', 105 | success: function (data) { 106 | 107 | for (var key in data) { 108 | 109 | var results = data[key]; 110 | 111 | //console.log(results); 112 | 113 | //The API returns a link to Google maps containing lat and long. This pulls it apart. 114 | var googleLink = results['GoogleLink']; 115 | var latLong = decodeURIComponent(googleLink.substring(googleLink.indexOf("=")+1, googleLink.lastIndexOf("("))); 116 | 117 | var split = latLong.split(','); 118 | 119 | //covert values to floats, to play nice with .LatLng() below. 120 | var latitude = parseFloat(split[0]); 121 | var longitude = parseFloat(split[1]); 122 | 123 | //set the markers. 124 | myLatlng = new google.maps.LatLng(latitude,longitude); 125 | 126 | allMarkers = new google.maps.Marker({ 127 | position: myLatlng, 128 | map: map, 129 | title: marketName[counter], 130 | html: 131 | '
' + 132 | '

' + marketName[counter].substring(4) + '

' + //substring removes distance from title 133 | '

' + results['Address'] + '

' + 134 | '

' + results['Products'].split(';') + '

' + 135 | '

' + results['Schedule'] + '

' + 136 | '
' 137 | }); 138 | 139 | //put all lat long in array 140 | allLatlng.push(myLatlng); 141 | 142 | //Put the marketrs in an array 143 | tempMarkerHolder.push(allMarkers); 144 | 145 | counter++; 146 | //console.log(counter); 147 | }; 148 | 149 | google.maps.event.addListener(allMarkers, 'click', function () { 150 | infowindow.setContent(this.html); 151 | infowindow.open(map, this); 152 | }); 153 | 154 | 155 | //console.log(allLatlng); 156 | // Make an array of the LatLng's of the markers you want to show 157 | // Create a new viewpoint bound 158 | var bounds = new google.maps.LatLngBounds (); 159 | // Go through each... 160 | for (var i = 0, LtLgLen = allLatlng.length; i < LtLgLen; i++) { 161 | // And increase the bounds to take this point 162 | bounds.extend (allLatlng[i]); 163 | } 164 | // Fit these bounds to the map 165 | map.fitBounds (bounds); 166 | 167 | 168 | } 169 | }); 170 | }); //end .each 171 | } 172 | }); 173 | 174 | return false; // important: prevent the form from submitting 175 | }); 176 | }); 177 | 178 | --------------------------------------------------------------------------------