-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 1d969f2
Showing
3 changed files
with
286 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8"> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||
<title>Snowmaking Weather Dashboard</title> | ||
<link rel="stylesheet" href="styles.css"> | ||
</head> | ||
<body> | ||
<div id="app"> | ||
<header> | ||
<h1>Snowmaking Dashboard</h1> | ||
<div class="location-input"> | ||
<input type="text" id="locationInput" placeholder="Enter location or use GPS"> | ||
<button id="locationBtn">Use GPS</button> | ||
<ul id="suggestions"></ul> | ||
<button id="submitBtn">Submit</button> | ||
</div> | ||
<div class="unit-switch"> | ||
<label> | ||
<input type="checkbox" id="unitSwitch"> | ||
<span>°F / °C</span> | ||
</label> | ||
</div> | ||
</header> | ||
|
||
<main> | ||
<section id="currentConditions" class="card"> | ||
<h2>Current Conditions</h2> | ||
<p>Temperature: <span id="temp"></span></p> | ||
<p>Humidity: <span id="humidity"></span></p> | ||
<p>Wet Bulb: <span id="wetBulb"></span></p> | ||
<div id="snowQualityGauge"> | ||
<p id="snowQuality">Snow Quality: <span id="quality"></span></p> | ||
<div id="snowIndicator"></div> | ||
</div> | ||
</section> | ||
|
||
<section id="forecast" class="card"> | ||
<h2>7-Day Snowmaking Forecast</h2> | ||
<div id="forecastContainer"> | ||
<!-- Forecast days will be injected here by JavaScript --> | ||
</div> | ||
</section> | ||
</main> | ||
</div> | ||
<script src="script.js"></script> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
const API_KEY = '93884a8e001a81fd2dc1b978e4980a43'; // Replace with your OpenWeatherMap API key | ||
|
||
document.getElementById('locationBtn').addEventListener('click', fetchWeatherByLocation); | ||
document.getElementById('submitBtn').addEventListener('click', submitLocation); | ||
document.getElementById('unitSwitch').addEventListener('change', toggleUnits); | ||
document.getElementById('locationInput').addEventListener('input', fetchLocationSuggestions); | ||
|
||
let isCelsius = false; | ||
|
||
// Display an error message to the user | ||
function displayError(message) { | ||
const errorContainer = document.createElement('p'); | ||
errorContainer.textContent = message; | ||
errorContainer.className = 'error-message'; | ||
document.body.prepend(errorContainer); | ||
setTimeout(() => errorContainer.remove(), 5000); | ||
} | ||
|
||
// Fetch weather data based on GPS location | ||
async function fetchWeatherByLocation() { | ||
if (navigator.geolocation) { | ||
navigator.geolocation.getCurrentPosition( | ||
async (position) => { | ||
const lat = position.coords.latitude; | ||
const lon = position.coords.longitude; | ||
await fetchNearestCity(lat, lon); | ||
await fetchWeatherData(lat, lon); | ||
}, | ||
(error) => { | ||
displayError("Unable to access GPS location."); | ||
console.error("Geolocation error:", error); | ||
} | ||
); | ||
} else { | ||
displayError("Geolocation is not supported by this browser."); | ||
} | ||
} | ||
|
||
// Fetch weather data based on location input | ||
async function submitLocation() { | ||
const location = document.getElementById('locationInput').value; | ||
try { | ||
const data = await fetchGeoLocation(location); | ||
if (data.length > 0) { | ||
const { lat, lon, name } = data[0]; | ||
document.getElementById('locationInput').value = name; // Autofill with selected location | ||
await fetchWeatherData(lat, lon); | ||
} else { | ||
displayError("Location not found. Please enter a valid location."); | ||
} | ||
} catch (error) { | ||
displayError("Failed to fetch location data. Please try again."); | ||
console.error("Error fetching location data:", error); | ||
} | ||
} | ||
|
||
// Fetch location suggestions for the input field | ||
async function fetchLocationSuggestions() { | ||
const query = document.getElementById('locationInput').value; | ||
if (query.length < 3) return; // Only fetch if query is longer than 2 characters | ||
|
||
try { | ||
const data = await fetchGeoLocation(query); | ||
|
||
const suggestionsList = document.getElementById('suggestions'); | ||
suggestionsList.innerHTML = ''; | ||
data.forEach(location => { | ||
const suggestionItem = document.createElement('li'); | ||
suggestionItem.textContent = location.name; | ||
suggestionItem.addEventListener('click', () => { | ||
document.getElementById('locationInput').value = location.name; | ||
suggestionsList.innerHTML = ''; | ||
}); | ||
suggestionsList.appendChild(suggestionItem); | ||
}); | ||
} catch (error) { | ||
displayError("Failed to fetch location suggestions."); | ||
console.error("Error fetching location suggestions:", error); | ||
} | ||
} | ||
|
||
// Fetch latitude and longitude based on a query using Geocoding API | ||
async function fetchGeoLocation(query) { | ||
const response = await fetch(`https://api.openweathermap.org/geo/1.0/direct?q=${query}&limit=5&appid=${API_KEY}`); | ||
|
||
if (!response.ok) { | ||
throw new Error(`Location fetch failed: ${response.status}`); | ||
} | ||
return await response.json(); | ||
} | ||
|
||
// Fetch the nearest city name based on latitude and longitude | ||
async function fetchNearestCity(lat, lon) { | ||
try { | ||
const response = await fetch(`https://api.openweathermap.org/geo/1.0/reverse?lat=${lat}&lon=${lon}&limit=1&appid=${API_KEY}`); | ||
|
||
if (!response.ok) { | ||
throw new Error(`Nearest city fetch failed: ${response.status}`); | ||
} | ||
|
||
const data = await response.json(); | ||
if (data.length > 0) { | ||
document.getElementById('locationInput').value = data[0].name; | ||
} else { | ||
displayError("Unable to find nearest city."); | ||
} | ||
} catch (error) { | ||
displayError("Failed to fetch nearest city."); | ||
console.error("Error fetching nearest city:", error); | ||
} | ||
} | ||
|
||
// Fetch weather data for a given latitude and longitude | ||
async function fetchWeatherData(lat, lon) { | ||
try { | ||
const response = await fetch(`https://api.openweathermap.org/data/2.5/onecall?lat=${lat}&lon=${lon}&appid=${API_KEY}&units=${isCelsius ? 'metric' : 'imperial'}`); | ||
|
||
if (!response.ok) { | ||
throw new Error(`Weather data fetch failed: ${response.status}`); | ||
} | ||
|
||
const data = await response.json(); | ||
|
||
if (data.current) { | ||
updateCurrentConditions(data.current); | ||
} else { | ||
displayError("Current weather data is unavailable."); | ||
} | ||
|
||
if (data.daily) { | ||
updateForecast(data.daily); | ||
} else { | ||
displayError("Daily forecast data is unavailable."); | ||
} | ||
} catch (error) { | ||
displayError("Failed to fetch weather data. Please try again."); | ||
console.error("Error fetching weather data:", error); | ||
} | ||
} | ||
|
||
// Toggle between Celsius and Fahrenheit | ||
function toggleUnits() { | ||
isCelsius = document.getElementById('unitSwitch').checked; | ||
const location = document.getElementById('locationInput').value; | ||
if (location) { | ||
submitLocation(); // Re-fetch data for the current location | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
body { | ||
font-family: Arial, sans-serif; | ||
margin: 0; | ||
background-color: white; | ||
color: #333; | ||
} | ||
|
||
#app { | ||
max-width: 600px; | ||
margin: auto; | ||
padding: 1em; | ||
} | ||
|
||
header { | ||
display: flex; | ||
flex-direction: column; | ||
align-items: center; | ||
gap: 1em; | ||
} | ||
|
||
.location-input { | ||
position: relative; | ||
display: flex; | ||
gap: 0.5em; | ||
} | ||
|
||
#suggestions { | ||
list-style: none; | ||
padding: 0; | ||
position: absolute; | ||
top: 100%; | ||
left: 0; | ||
width: 100%; | ||
max-height: 150px; | ||
overflow-y: auto; | ||
background: white; | ||
border: 1px solid #ddd; | ||
} | ||
|
||
#suggestions li { | ||
padding: 0.5em; | ||
cursor: pointer; | ||
} | ||
|
||
#suggestions li:hover { | ||
background-color: #f0f0f0; | ||
} | ||
|
||
.unit-switch { | ||
display: flex; | ||
align-items: center; | ||
} | ||
|
||
.unit-switch label { | ||
display: flex; | ||
align-items: center; | ||
cursor: pointer; | ||
} | ||
|
||
.unit-switch input { | ||
appearance: none; | ||
width: 40px; | ||
height: 20px; | ||
background: #ccc; | ||
border-radius: 20px; | ||
position: relative; | ||
outline: none; | ||
margin-right: 0.5em; | ||
} | ||
|
||
.unit-switch input:checked { | ||
background: #4caf50; | ||
} | ||
|
||
.unit-switch input::before { | ||
content: ""; | ||
position: absolute; | ||
width: 16px; | ||
height: 16px; | ||
background: white; | ||
border-radius: 50%; | ||
top: 2px; | ||
left: 2px; | ||
transition: transform 0.2s; | ||
} | ||
|
||
.unit-switch input:checked::before { | ||
transform: translateX(20px); | ||
} |