mirthbottle commited on
Commit
37edede
·
verified ·
1 Parent(s): 29393ea

try again to look up tidecharts for the next week and display them below the map - Follow Up Deployment

Browse files
Files changed (1) hide show
  1. index.html +107 -77
index.html CHANGED
@@ -46,30 +46,6 @@
46
  <p class="text-gray-600">Enter any address or place to see it on the map</p>
47
  </div>
48
 
49
- <div id="beachTideInfo" class="bg-blue-50 rounded-xl p-6 mb-8 hidden">
50
- <div class="flex flex-col md:flex-row gap-6">
51
- <div class="flex-1">
52
- <h2 class="text-2xl font-bold text-blue-800 mb-2" id="beachName">Nearby Beach</h2>
53
- <p class="text-blue-600" id="beachDistance">Distance: Calculating...</p>
54
- </div>
55
- <div class="flex-1">
56
- <h3 class="text-lg font-semibold text-blue-700 mb-2">Tide Information</h3>
57
- <div class="grid grid-cols-2 gap-4">
58
- <div class="bg-white p-3 rounded-lg shadow">
59
- <p class="text-sm text-blue-500">Next High Tide</p>
60
- <p id="highTideTime" class="font-medium text-blue-800">-</p>
61
- <p id="highTideHeight" class="text-sm text-blue-600">-</p>
62
- </div>
63
- <div class="bg-white p-3 rounded-lg shadow">
64
- <p class="text-sm text-blue-500">Next Low Tide</p>
65
- <p id="lowTideTime" class="font-medium text-blue-800">-</p>
66
- <p id="lowTideHeight" class="text-sm text-blue-600">-</p>
67
- </div>
68
- </div>
69
- </div>
70
- </div>
71
- </div>
72
-
73
  <div class="location-card bg-white rounded-xl p-6">
74
  <div class="flex flex-col md:flex-row gap-4">
75
  <div class="flex-grow">
@@ -100,24 +76,14 @@
100
  <h3 class="font-semibold text-lg text-gray-800 mb-1">Location Details</h3>
101
  <p id="address" class="text-gray-600"></p>
102
  <p id="coordinates" class="text-sm text-gray-500 mt-1"></p>
103
- <div id="tideInfo" class="mt-4 hidden">
104
- <h3 class="font-semibold text-lg text-gray-800 mb-1">Tide Information</h3>
105
- <div class="grid grid-cols-2 gap-4 mt-2">
106
- <div class="bg-blue-50 p-3 rounded-lg">
107
- <p class="text-sm text-blue-500">Next High Tide</p>
108
- <p id="highTideTime" class="font-medium"></p>
109
- <p id="highTideHeight" class="text-sm text-gray-500"></p>
110
- </div>
111
- <div class="bg-blue-50 p-3 rounded-lg">
112
- <p class="text-sm text-blue-500">Next Low Tide</p>
113
- <p id="lowTideTime" class="font-medium"></p>
114
- <p id="lowTideHeight" class="text-sm text-gray-500"></p>
115
- </div>
116
- </div>
117
- </div>
118
  </div>
119
  </div>
120
 
 
 
 
 
 
121
  <div class="mt-6 text-center text-gray-500 text-sm">
122
  <p>Click the search button or press Enter to find your location</p>
123
  </div>
@@ -172,9 +138,10 @@
172
  document.getElementById('locationInfo').classList.remove('hidden');
173
  document.getElementById('address').textContent = displayName;
174
  document.getElementById('coordinates').textContent = `Latitude: ${lat.toFixed(6)}, Longitude: ${lon.toFixed(6)}`;
 
 
 
175
 
176
- // Check if near coast and fetch tide data
177
- fetchTideData(lat, lon);
178
  } else {
179
  alert('Location not found. Please try a different search term.');
180
  }
@@ -206,47 +173,110 @@
206
  }
207
  }
208
  });
