diff --git a/loko/authorizations/templates/authorizations/new_authorization_default.html b/loko/authorizations/templates/authorizations/new_authorization_default.html index 7741564..183b108 100644 --- a/loko/authorizations/templates/authorizations/new_authorization_default.html +++ b/loko/authorizations/templates/authorizations/new_authorization_default.html @@ -219,9 +219,6 @@ - @@ -478,52 +475,118 @@ if (!drawing) return; addVertex(e.lngLat.lng, e.lngLat.lat); }); + + map.on('dblclick', function (e) { + if (!drawing) return; + e.preventDefault(); + handleDoubleClick(); + }); } function addVertex(lng, lat) { vertices.push([lng, lat]); + const isFirst = markers.length === 0; + const el = document.createElement('div'); - el.style.cssText = 'width:10px;height:10px;border-radius:50%;background:#0d6efd;border:2px solid #fff;box-shadow:0 0 3px rgba(0,0,0,.4);cursor:pointer;'; + if (isFirst) { + el.className = 'poly-marker poly-marker-first'; + el.style.cssText = 'width:14px;height:14px;border-radius:50%;background:#198754;border:2px solid #fff;box-shadow:0 0 4px rgba(0,0,0,.5);cursor:pointer;transition:transform 0.15s;'; + el.title = '{% translate "Cliquer pour fermer le polygone" %}'; + el.addEventListener('mouseenter', function () { + if (vertices.length >= 3) el.style.transform = 'scale(1.3)'; + }); + el.addEventListener('mouseleave', function () { + el.style.transform = 'scale(1)'; + }); + el.addEventListener('click', function (ev) { + ev.stopPropagation(); + if (vertices.length >= 3) { + finishPolygon(); + } + }); + } else { + el.className = 'poly-marker'; + el.style.cssText = 'width:10px;height:10px;border-radius:50%;background:#0d6efd;border:2px solid #fff;box-shadow:0 0 3px rgba(0,0,0,.4);cursor:default;'; + } + const marker = new maplibregl.Marker({ element: el }).setLngLat([lng, lat]).addTo(map); markers.push(marker); - // Clicking the first vertex closes the polygon - if (markers.length === 1) { - el.title = '{% translate "Cliquer pour fermer le polygone" %}'; - el.addEventListener('click', function (ev) { - ev.stopPropagation(); - finishPolygon(); - }); - } renderPreview(); + updateGeoJSON(); + updateHint(); + } + + function handleDoubleClick() { + if (!drawing) return; + // In MapLibre, dblclick triggers two click events first. + // Remove the duplicated last vertex if close to the preceding one. + if (vertices.length >= 2) { + const last = vertices[vertices.length - 1]; + const prev = vertices[vertices.length - 2]; + if (Math.hypot(last[0] - prev[0], last[1] - prev[1]) < 0.0001) { + vertices.pop(); + const lastMarker = markers.pop(); + if (lastMarker) lastMarker.remove(); + } + } + if (vertices.length >= 3) { + finishPolygon(); + } + } + + function updateGeoJSON() { + if (vertices.length >= 3) { + const coords = [vertices.concat([vertices[0]])]; + const geojson = JSON.stringify({ type: 'Polygon', coordinates: coords }); + document.getElementById('id_geom_geojson').value = geojson; + } else { + document.getElementById('id_geom_geojson').value = ''; + } } function renderPreview() { if (!map.getSource('poly-preview')) return; - const coords = vertices.length >= 3 - ? [vertices.concat([vertices[0]])] - : []; - const geojson = coords.length ? { - type: 'Feature', - geometry: { type: 'Polygon', coordinates: coords }, - } : { type: 'FeatureCollection', features: [] }; - map.getSource('poly-preview').setData(geojson); + if (vertices.length >= 3) { + const coords = [vertices.concat([vertices[0]])]; + map.getSource('poly-preview').setData({ + type: 'Feature', + geometry: { type: 'Polygon', coordinates: coords }, + }); + } else if (vertices.length === 2) { + map.getSource('poly-preview').setData({ + type: 'Feature', + geometry: { type: 'LineString', coordinates: vertices }, + }); + } else { + map.getSource('poly-preview').setData({ + type: 'FeatureCollection', + features: [], + }); + } } - function finishPolygon() { - if (vertices.length < 3) return; - drawing = false; - const geojson = JSON.stringify({ type: 'Polygon', coordinates: [vertices.concat([vertices[0]])] }); - document.getElementById('id_geom_geojson').value = geojson; - renderPreview(); - updateUI(false); - document.getElementById('poly-hint').textContent = - '{% translate "Polygone enregistré. Cliquez sur « Dessiner » pour le redessiner." %}'; - map.getCanvas().style.cursor = 'default'; + function updateHint() { + const hintEl = document.getElementById('poly-hint'); + if (!hintEl) return; + if (!drawing) { + if (vertices.length >= 3 || document.getElementById('id_geom_geojson').value) { + hintEl.textContent = '{% translate "Polygone enregistré. Cliquez sur « Dessiner » pour le redessiner." %}'; + } else { + hintEl.textContent = '{% translate "Cliquez sur « Dessiner un polygone » puis cliquez sur la carte pour ajouter des sommets. Cliquez sur le premier sommet pour fermer le polygone." %}'; + } + return; + } + + if (vertices.length <= 1) { + hintEl.textContent = '{% translate "Cliquez sur la carte pour ajouter des sommets." %}'; + } else { + hintEl.textContent = '{% translate "Cliquez sur la carte pour ajouter des sommets. Cliquez sur le premier sommet pour fermer le polygone." %}'; + } } - function clearPolygon() { - drawing = false; + function startDrawing() { + drawing = true; vertices = []; markers.forEach(m => m.remove()); markers = []; @@ -531,35 +594,45 @@ if (map.getSource('poly-preview')) { map.getSource('poly-preview').setData({ type: 'FeatureCollection', features: [] }); } - updateUI(false); - document.getElementById('poly-hint').textContent = - '{% translate "Cliquez sur « Dessiner un polygone » puis cliquez sur la carte pour ajouter des sommets." %}'; - map.getCanvas().style.cursor = 'default'; + map.doubleClickZoom.disable(); + map.getCanvas().style.cursor = 'crosshair'; + document.getElementById('poly-draw-btn').classList.add('active'); + updateHint(); } - function updateUI(isDrawing) { - document.getElementById('poly-draw-btn').classList.toggle('d-none', isDrawing); - document.getElementById('poly-finish-btn').classList.toggle('d-none', !isDrawing); - map.getCanvas().style.cursor = isDrawing ? 'crosshair' : 'default'; + function finishPolygon() { + if (vertices.length < 3) return; + drawing = false; + map.doubleClickZoom.enable(); + map.getCanvas().style.cursor = 'default'; + updateGeoJSON(); + renderPreview(); + document.getElementById('poly-draw-btn').classList.remove('active'); + updateHint(); + } + + function clearPolygon() { + drawing = false; + map.doubleClickZoom.enable(); + map.getCanvas().style.cursor = 'default'; + vertices = []; + markers.forEach(m => m.remove()); + markers = []; + document.getElementById('id_geom_geojson').value = ''; + if (map.getSource('poly-preview')) { + map.getSource('poly-preview').setData({ type: 'FeatureCollection', features: [] }); + } + document.getElementById('poly-draw-btn').classList.remove('active'); + updateHint(); } document.addEventListener('DOMContentLoaded', function () { initMap(); document.getElementById('poly-draw-btn').addEventListener('click', function () { - drawing = true; - vertices = []; - markers.forEach(m => m.remove()); - markers = []; - if (map.getSource('poly-preview')) { - map.getSource('poly-preview').setData({ type: 'FeatureCollection', features: [] }); - } - updateUI(true); - document.getElementById('poly-hint').textContent = - '{% translate "Cliquez sur la carte pour ajouter des sommets. Cliquez sur le premier sommet pour fermer le polygone." %}'; + startDrawing(); }); - document.getElementById('poly-finish-btn').addEventListener('click', finishPolygon); document.getElementById('poly-clear-btn').addEventListener('click', clearPolygon); // -----------------------------------------------------------------------