feat: Introduce initial web application structure with dark theme styling, data collection, and client-side logic.
This commit is contained in:
+63
-22
@@ -70,18 +70,18 @@ function initMap() {
|
||||
|
||||
// Initialize Heatmap layer (requires Leaflet.heat)
|
||||
heatLayer = L.heatLayer([], {
|
||||
radius: 70,
|
||||
blur: 50,
|
||||
maxZoom: 10,
|
||||
radius: 160, // Large radius for field blending
|
||||
blur: 50, // Lower blur for more defined radar-like edges
|
||||
max: 1.0, // We will pass normalized intensities [0, 1]
|
||||
gradient: {
|
||||
0.0: "blue",
|
||||
0.2: "cyan",
|
||||
0.4: "lime",
|
||||
0.6: "yellow",
|
||||
0.8: "orange",
|
||||
1.0: "red",
|
||||
0.0: "#3b82f6", // Blue (Coldest in localized set)
|
||||
0.2: "#06b6d4", // Cyan
|
||||
0.4: "#10b981", // Green
|
||||
0.6: "#facc15", // Yellow
|
||||
0.8: "#f97316", // Orange
|
||||
1.0: "#ef4444", // Red (Hottest in localized set)
|
||||
},
|
||||
opacity: 0.5,
|
||||
opacity: 0.45,
|
||||
}).addTo(map);
|
||||
|
||||
// Close panel and clear selection when clicking on empty map space
|
||||
@@ -101,10 +101,10 @@ function updateMapVisibility() {
|
||||
// These are the "Ankara-style" local station markers
|
||||
if (zoom < 7) {
|
||||
if (map.hasLayer(nearbyLayerGroup)) map.removeLayer(nearbyLayerGroup);
|
||||
if (map.hasLayer(heatLayer)) map.removeLayer(heatLayer);
|
||||
if (heatLayer && map.hasLayer(heatLayer)) map.removeLayer(heatLayer);
|
||||
} else {
|
||||
if (!map.hasLayer(nearbyLayerGroup)) map.addLayer(nearbyLayerGroup);
|
||||
if (!map.hasLayer(heatLayer)) map.addLayer(heatLayer);
|
||||
if (heatLayer && !map.hasLayer(heatLayer)) map.addLayer(heatLayer);
|
||||
}
|
||||
|
||||
// 2. Handle Primary City Markers (Major vs Minor)
|
||||
@@ -309,16 +309,31 @@ function renderNearbyStations(data) {
|
||||
// Filter out stations too far if needed, but il handles grouping nicely.
|
||||
// Skip if it is the exact same marker as main (though coordinates might slightly differ)
|
||||
const sym = data.temp_symbol || "°C";
|
||||
// Wind info if available
|
||||
let windHtml = "";
|
||||
if (st.wind_dir != null) {
|
||||
const rot = (parseFloat(st.wind_dir) + 180) % 360;
|
||||
const speed = st.wind_speed != null ? `${st.wind_speed}k` : "";
|
||||
windHtml = `
|
||||
<div class="wind-info">
|
||||
<span class="wind-arrow" style="transform: rotate(${rot}deg)">↑</span>
|
||||
<span class="wind-speed">${speed}</span>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
const iconHtml = `
|
||||
<div class="nearby-marker">
|
||||
${st.name}: <span class="nearby-temp">${st.temp}</span><span class="nearby-unit">${sym}</span>
|
||||
<span class="nearby-name">${st.name}</span>
|
||||
<span class="nearby-temp">${st.temp}</span><span class="nearby-unit">${sym}</span>
|
||||
${windHtml}
|
||||
</div>
|
||||
`;
|
||||
const icon = L.divIcon({
|
||||
html: iconHtml,
|
||||
className: "",
|
||||
iconSize: null,
|
||||
iconAnchor: [-5, 5],
|
||||
iconAnchor: [0, 0],
|
||||
});
|
||||
|
||||
const marker = L.marker([st.lat, st.lon], { icon }).addTo(nearbyLayerGroup);
|
||||
@@ -327,16 +342,42 @@ function renderNearbyStations(data) {
|
||||
|
||||
// Update Heatmap
|
||||
if (heatLayer) {
|
||||
const heatData = data.mgm_nearby.map((st) => [
|
||||
st.lat,
|
||||
st.lon,
|
||||
st.temp || 10,
|
||||
]);
|
||||
// Add current city center to heat data
|
||||
const allStations = [...data.mgm_nearby];
|
||||
if (data.lat && data.lon && data.current?.temp != null) {
|
||||
heatData.push([data.lat, data.lon, data.current.temp]);
|
||||
allStations.push({
|
||||
lat: data.lat,
|
||||
lon: data.lon,
|
||||
temp: data.current.temp,
|
||||
});
|
||||
}
|
||||
|
||||
// Dynamic Normalization: calculate min/max in current set to show contrast.
|
||||
// This allows seeing the 'heat island' even with subtle 0.5C differences.
|
||||
const temps = allStations
|
||||
.map((s) => parseFloat(s.temp))
|
||||
.filter((t) => !isNaN(t));
|
||||
|
||||
if (temps.length > 0) {
|
||||
const minT = Math.min(...temps);
|
||||
const maxT = Math.max(...temps);
|
||||
const range = maxT - minT || 1.0;
|
||||
|
||||
const heatData = allStations.map((st) => {
|
||||
const val = parseFloat(st.temp) || minT;
|
||||
// Normalize val to 0.0 - 1.0 based on current city data range
|
||||
const normalized = range > 0 ? (val - minT) / range : 0.5;
|
||||
// We use Math.max(0.1, ...) to ensure even the coldest point has some visible 'field'
|
||||
return [st.lat, st.lon, Math.max(0.1, normalized)];
|
||||
});
|
||||
|
||||
// Ensure layer is on map before updating to avoid internal Leaflet.heat errors
|
||||
if (!map.hasLayer(heatLayer) && map.getZoom() >= 7) {
|
||||
heatLayer.addTo(map);
|
||||
}
|
||||
if (map.hasLayer(heatLayer)) {
|
||||
heatLayer.setLatLngs(heatData);
|
||||
}
|
||||
}
|
||||
heatLayer.setLatLngs(heatData);
|
||||
}
|
||||
|
||||
if (latLngs.length > 1) {
|
||||
|
||||
Reference in New Issue
Block a user