209
- // Function to fetch tide data
210
- async function fetchTideData(lat, lon) {
211
- try {
212
- // First check if location is near coast
213
- const coastlineResponse = await fetch(`https://api.onwater.io/api/v1/results/${lat},${lon}?access_key=demo`);
214
- const coastlineData = await coastlineResponse.json();
215
-
216
- if (coastlineData.water) {
217
- // Get tide data (using WorldTides API - note: you'll need to get your own API key)
218
- const now = Math.floor(Date.now() / 1000);
219
- const tideResponse = await fetch(`https://www.worldtides.info/api/v2?heights&lat=${lat}&lon=${lon}&start=${now}&length=86400&key=YOUR_API_KEY`);
220
- const tideData = await tideResponse.json();
221
 
222
- if (tideData.heights && tideData.heights.length > 0) {
223
- // Find next high and low tides
224
- const nextHigh = tideData.heights.find(h => h.type === 'high');
225
- const nextLow = tideData.heights.find(h => h.type === 'low');
226
-
227
- if (nextHigh && nextLow) {
228
- const formatTime = (timestamp) => {
229
- return new Date(timestamp * 1000).toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'});
230
- };
231
-
232
- document.getElementById('beachTideInfo').classList.remove('hidden');
233
- document.getElementById('highTideTime').textContent = formatTime(nextHigh.dt);
234
- document.getElementById('highTideHeight').textContent = `${nextHigh.height.toFixed(2)}m`;
235
- document.getElementById('lowTideTime').textContent = formatTime(nextLow.dt);
236
- document.getElementById('lowTideHeight').textContent = `${nextLow.height.toFixed(2)}m`;
237
-
238
- // Try to get nearest beach name (simplified example)
239
- const beachResponse = await fetch(`https://nominatim.openstreetmap.org/reverse?format=json&lat=${lat}&lon=${lon}&zoom=10`);
240
- const beachData = await beachResponse.json();
241
- if (beachData.address && beachData.address.tourism === 'beach') {
242
- document.getElementById('beachName').textContent = beachData.display_name || 'Nearby Beach';
243
  }
244
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
245
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
246
  }
247
- } catch (error) {
248
- console.error('Error fetching tide data:', error);
249
- // Silently fail - tide info is optional
250
  }
251
  }
252
  });
 
46
  <p class="text-gray-600">Enter any address or place to see it on the map</p>
47
  </div>
48
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  <div class="location-card bg-white rounded-xl p-6">
50
  <div class="flex flex-col md:flex-row gap-4">
51
  <div class="flex-grow">
 
76
  <h3 class="font-semibold text-lg text-gray-800 mb-1">Location Details</h3>
77
  <p id="address" class="text-gray-600"></p>
78
  <p id="coordinates" class="text-sm text-gray-500 mt-1"></p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
  </div>
80
  </div>
81
 
82
+ <div id="tideInfo" class="location-card bg-white rounded-xl p-6 mt-6 hidden">
83
+ <h3 class="font-semibold text-lg text-gray-800 mb-4">Tide Information</h3>
84
+ <div id="tideChart" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4"></div>
85
+ </div>
86
+
87
  <div class="mt-6 text-center text-gray-500 text-sm">
88
  <p>Click the search button or press Enter to find your location</p>
89
  </div>
 
138
  document.getElementById('locationInfo').classList.remove('hidden');
139
  document.getElementById('address').textContent = displayName;
140
  document.getElementById('coordinates').textContent = `Latitude: ${lat.toFixed(6)}, Longitude: ${lon.toFixed(6)}`;
141
+
142
+ // Check if location is near coast and get tide data
143
+ getTideData(lat, lon);
144
 
 
 
145
  } else {
146
  alert('Location not found. Please try a different search term.');
147
  }
 
173
  }
174
  }
175
  });
