1 2let map, markers = [], userLocation = null; 3 4function initMap() { 5 const center = { lat: 39.8283, lng: -98.5795 }; 6 map = new google.maps.Map(document.getElementById("map"), { 7 zoom: 4, 8 center, 9 }); 10 11 initSearchBar(); 12 populateDropdowns(); 13 renderMarkers(DiveRiteData.stores); 14} 15 16function initSearchBar() { 17 const input = document.createElement("input"); 18 input.id = "location-search"; 19 input.placeholder = "Enter a location"; 20 input.className = "search-box"; 21 document.querySelector(".filter-bar").prepend(input); 22 23 const radius = document.createElement("select"); 24 radius.id = "search-radius"; 25 [5, 10, 25, 50, 100].forEach(miles => { 26 const opt = document.createElement("option"); 27 opt.value = miles; 28 opt.textContent = `${miles} mi`; 29 radius.appendChild(opt); 30 }); 31 document.querySelector(".filter-bar").prepend(radius); 32 33 const autocomplete = new google.maps.places.Autocomplete(input); 34 autocomplete.addListener("place_changed", () => { 35 const place = autocomplete.getPlace(); 36 if (place.geometry) { 37 userLocation = place.geometry.location; 38 updateMap(); 39 } 40 }); 41} 42 43function populateDropdowns() { 44 const countrySel = document.getElementById("filter-country"); 45 const stateSel = document.getElementById("filter-state"); 46 const citySel = document.getElementById("filter-city"); 47 48 const countries = [...new Set(DiveRiteData.stores.map(s => s.country))].sort((a, b) => { 49 if (a === "United States") return -1; 50 if (b === "United States") return 1; 51 return a.localeCompare(b); 52 }); 53 54 countries.forEach(c => { 55 const opt = document.createElement("option"); 56 opt.value = c; 57 opt.textContent = c; 58 countrySel.appendChild(opt); 59 }); 60 61 countrySel.addEventListener("change", () => { 62 const country = countrySel.value; 63 const states = [...new Set(DiveRiteData.stores.filter(s => s.country === country).map(s => s.state))].sort(); 64 stateSel.innerHTML = "<option value=''>All States</option>"; 65 states.forEach(st => { 66 const opt = document.createElement("option"); 67 opt.value = st; 68 opt.textContent = st; 69 stateSel.appendChild(opt); 70 }); 71 citySel.innerHTML = "<option value=''>All Cities</option>"; 72 updateMap(); 73 }); 74 75 stateSel.addEventListener("change", () => { 76 const country = countrySel.value; 77 const state = stateSel.value; 78 const cities = [...new Set(DiveRiteData.stores.filter(s => s.country === country && s.state === state).map(s => s.city))].sort(); 79 citySel.innerHTML = "<option value=''>All Cities</option>"; 80 cities.forEach(ct => { 81 const opt = document.createElement("option"); 82 opt.value = ct; 83 opt.textContent = ct; 84 citySel.appendChild(opt); 85 }); 86 updateMap(); 87 }); 88 89 citySel.addEventListener("change", updateMap); 90} 91 92function updateMap() { 93 const country = document.getElementById("filter-country").value; 94 const state = document.getElementById("filter-state").value; 95 const city = document.getElementById("filter-city").value; 96 const radius = parseFloat(document.getElementById("search-radius").value || 100); 97 98 const filtered = DiveRiteData.stores.filter(s => { 99 const matchCountry = !country || s.country === country; 100 const matchState = !state || s.state === state; 101 const matchCity = !city || s.city === city; 102 const matchRadius = !userLocation || haversineDistance(userLocation.lat(), userLocation.lng(), s.lat, s.lng) <= radius; 103 return matchCountry && matchState && matchCity && matchRadius; 104 }); 105 106 renderMarkers(filtered); 107} 108 109function renderMarkers(stores) { 110 markers.forEach(m => m.setMap(null)); 111 markers = []; 112 113 const bounds = new google.maps.LatLngBounds(); 114 const list = document.getElementById("store-list"); 115 list.innerHTML = ""; 116 117 stores.forEach(store => { 118 119 120 const pos = { lat: parseFloat(store.lat), lng: parseFloat(store.lng) }; 121 console.log("Marker Position:", pos); 122 const marker = new google.maps.Marker({ 123 position: pos, 124 map, 125 title: store.title ? store.title.trim() : "Dealer", 126 }); 127 markers.push(marker); 128 bounds.extend(pos); 129 130 const infoWindow = new google.maps.InfoWindow({ 131 content: `
132 <div style="min-width:200px"> 133 <strong>${store.title || 'Dealer'}</strong><br> 134 ${store.street}, ${store.city}, ${store.state} ${store.postal_code}<br> 135 <a href="tel:${store.phone}">${store.phone}</a><br> 136 <a href="https://maps.google.com/?q=${store.lat},${store.lng}" target="_blank">Directions</a> 137 </div> 138 ` 139 }); 140 marker.addListener("click", () => { 141 infoWindow.open(map, marker); 142 }); 143 144 const item = document.createElement("div"); 145 item.className = "store-item"; 146 item.innerHTML = ` 147 <strong>${store.title || 'Dealer'}</strong><br> 148 ${store.street}, ${store.city}, ${store.state} ${store.postal_code}<br> 149 <a href="tel:${store.phone}">${store.phone}</a><br> 150 <a href="https://maps.google.com/?q=${store.lat},${store.lng}" target="_blank">Directions</a> 151 `; 152 list.appendChild(item); 153 }); 154 155 if (stores.length > 0) { 156 map.fitBounds(bounds); 157 } 158} 159 160function haversineDistance(lat1, lon1, lat2, lon2) { 161 function toRad(x) { return x * Math.PI / 180; } 162 const R = 3958.8; // Miles 163 const dLat = toRad(lat2 - lat1); 164 const dLon = toRad(lon2 - lon1); 165 const a = Math.sin(dLat / 2) ** 2 + 166 Math.cos(toRad(lat1)) * Math.cos(toRad(lat2)) * 167 Math.sin(dLon / 2) ** 2; 168 return R * (2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a))); 169} 170 171 172window.addEventListener("load", () => { 173 initMap(); 174 if (navigator.geolocation) { 175 navigator.geolocation.getCurrentPosition( 176 (pos) => { 177 userLocation = new google.maps.LatLng(pos.coords.latitude, pos.coords.longitude); 178 updateMap(); 179 }, 180 (err) => { 181 console.warn("Geolocation failed or blocked:", err.message); 182 } 183 ); 184 } 185}); 186
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.