Refactor carto to share more code
This commit is contained in:
parent
902184fab2
commit
febef735b8
8 changed files with 192 additions and 184 deletions
|
@ -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: {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
|
||||||
});
|
|
||||||
}
|
|
|
@ -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:
|
||||||
'© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
'© <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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
|
@ -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 }
|
||||||
|
|
Loading…
Reference in a new issue