class GeoJSONHandler {
constructor(mapSelector) {
this.mapSelector = mapSelector;
}
addGeoJSONToSelection(geoJSON) {
this.mapSelector.selectedAreas.push(geoJSON);
this.renderGeoJSONOnMap(geoJSON);
this.mapSelector.uiManager.updateSelectedAreasList();
}
renderGeoJSONOnMap(geoJSON) {
try {
if (!this._isValidGeoJSON(geoJSON)) {
console.warn("GeoJSON invalide ou sans géométrie", geoJSON);
return;
}
if (geoJSON.geometry.type === 'Point' && geoJSON.properties?.type === 'circle') {
this._renderCircle(geoJSON);
} else {
this._renderPolygon(geoJSON);
}
} catch (error) {
console.error("Erreur lors du rendu du GeoJSON sur la carte", error);
}
}
_isValidGeoJSON(geoJSON) {
return geoJSON && geoJSON.geometry;
}
_renderCircle(geoJSON) {
const coordinates = geoJSON.geometry.coordinates;
if (!this._isValidCoordinates(coordinates)) {
console.warn("Coordonnées de point invalides", coordinates);
return;
}
const radius = parseFloat(geoJSON.properties.radius);
if (isNaN(radius)) {
console.warn("Rayon invalide", geoJSON.properties.radius);
return;
}
if (geoJSON.properties.source === 'search') {
return;
}
const circle = L.circle([coordinates[1], coordinates[0]], {
radius: radius,
color: "#00394D",
fillColor: "#00394D",
fillOpacity: 0.2,
weight: 2
});
const popupContent = this._createCirclePopupContent(radius);
circle.bindPopup(popupContent);
circle.on('click', (e) => {
e.target.openPopup();
});
this.mapSelector.drawnItems.addLayer(circle);
}
_renderPolygon(geoJSON) {
L.geoJSON(geoJSON, {
style: {
color: "#00394D",
fillColor: "#00394D",
fillOpacity: 0.2,
weight: 2,
}
}).eachLayer(layer => {
if (geoJSON.properties?.name) {
let popupContent = geoJSON.properties.name;
if (geoJSON.geometry.type === 'Polygon' || geoJSON.geometry.type === 'MultiPolygon') {
const areaInSqMeters = this.calculatePolygonArea(geoJSON);
if (areaInSqMeters > 0) {
const areaText = this._formatAreaText(areaInSqMeters);
popupContent += `
Surface: ${areaText}`;
}
}
layer.bindPopup(popupContent);
}
this.mapSelector.drawnItems.addLayer(layer);
});
}
_isValidCoordinates(coordinates) {
return Array.isArray(coordinates) &&
coordinates.length >= 2 &&
typeof coordinates[0] === 'number' &&
typeof coordinates[1] === 'number';
}
calculatePolygonArea(geoJson) {
return GeoJSONHandler.calculateArea(geoJson);
}
static calculateArea(geoJson) {
if (!geoJson || !geoJson.geometry) return 0;
try {
if (geoJson.geometry.type === 'Point' && geoJson.properties?.radius) {
return GeoJSONHandler._calculateCircleArea(geoJson);
}
if (geoJson.geometry.type === 'Polygon') {
return GeoJSONHandler._calculatePolygonArea(geoJson);
}
if (geoJson.geometry.type === 'MultiPolygon') {
return GeoJSONHandler._calculateMultiPolygonArea(geoJson);
}
return 0;
} catch (err) {
console.error("Erreur lors du calcul de l'aire", err);
return 0;
}
}
static _calculateCircleArea(geoJson) {
const radius = parseFloat(geoJson.properties.radius);
return !isNaN(radius) ? Math.PI * Math.pow(radius, 2) : 0;
}
static _calculatePolygonArea(geoJson) {
const coordinates = geoJson.geometry.coordinates[0];
if (!coordinates || coordinates.length < 3) return 0;
const latLngs = coordinates.map(coord => ({lat: coord[1], lng: coord[0]}));
if (L.GeometryUtil?.geodesicArea) {
try {
const leafletLatLngs = latLngs.map(coord => L.latLng(coord.lat, coord.lng));
const area = L.GeometryUtil.geodesicArea(leafletLatLngs);
return isNaN(area) ? 0 : Math.abs(area);
} catch (e) {
console.warn("Erreur lors du calcul de l'aire géodésique", e);
}
}
return GeoJSONHandler.approximateArea(latLngs);
}
static approximateArea(latLngs) {
let area = 0;
const length = latLngs.length;
for (let i = 0; i < length - 1; i++) {
area += latLngs[i].lng * latLngs[i + 1].lat - latLngs[i + 1].lng * latLngs[i].lat;
}
area += latLngs[length - 1].lng * latLngs[0].lat - latLngs[0].lng * latLngs[length - 1].lat;
const avgLat = latLngs.reduce((sum, point) => sum + point.lat, 0) / length;
const latFactor = 111111;
const lngFactor = 111111 * Math.cos(avgLat * Math.PI / 180);
return Math.abs(area) * latFactor * lngFactor / 2;
}
static _calculateMultiPolygonArea(geoJson) {
let totalArea = 0;
for (const polygonCoordinates of geoJson.geometry.coordinates) {
const polygonGeoJson = {
type: "Feature",
geometry: {
type: "Polygon",
coordinates: polygonCoordinates
}
};
totalArea += GeoJSONHandler._calculatePolygonArea(polygonGeoJson);
}
return totalArea;
}
_formatRadiusText(radius) {
return radius >= 1000 ? `${(radius/1000).toFixed(2)} km` : `${Math.round(radius)} m`;
}
_formatAreaText(areaInSqMeters) {
return areaInSqMeters > 10000 ? `${(areaInSqMeters/1000000).toFixed(2)} km²` : `${Math.round(areaInSqMeters)} m²`;
}
_createCirclePopupContent(radius) {
const areaInSqMeters = Math.PI * Math.pow(radius, 2);
const radiusText = this._formatRadiusText(radius);
const areaText = this._formatAreaText(areaInSqMeters);
return `Rayon: ${radiusText}
Surface: ${areaText}`;
}
createZoneLabel(area, index) {
let label = '';
if (area.properties?.name) {
label = area.properties.name.split(',')[0];
} else if (area.properties?.label) {
label = area.properties.label;
} else {
label = `Zone ${index + 1}`;
}
let surfaceText = '';
let surfaceArea = 0;
if (area.geometry) {
if (area.geometry.type === 'Point' && area.properties?.radius) {
surfaceArea = Math.PI * Math.pow(parseFloat(area.properties.radius), 2);
} else if (area.geometry.type === 'Polygon') {
surfaceArea = this.calculatePolygonArea(area);
}
if (surfaceArea > 0) {
surfaceText = this._formatAreaText(surfaceArea);
label += `: ${surfaceText}`;
}
}
return label;
}
clearAllPolygons() {
this.mapSelector.drawnItems.clearLayers()
}
}