Spaces:
Sleeping
Sleeping
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Edit Farm</title> | |
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet"> | |
<style> | |
#map { | |
height: 50vh; | |
width: 100%; | |
border-radius: 8px; | |
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); | |
margin-bottom: 20px; | |
} | |
.form-section { | |
background-color: #f8f9fa; | |
padding: 20px; | |
border-radius: 8px; | |
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); | |
margin-bottom: 20px; | |
} | |
</style> | |
</head> | |
<body class="bg-light"> | |
<div class="container py-5"> | |
<div class="d-flex justify-content-between align-items-center mb-4"> | |
<h1>Edit Farm</h1> | |
<div> | |
<a href="/farm_details/{{ farm.id }}" class="btn btn-secondary">Back to Farm Details</a> | |
</div> | |
</div> | |
<form id="editFarmForm" action="/edit_farm/{{ farm.id }}" method="POST"> | |
<div class="row"> | |
<!-- Farmer Details Section --> | |
<div class="col-lg-6"> | |
<div class="form-section"> | |
<h3 class="mb-3">Farmer Details</h3> | |
<div class="mb-3"> | |
<label for="farmer_name" class="form-label">Farmer Name *</label> | |
<input type="text" class="form-control" id="farmer_name" name="farmer_name" value="{{ farm.farmer_name }}" required> | |
</div> | |
<div class="mb-3"> | |
<label for="contact" class="form-label">Contact Number *</label> | |
<input type="text" class="form-control" id="contact" name="contact" value="{{ farm.contact }}" required> | |
</div> | |
<div class="mb-3"> | |
<label for="address" class="form-label">Address *</label> | |
<textarea class="form-control" id="address" name="address" rows="3" required>{{ farm.address }}</textarea> | |
</div> | |
<div class="mb-3"> | |
<label for="crop_type" class="form-label">Main Crop Type (For compatibility)</label> | |
<select class="form-control" id="crop_type" name="crop_type"> | |
<option value="">Select Crop Type</option> | |
<option value="Rice" {% if farm.crop_type == 'Rice' %}selected{% endif %}>Rice</option> | |
<option value="Wheat" {% if farm.crop_type == 'Wheat' %}selected{% endif %}>Wheat</option> | |
<option value="Corn" {% if farm.crop_type == 'Corn' %}selected{% endif %}>Corn</option> | |
<option value="Cotton" {% if farm.crop_type == 'Cotton' %}selected{% endif %}>Cotton</option> | |
<option value="Sugarcane" {% if farm.crop_type == 'Sugarcane' %}selected{% endif %}>Sugarcane</option> | |
<option value="Vegetables" {% if farm.crop_type == 'Vegetables' %}selected{% endif %}>Vegetables</option> | |
<option value="Fruits" {% if farm.crop_type == 'Fruits' %}selected{% endif %}>Fruits</option> | |
<option value="Other" {% if farm.crop_type == 'Other' %}selected{% endif %}>Other</option> | |
</select> | |
</div> | |
<div class="mb-3"> | |
<h4>Crop Details</h4> | |
<div class="table-responsive"> | |
<table class="table table-bordered" id="crops-table"> | |
<thead> | |
<tr> | |
<th>Crop Name</th> | |
<th>Area (acres)</th> | |
<th>Sowing Month</th> | |
<th>Actions</th> | |
</tr> | |
</thead> | |
<tbody id="crops-tbody"> | |
{% if crops_data and crops_data|length > 0 %} | |
{% for crop in crops_data %} | |
<tr> | |
<td> | |
<input type="text" class="form-control" name="crop_name[]" value="{{ crop.name }}" required> | |
</td> | |
<td> | |
<input type="number" class="form-control" name="crop_area[]" step="0.01" min="0" value="{{ crop.area }}" required> | |
</td> | |
<td> | |
<select class="form-control" name="crop_month[]" required> | |
<option value="">Select Month</option> | |
<option value="January" {% if crop.sowing_month == 'January' %}selected{% endif %}>January</option> | |
<option value="February" {% if crop.sowing_month == 'February' %}selected{% endif %}>February</option> | |
<option value="March" {% if crop.sowing_month == 'March' %}selected{% endif %}>March</option> | |
<option value="April" {% if crop.sowing_month == 'April' %}selected{% endif %}>April</option> | |
<option value="May" {% if crop.sowing_month == 'May' %}selected{% endif %}>May</option> | |
<option value="June" {% if crop.sowing_month == 'June' %}selected{% endif %}>June</option> | |
<option value="July" {% if crop.sowing_month == 'July' %}selected{% endif %}>July</option> | |
<option value="August" {% if crop.sowing_month == 'August' %}selected{% endif %}>August</option> | |
<option value="September" {% if crop.sowing_month == 'September' %}selected{% endif %}>September</option> | |
<option value="October" {% if crop.sowing_month == 'October' %}selected{% endif %}>October</option> | |
<option value="November" {% if crop.sowing_month == 'November' %}selected{% endif %}>November</option> | |
<option value="December" {% if crop.sowing_month == 'December' %}selected{% endif %}>December</option> | |
</select> | |
</td> | |
<td> | |
<button type="button" class="btn btn-danger btn-sm remove-crop">Remove</button> | |
</td> | |
</tr> | |
{% endfor %} | |
{% else %} | |
<tr> | |
<td> | |
<input type="text" class="form-control" name="crop_name[]" required> | |
</td> | |
<td> | |
<input type="number" class="form-control" name="crop_area[]" step="0.01" min="0" required> | |
</td> | |
<td> | |
<select class="form-control" name="crop_month[]" required> | |
<option value="">Select Month</option> | |
<option value="January">January</option> | |
<option value="February">February</option> | |
<option value="March">March</option> | |
<option value="April">April</option> | |
<option value="May">May</option> | |
<option value="June">June</option> | |
<option value="July">July</option> | |
<option value="August">August</option> | |
<option value="September">September</option> | |
<option value="October">October</option> | |
<option value="November">November</option> | |
<option value="December">December</option> | |
</select> | |
</td> | |
<td> | |
<button type="button" class="btn btn-danger btn-sm remove-crop">Remove</button> | |
</td> | |
</tr> | |
{% endif %} | |
</tbody> | |
</table> | |
<button type="button" id="add-crop" class="btn btn-success">Add Another Crop</button> | |
</div> | |
</div> | |
</div> | |
</div> | |
<!-- Farm Geolocation Section --> | |
<div class="col-lg-6"> | |
<div class="form-section"> | |
<h3 class="mb-3">Farm Location</h3> | |
<div class="mb-3"> | |
<div id="map"></div> | |
</div> | |
<div class="row mb-3"> | |
<div class="col-6"> | |
<button type="button" id="startDrawingBtn" class="btn btn-success w-100">Edit Drawing</button> | |
</div> | |
<div class="col-6"> | |
<button type="button" id="clearDrawingBtn" class="btn btn-danger w-100">Clear Drawing</button> | |
</div> | |
</div> | |
<div class="alert alert-info" id="drawingStatus"> | |
Edit the farm boundary on the map if needed. | |
</div> | |
<input type="hidden" id="field_coordinates" name="field_coordinates" value="{{ farm.field_coordinates }}"> | |
<input type="hidden" id="center_lat" name="center_lat" value="{{ farm.center_lat }}"> | |
<input type="hidden" id="center_lng" name="center_lng" value="{{ farm.center_lng }}"> | |
<div class="mb-3"> | |
<label for="area" class="form-label">Farm Area (acres)</label> | |
<input type="number" class="form-control" id="area" name="area" step="0.01" min="0" value="{{ farm.area }}"> | |
<small class="text-muted">Leave empty to calculate automatically from the drawn boundary.</small> | |
</div> | |
</div> | |
<div class="d-grid"> | |
<button type="submit" id="submitBtn" class="btn btn-primary btn-lg">Save Changes</button> | |
</div> | |
</div> | |
</div> | |
</form> | |
</div> | |
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script> | |
<script> | |
let map; | |
let polygon = null; | |
let drawingManager; | |
function initMap() { | |
// Center the map on farm coordinates | |
const farmCenter = { | |
lat: {{ farm.latitude }}, | |
lng: {{ farm.longitude }} | |
}; | |
map = new google.maps.Map(document.getElementById('map'), { | |
zoom: 16, | |
center: farmCenter, | |
mapTypeId: 'satellite', | |
mapTypeControl: true, | |
streetViewControl: false, | |
fullscreenControl: true, | |
}); | |
// Initialize drawing tools | |
drawingManager = new google.maps.drawing.DrawingManager({ | |
drawingMode: null, | |
drawingControl: false, | |
polygonOptions: { | |
fillColor: '#4CAF50', | |
fillOpacity: 0.4, | |
strokeWeight: 2, | |
strokeColor: '#4CAF50', | |
editable: true | |
} | |
}); | |
drawingManager.setMap(map); | |
// Load existing farm boundary if exists | |
{% if farm.field_coordinates %} | |
try { | |
const fieldCoords = JSON.parse('{{ farm.field_coordinates|safe }}'); | |
const paths = fieldCoords.map(coord => new google.maps.LatLng(coord.lat, coord.lng)); | |
polygon = new google.maps.Polygon({ | |
paths: paths, | |
fillColor: '#4CAF50', | |
fillOpacity: 0.4, | |
strokeWeight: 2, | |
strokeColor: '#4CAF50', | |
editable: true | |
}); | |
polygon.setMap(map); | |
// Add listener for polygon changes | |
google.maps.event.addListener(polygon.getPath(), 'set_at', updateCoordinatesFields); | |
google.maps.event.addListener(polygon.getPath(), 'insert_at', updateCoordinatesFields); | |
// Update status | |
document.getElementById('drawingStatus').className = 'alert alert-success'; | |
document.getElementById('drawingStatus').textContent = 'Farm boundary loaded successfully!'; | |
} catch (e) { | |
console.error('Error parsing farm boundary:', e); | |
} | |
{% endif %} | |
// Setup event listeners for drawing | |
google.maps.event.addListener(drawingManager, 'polygoncomplete', function(poly) { | |
// Remove old polygon if exists | |
if (polygon !== null) { | |
polygon.setMap(null); | |
} | |
polygon = poly; | |
drawingManager.setDrawingMode(null); | |
document.getElementById('startDrawingBtn').textContent = "Edit Drawing"; | |
// Update hidden fields with polygon data | |
updateCoordinatesFields(); | |
// Add listener for polygon changes | |
google.maps.event.addListener(polygon.getPath(), 'set_at', updateCoordinatesFields); | |
google.maps.event.addListener(polygon.getPath(), 'insert_at', updateCoordinatesFields); | |
// Update status | |
document.getElementById('drawingStatus').className = 'alert alert-success'; | |
document.getElementById('drawingStatus').textContent = 'Farm boundary updated successfully!'; | |
}); | |
// Setup buttons | |
document.getElementById('startDrawingBtn').addEventListener('click', function() { | |
if (drawingManager.getDrawingMode() == google.maps.drawing.OverlayType.POLYGON) { | |
drawingManager.setDrawingMode(null); | |
this.textContent = polygon ? "Edit Drawing" : "Start Drawing"; | |
} else { | |
drawingManager.setDrawingMode(google.maps.drawing.OverlayType.POLYGON); | |
this.textContent = "Cancel Drawing"; | |
} | |
}); | |
document.getElementById('clearDrawingBtn').addEventListener('click', function() { | |
if (polygon) { | |
polygon.setMap(null); | |
polygon = null; | |
} | |
document.getElementById('startDrawingBtn').textContent = "Start Drawing"; | |
document.getElementById('drawingStatus').className = 'alert alert-warning'; | |
document.getElementById('drawingStatus').textContent = 'Please draw your farm boundary on the map.'; | |
// Clear hidden fields | |
document.getElementById('field_coordinates').value = ''; | |
document.getElementById('center_lat').value = ''; | |
document.getElementById('center_lng').value = ''; | |
}); | |
} | |
function updateCoordinatesFields() { | |
if (!polygon) return; | |
// Get polygon path and convert to array of coordinates | |
const path = polygon.getPath(); | |
const coordinates = []; | |
for (let i = 0; i < path.getLength(); i++) { | |
const point = path.getAt(i); | |
coordinates.push({ | |
lat: point.lat(), | |
lng: point.lng() | |
}); | |
} | |
// Calculate center of polygon | |
const bounds = new google.maps.LatLngBounds(); | |
path.forEach(latlng => bounds.extend(latlng)); | |
const center = bounds.getCenter(); | |
// Update hidden fields | |
document.getElementById('field_coordinates').value = JSON.stringify(coordinates); | |
document.getElementById('center_lat').value = center.lat(); | |
document.getElementById('center_lng').value = center.lng(); | |
// If area input is empty, compute and populate approximate area (acres) | |
try { | |
// compute approximate area using same method as add_farm | |
if (coordinates.length >= 3) { | |
let latSum = 0; | |
coordinates.forEach(p => latSum += p.lat); | |
const latAvg = latSum / coordinates.length; | |
const latAvgRad = latAvg * Math.PI / 180.0; | |
const metersPerDegLat = 111132.92; | |
const metersPerDegLon = 111320.0 * Math.cos(latAvgRad); | |
const pts = coordinates.map(p => ({ x: p.lng * metersPerDegLon, y: p.lat * metersPerDegLat })); | |
let area = 0; | |
for (let i = 0; i < pts.length; i++) { | |
const j = (i + 1) % pts.length; | |
area += pts[i].x * pts[j].y - pts[j].x * pts[i].y; | |
} | |
area = Math.abs(area) / 2.0; // m^2 | |
const acres = Math.round((area / 4046.8564224) * 10000) / 10000; | |
const areaInput = document.getElementById('area'); | |
if (areaInput && (!areaInput.value || Number(areaInput.value) === 0)) { | |
areaInput.value = acres; | |
} | |
} | |
} catch (e) { | |
console.error('Error computing area:', e); | |
} | |
} | |
// Crop management | |
document.getElementById('add-crop').addEventListener('click', function() { | |
const tbody = document.getElementById('crops-tbody'); | |
const newRow = document.createElement('tr'); | |
newRow.innerHTML = ` | |
<td> | |
<input type="text" class="form-control" name="crop_name[]" required> | |
</td> | |
<td> | |
<input type="number" class="form-control" name="crop_area[]" step="0.01" min="0" required> | |
</td> | |
<td> | |
<select class="form-control" name="crop_month[]" required> | |
<option value="">Select Month</option> | |
<option value="January">January</option> | |
<option value="February">February</option> | |
<option value="March">March</option> | |
<option value="April">April</option> | |
<option value="May">May</option> | |
<option value="June">June</option> | |
<option value="July">July</option> | |
<option value="August">August</option> | |
<option value="September">September</option> | |
<option value="October">October</option> | |
<option value="November">November</option> | |
<option value="December">December</option> | |
</select> | |
</td> | |
<td> | |
<button type="button" class="btn btn-danger btn-sm remove-crop">Remove</button> | |
</td> | |
`; | |
tbody.appendChild(newRow); | |
// Add event listener to new remove button | |
newRow.querySelector('.remove-crop').addEventListener('click', function() { | |
if (tbody.children.length > 1) { | |
tbody.removeChild(newRow); | |
} else { | |
alert('You must have at least one crop entry.'); | |
} | |
}); | |
}); | |
// Add event listeners to existing remove buttons | |
document.querySelectorAll('.remove-crop').forEach(button => { | |
button.addEventListener('click', function() { | |
const tbody = document.getElementById('crops-tbody'); | |
if (tbody.children.length > 1) { | |
tbody.removeChild(this.closest('tr')); | |
} else { | |
alert('You must have at least one crop entry.'); | |
} | |
}); | |
}); | |
</script> | |
<script async defer src="https://maps.googleapis.com/maps/api/js?key=AIzaSyBvVLjWmCja331H8SuIZ4UlJdZytuYkC6Y&libraries=drawing&callback=initMap"></script> | |
</body> | |
</html> | |