176
+ // Function to get tide data from NOAA API
177
+ function getTideData(lat, lon) {
178
+ // First get the nearest tide station
179
+ fetch(`https://api.tidesandcurrents.noaa.gov/mdapi/prod/webapi/stations.json?type=tidepredictions&units=metric`)
180
+ .then(response => response.json())
181
+ .then(data => {
182
+ // Find nearest station
183
+ let nearestStation = null;
184
+ let minDistance = Infinity;
 
 
 
185
 
186
+ data.stations.forEach(station => {
187
+ if (station.lat && station.lng) {
188
+ const distance = getDistance(lat, lon, parseFloat(station.lat), parseFloat(station.lng));
189
+ if (distance < minDistance && distance < 100) { // Within 100km
190
+ minDistance = distance;
191
+ nearestStation = station;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
192
  }
193
  }
194
+ });
195
+
196
+ if (nearestStation) {
197
+ // Get tide predictions for next 7 days
198
+ const today = new Date();
199
+ const endDate = new Date();
200
+ endDate.setDate(today.getDate() + 7);
201
+
202
+ const dateFormat = (d) => d.toISOString().split('T')[0];
203
+ const stationId = nearestStation.id;
204
+
205
+ fetch(`https://api.tidesandcurrents.noaa.gov/api/prod/datagetter?product=predictions&application=NOS.COOPS.TAC.WL&begin_date=${dateFormat(today)}&end_date=${dateFormat(endDate)}&datum=MLLW&station=${stationId}&time_zone=lst_ldt&units=english&interval=hilo&format=json`)
206
+ .then(response => response.json())
207
+ .then(tideData => {
208
+ displayTideData(tideData, nearestStation.name);
209
+ })
210
+ .catch(error => {
211
+ console.error('Tide data error:', error);
212
+ });
213
+ } else {
214
+ document.getElementById('tideInfo').classList.add('hidden');
215
+ }
216
+ })
217
+ .catch(error => {
218
+ console.error('Station data error:', error);
219
+ });
220
+ }
221
+
222
+ // Helper function to calculate distance between coordinates
223
+ function getDistance(lat1, lon1, lat2, lon2) {
224
+ const R = 6371; // Earth radius in km
225
+ const dLat = (lat2 - lat1) * Math.PI / 180;
226
+ const dLon = (lon2 - lon1) * Math.PI / 180;
227
+ const a =
228
+ Math.sin(dLat/2) * Math.sin(dLat/2) +
229
+ Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) *
230
+ Math.sin(dLon/2) * Math.sin(dLon/2);
231
+ const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
232
+ return R * c;
233
+ }
234
+
235
+ // Function to display tide data
236
+ function displayTideData(tideData, stationName) {
237
+ const tideContainer = document.getElementById('tideChart');
238
+ tideContainer.innerHTML = '';
239
+
240
+ if (tideData.predictions && tideData.predictions.length > 0) {
241
+ document.getElementById('tideInfo').classList.remove('hidden');
242
+
243
+ // Group predictions by date
244
+ const predictionsByDate = {};
245
+ tideData.predictions.forEach(prediction => {
246
+ const date = prediction.t.split(' ')[0];
247
+ if (!predictionsByDate[date]) {
248
+ predictionsByDate[date] = [];
249
  }
250
+ predictionsByDate[date].push(prediction);
251
+ });
252
+
253
+ // Create cards for each date
254
+ for (const date in predictionsByDate) {
255
+ const predictions = predictionsByDate[date];
256
+ const dateObj = new Date(date);
257
+ const dayName = dateObj.toLocaleDateString('en-US', { weekday: 'long' });
258
+ const formattedDate = dateObj.toLocaleDateString('en-US', { month: 'short', day: 'numeric' });
259
+
260
+ const card = document.createElement('div');
261
+ card.className = 'bg-gray-50 p-4 rounded-lg';
262
+ card.innerHTML = `
263
+ <h4 class="font-medium text-gray-700 mb-2">${dayName}<br><span class="text-sm text-gray-500">${formattedDate}</span></h4>
264
+ <div class="space-y-2">
265
+ ${predictions.map(p => `
266
+ <div class="flex justify-between items-center">
267
+ <span class="text-sm ${p.type === 'H' ? 'text-blue-600' : 'text-amber-600'} font-medium">
268
+ ${p.type === 'H' ? 'High' : 'Low'} Tide
269
+ </span>
270
+ <span class="text-sm text-gray-700">${p.t.split(' ')[1]}</span>
271
+ <span class="text-sm font-medium">${p.v} ft</span>
272
+ </div>
273
+ `).join('')}
274
+ </div>
275
+ `;
276
+ tideContainer.appendChild(card);
277
  }
278
+ } else {
279
+ document.getElementById('tideInfo').classList.add('hidden');
 
280
  }
281
  }
282
  });