demarches-normaliennes/app/javascript/shared/carte.js

256 lines
5.7 KiB
JavaScript
Raw Normal View History

2019-04-25 16:30:51 +02:00
/* globals FreeDraw L */
2018-10-16 10:49:00 +02:00
import { fire, getJSON, delegate } from '@utils';
import polygonArea from './polygon_area';
2018-10-03 10:39:35 +02:00
2018-10-16 10:49:00 +02:00
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);
const loadTilesLayer = process.env.RAILS_ENV != 'test';
if (loadTilesLayer) {
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution:
'&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);
}
2018-10-16 10:49:00 +02:00
if (editable) {
const freeDraw = new FreeDraw({
2019-04-25 16:30:51 +02:00
mode: FreeDraw.NONE,
2018-10-16 10:49:00 +02:00
smoothFactor: 4,
mergePolygons: false
});
map.addLayer(freeDraw);
map.freeDraw = freeDraw;
}
2018-10-16 10:49:00 +02:00
MAPS.set(element, map);
return map;
}
}
2018-10-13 10:33:56 +02:00
2019-04-25 16:30:51 +02:00
export function drawPolygons(map, data, { editable, initial }) {
if (initial) {
drawUserSelection(map, data, editable);
}
clearLayers(map);
drawCadastre(map, data, editable);
drawQuartiersPrioritaires(map, data, editable);
drawParcellesAgricoles(map, data, editable);
bringToFrontUserSelection(map);
}
export function drawUserSelection(map, { selection }, editable = false) {
if (selection) {
const coordinates = toLatLngs(selection);
let polygon;
if (editable) {
coordinates.forEach(polygon => map.freeDraw.create(polygon));
[polygon] = markFreeDrawLayers(map);
} else {
polygon = L.polygon(coordinates, {
color: 'red',
zIndex: 3
});
polygon.addTo(map);
}
if (polygon) {
map.fitBounds(polygon.getBounds());
}
}
}
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;
}
markFreeDrawLayers(map);
fire(input, 'change');
});
}
function drawCadastre(map, { cadastres }, editable = false) {
2018-10-16 10:49:00 +02:00
drawLayer(
map,
cadastres,
2019-04-25 16:30:51 +02:00
editable ? CADASTRE_POLYGON_STYLE : noEditStyle(CADASTRE_POLYGON_STYLE)
2018-10-16 10:49:00 +02:00
);
}
2018-10-13 10:33:56 +02:00
2019-04-25 16:30:51 +02:00
function drawQuartiersPrioritaires(
2018-10-16 10:49:00 +02:00
map,
{ quartiersPrioritaires },
editable = false
) {
drawLayer(
map,
quartiersPrioritaires,
2019-04-25 16:30:51 +02:00
editable ? QP_POLYGON_STYLE : noEditStyle(QP_POLYGON_STYLE)
2018-10-16 10:49:00 +02:00
);
}
2019-04-25 16:30:51 +02:00
function drawParcellesAgricoles(map, { parcellesAgricoles }, editable = false) {
2018-10-23 15:38:20 +02:00
drawLayer(
map,
parcellesAgricoles,
2019-04-25 16:30:51 +02:00
editable ? RPG_POLYGON_STYLE : noEditStyle(RPG_POLYGON_STYLE)
2018-10-23 15:38:20 +02:00
);
}
2019-04-25 16:30:51 +02:00
function geocodeAddress(map, query) {
2018-10-16 10:49:00 +02:00
getJSON('/address/geocode', { request: query }).then(data => {
if (data.lat !== null) {
map.setView(new L.LatLng(data.lat, data.lon), data.zoom);
}
});
2018-10-13 10:33:56 +02:00
}
2019-04-25 16:30:51 +02:00
function getCurrentMap(element) {
if (!element.matches('.carte')) {
const closestCarteElement = element.closest('.carte');
const closestToolbarElement = element.closest('.toolbar');
element = closestCarteElement
? closestCarteElement
: closestToolbarElement.parentElement.querySelector('.carte');
}
2018-10-16 10:49:00 +02:00
if (MAPS.has(element)) {
return MAPS.get(element);
}
}
const EMPTY_GEO_JSON = '[]';
const ERROR_GEO_JSON = '';
2018-11-30 13:19:19 +01:00
function toLatLngs({ coordinates }) {
return coordinates.map(polygon =>
polygon[0].map(point => ({ lng: point[0], lat: point[1] }))
);
}
2018-10-16 10:49:00 +02:00
function findInput(selector) {
return typeof selector === 'string'
? document.querySelector(selector)
: selector;
}
2019-04-25 16:30:51 +02:00
function createLayer(map) {
const layer = new L.GeoJSON(undefined, {
2018-10-16 10:49:00 +02:00
interactive: false
2019-04-25 16:30:51 +02:00
});
2018-10-16 10:49:00 +02:00
layer.addTo(map);
return layer;
}
2019-04-25 16:30:51 +02:00
function clearLayers(map) {
map.eachLayer(layer => {
if (layer instanceof L.GeoJSON) {
map.removeLayer(layer);
}
});
}
2018-10-16 10:49:00 +02:00
2019-04-25 16:30:51 +02:00
function bringToFrontUserSelection(map) {
map.eachLayer(layer => {
if (layer.isFreeDraw) {
layer.bringToFront();
}
});
2018-10-16 10:49:00 +02:00
}
2019-04-25 16:30:51 +02:00
function markFreeDrawLayers(map) {
return map.freeDraw.all().map(layer => {
layer.isFreeDraw = true;
return layer;
});
}
2018-10-13 10:33:23 +02:00
2019-04-25 16:30:51 +02:00
function drawLayer(map, data, style) {
2018-10-13 10:33:23 +02:00
if (Array.isArray(data) && data.length > 0) {
2019-04-25 16:30:51 +02:00
const layer = createLayer(map);
2018-10-13 10:33:23 +02:00
data.forEach(function(item) {
layer.addData(item.geometry);
});
layer.setStyle(style).addTo(map);
}
}
2018-10-16 10:49:00 +02:00
function noEditStyle(style) {
2018-10-13 10:34:26 +02:00
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
};
2018-10-16 10:49:00 +02:00
const CADASTRE_POLYGON_STYLE = Object.assign({}, POLYGON_STYLE, {
2018-10-13 10:34:26 +02:00
fillColor: '#8a6d3b'
});
2018-10-16 10:49:00 +02:00
const QP_POLYGON_STYLE = Object.assign({}, POLYGON_STYLE, {
2018-10-13 10:34:26 +02:00
fillColor: '#31708f'
});
2018-10-23 15:38:20 +02:00
const RPG_POLYGON_STYLE = Object.assign({}, POLYGON_STYLE, {
fillColor: '#31708f'
});
2018-10-16 10:49:00 +02:00
delegate('click', '.carte.edit', event => {
2019-04-25 16:30:51 +02:00
const map = getCurrentMap(event.target);
2019-04-25 16:30:51 +02:00
if (map) {
const isPath = event.target.matches('.leaflet-container g path');
2018-10-16 10:49:00 +02:00
if (isPath) {
setTimeout(() => {
2019-04-25 16:30:51 +02:00
map.freeDraw.mode(FreeDraw.EDIT | FreeDraw.DELETE);
2018-10-16 10:49:00 +02:00
}, 50);
} else {
2019-04-25 16:30:51 +02:00
map.freeDraw.mode(FreeDraw.NONE);
2018-10-16 10:49:00 +02:00
}
}
2018-10-16 10:49:00 +02:00
});
2019-04-25 16:30:51 +02:00
delegate('click', '.toolbar .new-area', event => {
event.preventDefault();
const map = getCurrentMap(event.target);
if (map) {
map.freeDraw.mode(FreeDraw.CREATE);
}
});
delegate('autocomplete:select', '.toolbar [data-address]', event => {
const map = getCurrentMap(event.target);
if (map) {
geocodeAddress(map, event.detail.label);
}
});