Skip to content

Commit

Permalink
[Carte] sélection des couches au survol (#1321)
Browse files Browse the repository at this point in the history
resolves #1224 
fixes #1327
  • Loading branch information
thoomasbro authored Apr 15, 2024
2 parents d8d6780 + 8c7bc55 commit f7468fc
Show file tree
Hide file tree
Showing 62 changed files with 992 additions and 338 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ context('LayerTree > Regulatory Layers', () => {
cy.getDataCy('regulatory-layers-result-title').contains('2 résultat').click()

cy.log("zoom on the regulation's zone and show metadata")
cy.getDataCy('result-group').contains('ZMEL_Cale_Querlen').click()
cy.getDataCy('result-group').contains('ZMEL Cale Querlen').click()
cy.getDataCy('regulatory-result-zone').contains('Zone au sud de la cale').click()
cy.getDataCy('regulatory-metadata-header').contains('ZMEL Cale Querlen').click()
cy.wait(1000) // let OL do the rendering
Expand Down
9 changes: 4 additions & 5 deletions frontend/cypress/e2e/side_window/reporting/filters.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ context('Reportings', () => {
})

it('Should filter reportings by themes', () => {
cy.wait(200)
cy.fill('Thématiques', ['Arrêté à visa environnemental'])
cy.getDataCy('reportings-filter-tags').find('.Component-SingleTag > span').contains('Arrêté à visa environnemental')

Expand Down Expand Up @@ -201,9 +202,7 @@ context('Reportings', () => {
cy.wait(500)
cy.wait('@getReportings')

// because we have two enpty tr at the beginning and at the end of the table
// we add 2 to the length
cy.get('.Table-SimpleTable tr').should('have.length', 5)
cy.getDataCy('reporting-row').should('have.length', 3)
cy.fill('Rechercher une cible', undefined)
})

Expand Down Expand Up @@ -234,10 +233,10 @@ context('Reportings', () => {
cy.wait(500)
cy.wait('@getReportings')

cy.get('*[data-cy="reporting-theme-filter"]').click()
cy.getDataCy('reporting-theme-filter').click()
cy.get('#themes-listbox > div').should('have.length', 34)

cy.get('*[data-cy="reporting-sub-theme-filter"]').click()
cy.getDataCy('reporting-sub-theme-filter').click()
cy.get('#subThemes-listbox > div').should('have.length', 161)
})
})
2 changes: 2 additions & 0 deletions frontend/src/domain/entities/AMPs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,5 @@ export type AMPFromAPI = {
url_legicem: string | null
}
export type AMP = AMPFromAPI & { bbox: Extent }

export type AMPProperties = Omit<AMP, 'geometry' | 'geom'>
93 changes: 75 additions & 18 deletions frontend/src/domain/entities/layers/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -250,23 +250,80 @@ export const BaseLayerLabel: Record<BaseLayer, string> = {
[BaseLayer.SHOM]: 'Carte marine (SHOM)'
}

export const SelectableLayers = [
Layers.MISSIONS.code,
Layers.REGULATORY_ENV_PREVIEW.code,
Layers.REGULATORY_ENV.code,
Layers.AMP.code,
Layers.STATIONS.code,
Layers.SEMAPHORES.code,
Layers.REPORTINGS.code,
Layers.MISSION_TO_ATTACH_ON_REPORTING.code,
Layers.REPORTING_TO_ATTACH_ON_MISSION.code
// Priority of selectable items is determined by the order of the layers in this array
// The first layer in the array has the highest priority
// Different hoverable arrays are used depending on the zoom level
// Zoom level goes from 0 (furthest from earth) to 26 (closest from earth)
export const SelectableLayers0To7 = [
[MonitorEnvLayers.MISSIONS],
[MonitorEnvLayers.MISSION_TO_ATTACH_ON_REPORTING],
[MonitorEnvLayers.REPORTING_TO_ATTACH_ON_MISSION],
[MonitorEnvLayers.REPORTINGS],
[MonitorEnvLayers.SEMAPHORES],
[MonitorEnvLayers.STATIONS],
[
MonitorEnvLayers.AMP,
MonitorEnvLayers.AMP_PREVIEW,
MonitorEnvLayers.REGULATORY_ENV_PREVIEW,
MonitorEnvLayers.REGULATORY_ENV
]
]
export const HoverableLayers = [
Layers.MISSIONS.code,
Layers.ACTIONS.code,
Layers.STATIONS.code,
Layers.SEMAPHORES.code,
Layers.REPORTINGS.code,
Layers.MISSION_TO_ATTACH_ON_REPORTING.code,
Layers.REPORTING_TO_ATTACH_ON_MISSION.code

export const SelectableLayers7To26 = [
[MonitorEnvLayers.MISSIONS],
[MonitorEnvLayers.MISSION_TO_ATTACH_ON_REPORTING],
[MonitorEnvLayers.REPORTING_TO_ATTACH_ON_MISSION],
[MonitorEnvLayers.REPORTINGS],
[MonitorEnvLayers.SEMAPHORES],
[MonitorEnvLayers.STATIONS],
[
MonitorEnvLayers.AMP,
MonitorEnvLayers.AMP_PREVIEW,
MonitorEnvLayers.REGULATORY_ENV_PREVIEW,
MonitorEnvLayers.REGULATORY_ENV
]
]

// Priority of hoverable items is determined by the order of the layers in this array
// The first layer in the array has the highest priority
// Different hoverable arrays are used depending on the zoom level
// Zoom level goes from 0 (furthest from earth) to 26 (closest from earth)

export const HoverableLayers0To7 = [
[MonitorEnvLayers.ACTIONS],
[MonitorEnvLayers.MISSIONS],
[MonitorEnvLayers.MISSION_TO_ATTACH_ON_REPORTING],
[MonitorEnvLayers.REPORTING_TO_ATTACH_ON_MISSION],
[MonitorEnvLayers.REPORTINGS],
[MonitorEnvLayers.SEMAPHORES],
[MonitorEnvLayers.STATIONS]
]

export const HoverableLayers7To26 = [
[MonitorEnvLayers.ACTIONS],
[MonitorEnvLayers.MISSIONS],
[MonitorEnvLayers.MISSION_TO_ATTACH_ON_REPORTING],
[MonitorEnvLayers.REPORTING_TO_ATTACH_ON_MISSION],
[MonitorEnvLayers.REPORTINGS],
[MonitorEnvLayers.SEMAPHORES],
[MonitorEnvLayers.STATIONS],
[
MonitorEnvLayers.AMP,
MonitorEnvLayers.AMP_PREVIEW,
MonitorEnvLayers.REGULATORY_ENV_PREVIEW,
MonitorEnvLayers.REGULATORY_ENV
]
]

export type RegulatoryOrAMPLayerType =
| MonitorEnvLayers.AMP
| MonitorEnvLayers.AMP_PREVIEW
| MonitorEnvLayers.REGULATORY_ENV
| MonitorEnvLayers.REGULATORY_ENV_PREVIEW

export const RegulatoryOrAMPLayerTypeAsList = [
MonitorEnvLayers.AMP,
MonitorEnvLayers.AMP_PREVIEW,
MonitorEnvLayers.REGULATORY_ENV,
MonitorEnvLayers.REGULATORY_ENV_PREVIEW
]
50 changes: 50 additions & 0 deletions frontend/src/domain/entities/layers/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { MonitorEnvLayers, type RegulatoryOrAMPLayerType } from 'domain/entities/layers/constants'

import type { AMPProperties } from 'domain/entities/AMPs'
import type { RegulatoryLayerCompactProperties } from 'domain/entities/regulatory'

export const getTitle = name => (name ? `${name?.replace(/[_]/g, ' ')}` : '')

export const getGroupName = (
layer: AMPProperties | RegulatoryLayerCompactProperties,
layerType: RegulatoryOrAMPLayerType
) => {
if (layerType === MonitorEnvLayers.AMP || layerType === MonitorEnvLayers.AMP_PREVIEW) {
return (layer as AMPProperties).name
}

return (layer as RegulatoryLayerCompactProperties).layer_name
}

export const getName = (
layer: AMPProperties | RegulatoryLayerCompactProperties,
layerType: RegulatoryOrAMPLayerType
) => {
if (layerType === MonitorEnvLayers.AMP || layerType === MonitorEnvLayers.AMP_PREVIEW) {
return (layer as AMPProperties).type
}

return (layer as RegulatoryLayerCompactProperties).entity_name
}

export const getLegendKey = (
layer: AMPProperties | RegulatoryLayerCompactProperties,
layerType: RegulatoryOrAMPLayerType
) => {
if (layerType === MonitorEnvLayers.AMP || layerType === MonitorEnvLayers.AMP_PREVIEW) {
return (layer as AMPProperties).name
}

return (layer as RegulatoryLayerCompactProperties).entity_name
}

export const getLegendType = (
layer: AMPProperties | RegulatoryLayerCompactProperties,
layerType: RegulatoryOrAMPLayerType
) => {
if (layerType === MonitorEnvLayers.AMP || layerType === MonitorEnvLayers.AMP_PREVIEW) {
return (layer as AMPProperties).type
}

return (layer as RegulatoryLayerCompactProperties).thematique
}
2 changes: 0 additions & 2 deletions frontend/src/domain/entities/regulatory.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import type { GeoJSON } from '../types/GeoJSON'

export const getTitle = topic => (topic ? `${topic?.replace(/[_]/g, ' ')}` : '')

export type RegulatoryLayerWithMetadataFromAPI = {
entity_name: string
facade: string
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/domain/shared_slices/Global.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import { createSlice, type PayloadAction } from '@reduxjs/toolkit'

import type { MapToolType } from '../entities/map/constants'
import type { Extent } from 'ol/extent'

export enum ReportingContext {
MAP = 'map',
Expand All @@ -27,7 +28,7 @@ type Toast = {
}

type OverlayCoordinates = {
coordinates: [number, number]
coordinates: Extent
name: string
}
type GlobalOverlayCoordinates = {
Expand Down
71 changes: 69 additions & 2 deletions frontend/src/domain/types/map.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,78 @@
import type { InteractionListener, InteractionType } from '../entities/map/constants'
import Feature, { type FeatureLike } from 'ol/Feature'
import { GeoJSON } from 'ol/format'

import { OPENLAYERS_PROJECTION, type InteractionListener, type InteractionType } from '../entities/map/constants'

import type { Coordinate } from 'ol/coordinate'
import type { Geometry } from 'ol/geom'

export type OverlayItem<T, P> = {
layerType: T
properties: P
}
export type MapClickEvent = {
coordinates: Coordinate | undefined
ctrlKeyPressed: boolean
feature: Object
feature: SerializedFeature<Record<string, any>> | undefined
featureList: SerializedFeature<Record<string, any>>[] | undefined
}

export type InteractionTypeAndListener = {
listener: InteractionListener
type: InteractionType
}

export type SerializedFeature<T> = {
geometry: Geometry
id: string | number
properties: T
}

export const convertToSerializedFeature = <P>(
feature: Feature<Geometry> | undefined
): SerializedFeature<P> | undefined => {
if (!feature) {
return undefined
}
const geometry = feature.getGeometry()
if (!geometry) {
return undefined
}

return {
geometry,
id: feature.getId() as string | number,
properties: feature.getProperties() as P
}
}

const parser = new GeoJSON({ featureProjection: OPENLAYERS_PROJECTION })

export function getGeoJSONFromFeature<P>(feature: Feature<Geometry> | FeatureLike | undefined) {
if (!feature || !(feature instanceof Feature)) {
return undefined
}

return parser.writeFeatureObject(feature) as SerializedFeature<P>
}

export const getGeoJSONFromFeatureList = (features: (Feature<Geometry> | FeatureLike | undefined)[]) =>
features.reduce((acc, feature) => {
const geoJSONFeature = getGeoJSONFromFeature(feature)
if (geoJSONFeature) {
acc.push(geoJSONFeature)
}

return acc
}, [] as SerializedFeature<any>[])

export const convertToFeature = <P>(
serializedFeature: SerializedFeature<P> | undefined
): Feature<Geometry> | undefined => {
if (!serializedFeature) {
return undefined
}
const feature = parser.readFeature(serializedFeature)

return feature
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { getGeoJSONFromFeature } from 'domain/types/map'
import Feature from 'ol/Feature'
import GeoJSON from 'ol/format/GeoJSON'
import Point from 'ol/geom/Point'

import { OPENLAYERS_PROJECTION } from '../../entities/map/constants'
import { updateInterestPointKeyBeingDrawed } from '../../shared_slices/InterestPoint'

export const saveInterestPointFeature = (feature?: Feature | undefined) => (dispatch, getState) => {
Expand Down Expand Up @@ -31,9 +30,3 @@ export const saveInterestPointFeature = (feature?: Feature | undefined) => (disp
})
)
}

function getGeoJSONFromFeature(feature) {
const parser = new GeoJSON()

return parser.writeFeatureObject(feature, { featureProjection: OPENLAYERS_PROJECTION })
}
4 changes: 2 additions & 2 deletions frontend/src/features/Reportings/Filters/Table/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ export function TableReportingsFiltersWithRef(
value={targetTypeFilter}
/>
<CheckPicker
key={themesOptions.length}
key={`theme${themesOptions.length}${JSON.stringify(themeFilter)}`}
customSearch={themeCustomSearch}
data-cy="reporting-theme-filter"
isLabelHidden
Expand All @@ -216,7 +216,7 @@ export function TableReportingsFiltersWithRef(
value={themeFilter}
/>
<CheckPicker
key={subThemesOptions.length}
key={`subtheme${subThemesOptions.length}${JSON.stringify(subThemesFilter)}`}
customSearch={subThemeCustomSearch}
data-cy="reporting-sub-theme-filter"
isLabelHidden
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { convertToFeature } from 'domain/types/map'
import VectorLayer from 'ol/layer/Vector'
import VectorSource from 'ol/source/Vector'
import { type MutableRefObject, useEffect, useRef } from 'react'
Expand Down Expand Up @@ -34,12 +35,9 @@ export function HoveredMissionToAttachLayer({ currentFeatureOver, map }: BaseMap

useEffect(() => {
vectorSourceRef.current?.clear(true)

if (
currentFeatureOver &&
currentFeatureOver.getId()?.toString()?.includes(Layers.MISSION_TO_ATTACH_ON_REPORTING.code)
) {
vectorSourceRef.current?.addFeature(currentFeatureOver)
const feature = convertToFeature(currentFeatureOver)
if (feature && feature.getId()?.toString()?.includes(Layers.MISSION_TO_ATTACH_ON_REPORTING.code)) {
vectorSourceRef.current?.addFeature(feature)
}
}, [currentFeatureOver])

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { customDayjs } from '@mtes-mct/monitor-ui'
import { convertToFeature } from 'domain/types/map'
import VectorLayer from 'ol/layer/Vector'
import VectorSource from 'ol/source/Vector'
import { useEffect, useMemo, useRef, type MutableRefObject } from 'react'
Expand Down Expand Up @@ -72,7 +73,7 @@ export function MissionToAttachLayer({ map, mapClickEvent }: BaseMapChildrenProp
}, [isMissionAttachmentInProgress])

useEffect(() => {
const feature = mapClickEvent?.feature
const feature = convertToFeature(mapClickEvent?.feature)
if (feature && feature.getId()?.toString()?.includes(Layers.MISSION_TO_ATTACH_ON_REPORTING.code)) {
const { missionId } = feature.getProperties()
dispatch(attachMission(missionId))
Expand Down
Loading

0 comments on commit f7468fc

Please sign in to comment.