import L from 'leaflet'; import FreeDraw, { NONE, EDIT, DELETE } from 'leaflet-freedraw'; import { fire, getJSON, delegate } from '@utils'; import polygonArea from './polygon_area'; const LAYERS = {}; const MAPS = new WeakMap(); export function initMap(element, position, editable = false) { if (MAPS.has(element)) { return MAPS.get(element); } else { const map = L.map(element, { scrollWheelZoom: false }).setView([position.lat, position.lon], editable ? 18 : position.zoom); L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { attribution: '© OpenStreetMap contributors' }).addTo(map); if (editable) { const freeDraw = new FreeDraw({ mode: NONE, smoothFactor: 4, mergePolygons: false }); map.addLayer(freeDraw); map.freeDraw = freeDraw; } MAPS.set(element, map); return map; } } export function drawCadastre(map, { cadastres }, editable = false) { drawLayer( map, cadastres, editable ? CADASTRE_POLYGON_STYLE : noEditStyle(CADASTRE_POLYGON_STYLE), 'cadastres' ); } export function drawQuartiersPrioritaires( map, { quartiersPrioritaires }, editable = false ) { drawLayer( map, quartiersPrioritaires, editable ? QP_POLYGON_STYLE : noEditStyle(QP_POLYGON_STYLE), 'quartiersPrioritaires' ); } export function drawParcellesAgricoles( map, { parcellesAgricoles }, editable = false ) { drawLayer( map, parcellesAgricoles, editable ? RPG_POLYGON_STYLE : noEditStyle(RPG_POLYGON_STYLE), 'parcellesAgricoles' ); } export function drawUserSelection(map, { selection }, editable = false) { if (selection) { const coordinates = toLatLngs(selection); if (editable) { coordinates.forEach(polygon => map.freeDraw.create(polygon)); const polygon = map.freeDraw.all()[0]; if (polygon) { map.fitBounds(polygon.getBounds()); } } else { const polygon = L.polygon(coordinates, { color: 'red', zIndex: 3 }).addTo(map); map.fitBounds(polygon.getBounds()); } } } export function geocodeAddress(map, query) { getJSON('/address/geocode', { request: query }).then(data => { if (data.lat !== null) { map.setView(new L.LatLng(data.lat, data.lon), data.zoom); } }); } export function getCurrentMap(input) { let element = input.closest('.toolbar').parentElement.querySelector('.carte'); if (MAPS.has(element)) { return MAPS.get(element); } } const EMPTY_GEO_JSON = '[]'; const ERROR_GEO_JSON = ''; export function addFreeDrawEvents(map, selector) { const input = findInput(selector); map.freeDraw.on('markers', ({ latLngs }) => { if (latLngs.length === 0) { input.value = EMPTY_GEO_JSON; } else if (polygonArea(latLngs) < 300000) { input.value = JSON.stringify(latLngs); } else { input.value = ERROR_GEO_JSON; } fire(input, 'change'); }); } function toLatLngs({ coordinates }) { return coordinates.map(polygon => polygon[0].map(point => ({ lng: point[0], lat: point[1] })) ); } function findInput(selector) { return typeof selector === 'string' ? document.querySelector(selector) : selector; } function createLayer(map, layerName) { const layer = (LAYERS[layerName] = new L.GeoJSON(undefined, { interactive: false })); layer.addTo(map); return layer; } function removeLayer(map, layerName) { const layer = LAYERS[layerName]; if (layer) { delete LAYERS[layerName]; map.removeLayer(layer); } } function drawLayer(map, data, style, layerName = 'default') { removeLayer(map, layerName); if (Array.isArray(data) && data.length > 0) { const layer = createLayer(map, layerName); data.forEach(function(item) { layer.addData(item.geometry); }); layer.setStyle(style).addTo(map); } } function noEditStyle(style) { return Object.assign({}, style, { opacity: 0.7, fillOpacity: 0.5, color: style.fillColor }); } const POLYGON_STYLE = { weight: 2, opacity: 0.3, color: 'white', dashArray: '3', fillOpacity: 0.7 }; const CADASTRE_POLYGON_STYLE = Object.assign({}, POLYGON_STYLE, { fillColor: '#8a6d3b' }); const QP_POLYGON_STYLE = Object.assign({}, POLYGON_STYLE, { fillColor: '#31708f' }); const RPG_POLYGON_STYLE = Object.assign({}, POLYGON_STYLE, { fillColor: '#31708f' }); delegate('click', '.carte.edit', event => { let element = event.target; let isPath = element.matches('.leaflet-container g path'); let map = element.matches('.carte') ? element : element.closest('.carte'); let freeDraw = MAPS.has(map) ? MAPS.get(map).freeDraw : null; if (freeDraw) { if (isPath) { setTimeout(() => { freeDraw.mode(EDIT | DELETE); }, 50); } else { freeDraw.mode(NONE); } } });