Spaces:
Sleeping
Sleeping
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <title>Pest GeoSpatial Analytics</title> | |
| <style> | |
| /* Import a Google Font for a modern look */ | |
| @import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap'); | |
| @keyframes fadeIn { | |
| from { opacity: 0; transform: translateY(20px); } | |
| to { opacity: 1; transform: translateY(0); } | |
| } | |
| body { | |
| margin: 0; | |
| padding: 0; | |
| font-family: 'Roboto', sans-serif; | |
| background: linear-gradient(135deg, #e8f5e9, #c8e6c9); | |
| display: flex; | |
| justify-content: center; | |
| align-items: center; | |
| min-height: 100vh; | |
| } | |
| .container { | |
| width: 95%; | |
| max-width: 800px; | |
| background: #fff; | |
| padding: 40px; | |
| margin: 20px; | |
| border-radius: 12px; | |
| box-shadow: 0 12px 24px rgba(0, 0, 0, 0.2); | |
| animation: fadeIn 1s ease-out; | |
| } | |
| h1 { | |
| color: #2e7d32; | |
| text-align: center; | |
| margin-bottom: 30px; | |
| font-size: 2.8em; | |
| } | |
| form { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 20px; | |
| } | |
| label { | |
| font-weight: 500; | |
| margin-bottom: 8px; | |
| color: #333; | |
| } | |
| select, button { | |
| width: 100%; | |
| padding: 14px 18px; | |
| border: 1px solid #ccc; | |
| border-radius: 8px; | |
| font-size: 1em; | |
| transition: all 0.3s ease; | |
| } | |
| select:focus, button:focus { | |
| outline: none; | |
| border-color: #2e7d32; | |
| box-shadow: 0 0 8px rgba(46, 125, 50, 0.5); | |
| } | |
| button { | |
| background-color: #2e7d32; | |
| color: #fff; | |
| font-weight: 700; | |
| cursor: pointer; | |
| margin-top: 10px; | |
| } | |
| button:hover { | |
| background-color: #276a2e; | |
| transform: scale(1.02); | |
| } | |
| .note { | |
| font-style: italic; | |
| color: #555; | |
| margin-top: 10px; | |
| text-align: center; | |
| } | |
| .map { | |
| margin-top: 40px; | |
| text-align: center; | |
| } | |
| .map h2 { | |
| color: #2e7d32; | |
| margin-bottom: 20px; | |
| font-size: 2em; | |
| } | |
| .map img { | |
| max-width: 100%; | |
| border: 3px solid #2e7d32; | |
| border-radius: 8px; | |
| transition: opacity 0.5s ease; | |
| } | |
| .error { | |
| color: red; | |
| font-weight: 700; | |
| margin-top: 20px; | |
| font-size: 1.2em; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="container"> | |
| <h1>Pest GeoSpatial Analytics</h1> | |
| <form method="GET" action="/"> | |
| <!-- Crop selection --> | |
| <label for="crop">Crop:</label> | |
| <select id="crop" name="crop" onchange="updatePestDropdown()"> | |
| <option value="">--Select Crop--</option> | |
| {% for c in crops %} | |
| <option value="{{ c }}" {% if selected_crop == c %}selected{% endif %}>{{ c }}</option> | |
| {% endfor %} | |
| </select> | |
| <!-- Pest selection (populated dynamically) --> | |
| <label for="pest">Pest:</label> | |
| <select id="pest" name="pest"> | |
| <option value="">--Select Pest--</option> | |
| <!-- Options will be set by JavaScript based on selected crop --> | |
| </select> | |
| <!-- Year selection --> | |
| <label for="year">Year:</label> | |
| <select id="year" name="year" onchange="fetchWeeks()"> | |
| <option value="">--Select Year--</option> | |
| {% for y in years %} | |
| <option value="{{ y }}" {% if selected_year == y %}selected{% endif %}>{{ y }}</option> | |
| {% endfor %} | |
| </select> | |
| <!-- Week selection (populated dynamically) --> | |
| <label for="week">Week:</label> | |
| <select id="week" name="week"> | |
| <option value="">--Select Week--</option> | |
| {% if selected_week %} | |
| <option value="{{ selected_week }}" selected>{{ selected_week }}</option> | |
| {% endif %} | |
| </select> | |
| <!-- Parameter selection --> | |
| <label for="param">Parameter:</label> | |
| <select id="param" name="param"> | |
| <option value="">--Select Parameter--</option> | |
| {% for code, label in params.items() %} | |
| <option value="{{ code }}" {% if selected_param == code %}selected{% endif %}>{{ label }}</option> | |
| {% endfor %} | |
| </select> | |
| <button type="submit">Load Map</button> | |
| <p class="note">Select a Crop, Pest, Year, Week, and Parameter to load the corresponding map.</p> | |
| </form> | |
| {% if image_url %} | |
| <div class="map" id="mapContainer"> | |
| <h2>Fetched Results</h2> | |
| <!-- Use the proxy URL for the image --> | |
| <img src="{{ image_url }}" alt="Map for {{ selected_param }} parameter" onerror="handleImageError(this)"> | |
| <div id="dataNotAvailable" class="error" style="display:none;">Data Not Available. Cannot plot map.</div> | |
| </div> | |
| {% endif %} | |
| </div> | |
| <script> | |
| // Crop-to-Pest mapping provided from the server | |
| const cropToPests = {{ crop_to_pests | tojson }}; | |
| // Update the pest dropdown based on the selected crop | |
| function updatePestDropdown() { | |
| const cropSelect = document.getElementById("crop"); | |
| const pestSelect = document.getElementById("pest"); | |
| const selectedCrop = cropSelect.value; | |
| pestSelect.innerHTML = ""; | |
| const defaultOption = document.createElement("option"); | |
| defaultOption.value = ""; | |
| defaultOption.textContent = "--Select Pest--"; | |
| pestSelect.appendChild(defaultOption); | |
| if (selectedCrop && cropToPests[selectedCrop]) { | |
| const pests = cropToPests[selectedCrop]; | |
| pests.forEach(function(p) { | |
| const option = document.createElement("option"); | |
| option.value = p; | |
| option.textContent = p; | |
| if (p === "{{ selected_pest }}") { | |
| option.selected = true; | |
| } | |
| pestSelect.appendChild(option); | |
| }); | |
| } | |
| if (document.getElementById("year").value) { | |
| fetchWeeks(); | |
| } | |
| } | |
| // Fetch week options dynamically from the /fetch_weeks endpoint | |
| function fetchWeeks() { | |
| const crop = document.getElementById("crop").value; | |
| const pest = document.getElementById("pest").value; | |
| const year = document.getElementById("year").value; | |
| if (!crop || !pest || !year) return; | |
| fetch(`/fetch_weeks?crop=${crop}&pest=${pest}&year=${year}`) | |
| .then(response => response.json()) | |
| .then(data => { | |
| const weekSelect = document.getElementById("week"); | |
| weekSelect.innerHTML = ""; | |
| const defaultOption = document.createElement("option"); | |
| defaultOption.value = ""; | |
| defaultOption.textContent = "--Select Week--"; | |
| weekSelect.appendChild(defaultOption); | |
| data.weeks.forEach(function(week) { | |
| const option = document.createElement("option"); | |
| option.value = week; | |
| option.textContent = week; | |
| if (week === "{{ selected_week }}") { | |
| option.selected = true; | |
| } | |
| weekSelect.appendChild(option); | |
| }); | |
| }) | |
| .catch(err => console.error("Error fetching weeks:", err)); | |
| } | |
| function handleImageError(img) { | |
| img.style.display = "none"; | |
| document.getElementById("dataNotAvailable").style.display = "block"; | |
| } | |
| window.onload = function() { | |
| updatePestDropdown(); | |
| if ("{{ selected_year }}" && "{{ selected_crop }}" && "{{ selected_pest }}") { | |
| fetchWeeks(); | |
| } | |
| }; | |
| </script> | |
| </body> | |
| </html> | |