feat: flooded zones render as water and auto-surface
CI/CD Pipeline - Northern Thailand Ping River Monitor / Test Suite (3.11) (push) Failing after 23s
CI/CD Pipeline - Northern Thailand Ping River Monitor / Build Docker Image (push) Skipped
CI/CD Pipeline - Northern Thailand Ping River Monitor / Integration Test with Services (push) Skipped
CI/CD Pipeline - Northern Thailand Ping River Monitor / Deploy to Staging (push) Skipped
CI/CD Pipeline - Northern Thailand Ping River Monitor / Deploy to Production (push) Skipped
CI/CD Pipeline - Northern Thailand Ping River Monitor / Performance Test (push) Skipped
CI/CD Pipeline - Northern Thailand Ping River Monitor / Code Quality (push) Successful in 16s
CI/CD Pipeline - Northern Thailand Ping River Monitor / Cleanup (push) Successful in 0s
CI/CD Pipeline - Northern Thailand Ping River Monitor / Test Suite (3.11) (push) Failing after 23s
CI/CD Pipeline - Northern Thailand Ping River Monitor / Build Docker Image (push) Skipped
CI/CD Pipeline - Northern Thailand Ping River Monitor / Integration Test with Services (push) Skipped
CI/CD Pipeline - Northern Thailand Ping River Monitor / Deploy to Staging (push) Skipped
CI/CD Pipeline - Northern Thailand Ping River Monitor / Deploy to Production (push) Skipped
CI/CD Pipeline - Northern Thailand Ping River Monitor / Performance Test (push) Skipped
CI/CD Pipeline - Northern Thailand Ping River Monitor / Code Quality (push) Successful in 16s
CI/CD Pipeline - Northern Thailand Ping River Monitor / Cleanup (push) Successful in 0s
When P.1's current level reaches a zone's trigger level the zone fills water-blue (solid border, .62 opacity) instead of the amber risk ramp, and the zone layer adds itself to the map automatically - no toggle needed during an actual flood. A manual hide sets a session flag so auto-show does not fight the user.
This commit is contained in:
+31
-14
@@ -627,12 +627,16 @@
|
|||||||
const st = zoneStage(zone);
|
const st = zoneStage(zone);
|
||||||
const p = st ? st.p_exceed : 0;
|
const p = st ? st.p_exceed : 0;
|
||||||
const flooded = state.p1Now != null && state.p1Now >= level;
|
const flooded = state.p1Now != null && state.p1Now >= level;
|
||||||
|
if (flooded) {
|
||||||
|
// river has reached this zone's trigger level: render as water
|
||||||
|
return { color: '#1b5e88', weight: 2, dashArray: null, fillColor: '#2f86c8', fillOpacity: .62 };
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
color: flooded ? '#7a1512' : '#8a5a2b',
|
color: '#8a5a2b',
|
||||||
weight: flooded ? 2.5 : 1.2,
|
weight: 1.2,
|
||||||
dashArray: flooded ? null : '4 4',
|
dashArray: '4 4',
|
||||||
fillColor: ZONE_COLORS[zone] || '#f9e3a1',
|
fillColor: ZONE_COLORS[zone] || '#f9e3a1',
|
||||||
fillOpacity: flooded ? .72 : .38 + .3 * Math.min(1, p),
|
fillOpacity: .38 + .3 * Math.min(1, p),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -650,15 +654,9 @@
|
|||||||
${flooded ? '<div class="popup-time" style="color:#8d2f22;font-weight:800">River is at or above this zone’s level now</div>' : ''}</div>`;
|
${flooded ? '<div class="popup-time" style="color:#8d2f22;font-weight:800">River is at or above this zone’s level now</div>' : ''}</div>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function toggleFloodZones() {
|
async function showFloodZones(fly) {
|
||||||
if (!state.map) return;
|
if (!state.map || zoneLayer) return;
|
||||||
const button = $('zones-toggle');
|
const button = $('zones-toggle');
|
||||||
if (zoneLayer) {
|
|
||||||
state.map.removeLayer(zoneLayer);
|
|
||||||
zoneLayer = null;
|
|
||||||
if (button) button.textContent = 'Show flood zones on map';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
if (!zoneData) {
|
if (!zoneData) {
|
||||||
const response = await fetch('/static/flood-zones-p1.geojson');
|
const response = await fetch('/static/flood-zones-p1.geojson');
|
||||||
@@ -668,16 +666,35 @@
|
|||||||
zoneLayer = L.geoJSON(zoneData, { style: zoneStyle })
|
zoneLayer = L.geoJSON(zoneData, { style: zoneStyle })
|
||||||
.bindPopup((layer) => zonePopupHtml(layer.feature))
|
.bindPopup((layer) => zonePopupHtml(layer.feature))
|
||||||
.addTo(state.map);
|
.addTo(state.map);
|
||||||
state.map.flyToBounds(zoneLayer.getBounds(), { maxZoom: 13, duration: .8 });
|
|
||||||
if (button) button.textContent = 'Hide flood zones';
|
if (button) button.textContent = 'Hide flood zones';
|
||||||
document.getElementById('station-map').scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
if (fly) {
|
||||||
|
state.map.flyToBounds(zoneLayer.getBounds(), { maxZoom: 13, duration: .8 });
|
||||||
|
document.getElementById('station-map').scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (button) button.textContent = 'Flood zones unavailable';
|
if (button) button.textContent = 'Flood zones unavailable';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toggleFloodZones() {
|
||||||
|
if (zoneLayer) {
|
||||||
|
state.map.removeLayer(zoneLayer);
|
||||||
|
zoneLayer = null;
|
||||||
|
state.zonesUserHidden = true; // don't auto-show again this session
|
||||||
|
const button = $('zones-toggle');
|
||||||
|
if (button) button.textContent = 'Show flood zones on map';
|
||||||
|
} else {
|
||||||
|
state.zonesUserHidden = false;
|
||||||
|
showFloodZones(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function restyleFloodZones() {
|
function restyleFloodZones() {
|
||||||
if (zoneLayer) zoneLayer.setStyle(zoneStyle);
|
if (zoneLayer) zoneLayer.setStyle(zoneStyle);
|
||||||
|
// Flooding in progress: surface the zones even if the layer is off,
|
||||||
|
// unless the user explicitly hid it.
|
||||||
|
const anyFlooded = state.p1Now != null && (state.p1Stages || []).some((s) => state.p1Now >= s.level);
|
||||||
|
if (anyFlooded && !zoneLayer && !state.zonesUserHidden) showFloodZones(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
function pointInRing(lat, lon, ring) {
|
function pointInRing(lat, lon, ring) {
|
||||||
|
|||||||
Reference in New Issue
Block a user