hoàn thành chức năng tính ndvi analysys 2 màn hình

This commit is contained in:
Victor Phan
2025-12-24 13:57:08 +07:00
parent be90d26d24
commit 5342df77b4
25 changed files with 4755 additions and 460 deletions
+65 -20
View File
@@ -452,16 +452,19 @@
<div id="ndviContent" class="content" style="display: none;">
<!-- NDVI Configuration -->
<div class="section">
<h2>⚙️ Cấu hình NDVI</h2>
<!-- NDVI Map for selecting bbox -->
<div class="form-group">
<label>Bbox (dùng bbox từ prediction hoặc nhập mới):</label>
<label>Chọn bbox trên bản đồ hoặc nhập tọa độ:</label>
<div id="ndviMap" style="height: 300px; border-radius: 10px; margin-bottom: 15px; box-shadow: 0 2px 8px rgba(0,0,0,0.08);"></div>
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 10px;">
<input type="number" id="ndviMinLon" placeholder="Min Lon" step="0.0001">
<input type="number" id="ndviMinLat" placeholder="Min Lat" step="0.0001">
<input type="number" id="ndviMaxLon" placeholder="Max Lon" step="0.0001">
<input type="number" id="ndviMaxLat" placeholder="Max Lat" step="0.0001">
</div>
<div style="font-size: 12px; color: #1976d2; margin-top: 8px;">✏️ Vẽ hình chữ nhật trên bản đồ để chọn bbox NDVI, các ô tọa độ sẽ tự động cập nhật.</div>
</div>
<div class="form-row">
@@ -548,6 +551,7 @@
<script>
// Map setup
let map, drawnItems, drawControl;
let ndviMap, ndviDrawnItems, ndviDrawControl;
let selectedBbox = null;
let currentPredictionFile = null;
let currentReportFile = null;
@@ -558,15 +562,11 @@
// Initialize map
function initMap() {
map = L.map('predictMap').setView([9.5, 105.9], 9);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors'
}).addTo(map);
// Initialize drawing
drawnItems = new L.FeatureGroup();
map.addLayer(drawnItems);
drawControl = new L.Control.Draw({
draw: {
rectangle: true,
@@ -582,13 +582,10 @@
}
});
map.addControl(drawControl);
// Handle drawing
map.on(L.Draw.Event.CREATED, function(event) {
drawnItems.clearLayers();
const layer = event.layer;
drawnItems.addLayer(layer);
const bounds = layer.getBounds();
let bbox = {
min_lon: bounds.getWest(),
@@ -596,33 +593,24 @@
max_lon: bounds.getEast(),
max_lat: bounds.getNorth()
};
// Validate bbox (must be within valid geographic coordinates)
if (bbox.min_lon < -180 || bbox.max_lon > 180 || bbox.min_lat < -90 || bbox.max_lat > 90) {
alert('❌ Bbox không hợp lệ! Vui lòng vẽ trong phạm vi bản đồ hợp lệ.\nKinh độ: -180 đến 180, Vĩ độ: -90 đến 90');
drawnItems.clearLayers();
return;
}
selectedBbox = bbox;
// Cache bbox to localStorage
localStorage.setItem('prediction_bbox', JSON.stringify(selectedBbox));
console.log('Selected bbox:', selectedBbox);
});
// On load, restore bbox from cache if exists
// Restore bbox from cache if exists
const cachedBbox = localStorage.getItem('prediction_bbox');
if (cachedBbox) {
try {
const bbox = JSON.parse(cachedBbox);
// Validate bbox before restoring
if (bbox.min_lon < -180 || bbox.max_lon > 180 ||
bbox.min_lat < -90 || bbox.max_lat > 90) {
if (bbox.min_lon < -180 || bbox.max_lon > 180 || bbox.min_lat < -90 || bbox.max_lat > 90) {
console.warn('Cache bbox không hợp lệ, đã xóa:', bbox);
localStorage.removeItem('prediction_bbox');
} else {
// Draw rectangle on map
const bounds = [
[bbox.min_lat, bbox.min_lon],
[bbox.max_lat, bbox.max_lon]
@@ -641,6 +629,63 @@
localStorage.removeItem('prediction_bbox');
}
}
// NDVI Map setup
ndviMap = L.map('ndviMap').setView([9.5, 105.9], 9);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors'
}).addTo(ndviMap);
ndviDrawnItems = new L.FeatureGroup();
ndviMap.addLayer(ndviDrawnItems);
ndviDrawControl = new L.Control.Draw({
draw: {
rectangle: true,
polygon: false,
circle: false,
marker: false,
polyline: false,
circlemarker: false
},
edit: {
featureGroup: ndviDrawnItems,
remove: true
}
});
ndviMap.addControl(ndviDrawControl);
ndviMap.on(L.Draw.Event.CREATED, function(event) {
ndviDrawnItems.clearLayers();
const layer = event.layer;
ndviDrawnItems.addLayer(layer);
const bounds = layer.getBounds();
// Update NDVI bbox inputs
document.getElementById('ndviMinLon').value = bounds.getWest().toFixed(4);
document.getElementById('ndviMinLat').value = bounds.getSouth().toFixed(4);
document.getElementById('ndviMaxLon').value = bounds.getEast().toFixed(4);
document.getElementById('ndviMaxLat').value = bounds.getNorth().toFixed(4);
});
// Sync NDVI bbox inputs to map
['ndviMinLon','ndviMinLat','ndviMaxLon','ndviMaxLat'].forEach(id => {
document.getElementById(id).addEventListener('change', function() {
const minLon = parseFloat(document.getElementById('ndviMinLon').value);
const minLat = parseFloat(document.getElementById('ndviMinLat').value);
const maxLon = parseFloat(document.getElementById('ndviMaxLon').value);
const maxLat = parseFloat(document.getElementById('ndviMaxLat').value);
if (!isNaN(minLon) && !isNaN(minLat) && !isNaN(maxLon) && !isNaN(maxLat)) {
ndviDrawnItems.clearLayers();
const bounds = [
[minLat, minLon],
[maxLat, maxLon]
];
const rectangle = L.rectangle(bounds, {
color: '#2ecc71',
weight: 3,
fillOpacity: 0.2
});
ndviDrawnItems.addLayer(rectangle);
ndviMap.fitBounds(bounds);
}
});
});
}
// Load models list