Use new optional layers in maps module

This commit is contained in:
Paul Chavard 2020-10-15 17:22:08 +02:00
parent eaa9b1c071
commit 1af0d30d94
14 changed files with 280 additions and 184 deletions

View file

@ -1,13 +1,15 @@
import React, { useState, useCallback, useRef, useMemo } from 'react';
import PropTypes from 'prop-types';
import mapboxgl from 'mapbox-gl';
import ReactMapboxGl, { GeoJSONLayer, ZoomControl } from 'react-mapbox-gl';
import { GeoJSONLayer, ZoomControl } from 'react-mapbox-gl';
import DrawControl from 'react-mapbox-gl-draw';
import '@mapbox/mapbox-gl-draw/dist/mapbox-gl-draw.css';
import { getJSON, ajax, fire } from '@utils';
import { getMapStyle, SwitchMapStyle } from '../MapStyles';
import Mapbox from '../shared/mapbox/Mapbox';
import { getMapStyle } from '../shared/mapbox/styles';
import SwitchMapStyle from '../shared/mapbox/SwitchMapStyle';
import ComboAdresseSearch from '../ComboAdresseSearch';
import {
@ -22,9 +24,7 @@ import {
generateId,
useEvent,
findFeature
} from '../shared/map';
const Map = ReactMapboxGl({});
} from '../shared/mapbox/utils';
function MapEditor({ featureCollection, url, preview, options }) {
const drawControl = useRef(null);
@ -38,10 +38,11 @@ function MapEditor({ featureCollection, url, preview, options }) {
const [cadastresFeatureCollection, setCadastresFeatureCollection] = useState(
filterFeatureCollection(featureCollection, 'cadastre')
);
const mapStyle = useMemo(
() => getMapStyle(style, options.cadastres, options.mnhn),
[style, options]
);
const mapStyle = useMemo(() => getMapStyle(style, options.layers), [
style,
options
]);
const hasCadastres = useMemo(() => options.layers.includes('cadastres'));
const translations = [
['.mapbox-gl-draw_line', 'Tracer une ligne'],
@ -288,7 +289,7 @@ function MapEditor({ featureCollection, url, preview, options }) {
}}
/>
</div>
<Map
<Mapbox
onStyleLoad={(map) => onMapLoad(map)}
fitBounds={bbox}
fitBoundsOptions={{ padding: 100 }}
@ -299,7 +300,7 @@ function MapEditor({ featureCollection, url, preview, options }) {
height: '500px'
}}
>
{options.cadastres ? (
{hasCadastres ? (
<GeoJSONLayer
data={cadastresFeatureCollection}
fillPaint={polygonCadastresFill}
@ -321,7 +322,7 @@ function MapEditor({ featureCollection, url, preview, options }) {
/>
<SwitchMapStyle style={style} setStyle={setStyle} ign={options.ign} />
<ZoomControl />
</Map>
</Mapbox>
</>
);
}
@ -335,8 +336,7 @@ MapEditor.propTypes = {
url: PropTypes.string,
preview: PropTypes.bool,
options: PropTypes.shape({
cadastres: PropTypes.bool,
mnhn: PropTypes.bool,
layers: PropTypes.array,
ign: PropTypes.bool
})
};

View file

@ -1,10 +1,11 @@
import React, { useState, useCallback, useMemo } from 'react';
import ReactMapboxGl, { ZoomControl, GeoJSONLayer } from 'react-mapbox-gl';
import { ZoomControl, GeoJSONLayer } from 'react-mapbox-gl';
import mapboxgl, { Popup } from 'mapbox-gl';
import PropTypes from 'prop-types';
import { getMapStyle, SwitchMapStyle } from '../MapStyles';
import Mapbox from '../shared/mapbox/Mapbox';
import { getMapStyle } from '../shared/mapbox/styles';
import SwitchMapStyle from '../shared/mapbox/SwitchMapStyle';
import {
filterFeatureCollection,
filterFeatureCollectionByGeometryType,
@ -12,9 +13,7 @@ import {
findFeature,
fitBounds,
getCenter
} from '../shared/map';
const Map = ReactMapboxGl({});
} from '../shared/mapbox/utils';
const MapReader = ({ featureCollection, options }) => {
const [currentMap, setCurrentMap] = useState(null);
@ -51,11 +50,11 @@ const MapReader = ({ featureCollection, options }) => {
),
[selectionsUtilisateurFeatureCollection]
);
const hasCadastres = !!cadastresFeatureCollection.length;
const mapStyle = useMemo(
() => getMapStyle(style, hasCadastres, options.mnhn),
[style, options, cadastresFeatureCollection]
);
const hasCadastres = useMemo(() => options.layers.includes('cadastres'));
const mapStyle = useMemo(() => getMapStyle(style, options.layers), [
style,
options
]);
const popup = useMemo(
() =>
new Popup({
@ -147,7 +146,7 @@ const MapReader = ({ featureCollection, options }) => {
}
return (
<Map
<Mapbox
onStyleLoad={(map) => onMapLoad(map)}
fitBounds={boundData}
fitBoundsOptions={{ padding: 100 }}
@ -186,7 +185,7 @@ const MapReader = ({ featureCollection, options }) => {
<SwitchMapStyle style={style} setStyle={setStyle} ign={options.ign} />
<ZoomControl />
</Map>
</Mapbox>
);
};
@ -197,8 +196,8 @@ MapReader.propTypes = {
features: PropTypes.array
}),
options: PropTypes.shape({
ign: PropTypes.bool,
mnhn: PropTypes.bool
layers: PropTypes.array,
ign: PropTypes.bool
})
};

View file

@ -1,96 +0,0 @@
const IGN_TOKEN = 'rc1egnbeoss72hxvd143tbyk';
function ignServiceURL(layer, format = 'image/png') {
const url = `https://wxs.ign.fr/${IGN_TOKEN}/geoportail/wmts`;
const query =
'service=WMTS&request=GetTile&version=1.0.0&tilematrixset=PM&tilematrix={z}&tilecol={x}&tilerow={y}&style=normal';
return `${url}?${query}&layer=${layer}&format=${format}`;
}
function rasterSource(tiles, attribution) {
return {
type: 'raster',
tiles,
tileSize: 256,
attribution,
minzoom: 0,
maxzoom: 18
};
}
export default {
version: 8,
metadat: {
'mapbox:autocomposite': false,
'mapbox:groups': {
1444849242106.713: { collapsed: false, name: 'Places' },
1444849334699.1902: { collapsed: true, name: 'Bridges' },
1444849345966.4436: { collapsed: false, name: 'Roads' },
1444849354174.1904: { collapsed: true, name: 'Tunnels' },
1444849364238.8171: { collapsed: false, name: 'Buildings' },
1444849382550.77: { collapsed: false, name: 'Water' },
1444849388993.3071: { collapsed: false, name: 'Land' }
},
'mapbox:type': 'template',
'openmaptiles:mapbox:owner': 'openmaptiles',
'openmaptiles:mapbox:source:url': 'mapbox://openmaptiles.4qljc88t',
'openmaptiles:version': '3.x',
'maputnik:renderer': 'mbgljs'
},
center: [0, 0],
zoom: 1,
bearing: 0,
pitch: 0,
sources: {
'decoupage-administratif': {
type: 'vector',
url:
'https://openmaptiles.geo.data.gouv.fr/data/decoupage-administratif.json'
},
openmaptiles: {
type: 'vector',
url: 'https://openmaptiles.geo.data.gouv.fr/data/france-vector.json'
},
'photographies-aeriennes': {
type: 'raster',
tiles: [
'https://tiles.geo.api.gouv.fr/photographies-aeriennes/tiles/{z}/{x}/{y}'
],
tileSize: 256,
attribution: 'Images aériennes © IGN',
minzoom: 0,
maxzoom: 19
},
cadastre: {
type: 'vector',
url: 'https://openmaptiles.geo.data.gouv.fr/data/cadastre.json'
},
'plan-ign': rasterSource(
[ignServiceURL('GEOGRAPHICALGRIDSYSTEMS.PLANIGNV2')],
'IGN-F/Géoportail'
),
'protectedareas-gp': rasterSource(
[ignServiceURL('PROTECTEDAREAS.GP')],
'IGN-F/Géoportail/MNHN'
),
'protectedareas-pn': rasterSource(
[ignServiceURL('PROTECTEDAREAS.PN')],
'IGN-F/Géoportail/MNHN'
),
'protectedareas-pnr': rasterSource(
[ignServiceURL('PROTECTEDAREAS.PNR')],
'IGN-F/Géoportail/MNHN'
),
'protectedareas-sic': rasterSource(
[ignServiceURL('PROTECTEDAREAS.SIC')],
'IGN-F/Géoportail/MNHN'
),
'protectedareas-zps': rasterSource(
[ignServiceURL('PROTECTEDAREAS.ZPS')],
'IGN-F/Géoportail/MNHN'
)
},
sprite: 'https://openmaptiles.github.io/osm-bright-gl-style/sprite',
glyphs: 'https://openmaptiles.geo.data.gouv.fr/fonts/{fontstack}/{range}.pbf'
};

View file

@ -1,55 +0,0 @@
import baseStyle from './base-style';
import cadastre from './cadastre';
import orthoStyle from './ortho-style';
import vectorStyle from './vector-style';
function rasterStyle(source) {
return {
id: source,
source,
type: 'raster',
paint: { 'raster-resampling': 'linear' }
};
}
export function getMapStyle(style, hasCadastres, hasMNHN) {
const mapStyle = { ...baseStyle };
switch (style) {
case 'ortho':
mapStyle.layers = orthoStyle;
mapStyle.id = 'ortho';
mapStyle.name = 'Photographies aériennes';
break;
case 'vector':
mapStyle.layers = vectorStyle;
mapStyle.id = 'vector';
mapStyle.name = 'Carte OSM';
break;
case 'ign':
mapStyle.layers = [rasterStyle('plan-ign')];
mapStyle.id = 'ign';
mapStyle.name = 'Carte IGN';
break;
}
if (hasCadastres) {
mapStyle.layers = mapStyle.layers.concat(cadastre);
mapStyle.id += '-cadastre';
}
if (hasMNHN) {
mapStyle.layers = mapStyle.layers.concat([
rasterStyle('protectedareas-gp'),
rasterStyle('protectedareas-pn'),
rasterStyle('protectedareas-pnr'),
rasterStyle('protectedareas-sic'),
rasterStyle('protectedareas-zps')
]);
mapStyle.id += '-mnhn';
}
return mapStyle;
}
export { SwitchMapStyle } from './SwitchMapStyle';

View file

@ -0,0 +1,3 @@
import ReactMapboxGl from 'react-mapbox-gl';
export default ReactMapboxGl({});

View file

@ -1,8 +1,9 @@
import React from 'react';
import ortho from './images/preview-ortho.png';
import vector from './images/preview-vector.png';
import PropTypes from 'prop-types';
import ortho from './styles/images/preview-ortho.png';
import vector from './styles/images/preview-vector.png';
const STYLES = {
ortho: {
title: 'Satellite',
@ -34,7 +35,7 @@ function getNextStyle(style, ign) {
return styles[index];
}
export const SwitchMapStyle = ({ style, setStyle, ign }) => {
function SwitchMapStyle({ style, setStyle, ign }) {
const nextStyle = getNextStyle(style, ign);
const { title, preview, color } = (ign ? IGN_STYLES : STYLES)[nextStyle];
@ -69,10 +70,12 @@ export const SwitchMapStyle = ({ style, setStyle, ign }) => {
</div>
</div>
);
};
}
SwitchMapStyle.propTypes = {
style: PropTypes.string,
setStyle: PropTypes.func,
ign: PropTypes.bool
};
export default SwitchMapStyle;

View file

@ -0,0 +1,213 @@
import cadastreLayers from './cadastre-layers';
const IGN_TOKEN = 'rc1egnbeoss72hxvd143tbyk';
function ignServiceURL(layer, format = 'image/png') {
const url = `https://wxs.ign.fr/${IGN_TOKEN}/geoportail/wmts`;
const query =
'service=WMTS&request=GetTile&version=1.0.0&tilematrixset=PM&tilematrix={z}&tilecol={x}&tilerow={y}&style=normal';
return `${url}?${query}&layer=${layer}&format=${format}`;
}
const OPTIONAL_LAYERS = [
{
label: 'UNESCO',
id: 'unesco',
layers: [
['Aires protégées Géoparcs', 'PROTECTEDAREAS.GP'],
['Réserves de biosphère', 'PROTECTEDAREAS.BIOS']
]
},
{
label: 'Arrêtés de protection',
id: 'arretes_protection',
layers: [
['Arrêtés de protection de biotope', 'PROTECTEDAREAS.APB'],
['Arrêtés de protection de géotope', 'PROTECTEDAREAS.APG']
]
},
{
label: 'Conservatoire du Littoral',
id: 'conservatoire_littoral',
layers: [
[
'Conservatoire du littoral : parcelles protégées',
'PROTECTEDAREAS.MNHN.CDL.PARCELS'
],
[
'Conservatoire du littoral : périmètres dintervention',
'PROTECTEDAREAS.MNHN.CDL.PERIMETER'
]
]
},
{
label: 'Réserves nationales de chasse et de faune sauvage',
id: 'reserves_chasse_faune_sauvage',
layers: [
[
'Réserves nationales de chasse et de faune sauvage',
'PROTECTEDAREAS.RNCF'
]
]
},
{
label: 'Réserves biologiques',
id: 'reserves_biologiques',
layers: [['Réserves biologiques', 'PROTECTEDAREAS.RB']]
},
{
label: 'Réserves naturelles',
id: 'reserves_naturelles',
layers: [
['Réserves naturelles nationales', 'PROTECTEDAREAS.RN'],
[
'Périmètres de protection de réserves naturelles',
'PROTECTEDAREAS.MNHN.RN.PERIMETER'
],
['Réserves naturelles de Corse', 'PROTECTEDAREAS.RNC'],
[
'Réserves naturelles régionales',
'PROTECTEDSITES.MNHN.RESERVES-REGIONALES'
]
]
},
{
label: 'Natura 2000',
id: 'natura_2000',
layers: [
['Sites Natura 2000 (Directive Habitats)', 'PROTECTEDAREAS.SIC'],
['Sites Natura 2000 (Directive Oiseaux)', 'PROTECTEDAREAS.ZPS']
]
},
{
label: 'Zones humides dimportance internationale',
id: 'zones_humides',
layers: [
['Zones humides dimportance internationale', 'PROTECTEDAREAS.RAMSAR']
]
},
{
label: 'ZNIEFF',
id: 'znieff',
layers: [
[
'Zones naturelles dintérêt écologique faunistique et floristique de type 1 (ZNIEFF 1 mer)',
'PROTECTEDAREAS.ZNIEFF1.SEA'
],
[
'Zones naturelles dintérêt écologique faunistique et floristique de type 1 (ZNIEFF 1)',
'PROTECTEDAREAS.ZNIEFF1'
],
[
'Zones naturelles dintérêt écologique faunistique et floristique de type 2 (ZNIEFF 2 mer)',
'PROTECTEDAREAS.ZNIEFF2.SEA'
],
[
'Zones naturelles dintérêt écologique faunistique et floristique de type 2 (ZNIEFF 2)',
'PROTECTEDAREAS.ZNIEFF2'
]
]
},
{
label: 'Cadastre',
id: 'cadastres',
layers: [['Cadastre', 'CADASTRE']]
}
];
function buildSources() {
return Object.fromEntries(
OPTIONAL_LAYERS.flatMap(({ layers }) => layers).map(([, code]) => [
code.toLowerCase().replace(/\./g, '-'),
rasterSource([ignServiceURL(code)], 'IGN-F/Géoportail/MNHN')
])
);
}
function rasterSource(tiles, attribution) {
return {
type: 'raster',
tiles,
tileSize: 256,
attribution,
minzoom: 0,
maxzoom: 18
};
}
export function buildLayers(ids) {
return OPTIONAL_LAYERS.filter(({ id }) => ids.includes(id))
.flatMap(({ layers }) => layers)
.map(([, code]) =>
code === 'CADASTRE'
? cadastreLayers
: rasterLayer(code.toLowerCase().replace(/\./g, '-'))
);
}
export function rasterLayer(source) {
return {
id: source,
source,
type: 'raster',
paint: { 'raster-resampling': 'linear' }
};
}
export default {
version: 8,
metadat: {
'mapbox:autocomposite': false,
'mapbox:groups': {
1444849242106.713: { collapsed: false, name: 'Places' },
1444849334699.1902: { collapsed: true, name: 'Bridges' },
1444849345966.4436: { collapsed: false, name: 'Roads' },
1444849354174.1904: { collapsed: true, name: 'Tunnels' },
1444849364238.8171: { collapsed: false, name: 'Buildings' },
1444849382550.77: { collapsed: false, name: 'Water' },
1444849388993.3071: { collapsed: false, name: 'Land' }
},
'mapbox:type': 'template',
'openmaptiles:mapbox:owner': 'openmaptiles',
'openmaptiles:mapbox:source:url': 'mapbox://openmaptiles.4qljc88t',
'openmaptiles:version': '3.x',
'maputnik:renderer': 'mbgljs'
},
center: [0, 0],
zoom: 1,
bearing: 0,
pitch: 0,
sources: {
'decoupage-administratif': {
type: 'vector',
url:
'https://openmaptiles.geo.data.gouv.fr/data/decoupage-administratif.json'
},
openmaptiles: {
type: 'vector',
url: 'https://openmaptiles.geo.data.gouv.fr/data/france-vector.json'
},
'photographies-aeriennes': {
type: 'raster',
tiles: [
'https://tiles.geo.api.gouv.fr/photographies-aeriennes/tiles/{z}/{x}/{y}'
],
tileSize: 256,
attribution: 'Images aériennes © IGN',
minzoom: 0,
maxzoom: 19
},
cadastre: {
type: 'vector',
url: 'https://openmaptiles.geo.data.gouv.fr/data/cadastre.json'
},
'plan-ign': rasterSource(
[ignServiceURL('GEOGRAPHICALGRIDSYSTEMS.PLANIGNV2')],
'IGN-F/Géoportail'
),
...buildSources()
},
sprite: 'https://openmaptiles.github.io/osm-bright-gl-style/sprite',
glyphs: 'https://openmaptiles.geo.data.gouv.fr/fonts/{fontstack}/{range}.pbf'
};

View file

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View file

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View file

@ -0,0 +1,29 @@
import baseStyle, { rasterLayer, buildLayers } from './base';
import orthoStyle from './ortho-style';
import vectorStyle from './vector-style';
export function getMapStyle(style, optionalLayers) {
const mapStyle = { ...baseStyle };
switch (style) {
case 'ortho':
mapStyle.layers = orthoStyle;
mapStyle.id = 'ortho';
mapStyle.name = 'Photographies aériennes';
break;
case 'vector':
mapStyle.layers = vectorStyle;
mapStyle.id = 'vector';
mapStyle.name = 'Carte OSM';
break;
case 'ign':
mapStyle.layers = [rasterLayer('plan-ign')];
mapStyle.id = 'ign';
mapStyle.name = 'Carte IGN';
break;
}
mapStyle.layers = mapStyle.layers.concat(buildLayers(optionalLayers));
return mapStyle;
}