Spaces:
Running
Running
File size: 8,824 Bytes
bdb271a |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 |
// 1. EXTENDED COORDINATE DATABASE
// defines a static database of coordinates for Philippine cities and provinces
const cityCoords = {
// --- NCR ---
"Manila": [14.5995, 120.9842],
"Quezon City": [14.6760, 121.0437],
"Makati": [14.5547, 121.0244],
"Taguig": [14.5176, 121.0509],
"Pasig": [14.5763, 121.0851],
"Mandaluyong": [14.5794, 121.0359],
"Marikina": [14.6333, 121.0980],
"Las Pinas": [14.4445, 120.9939],
"Muntinlupa": [14.4081, 121.0415],
"Caloocan": [14.6401, 120.9745],
"Parañaque": [14.4793, 121.0198],
"Valenzuela": [14.7011, 120.9830],
"Pasay": [14.5378, 121.0014],
"Malabon": [14.6625, 120.9512],
"Navotas": [14.6732, 120.9350],
"San Juan": [14.6019, 121.0355],
"Pateros": [14.5454, 121.0687],
// --- CAVITE ---
"Cavite": [14.2831, 120.9168],
"Naic": [14.3168, 120.7628],
"Bacoor": [14.4624, 120.9645],
"Imus": [14.4297, 120.9367],
"Dasmarinas": [14.3294, 120.9367],
"General Trias": [14.3876, 120.8842],
"Tagaytay": [14.1153, 120.9621],
"Kawit": [14.4448, 120.9022],
"Noveleta": [14.4263, 120.8820],
"Rosario": [14.4153, 120.8532],
"Tanza": [14.3949, 120.8532],
"Silang": [14.2312, 120.9746],
"Trece Martires": [14.2883, 120.8677],
// --- LAGUNA ---
"Laguna": [14.2166, 121.1667],
"Calamba": [14.2142, 121.1553],
"Santa Rosa": [14.3121, 121.1132],
"Binan": [14.3400, 121.0827],
"San Pedro": [14.3644, 121.0370],
"Cabuyao": [14.2796, 121.1219],
"Los Banos": [14.1708, 121.2413],
// --- RIZAL ---
"Rizal": [14.5906, 121.2236],
"Antipolo": [14.5844, 121.1763],
"Cainta": [14.5760, 121.1213],
"Taytay": [14.5623, 121.1376],
"San Mateo": [14.6963, 121.1215],
"Binangonan": [14.4759, 121.1893],
// --- BULACAN ---
"Bulacan": [14.8524, 120.8228],
"Malolos": [14.8527, 120.8160],
"Meycauayan": [14.7356, 120.9622],
"San Jose del Monte": [14.8143, 121.0427],
"Bocaue": [14.8066, 120.9256],
// --- MAJOR PROVINCES / CITIES ---
"Pampanga": [15.0359, 120.6924],
"Tarlac": [15.4802, 120.5979],
"Batangas": [13.7565, 121.0583],
"Baguio": [16.4023, 120.5960],
"Cebu": [10.3157, 123.8854],
"Iloilo": [10.7202, 122.5621],
"Davao": [7.1907, 125.4553],
"Cagayan": [17.6133, 121.7302],
"Bicol": [13.4350, 123.4100],
"Albay": [13.1391, 123.7438],
"Tacloban": [11.2442, 125.0039],
"Zamboanga": [6.9214, 122.0790],
"Palawan": [9.8349, 118.7384],
"Mindoro": [13.0264, 121.2227],
"Isabela": [16.9754, 121.8107],
"Pangasinan": [15.9236, 120.3392],
"Philippines": [12.8797, 121.7740] // CENTER OF PH
};
let map;
let markers = [];
// initializes the map view and starts fetching data
document.addEventListener("DOMContentLoaded", () => {
// sets the initial map center on the CALABARZON/NCR area
map = L.map('map').setView([14.40, 121.00], 10);
// adds the dark-themed tile layer to the map
L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png', {
attribution: '© OpenStreetMap © CARTO',
subdomains: 'abcd',
maxZoom: 19
}).addTo(map);
console.log("ALISTO Map: Loaded");
// fetches the first set of post data
fetchDataAndPlot();
// sets a timer to refresh data every 30 seconds
setInterval(fetchDataAndPlot, 30000);
});
// fetches the list of active disaster posts from the API
function fetchDataAndPlot() {
fetch('/api/posts')
.then(response => response.json())
.then(data => {
// updates the alert count in the map sidebar
updateSidebar(data);
// plots the markers on the map
plotMarkers(data);
})
.catch(err => console.error("Map Fetch Error:", err));
}
// updates the displayed alert count and system status in the floating sidebar
function updateSidebar(data) {
const countEl = document.getElementById('alert-count');
const statusEl = document.getElementById('status-text');
if(countEl) countEl.innerText = data.length;
if(statusEl) statusEl.innerText = "System Active";
}
// clears existing markers and plots new circular markers for each post
function plotMarkers(posts) {
// removes all existing markers from the map
markers.forEach(m => map.removeLayer(m));
markers = [];
// iterates through all posts to find coordinates and draw markers
posts.forEach(async post => {
// asynchronously finds the latitude and longitude for the location
let coords = await getCoordinatesSmart(post.location);
if (coords) {
// sets color and size based on post urgency level
const urgencyColor = post.urgency_level === 'High' ? '#ff4444' : '#ed4801';
const radius = post.urgency_level === 'High' ? 14 : 8;
// creates and adds a circular marker (L.circleMarker) to the map
const circle = L.circleMarker(coords, {
color: urgencyColor,
fillColor: urgencyColor,
fillOpacity: 0.7,
radius: radius
}).addTo(map);
const timeStr = new Date(post.timestamp).toLocaleTimeString();
// binds a detailed pop-up box to the circular marker
circle.bindPopup(`
<div style="font-family: 'Roboto', sans-serif; color: #333; min-width: 200px;">
<strong style="text-transform:uppercase; color: #d32f2f; font-size: 1.1em;">
${post.disaster_type}
</strong>
<div style="color: #ed4801; font-weight: 700; font-size: 0.9em; margin-bottom: 4px; text-transform: uppercase;">
⚠ ${post.assistance_type || "General Help"}
</div>
<span style="font-size: 0.9em; color: #555;">📍 ${post.location}</span>
<hr style="margin:8px 0; border:0; border-top:1px solid #ccc;">
<div style="font-size: 0.9em; margin-bottom: 5px; font-weight: 500;">
"${post.title}"
</div>
<small style="color: #888;">${timeStr}</small>
</div>
`);
// adds the new marker to the global array
markers.push(circle);
}
});
}
// --- NEW SMART FINDER (Hybrid: Static List + API) ---
// function to look up coordinates, prioritizing the static list then Nominatim API
async function getCoordinatesSmart(locationStr) {
if (!locationStr) return cityCoords["Philippines"];
// 1. Try Static List (Instant)
// direct match check
const exactMatch = Object.keys(cityCoords).find(k => k.toLowerCase() === locationStr.toLowerCase());
if (exactMatch) return cityCoords[exactMatch];
// fuzzy match check
const fuzzyKey = Object.keys(cityCoords).find(city => locationStr.toLowerCase().includes(city.toLowerCase()));
if (fuzzyKey) return cityCoords[fuzzyKey];
// 2. Try OpenStreetMap API (Dynamic)
// checks local cache before making a network request
if (!window.coordCache) window.coordCache = {};
if (window.coordCache[locationStr]) return window.coordCache[locationStr];
try {
console.log(`Fetching coords for: ${locationStr}...`);
// fetches coordinates from the Nominatim API
const response = await fetch(`https://nominatim.openstreetmap.org/search?format=json&q=${locationStr}, Philippines`);
const data = await response.json();
// processes and caches the result
if (data && data.length > 0) {
const lat = parseFloat(data[0].lat);
const lon = parseFloat(data[0].lon);
const result = [lat, lon];
window.coordCache[locationStr] = result;
return result;
}
} catch (e) {
console.error("Geocoding failed:", e);
}
// 3. Fallback
// returns the center of the Philippines if geocoding fails
return cityCoords["Philippines"];
} |