From de78ef8df67b65f3884003ecba4344a8c8ccce30 Mon Sep 17 00:00:00 2001 From: Claire Dagan Date: Tue, 10 Dec 2024 18:40:00 +0100 Subject: [PATCH] [Layers] Add the option of displaying only the layer stroke or the filled layer --- frontend/package-lock.json | 9 +- frontend/package.json | 2 +- frontend/src/domain/shared_slices/Map.ts | 7 +- .../components/VigilanceAreaLayer/style.ts | 10 +- .../overlays/OverlayContent.tsx | 123 ++++++++++++------ .../map/layers/AMP/AMPLayers.style.ts | 10 +- .../features/map/layers/IsolationLayer.tsx | 20 +-- ...administrativeAndRegulatoryLayers.style.ts | 10 +- 8 files changed, 116 insertions(+), 75 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 77267b6f7..1c0270782 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -9,7 +9,7 @@ "version": "0.1.0", "license": "AGPL-3.0", "dependencies": { - "@mtes-mct/monitor-ui": "24.10.2", + "@mtes-mct/monitor-ui": "24.11.0", "@react-pdf/renderer": "4.1.5", "@reduxjs/toolkit": "2.4.0", "@sentry/browser": "8.41.0", @@ -3552,9 +3552,10 @@ "integrity": "sha512-HPnRdYO0WjFjRTSwO3frz1wKaU649OBFPX3Zo/2WZvuRi6zMiRGui8SnPQiQABgqCf8YikDe5t3HViTVw1WUzA==" }, "node_modules/@mtes-mct/monitor-ui": { - "version": "24.10.2", - "resolved": "https://registry.npmjs.org/@mtes-mct/monitor-ui/-/monitor-ui-24.10.2.tgz", - "integrity": "sha512-2t4qjwLjAVwjhkYIERVtFtg7Tqt/h9yXKEahSsBpQNCiMZD5p7Z5/fCNp02DO5bF5Op13Wmrt1jwG5lh8Ub4mA==", + "version": "24.11.0", + "resolved": "https://registry.npmjs.org/@mtes-mct/monitor-ui/-/monitor-ui-24.11.0.tgz", + "integrity": "sha512-fGMhKV6teLJZg1bz/z95RGcH8j2r71EawLAmvGsq0i/uf6ItQ3q8dRb3oHpVeMbPY9QNYC9BG53/CT1nWe5C/g==", + "license": "AGPL-3.0", "dependencies": { "@babel/runtime": "7.26.0", "@tanstack/react-table": "8.20.5", diff --git a/frontend/package.json b/frontend/package.json index ca45b63a7..037b10f9c 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -26,7 +26,7 @@ "test:unit:watch": "npm run test:unit -- --watch" }, "dependencies": { - "@mtes-mct/monitor-ui": "24.10.2", + "@mtes-mct/monitor-ui": "24.11.0", "@react-pdf/renderer": "4.1.5", "@reduxjs/toolkit": "2.4.0", "@sentry/browser": "8.41.0", diff --git a/frontend/src/domain/shared_slices/Map.ts b/frontend/src/domain/shared_slices/Map.ts index 79ca29d44..b5de103e1 100644 --- a/frontend/src/domain/shared_slices/Map.ts +++ b/frontend/src/domain/shared_slices/Map.ts @@ -7,7 +7,8 @@ import type { Coordinate } from 'ol/coordinate' import type { Extent } from 'ol/extent' type LayerType = { - id: number | undefined + id: number + isFilled: boolean type: RegulatoryOrAMPOrViglanceAreaLayerType } @@ -15,7 +16,7 @@ type MapSliceStateType = { coordinatesFormat: CoordinatesFormat currentMapExtentTracker?: number[] distanceUnit: DistanceUnit - excludedLayers?: LayerType[] + excludedLayers?: Omit[] fitToExtent?: Extent isAreaSelected: boolean isolatedLayer: LayerType | undefined @@ -85,7 +86,7 @@ const mapSlice = createSlice({ }, setIsolateMode( state, - action: PayloadAction<{ excludedLayers: LayerType[]; isolatedLayer: LayerType | undefined }> + action: PayloadAction<{ excludedLayers: Omit[]; isolatedLayer: LayerType | undefined }> ) { state.isolatedLayer = action.payload.isolatedLayer state.excludedLayers = action.payload.excludedLayers diff --git a/frontend/src/features/VigilanceArea/components/VigilanceAreaLayer/style.ts b/frontend/src/features/VigilanceArea/components/VigilanceAreaLayer/style.ts index 59170c2c6..648c6850a 100644 --- a/frontend/src/features/VigilanceArea/components/VigilanceAreaLayer/style.ts +++ b/frontend/src/features/VigilanceArea/components/VigilanceAreaLayer/style.ts @@ -4,10 +4,10 @@ import { Fill, Stroke, Style } from 'ol/style' import { Layers } from '../../../../domain/entities/layers/constants' import { getColorWithAlpha, stringToColorInGroup } from '../../../../utils/utils' -const getStyle = (color: string, isSelected: boolean | undefined, isLayerFilled: boolean = false) => +const getStyle = (color: string, isSelected: boolean | undefined, isLayerFilled: boolean = true) => new Style({ fill: new Fill({ - color: isLayerFilled ? 'transparent' : getColorWithAlpha(color, 0.5) + color: isLayerFilled ? getColorWithAlpha(color, 0.5) : 'transparent' }), stroke: new Stroke({ color: getColorWithAlpha(THEME.color.rufous, 1), @@ -35,11 +35,11 @@ export const getVigilanceAreaLayerStyle = feature => { return getStyle(colorWithAlpha, feature.get('isSelected')) } -export const getIsolatedVigilanceAreaLayerStyle = (feature, excludeLayerIds) => { +export const getIsolatedVigilanceAreaLayerStyle = (feature, excludeLayerIds, isFilled) => { const isArchived = feature.get('isArchived') const colorWithAlpha = getVigilanceAreaColorWithAlpha(feature.get('name'), feature.get('comments'), isArchived) - const isLayerFilled = excludeLayerIds.includes(feature.get('id')) + const isLayerFilled = !excludeLayerIds.includes(feature.get('id')) - return getStyle(colorWithAlpha, feature.get('isSelected'), isLayerFilled) + return getStyle(colorWithAlpha, feature.get('isSelected'), isLayerFilled && isFilled) } diff --git a/frontend/src/features/layersSelector/overlays/OverlayContent.tsx b/frontend/src/features/layersSelector/overlays/OverlayContent.tsx index 8b078109b..4349d527b 100644 --- a/frontend/src/features/layersSelector/overlays/OverlayContent.tsx +++ b/frontend/src/features/layersSelector/overlays/OverlayContent.tsx @@ -68,6 +68,7 @@ export function OverlayContent({ items }: OverlayContentProps) { const dispatch = useAppDispatch() const isolatedLayer = useAppSelector(state => state.map.isolatedLayer) + const excludedLayers = useAppSelector(state => state.map.excludedLayers) const { layerId, layerType } = useAppSelector(state => getDisplayedMetadataLayerIdAndType(state)) const selectedVigilanceAreaId = useAppSelector(state => state.vigilanceArea.selectedVigilanceAreaId) @@ -117,7 +118,7 @@ export function OverlayContent({ items }: OverlayContentProps) { dispatch(vigilanceAreaActions.addAmpIdsToVigilanceArea([id])) } - const isolateLayer = (e, id, type) => { + const isolateLayer = (e, id: number, type: RegulatoryOrAMPOrViglanceAreaLayerType) => { e.stopPropagation() if (isolatedLayer?.id === id) { @@ -128,11 +129,30 @@ export function OverlayContent({ items }: OverlayContentProps) { const layerToIsolate = { id, + isFilled: true, type } - const excludedLayers = + const newExcludedLayers = items?.map(item => ({ id: item.properties.id, type: item.layerType })).filter(item => item.id !== id) ?? [] - dispatch(mapActions.setIsolateMode({ excludedLayers, isolatedLayer: layerToIsolate })) + dispatch(mapActions.setIsolateMode({ excludedLayers: newExcludedLayers, isolatedLayer: layerToIsolate })) + } + + const updateFillingMode = e => { + e.stopPropagation() + + if (!isolatedLayer) { + return + } + + dispatch( + mapActions.setIsolateMode({ + excludedLayers: excludedLayers ?? [], + isolatedLayer: { + ...isolatedLayer, + isFilled: !isolatedLayer.isFilled + } + }) + ) } return ( @@ -207,37 +227,51 @@ export function OverlayContent({ items }: OverlayContentProps) { {getTitle(name) && ( {` / ${getTitle(name)}`} )} - {items.length > 1 && isVigilanceArea && ( - {vigilanceAreaPeriod} - )} - {items.length > 1 && ( - isolateLayer(e, id, item.layerType)} - /> - )} - {isLinkingRegulatoryToVigilanceArea && isRegulatory && ( - addRegulatoryToVigilanceArea(e, id)} - size={Size.SMALL} - title={`Ajouter la zone réglementaire ${name}`} - /> - )} - {isLinkingAmpToVigilanceArea && isAMP && ( - addAMPToVigilanceArea(e, id)} - size={Size.SMALL} - title={`Ajouter l'AMP ${name}`} - /> - )} + + {items.length > 1 && isVigilanceArea && {vigilanceAreaPeriod}} + {items.length > 1 && ( + <> + {isolatedLayer?.id === id && ( + + )} + isolateLayer(e, id, item.layerType)} + /> + + )} + {isLinkingRegulatoryToVigilanceArea && isRegulatory && ( + addRegulatoryToVigilanceArea(e, id)} + size={Size.SMALL} + title={`Ajouter la zone réglementaire ${name}`} + /> + )} + {isLinkingAmpToVigilanceArea && isAMP && ( + addAMPToVigilanceArea(e, id)} + size={Size.SMALL} + title={`Ajouter l'AMP ${name}`} + /> + )} + {items.length === 1 && isVigilanceArea && {vigilanceAreaPeriod}} @@ -288,21 +322,24 @@ const Wrapper = styled.div` display: flex; align-items: center; ` - +const ButtonContainer = styled.div` + display: flex; + gap: 12px; + line-height: 0; + margin-left: auto; +` const Period = styled.span` color: ${p => p.theme.color.slateGray}; font-size: 13px; padding-left: 24px; ` -const StyledTooltip = styled(Tooltip)` - display: flex; - margin-left: auto; -` - const StyledIconButton = styled(IconButton)` - > svg { - height: 18px; - width: 18px; + padding: 0; + > span { + > svg { + height: 18px; + width: 18px; + } } ` diff --git a/frontend/src/features/map/layers/AMP/AMPLayers.style.ts b/frontend/src/features/map/layers/AMP/AMPLayers.style.ts index e6243eba1..31b1367e7 100644 --- a/frontend/src/features/map/layers/AMP/AMPLayers.style.ts +++ b/frontend/src/features/map/layers/AMP/AMPLayers.style.ts @@ -4,10 +4,10 @@ import { Fill, Stroke, Style } from 'ol/style' import { Layers } from '../../../../domain/entities/layers/constants' import { getColorWithAlpha, stringToColorInGroup } from '../../../../utils/utils' -const getStyle = (color: string, metadataIsShowed: boolean | undefined, isLayerFilled: boolean = false) => +const getStyle = (color: string, metadataIsShowed: boolean | undefined, isLayerFilled: boolean = true) => new Style({ fill: new Fill({ - color: isLayerFilled ? 'transparent' : getColorWithAlpha(color, 0.7) + color: isLayerFilled ? getColorWithAlpha(color, 0.7) : 'transparent' }), stroke: new Stroke({ color: getColorWithAlpha(THEME.color.darkGoldenrod, 1), @@ -31,9 +31,9 @@ export const getAMPLayerStyle = feature => { return style } -export const getIsolateAMPLayerStyle = (feature, excludeLayerIds) => { +export const getIsolateAMPLayerStyle = (feature, excludeLayerIds: number[], isFilled: boolean) => { const colorWithAlpha = getAMPColorWithAlpha(feature.get('designation'), feature.get('name')) - const isLayerFilled = excludeLayerIds.includes(feature.get('id')) + const isLayerFilled = !excludeLayerIds.includes(feature.get('id')) - return getStyle(colorWithAlpha, feature.get('metadataIsShowed'), isLayerFilled) + return getStyle(colorWithAlpha, feature.get('metadataIsShowed'), isLayerFilled && isFilled) } diff --git a/frontend/src/features/map/layers/IsolationLayer.tsx b/frontend/src/features/map/layers/IsolationLayer.tsx index 1ee949fee..0082e2994 100644 --- a/frontend/src/features/map/layers/IsolationLayer.tsx +++ b/frontend/src/features/map/layers/IsolationLayer.tsx @@ -45,9 +45,8 @@ export function IsolationLayer({ map }: BaseMapChildrenProps) { let regulatoryFeatures: Feature[] = [] if (regulatoryLayers?.entities) { const isolatedLayerTypeIsRegulatory = (isolatedLayer?.type.search('REGULATORY') ?? -1) > -1 - const regulatoryExcludedLayers = excludedLayers - ?.filter(layer => layer.type.search('REGULATORY') > -1) - .map(layer => layer.id) + const regulatoryExcludedLayers = + excludedLayers?.filter(layer => layer.type.search('REGULATORY') > -1).map(layer => layer.id) ?? [] let featuresToDisplay = regulatoryExcludedLayers ?? [] if (isolatedLayerTypeIsRegulatory && isolatedLayer?.id) { @@ -58,9 +57,11 @@ export function IsolationLayer({ map }: BaseMapChildrenProps) { const layer = regulatorylayer ? regulatoryLayers.entities[regulatorylayer] : undefined if (layer) { const feature = getRegulatoryFeature({ code: Layers.REGULATORY_ENV.code, layer }) + const featureIsFilled = + isolatedLayerTypeIsRegulatory && isolatedLayer?.id === regulatorylayer && isolatedLayer?.isFilled if (feature) { - feature.setStyle(getIsolateRegulatoryLayerStyle(feature, regulatoryExcludedLayers)) + feature.setStyle(getIsolateRegulatoryLayerStyle(feature, regulatoryExcludedLayers, featureIsFilled)) feats.push(feature) } } @@ -77,9 +78,8 @@ export function IsolationLayer({ map }: BaseMapChildrenProps) { if (ampLayers?.entities) { const isolatedLayerTypeIsAmp = (isolatedLayer?.type.search('AMP') ?? -1) > -1 - const ampExcludedLayers = excludedLayers - ?.filter(layer => (layer.type.search('AMP') ?? -1) > -1) - .map(layer => layer.id) + const ampExcludedLayers = + excludedLayers?.filter(layer => (layer.type.search('AMP') ?? -1) > -1).map(layer => layer.id) ?? [] let featuresToDisplay = ampExcludedLayers ?? [] if (isolatedLayerTypeIsAmp && isolatedLayer?.id) { featuresToDisplay = [...featuresToDisplay, isolatedLayer.id] @@ -90,9 +90,10 @@ export function IsolationLayer({ map }: BaseMapChildrenProps) { if (layer && layer.geom) { const feature = getAMPFeature({ code: Layers.AMP_PREVIEW.code, layer }) + const featureIsFilled = isolatedLayerTypeIsAmp && isolatedLayer?.id === id && isolatedLayer?.isFilled if (feature) { - feature.setStyle(getIsolateAMPLayerStyle(feature, ampExcludedLayers)) + feature.setStyle(getIsolateAMPLayerStyle(feature, ampExcludedLayers, featureIsFilled)) amplayers.push(feature) } } @@ -121,8 +122,9 @@ export function IsolationLayer({ map }: BaseMapChildrenProps) { const layer = id ? vigilanceAreas?.entities[id] : undefined if (layer && layer.geom) { const feature = getVigilanceAreaZoneFeature(layer, Layers.VIGILANCE_AREA.code) + const featureIsFilled = isolatedLayerIsVigilanceArea && isolatedLayer?.id === id && isolatedLayer?.isFilled if (feature) { - feature.setStyle(getIsolatedVigilanceAreaLayerStyle(feature, vigilanceAreasExcludedLayers)) + feature.setStyle(getIsolatedVigilanceAreaLayerStyle(feature, vigilanceAreasExcludedLayers, featureIsFilled)) vigilanceAreasLayers.push(feature) } } diff --git a/frontend/src/features/map/layers/styles/administrativeAndRegulatoryLayers.style.ts b/frontend/src/features/map/layers/styles/administrativeAndRegulatoryLayers.style.ts index aac5e2f2c..8dddf71d7 100644 --- a/frontend/src/features/map/layers/styles/administrativeAndRegulatoryLayers.style.ts +++ b/frontend/src/features/map/layers/styles/administrativeAndRegulatoryLayers.style.ts @@ -179,10 +179,10 @@ export const getRegulatoryLayerStyle = feature => { return getStyle(colorWithAlpha, feature.get('metadataIsShowed')) } -const getStyle = (color, metadataIsShowed, isLayerFilled = false) => +const getStyle = (color, metadataIsShowed, isLayerFilled = true) => new Style({ fill: new Fill({ - color: isLayerFilled ? 'transparent' : color + color: isLayerFilled ? color : 'transparent' }), stroke: new Stroke({ color: getColorWithAlpha(THEME.color.charcoal, 0.7), @@ -202,9 +202,9 @@ export const getRegulatoryEnvColorWithAlpha = ( return getColorWithAlpha(stringToColorInGroup(`${type}`, `${name}`), 0.6) } -export const getIsolateRegulatoryLayerStyle = (feature, excludeLayerIds) => { +export const getIsolateRegulatoryLayerStyle = (feature, excludeLayerIds: number[], isFilled: boolean) => { const colorWithAlpha = getRegulatoryEnvColorWithAlpha(feature.get('thematique'), feature.get('entity_name')) - const isLayerFilled = excludeLayerIds.includes(feature.get('id')) + const isLayerFilled = !excludeLayerIds.includes(feature.get('id')) - return getStyle(colorWithAlpha, feature.get('metadataIsShowed'), isLayerFilled) + return getStyle(colorWithAlpha, feature.get('metadataIsShowed'), isLayerFilled && isFilled) }