Refactor carto to share more code

This commit is contained in:
Paul Chavard 2018-10-16 11:49:00 +03:00
parent 902184fab2
commit febef735b8
8 changed files with 192 additions and 184 deletions

View file

@ -10,6 +10,7 @@ module.exports = {
plugins: ['prettier'], plugins: ['prettier'],
extends: ['eslint:recommended', 'prettier'], extends: ['eslint:recommended', 'prettier'],
env: { env: {
es6: true,
browser: true browser: true
}, },
rules: { rules: {

View file

@ -1,16 +1,17 @@
import { getData } from '../shared/data'; import { getData } from '../shared/data';
import { initMap } from '../shared/carto';
import { import {
initMap,
drawCadastre, drawCadastre,
drawQuartiersPrioritaires, drawQuartiersPrioritaires,
drawUserSelection drawUserSelection
} from './carto/draw'; } from '../shared/carto';
function initialize() { function initialize() {
if (document.getElementById('map')) { const element = document.getElementById('map');
const position = getData('carto').position;
const map = initMap(position); if (element) {
const data = getData('carto'); const data = getData('carto');
const map = initMap(element, data.position);
// draw external polygons // draw external polygons
drawCadastre(map, data); drawCadastre(map, data);

View file

@ -1,35 +0,0 @@
import L from 'leaflet';
import {
drawLayer,
noEditStyle,
CADASTRE_POLYGON_STYLE,
QP_POLYGON_STYLE
} from '../../shared/carto';
export function drawCadastre(map, data) {
drawLayer(
map,
data.cadastres,
noEditStyle(CADASTRE_POLYGON_STYLE),
'cadastres'
);
}
export function drawQuartiersPrioritaires(map, data) {
drawLayer(
map,
data.quartiersPrioritaires,
noEditStyle(QP_POLYGON_STYLE),
'quartiersPrioritaires'
);
}
export function drawUserSelection(map, data) {
if (data.selection.length > 0) {
const polygon = L.polygon(data.selection, {
color: 'red',
zIndex: 3
}).addTo(map);
map.fitBounds(polygon.getBounds());
}
}

View file

@ -1,81 +1,52 @@
import L from 'leaflet'; import { CREATE } from 'leaflet-freedraw';
import { on } from '@utils';
import FreeDraw, { NONE, CREATE } from 'leaflet-freedraw';
import { fire, on, getJSON } from '@utils';
import { getData } from '../shared/data'; import { getData } from '../shared/data';
import { initMap } from '../shared/carto'; import {
initMap,
import polygonArea from './carto/polygon_area'; geocodeAddress,
import drawFactory from './carto/draw'; drawUserSelection,
drawCadastre,
drawQuartiersPrioritaires,
addFreeDrawEvents
} from '../shared/carto';
function initialize() { function initialize() {
if (document.getElementById('map')) { const element = document.getElementById('map');
const data = getData('carto');
const position = data.position;
const map = initMap(position); if (element) {
const freeDraw = new FreeDraw({ const data = getData('carto');
mode: NONE, const map = initMap(element, data.position, true);
smoothFactor: 4,
mergePolygons: false addAddressSelectEvent(map);
on('#new', 'click', () => {
map.freeDraw.mode(CREATE);
}); });
map.addLayer(freeDraw); const cartoDrawZones = data => {
drawCadastre(map, data, true);
drawQuartiersPrioritaires(map, data, true);
};
addEventFreeDraw(freeDraw);
addEventSearchAddress(map);
const cartoDrawZones = drawFactory(map, freeDraw);
window.DS = { cartoDrawZones }; window.DS = { cartoDrawZones };
// draw external polygons
cartoDrawZones(data); cartoDrawZones(data);
if (freeDraw.polygons[0]) { // draw user polygon
map.setZoom(18); drawUserSelection(map, data, true);
map.fitBounds(freeDraw.polygons[0].getBounds()); addFreeDrawEvents(map, 'input[name=selection]');
}
} }
} }
addEventListener('turbolinks:load', initialize); addEventListener('turbolinks:load', initialize);
function addEventFreeDraw(freeDraw) { function addAddressSelectEvent(map) {
freeDraw.on('markers', ({ latLngs }) => {
const input = document.querySelector('input[name=selection]');
if (polygonArea(latLngs) < 300000) {
input.value = JSON.stringify(latLngs);
} else {
input.value = '{ "error": "TooManyPolygons" }';
}
fire(input, 'change');
});
on('#map', 'click', () => {
freeDraw.mode(NONE);
});
on('#new', 'click', () => {
freeDraw.mode(CREATE);
});
}
function getAddressPoint(map, request) {
getJSON('/address/geocode', { request }).then(data => {
if (data.lat !== null) {
map.setView(new L.LatLng(data.lat, data.lon), data.zoom);
}
});
}
function addEventSearchAddress(map) {
on( on(
'#search-by-address input[type=address]', '#search-by-address input[type=address]',
'autocomplete:select', 'autocomplete:select',
(_, seggestion) => { (_, { label }) => {
getAddressPoint(map, seggestion['label']); geocodeAddress(map, label);
} }
); );
} }

View file

@ -1,45 +0,0 @@
import { EDIT, DELETE } from 'leaflet-freedraw';
import { on } from '@utils';
import {
drawLayer,
CADASTRE_POLYGON_STYLE,
QP_POLYGON_STYLE
} from '../../shared/carto';
const SOURCES = {
cadastres: CADASTRE_POLYGON_STYLE,
quartiersPrioritaires: QP_POLYGON_STYLE
};
export default function draw(map, freeDraw) {
return data => {
if (data.selection) {
drawSelection(freeDraw, data.selection);
}
for (let source of Object.keys(SOURCES)) {
if (data[source]) {
drawLayer(map, data[source], SOURCES[source], source);
}
}
addEventEdit(freeDraw);
};
}
function drawSelection(selection, freeDraw) {
for (let polygon of selection) {
freeDraw.createPolygon(polygon);
}
}
function addEventEdit(freeDraw) {
document
.querySelector('.leaflet-container svg')
.removeAttribute('pointer-events');
on('.leaflet-container g path', 'click', () => {
setTimeout(() => {
freeDraw.mode(EDIT | DELETE);
}, 50);
});
}

View file

@ -1,57 +1,117 @@
import L from 'leaflet'; 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 LAYERS = {};
const MAPS = new WeakMap();
export function initMap(position) { export function initMap(element, position, editable = false) {
const map = L.map('map', { if (MAPS.has(element)) {
scrollWheelZoom: false return MAPS.get(element);
}).setView([position.lat, position.lon], position.zoom); } 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', { L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: attribution:
'&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors' '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map); }).addTo(map);
return map; if (editable) {
} const freeDraw = new FreeDraw({
mode: NONE,
smoothFactor: 4,
mergePolygons: false
});
map.addLayer(freeDraw);
map.freeDraw = freeDraw;
}
export function drawLayer(map, data, style, layerName = 'default') { MAPS.set(element, map);
removeLayer(map, layerName); return map;
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);
} }
} }
export function noEditStyle(style) { export function drawCadastre(map, { cadastres }, editable = false) {
return Object.assign({}, style, { drawLayer(
opacity: 0.7, map,
fillOpacity: 0.5, cadastres,
color: style.fillColor 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 drawUserSelection(map, { selection }, editable = false) {
let hasSelection = selection && selection.length > 0;
if (editable) {
if (hasSelection) {
selection.forEach(polygon => map.freeDraw.create(polygon));
let polygon = map.freeDraw.all()[0];
if (polygon) {
map.fitBounds(polygon.getBounds());
}
}
} else if (hasSelection) {
const polygon = L.polygon(selection, {
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);
}
}); });
} }
const POLYGON_STYLE = { export function getCurrentMap(input) {
weight: 2, let element = input.closest('.toolbar').parentElement.querySelector('.carte');
opacity: 0.3,
color: 'white',
dashArray: '3',
fillOpacity: 0.7
};
export const CADASTRE_POLYGON_STYLE = Object.assign({}, POLYGON_STYLE, { if (MAPS.has(element)) {
fillColor: '#8a6d3b' return MAPS.get(element);
}); }
}
export const QP_POLYGON_STYLE = Object.assign({}, POLYGON_STYLE, { export function addFreeDrawEvents(map, selector) {
fillColor: '#31708f' const input = findInput(selector);
}); map.freeDraw.on('markers', ({ latLngs }) => {
if (polygonArea(latLngs) < 300000) {
input.value = JSON.stringify(latLngs);
} else {
input.value = '{ "error": "TooManyPolygons" }';
}
fire(input, 'change');
});
}
function findInput(selector) {
return typeof selector === 'string'
? document.querySelector(selector)
: selector;
}
function createLayer(map, layerName) { function createLayer(map, layerName) {
const layer = (LAYERS[layerName] = new L.GeoJSON(undefined, { const layer = (LAYERS[layerName] = new L.GeoJSON(undefined, {
@ -69,3 +129,58 @@ function removeLayer(map, layerName) {
map.removeLayer(layer); 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'
});
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);
}
}
});

View file

@ -1,6 +1,6 @@
#carte-page.row #carte-page.row
.col-md-12.col-lg-12 .col-md-12.col-lg-12
#map.edit #map.carte.edit
%span.zones %span.zones
= render partial: 'zones', locals: { dossier: dossier, error: @error } = render partial: 'zones', locals: { dossier: dossier, error: @error }