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() } }