// Editor delle piantine (pagina /piantine, solo amministratore). // // Mappa Leaflet su tessere OpenStreetMap: mostra l'area del KML, i poligoni // dei territori già salvati e permette di disegnarne di nuovi con // leaflet-draw. Parla con il componente Livewire attraverso eventi: // JS → Livewire: 'poligono-disegnato', 'territorio-selezionato-mappa' // Livewire → JS: 'piantine-dati-aggiornati' import L from 'leaflet'; import 'leaflet/dist/leaflet.css'; import 'leaflet-draw'; import 'leaflet-draw/dist/leaflet.draw.css'; const STILE_AREA = { color: '#2563eb', weight: 2, dashArray: '8 6', fill: false, interactive: false }; const STILE_SALVATO = { color: '#6b7280', weight: 2, fillColor: '#6b7280', fillOpacity: 0.12 }; const STILE_SELEZIONATO = { color: '#4f46e5', weight: 3, fillColor: '#6366f1', fillOpacity: 0.2 }; const STILE_IN_ATTESA = { color: '#d81b1b', weight: 3, fillColor: '#ef4444', fillOpacity: 0.15 }; function initPiantine() { const contenitore = document.getElementById('piantine-map'); if (!contenitore || contenitore.dataset.inizializzato) { return; } contenitore.dataset.inizializzato = '1'; let dati = { area: null, poligoni: [], selezionato: null }; try { dati = JSON.parse(document.getElementById('piantine-dati').textContent); } catch { // si parte comunque con la mappa vuota } // Etichette in italiano per la barra di disegno. L.drawLocal.draw.toolbar.buttons.polygon = 'Disegna il poligono di un territorio'; L.drawLocal.draw.toolbar.actions = { title: 'Annulla il disegno', text: 'Annulla' }; L.drawLocal.draw.toolbar.finish = { title: 'Concludi il disegno', text: 'Concludi' }; L.drawLocal.draw.toolbar.undo = { title: 'Rimuovi l\'ultimo punto', text: 'Ultimo punto' }; L.drawLocal.draw.handlers.polygon.tooltip = { start: 'Clicca sulla mappa per iniziare il poligono.', cont: 'Continua a cliccare lungo il confine.', end: 'Clicca sul primo punto per chiudere il poligono.', }; const mappa = L.map(contenitore, { zoomControl: true }); L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 19, attribution: '© OpenStreetMap contributors', }).addTo(mappa); let layerArea = null; const layerSalvati = L.featureGroup().addTo(mappa); let layerInAttesa = null; mappa.addControl(new L.Control.Draw({ draw: { polygon: { allowIntersection: false, showArea: false, shapeOptions: STILE_IN_ATTESA }, polyline: false, rectangle: false, circle: false, circlemarker: false, marker: false, }, edit: false, })); function ridisegna(nuoviDati, adattaVista) { dati = nuoviDati; if (layerArea) { mappa.removeLayer(layerArea); layerArea = null; } if (dati.area) { layerArea = L.geoJSON(dati.area, { style: STILE_AREA, interactive: false }).addTo(mappa); } layerSalvati.clearLayers(); for (const poligono of dati.poligoni) { const selezionato = dati.selezionato === poligono.territorioId; const layer = L.geoJSON( { type: 'Feature', properties: {}, geometry: poligono.geometry }, { style: selezionato ? STILE_SELEZIONATO : STILE_SALVATO } ); layer.bindTooltip(`Terr. ${poligono.numero}`, { sticky: true }); layer.on('click', () => { window.Livewire.dispatch('territorio-selezionato-mappa', { territorioId: poligono.territorioId }); }); layerSalvati.addLayer(layer); } if (!adattaVista) { return; } const riferimento = layerArea ?? (dati.poligoni.length ? layerSalvati : null); if (riferimento) { mappa.fitBounds(riferimento.getBounds().pad(0.08)); } else { mappa.setView([41.9, 12.5], 6); // Italia: nessun dato ancora caricato } } ridisegna(dati, true); mappa.on(L.Draw.Event.CREATED, (evento) => { if (layerInAttesa) { mappa.removeLayer(layerInAttesa); } layerInAttesa = evento.layer; layerInAttesa.setStyle(STILE_IN_ATTESA); layerInAttesa.addTo(mappa); window.Livewire.dispatch('poligono-disegnato', { geometry: evento.layer.toGeoJSON().geometry }); }); let registrato = false; document.addEventListener('livewire:init', registraEventi); if (window.Livewire) { registraEventi(); } function registraEventi() { if (registrato) { return; } registrato = true; window.Livewire.on('piantine-dati-aggiornati', ({ dati: nuovi }) => { // Dopo un salvataggio il poligono provvisorio è diventato // definitivo (o è stato scartato): via il tracciato rosso. if (layerInAttesa) { mappa.removeLayer(layerInAttesa); layerInAttesa = null; } ridisegna(nuovi, false); }); } } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initPiantine); } else { initPiantine(); }