2021-05-06 18:51:19 +02:00
|
|
|
|
import React, { useMemo, useState, useEffect } from 'react';
|
|
|
|
|
import PropTypes from 'prop-types';
|
2021-06-30 10:28:02 +02:00
|
|
|
|
import { Popover, RadioGroup } from '@headlessui/react';
|
|
|
|
|
import { usePopper } from 'react-popper';
|
|
|
|
|
import { MapIcon } from '@heroicons/react/outline';
|
2021-07-01 18:50:35 +02:00
|
|
|
|
import { Slider } from '@reach/slider';
|
2021-07-07 14:12:50 +02:00
|
|
|
|
import { useId } from '@reach/auto-id';
|
2021-07-01 18:50:35 +02:00
|
|
|
|
import '@reach/slider/styles.css';
|
2021-05-06 18:51:19 +02:00
|
|
|
|
|
2021-07-01 18:50:35 +02:00
|
|
|
|
import { getMapStyle, getLayerName, NBS } from './styles';
|
2021-05-06 18:51:19 +02:00
|
|
|
|
|
|
|
|
|
const STYLES = {
|
2021-06-30 10:28:02 +02:00
|
|
|
|
ortho: 'Satellite',
|
|
|
|
|
vector: 'Vectoriel',
|
|
|
|
|
ign: 'Carte IGN'
|
2021-05-06 18:51:19 +02:00
|
|
|
|
};
|
|
|
|
|
|
2021-06-30 10:28:02 +02:00
|
|
|
|
function optionalLayersMap(optionalLayers) {
|
|
|
|
|
return Object.fromEntries(
|
2021-07-07 14:02:55 +02:00
|
|
|
|
optionalLayers.map((layer) => [
|
|
|
|
|
layer,
|
|
|
|
|
{
|
|
|
|
|
configurable: layer != 'cadastres',
|
|
|
|
|
enabled: true,
|
|
|
|
|
opacity: 70,
|
|
|
|
|
name: getLayerName(layer)
|
|
|
|
|
}
|
|
|
|
|
])
|
2021-06-30 10:28:02 +02:00
|
|
|
|
);
|
2021-05-06 18:51:19 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function useMapStyle(
|
|
|
|
|
optionalLayers,
|
|
|
|
|
{ onStyleChange, cadastreEnabled }
|
|
|
|
|
) {
|
|
|
|
|
const [styleId, setStyle] = useState('ortho');
|
2021-06-30 10:28:02 +02:00
|
|
|
|
const [layers, setLayers] = useState(() => optionalLayersMap(optionalLayers));
|
|
|
|
|
const setLayerEnabled = (layer, enabled) =>
|
|
|
|
|
setLayers((optionalLayers) => {
|
|
|
|
|
optionalLayers[layer].enabled = enabled;
|
|
|
|
|
return { ...optionalLayers };
|
|
|
|
|
});
|
|
|
|
|
const setLayerOpacity = (layer, opacity) =>
|
|
|
|
|
setLayers((optionalLayers) => {
|
|
|
|
|
optionalLayers[layer].opacity = opacity;
|
|
|
|
|
return { ...optionalLayers };
|
|
|
|
|
});
|
|
|
|
|
const enabledLayers = Object.entries(layers).filter(
|
|
|
|
|
([, { enabled }]) => enabled
|
|
|
|
|
);
|
2021-07-07 16:23:55 +02:00
|
|
|
|
const layerIds = enabledLayers.map(
|
|
|
|
|
([layer, { opacity }]) => `${layer}-${opacity}`
|
|
|
|
|
);
|
2021-06-30 10:28:02 +02:00
|
|
|
|
const style = useMemo(
|
|
|
|
|
() =>
|
|
|
|
|
getMapStyle(
|
|
|
|
|
styleId,
|
2021-07-01 18:50:35 +02:00
|
|
|
|
enabledLayers.map(([layer]) => layer),
|
|
|
|
|
Object.fromEntries(
|
|
|
|
|
enabledLayers.map(([layer, { opacity }]) => [layer, opacity])
|
|
|
|
|
)
|
2021-06-30 10:28:02 +02:00
|
|
|
|
),
|
2021-07-07 16:23:55 +02:00
|
|
|
|
[styleId, layerIds]
|
2021-06-30 10:28:02 +02:00
|
|
|
|
);
|
2021-05-06 18:51:19 +02:00
|
|
|
|
|
2021-07-07 16:23:55 +02:00
|
|
|
|
useEffect(() => onStyleChange(), [styleId, layerIds, cadastreEnabled]);
|
2021-05-06 18:51:19 +02:00
|
|
|
|
|
2021-06-30 10:28:02 +02:00
|
|
|
|
return { style, layers, setStyle, setLayerEnabled, setLayerOpacity };
|
2021-05-06 18:51:19 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-07-01 18:50:35 +02:00
|
|
|
|
function MapStyleControl({
|
|
|
|
|
style,
|
|
|
|
|
layers,
|
|
|
|
|
setStyle,
|
|
|
|
|
setLayerEnabled,
|
|
|
|
|
setLayerOpacity
|
|
|
|
|
}) {
|
2021-06-30 10:28:02 +02:00
|
|
|
|
const [buttonElement, setButtonElement] = useState();
|
|
|
|
|
const [panelElement, setPanelElement] = useState();
|
|
|
|
|
const { styles, attributes } = usePopper(buttonElement, panelElement, {
|
|
|
|
|
placement: 'bottom-end'
|
|
|
|
|
});
|
2021-07-07 14:02:55 +02:00
|
|
|
|
const configurableLayers = Object.entries(layers).filter(
|
|
|
|
|
([, { configurable }]) => configurable
|
|
|
|
|
);
|
2021-07-07 14:12:50 +02:00
|
|
|
|
const mapId = useId();
|
2021-05-06 18:51:19 +02:00
|
|
|
|
|
|
|
|
|
return (
|
2021-06-30 10:28:02 +02:00
|
|
|
|
<div className="form map-style-control mapboxgl-ctrl-group">
|
|
|
|
|
<Popover>
|
|
|
|
|
<Popover.Button
|
|
|
|
|
ref={setButtonElement}
|
|
|
|
|
className="map-style-button"
|
|
|
|
|
title="Sélectionner les couches cartographiques"
|
|
|
|
|
>
|
|
|
|
|
<MapIcon className="icon-size" />
|
|
|
|
|
</Popover.Button>
|
|
|
|
|
<Popover.Panel
|
|
|
|
|
className="flex map-style-panel mapboxgl-ctrl-group"
|
|
|
|
|
ref={setPanelElement}
|
|
|
|
|
style={styles.popper}
|
|
|
|
|
{...attributes.popper}
|
|
|
|
|
>
|
|
|
|
|
<RadioGroup
|
|
|
|
|
value={style}
|
|
|
|
|
onChange={setStyle}
|
|
|
|
|
className="styles-list"
|
|
|
|
|
as="ul"
|
|
|
|
|
>
|
|
|
|
|
{Object.entries(STYLES).map(([style, title]) => (
|
|
|
|
|
<RadioGroup.Option
|
|
|
|
|
key={style}
|
|
|
|
|
value={style}
|
|
|
|
|
as="li"
|
|
|
|
|
className="flex"
|
|
|
|
|
>
|
|
|
|
|
{({ checked }) => (
|
|
|
|
|
<>
|
|
|
|
|
<input
|
|
|
|
|
type="radio"
|
|
|
|
|
key={`${style}-${checked}`}
|
|
|
|
|
defaultChecked={checked}
|
|
|
|
|
name="map-style"
|
|
|
|
|
className="m-0 p-0 mr-1"
|
|
|
|
|
/>
|
|
|
|
|
<RadioGroup.Label>
|
|
|
|
|
{title.replace(/\s/g, ' ')}
|
|
|
|
|
</RadioGroup.Label>
|
|
|
|
|
</>
|
|
|
|
|
)}
|
|
|
|
|
</RadioGroup.Option>
|
|
|
|
|
))}
|
|
|
|
|
</RadioGroup>
|
2021-07-07 14:02:55 +02:00
|
|
|
|
{configurableLayers.length ? (
|
2021-06-30 10:28:02 +02:00
|
|
|
|
<ul className="layers-list">
|
2021-07-07 14:02:55 +02:00
|
|
|
|
{configurableLayers.map(([layer, { enabled, opacity, name }]) => (
|
|
|
|
|
<li key={layer}>
|
|
|
|
|
<div className="flex mb-1">
|
|
|
|
|
<input
|
2021-07-07 14:12:50 +02:00
|
|
|
|
id={`${mapId}-${layer}`}
|
2021-07-07 14:02:55 +02:00
|
|
|
|
className="m-0 p-0 mr-1"
|
|
|
|
|
type="checkbox"
|
|
|
|
|
checked={enabled}
|
|
|
|
|
onChange={(event) => {
|
|
|
|
|
setLayerEnabled(layer, event.target.checked);
|
2021-07-01 18:50:35 +02:00
|
|
|
|
}}
|
|
|
|
|
/>
|
2021-07-07 14:12:50 +02:00
|
|
|
|
<label className="m-0" htmlFor={`${mapId}-${layer}`}>
|
|
|
|
|
{name}
|
|
|
|
|
</label>
|
2021-07-07 14:02:55 +02:00
|
|
|
|
</div>
|
|
|
|
|
<Slider
|
|
|
|
|
min={10}
|
|
|
|
|
max={100}
|
|
|
|
|
step={5}
|
|
|
|
|
value={opacity}
|
|
|
|
|
onChange={(value) => {
|
|
|
|
|
setLayerOpacity(layer, value);
|
|
|
|
|
}}
|
|
|
|
|
className="mb-1"
|
|
|
|
|
title={`Réglage de l’opacité de la couche «${NBS}${name}${NBS}»`}
|
|
|
|
|
getAriaLabel={() =>
|
|
|
|
|
`Réglage de l’opacité de la couche «${NBS}${name}${NBS}»`
|
|
|
|
|
}
|
|
|
|
|
getAriaValueText={(value) =>
|
|
|
|
|
`L’opacité de la couche «${NBS}${name}${NBS}» est à ${value}${NBS}%`
|
|
|
|
|
}
|
|
|
|
|
/>
|
|
|
|
|
</li>
|
|
|
|
|
))}
|
2021-06-30 10:28:02 +02:00
|
|
|
|
</ul>
|
|
|
|
|
) : null}
|
|
|
|
|
</Popover.Panel>
|
|
|
|
|
</Popover>
|
2021-05-06 18:51:19 +02:00
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MapStyleControl.propTypes = {
|
|
|
|
|
style: PropTypes.string,
|
2021-06-30 10:28:02 +02:00
|
|
|
|
layers: PropTypes.object,
|
|
|
|
|
setStyle: PropTypes.func,
|
|
|
|
|
setLayerEnabled: PropTypes.func,
|
|
|
|
|
setLayerOpacity: PropTypes.func
|
2021-05-06 18:51:19 +02:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export default MapStyleControl;
|