From 91d82ed78f25778ddd5272a358f0a8be35f530f4 Mon Sep 17 00:00:00 2001 From: David Inga Date: Wed, 6 Mar 2024 15:08:53 +0100 Subject: [PATCH 1/4] added geosjon layer --- client/package.json | 2 + .../analysis-eudr/map/component.tsx | 66 ++++++ .../src/containers/analysis-eudr/map/index.ts | 1 + .../analysis-eudr/map/zoom/component.tsx | 51 +++++ .../analysis-eudr/map/zoom/index.ts | 1 + client/src/pages/eudr/index.tsx | 28 +-- client/yarn.lock | 211 +++++++++++++++++- 7 files changed, 330 insertions(+), 30 deletions(-) create mode 100644 client/src/containers/analysis-eudr/map/component.tsx create mode 100644 client/src/containers/analysis-eudr/map/index.ts create mode 100644 client/src/containers/analysis-eudr/map/zoom/component.tsx create mode 100644 client/src/containers/analysis-eudr/map/zoom/index.ts diff --git a/client/package.json b/client/package.json index 7fc759e1c..f688abb13 100644 --- a/client/package.json +++ b/client/package.json @@ -15,12 +15,14 @@ "test": "start-server-and-test 'yarn build && yarn start' http://localhost:3000/auth/signin 'nyc --reporter nyc-report-lcov-absolute yarn cypress:headless'" }, "dependencies": { + "@deck.gl/carto": "^8.9.35", "@deck.gl/core": "8.8.6", "@deck.gl/extensions": "8.8.6", "@deck.gl/geo-layers": "8.8.6", "@deck.gl/layers": "8.8.6", "@deck.gl/mapbox": "8.8.6", "@deck.gl/mesh-layers": "8.8.6", + "@deck.gl/react": "^8.9.35", "@dnd-kit/core": "5.0.3", "@dnd-kit/modifiers": "5.0.0", "@dnd-kit/sortable": "6.0.1", diff --git a/client/src/containers/analysis-eudr/map/component.tsx b/client/src/containers/analysis-eudr/map/component.tsx new file mode 100644 index 000000000..42bca1162 --- /dev/null +++ b/client/src/containers/analysis-eudr/map/component.tsx @@ -0,0 +1,66 @@ +import { useState, useCallback } from 'react'; +import DeckGL from '@deck.gl/react/typed'; +import { GeoJsonLayer } from '@deck.gl/layers/typed'; +import Map from 'react-map-gl/maplibre'; +import { type MapViewState } from '@deck.gl/core/typed'; + +import ZoomControl from './zoom'; + +import BasemapControl from '@/components/map/controls/basemap'; +import { INITIAL_VIEW_STATE, MAP_STYLES } from '@/components/map'; + +import type { BasemapValue } from '@/components/map/controls/basemap/types'; +import type { MapStyle } from '@/components/map/types'; + +const data = 'https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_10m_airports.geojson'; + +const EUDRMap = () => { + const [mapStyle, setMapStyle] = useState('terrain'); + const [viewState, setViewState] = useState(INITIAL_VIEW_STATE); + + const layer: GeoJsonLayer = new GeoJsonLayer({ + id: 'geojson-layer', + data, + // Styles + filled: true, + pointRadiusMinPixels: 2, + pointRadiusScale: 2000, + getFillColor: [200, 0, 80, 180], + // Interactive props + pickable: true, + autoHighlight: true, + }); + + const handleMapStyleChange = useCallback((newStyle: BasemapValue) => { + setMapStyle(newStyle); + }, []); + + const handleZoomIn = useCallback(() => { + const zoom = viewState.maxZoom === viewState.zoom ? viewState.zoom : viewState.zoom + 1; + setViewState({ ...viewState, zoom }); + }, [viewState]); + + const handleZoomOut = useCallback(() => { + const zoom = viewState.maxZoom === viewState.zoom ? viewState.zoom : viewState.zoom - 1; + setViewState({ ...viewState, zoom }); + }, [viewState]); + + return ( + <> + setViewState(viewState as MapViewState)} + controller={{ dragRotate: false }} + layers={[layer]} + > + + +
+ + +
+ + ); +}; + +export default EUDRMap; diff --git a/client/src/containers/analysis-eudr/map/index.ts b/client/src/containers/analysis-eudr/map/index.ts new file mode 100644 index 000000000..b404d7fd4 --- /dev/null +++ b/client/src/containers/analysis-eudr/map/index.ts @@ -0,0 +1 @@ +export { default } from './component'; diff --git a/client/src/containers/analysis-eudr/map/zoom/component.tsx b/client/src/containers/analysis-eudr/map/zoom/component.tsx new file mode 100644 index 000000000..8b2eeeba1 --- /dev/null +++ b/client/src/containers/analysis-eudr/map/zoom/component.tsx @@ -0,0 +1,51 @@ +import { MinusIcon, PlusIcon } from '@heroicons/react/solid'; +import cx from 'classnames'; + +import type { MapViewState } from '@deck.gl/core/typed'; +import type { FC } from 'react'; + +const COMMON_CLASSES = + 'p-2 transition-colors bg-white cursor-pointer hover:bg-gray-100 active:bg-navy-50 disabled:bg-gray-100 disabled:opacity-75 disabled:cursor-default'; + +const ZoomControl: FC<{ + viewState: MapViewState; + className?: string; + onZoomIn: () => void; + onZoomOut: () => void; +}> = ({ viewState, className = null, onZoomIn, onZoomOut }) => { + const { zoom, minZoom, maxZoom } = viewState; + + return ( +
+ + +
+ ); +}; + +export default ZoomControl; diff --git a/client/src/containers/analysis-eudr/map/zoom/index.ts b/client/src/containers/analysis-eudr/map/zoom/index.ts new file mode 100644 index 000000000..b404d7fd4 --- /dev/null +++ b/client/src/containers/analysis-eudr/map/zoom/index.ts @@ -0,0 +1 @@ +export { default } from './component'; diff --git a/client/src/pages/eudr/index.tsx b/client/src/pages/eudr/index.tsx index 3c7c4dd1f..be4350cd2 100644 --- a/client/src/pages/eudr/index.tsx +++ b/client/src/pages/eudr/index.tsx @@ -6,8 +6,7 @@ import { tasksSSR } from 'services/ssr'; import ApplicationLayout from 'layouts/application'; import CollapseButton from 'containers/collapse-button/component'; import TitleTemplate from 'utils/titleTemplate'; -import Map from 'components/map'; -import LayerManager from 'components/map/layer-manager'; +import Map from 'containers/analysis-eudr/map'; import SuppliersStackedBar from '@/containers/analysis-eudr/suppliers-stacked-bar'; import EUDRFilters from '@/containers/analysis-eudr/filters/component'; import SupplierListTable from '@/containers/analysis-eudr/supplier-list-table'; @@ -54,30 +53,7 @@ const MapPage: NextPageWithLayout = () => {
- - {() => ( - <> - - {/* {tooltipData && tooltipData.data?.v && ( - -
-
- {tooltipData.data.v} - {tooltipData.data.unit && ` ${tooltipData.data.unit}`} -
-
{tooltipData.data.name}
-
-
- )} */} - - )} -
+
diff --git a/client/yarn.lock b/client/yarn.lock index 2a07a1280..af3287489 100644 --- a/client/yarn.lock +++ b/client/yarn.lock @@ -326,6 +326,37 @@ __metadata: languageName: node linkType: hard +"@deck.gl/carto@npm:^8.9.35": + version: 8.9.35 + resolution: "@deck.gl/carto@npm:8.9.35" + dependencies: + "@babel/runtime": ^7.0.0 + "@loaders.gl/gis": ^3.4.13 + "@loaders.gl/loader-utils": ^3.4.13 + "@loaders.gl/mvt": ^3.4.13 + "@loaders.gl/tiles": ^3.4.13 + "@luma.gl/constants": ^8.5.21 + "@math.gl/web-mercator": ^3.6.2 + cartocolor: ^4.0.2 + d3-array: ^3.2.0 + d3-color: ^3.1.0 + d3-format: ^3.1.0 + d3-scale: ^4.0.0 + h3-js: ^3.7.0 + moment-timezone: ^0.5.33 + pbf: ^3.2.1 + quadbin: ^0.1.9 + peerDependencies: + "@deck.gl/aggregation-layers": ^8.0.0 + "@deck.gl/core": ^8.0.0 + "@deck.gl/extensions": ^8.0.0 + "@deck.gl/geo-layers": ^8.0.0 + "@deck.gl/layers": ^8.0.0 + "@loaders.gl/core": ^3.4.13 + checksum: 2c8edfd7974e4e4ee7874da5c8db2da75dc84074d4d121350228206150071ad82d5a541e79ee3bc059f6d8716929b701d1421407e5df052a4f9a097d016e4065 + languageName: node + linkType: hard + "@deck.gl/core@npm:8.8.6": version: 8.8.6 resolution: "@deck.gl/core@npm:8.8.6" @@ -437,6 +468,20 @@ __metadata: languageName: node linkType: hard +"@deck.gl/react@npm:^8.9.35": + version: 8.9.35 + resolution: "@deck.gl/react@npm:8.9.35" + dependencies: + "@babel/runtime": ^7.0.0 + peerDependencies: + "@deck.gl/core": ^8.0.0 + "@types/react": ">= 16.3" + react: ">=16.3" + react-dom: ">=16.3" + checksum: 98269a5c0d9a644f5fcd2a1eb401001edbd87f99bf6b6dd8c5f0a193dbd6e1f738e3ae94bc3559902b760411340a7f730aa1f674e7fa811c7b7fdb42cd4fc6ca + languageName: node + linkType: hard + "@dnd-kit/accessibility@npm:^3.0.0": version: 3.0.1 resolution: "@dnd-kit/accessibility@npm:3.0.1" @@ -1078,6 +1123,19 @@ __metadata: languageName: node linkType: hard +"@loaders.gl/gis@npm:3.4.15, @loaders.gl/gis@npm:^3.4.13": + version: 3.4.15 + resolution: "@loaders.gl/gis@npm:3.4.15" + dependencies: + "@loaders.gl/loader-utils": 3.4.15 + "@loaders.gl/schema": 3.4.15 + "@mapbox/vector-tile": ^1.3.1 + "@math.gl/polygon": ^3.5.1 + pbf: ^3.2.1 + checksum: dae1ac222e731a1ffad95f6f2176a33790fa097fa95e20817a4ca6325e1d7be5d8a4f69a2019cf0769aede7d73bff79f7ad38533add58978505a49862f42c685 + languageName: node + linkType: hard + "@loaders.gl/gltf@npm:3.3.1, @loaders.gl/gltf@npm:^3.2.5": version: 3.3.1 resolution: "@loaders.gl/gltf@npm:3.3.1" @@ -1100,6 +1158,15 @@ __metadata: languageName: node linkType: hard +"@loaders.gl/images@npm:3.4.15": + version: 3.4.15 + resolution: "@loaders.gl/images@npm:3.4.15" + dependencies: + "@loaders.gl/loader-utils": 3.4.15 + checksum: 7d5ac4948b6f612aed410eafb05b34bea7d067475a07d40c022ed9f09c2de7403f24ab1d694a647917275e5e18c70f3c94d5f50278ef15f7b7bd01375df83f47 + languageName: node + linkType: hard + "@loaders.gl/loader-utils@npm:3.3.1, @loaders.gl/loader-utils@npm:^3.2.5": version: 3.3.1 resolution: "@loaders.gl/loader-utils@npm:3.3.1" @@ -1111,6 +1178,17 @@ __metadata: languageName: node linkType: hard +"@loaders.gl/loader-utils@npm:3.4.15, @loaders.gl/loader-utils@npm:^3.4.13": + version: 3.4.15 + resolution: "@loaders.gl/loader-utils@npm:3.4.15" + dependencies: + "@babel/runtime": ^7.3.1 + "@loaders.gl/worker-utils": 3.4.15 + "@probe.gl/stats": ^3.5.0 + checksum: 04a91e56ecf8b792853a24184a27c3bf9824e62959e8d8c5f3b615724816c6bfdced8c56c02c9e22c6795a030c24009a75ae5b6f924627e2575e039c7234ba96 + languageName: node + linkType: hard + "@loaders.gl/math@npm:3.3.1": version: 3.3.1 resolution: "@loaders.gl/math@npm:3.3.1" @@ -1122,6 +1200,17 @@ __metadata: languageName: node linkType: hard +"@loaders.gl/math@npm:3.4.15": + version: 3.4.15 + resolution: "@loaders.gl/math@npm:3.4.15" + dependencies: + "@loaders.gl/images": 3.4.15 + "@loaders.gl/loader-utils": 3.4.15 + "@math.gl/core": ^3.5.1 + checksum: e0e41e5253f876ecd6a15ec0648954c3d88516794336dd431ab1a82dcd4a4d2fb4a69c7e087f83744c4ef7982e60aa4ee6fdf89c8686772c30291cc399e02beb + languageName: node + linkType: hard + "@loaders.gl/mvt@npm:^3.2.5": version: 3.3.1 resolution: "@loaders.gl/mvt@npm:3.3.1" @@ -1135,6 +1224,19 @@ __metadata: languageName: node linkType: hard +"@loaders.gl/mvt@npm:^3.4.13": + version: 3.4.15 + resolution: "@loaders.gl/mvt@npm:3.4.15" + dependencies: + "@loaders.gl/gis": 3.4.15 + "@loaders.gl/loader-utils": 3.4.15 + "@loaders.gl/schema": 3.4.15 + "@math.gl/polygon": ^3.5.1 + pbf: ^3.2.1 + checksum: f3f32d558e87a28256966c215456d482a5d910dd5e7426b57b65e78df5fef2dfd6869591152c61e49ecc719636c519e0047954227c66a30b240bf161dd13b38d + languageName: node + linkType: hard + "@loaders.gl/schema@npm:3.3.1, @loaders.gl/schema@npm:^3.2.5": version: 3.3.1 resolution: "@loaders.gl/schema@npm:3.3.1" @@ -1144,6 +1246,15 @@ __metadata: languageName: node linkType: hard +"@loaders.gl/schema@npm:3.4.15": + version: 3.4.15 + resolution: "@loaders.gl/schema@npm:3.4.15" + dependencies: + "@types/geojson": ^7946.0.7 + checksum: 948e039848d1a599d6fe60276e2fb44f3ffc27924f944d399f1bd264209bb7409ef288dfed1c4440fd527e8939c7753ddbf7c4f2e4d4ac6f420c8a13ed187ffc + languageName: node + linkType: hard + "@loaders.gl/terrain@npm:^3.2.5": version: 3.3.1 resolution: "@loaders.gl/terrain@npm:3.3.1" @@ -1187,6 +1298,23 @@ __metadata: languageName: node linkType: hard +"@loaders.gl/tiles@npm:^3.4.13": + version: 3.4.15 + resolution: "@loaders.gl/tiles@npm:3.4.15" + dependencies: + "@loaders.gl/loader-utils": 3.4.15 + "@loaders.gl/math": 3.4.15 + "@math.gl/core": ^3.5.1 + "@math.gl/culling": ^3.5.1 + "@math.gl/geospatial": ^3.5.1 + "@math.gl/web-mercator": ^3.5.1 + "@probe.gl/stats": ^3.5.0 + peerDependencies: + "@loaders.gl/core": ^3.4.0 + checksum: 18cc163c621b8ee388b0f78d5a95171a7c3540a5156d687b4d431ffc9f0533c4f220c8b265e7fbeaabc569260615229ed8871a7d2f2a08f7da0a5bcd6f083563 + languageName: node + linkType: hard + "@loaders.gl/worker-utils@npm:3.3.1": version: 3.3.1 resolution: "@loaders.gl/worker-utils@npm:3.3.1" @@ -1196,6 +1324,15 @@ __metadata: languageName: node linkType: hard +"@loaders.gl/worker-utils@npm:3.4.15": + version: 3.4.15 + resolution: "@loaders.gl/worker-utils@npm:3.4.15" + dependencies: + "@babel/runtime": ^7.3.1 + checksum: f4d77444a73b650b92340036af9e5d5a5449ef1e8940a2b33f4800444918c76e7d54f9bafd86c413cb94d777c256a22521bfbbd4e981757d39ecdfbb9994e28d + languageName: node + linkType: hard + "@luma.gl/constants@npm:8.5.16": version: 8.5.16 resolution: "@luma.gl/constants@npm:8.5.16" @@ -1210,6 +1347,13 @@ __metadata: languageName: node linkType: hard +"@luma.gl/constants@npm:^8.5.21": + version: 8.5.21 + resolution: "@luma.gl/constants@npm:8.5.21" + checksum: 2ac0eb0fb368d8a4722f140917de45100af7adde776c5be40935c86c996491e9145464f3dd5be69294a839fa145b456df828425a93f071bf68bf62c1f79c376f + languageName: node + linkType: hard + "@luma.gl/core@npm:^8.5.16": version: 8.5.16 resolution: "@luma.gl/core@npm:8.5.16" @@ -1328,6 +1472,15 @@ __metadata: languageName: node linkType: hard +"@mapbox/tile-cover@npm:3.0.1": + version: 3.0.1 + resolution: "@mapbox/tile-cover@npm:3.0.1" + dependencies: + tilebelt: ^1.0.1 + checksum: 0b28516ca3159a0ec3aca923d7031e2c1ba1e3ea73eead8f06448a7dd904a3a0c3d4ee3a998ae391b0e7444540eb29f79c21cd637a7845f0315c15a9c9455f76 + languageName: node + linkType: hard + "@mapbox/tiny-sdf@npm:^1.1.0": version: 1.2.5 resolution: "@mapbox/tiny-sdf@npm:1.2.5" @@ -3821,6 +3974,15 @@ __metadata: languageName: node linkType: hard +"cartocolor@npm:^4.0.2": + version: 4.0.2 + resolution: "cartocolor@npm:4.0.2" + dependencies: + colorbrewer: 1.0.0 + checksum: 3754e8211acb69e98d489a97dbd7536edcbf466004b3860a175d421296cbe198709c006ac106d0f6cdc379ab2e7e0c6227c88b555a8cf82699bfcc99af78e95a + languageName: node + linkType: hard + "caseless@npm:~0.12.0": version: 0.12.0 resolution: "caseless@npm:0.12.0" @@ -4067,6 +4229,13 @@ __metadata: languageName: node linkType: hard +"colorbrewer@npm:1.0.0": + version: 1.0.0 + resolution: "colorbrewer@npm:1.0.0" + checksum: 9513dfe9792824505bda88f1c41f53ad5965a21292d7a2902cbfade0d895e88b15e4b8e00ee08f0710d8d671c46c48f53bb471696a9a24db3cdb6d0862a4ff5d + languageName: node + linkType: hard + "colorette@npm:^1.2.2": version: 1.4.0 resolution: "colorette@npm:1.4.0" @@ -4328,7 +4497,7 @@ __metadata: languageName: node linkType: hard -"d3-array@npm:^3.1.6": +"d3-array@npm:^3.1.6, d3-array@npm:^3.2.0": version: 3.2.4 resolution: "d3-array@npm:3.2.4" dependencies: @@ -4337,7 +4506,7 @@ __metadata: languageName: node linkType: hard -"d3-color@npm:1 - 3": +"d3-color@npm:1 - 3, d3-color@npm:^3.1.0": version: 3.1.0 resolution: "d3-color@npm:3.1.0" checksum: 4931fbfda5d7c4b5cfa283a13c91a954f86e3b69d75ce588d06cde6c3628cebfc3af2069ccf225e982e8987c612aa7948b3932163ce15eb3c11cd7c003f3ee3b @@ -4351,7 +4520,7 @@ __metadata: languageName: node linkType: hard -"d3-format@npm:1 - 3": +"d3-format@npm:1 - 3, d3-format@npm:^3.1.0": version: 3.1.0 resolution: "d3-format@npm:3.1.0" checksum: f345ec3b8ad3cab19bff5dead395bd9f5590628eb97a389b1dd89f0b204c7c4fc1d9520f13231c2c7cf14b7c9a8cf10f8ef15bde2befbab41454a569bd706ca2 @@ -4381,7 +4550,7 @@ __metadata: languageName: node linkType: hard -"d3-scale@npm:4.0.2, d3-scale@npm:^4.0.2": +"d3-scale@npm:4.0.2, d3-scale@npm:^4.0.0, d3-scale@npm:^4.0.2": version: 4.0.2 resolution: "d3-scale@npm:4.0.2" dependencies: @@ -7486,12 +7655,14 @@ __metadata: version: 0.0.0-use.local resolution: "landgriffon-client@workspace:." dependencies: + "@deck.gl/carto": ^8.9.35 "@deck.gl/core": 8.8.6 "@deck.gl/extensions": 8.8.6 "@deck.gl/geo-layers": 8.8.6 "@deck.gl/layers": 8.8.6 "@deck.gl/mapbox": 8.8.6 "@deck.gl/mesh-layers": 8.8.6 + "@deck.gl/react": ^8.9.35 "@dnd-kit/core": 5.0.3 "@dnd-kit/modifiers": 5.0.0 "@dnd-kit/sortable": 6.0.1 @@ -8148,6 +8319,22 @@ __metadata: languageName: node linkType: hard +"moment-timezone@npm:^0.5.33": + version: 0.5.45 + resolution: "moment-timezone@npm:0.5.45" + dependencies: + moment: ^2.29.4 + checksum: a22e9f983fbe1a01757ce30685bce92e3f6efa692eb682afd47b82da3ff960b3c8c2c3883ec6715c124bc985a342b57cba1f6ba25a1c8b4c7ad766db3cd5e1d0 + languageName: node + linkType: hard + +"moment@npm:^2.29.4": + version: 2.30.1 + resolution: "moment@npm:2.30.1" + checksum: 859236bab1e88c3e5802afcf797fc801acdbd0ee509d34ea3df6eea21eb6bcc2abd4ae4e4e64aa7c986aa6cba563c6e62806218e6412a765010712e5fa121ba6 + languageName: node + linkType: hard + "ms@npm:2.0.0": version: 2.0.0 resolution: "ms@npm:2.0.0" @@ -9274,6 +9461,15 @@ __metadata: languageName: node linkType: hard +"quadbin@npm:^0.1.9": + version: 0.1.9 + resolution: "quadbin@npm:0.1.9" + dependencies: + "@mapbox/tile-cover": 3.0.1 + checksum: 318113ac94178659f8e589644b4a0c14817262eb0ab2418f7313052133a53009b52870220e88759efdea7f467448d7fdd063758deb8014be5652208e451a6733 + languageName: node + linkType: hard + "query-string@npm:8.1.0": version: 8.1.0 resolution: "query-string@npm:8.1.0" @@ -11140,6 +11336,13 @@ __metadata: languageName: node linkType: hard +"tilebelt@npm:^1.0.1": + version: 1.0.1 + resolution: "tilebelt@npm:1.0.1" + checksum: f201cf1718f53b8d7b2e89f53f90bbcf6eba5f58fe578da5ce35f93ea4e2302100f019fe2d388a0fb7ec5ceda0b6a0f08d10657b6b54eb5d74db218ad4bad177 + languageName: node + linkType: hard + "tiny-glob@npm:^0.2.9": version: 0.2.9 resolution: "tiny-glob@npm:0.2.9" From 4f4134a9b46b80b521636c538a3a9a6bed617aa6 Mon Sep 17 00:00:00 2001 From: David Inga Date: Wed, 6 Mar 2024 16:08:25 +0100 Subject: [PATCH 2/4] added toogle legend --- client/package.json | 2 + client/src/components/ui/popover.tsx | 29 ++++++ .../analysis-eudr/map/component.tsx | 2 + .../analysis-eudr/map/legend/component.tsx | 31 ++++++ .../analysis-eudr/map/legend/index.ts | 1 + client/yarn.lock | 99 +++++++++++++++++++ 6 files changed, 164 insertions(+) create mode 100644 client/src/components/ui/popover.tsx create mode 100644 client/src/containers/analysis-eudr/map/legend/component.tsx create mode 100644 client/src/containers/analysis-eudr/map/legend/index.ts diff --git a/client/package.json b/client/package.json index f688abb13..2c05f2a00 100644 --- a/client/package.json +++ b/client/package.json @@ -37,7 +37,9 @@ "@loaders.gl/core": "3.3.1", "@luma.gl/constants": "8.5.18", "@radix-ui/react-collapsible": "1.0.3", + "@radix-ui/react-dropdown-menu": "^2.0.6", "@radix-ui/react-label": "2.0.2", + "@radix-ui/react-popover": "^1.0.7", "@radix-ui/react-radio-group": "1.1.3", "@radix-ui/react-select": "2.0.0", "@radix-ui/react-slot": "1.0.2", diff --git a/client/src/components/ui/popover.tsx b/client/src/components/ui/popover.tsx new file mode 100644 index 000000000..bbba7e0eb --- /dev/null +++ b/client/src/components/ui/popover.tsx @@ -0,0 +1,29 @@ +import * as React from "react" +import * as PopoverPrimitive from "@radix-ui/react-popover" + +import { cn } from "@/lib/utils" + +const Popover = PopoverPrimitive.Root + +const PopoverTrigger = PopoverPrimitive.Trigger + +const PopoverContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, align = "center", sideOffset = 4, ...props }, ref) => ( + + + +)) +PopoverContent.displayName = PopoverPrimitive.Content.displayName + +export { Popover, PopoverTrigger, PopoverContent } diff --git a/client/src/containers/analysis-eudr/map/component.tsx b/client/src/containers/analysis-eudr/map/component.tsx index 42bca1162..5aa2189c2 100644 --- a/client/src/containers/analysis-eudr/map/component.tsx +++ b/client/src/containers/analysis-eudr/map/component.tsx @@ -5,6 +5,7 @@ import Map from 'react-map-gl/maplibre'; import { type MapViewState } from '@deck.gl/core/typed'; import ZoomControl from './zoom'; +import LegendControl from './legend'; import BasemapControl from '@/components/map/controls/basemap'; import { INITIAL_VIEW_STATE, MAP_STYLES } from '@/components/map'; @@ -58,6 +59,7 @@ const EUDRMap = () => {
+
); diff --git a/client/src/containers/analysis-eudr/map/legend/component.tsx b/client/src/containers/analysis-eudr/map/legend/component.tsx new file mode 100644 index 000000000..53c7d138e --- /dev/null +++ b/client/src/containers/analysis-eudr/map/legend/component.tsx @@ -0,0 +1,31 @@ +import { useState } from 'react'; +import classNames from 'classnames'; + +import SandwichIcon from 'components/icons/sandwich'; +import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'; + +const EURDLegend = () => { + const [isOpen, setIsOpen] = useState(false); + + return ( +
+ + + + + + Place content for the popover here. + + +
+ ); +}; + +export default EURDLegend; diff --git a/client/src/containers/analysis-eudr/map/legend/index.ts b/client/src/containers/analysis-eudr/map/legend/index.ts new file mode 100644 index 000000000..b404d7fd4 --- /dev/null +++ b/client/src/containers/analysis-eudr/map/legend/index.ts @@ -0,0 +1 @@ +export { default } from './component'; diff --git a/client/yarn.lock b/client/yarn.lock index af3287489..47369494e 100644 --- a/client/yarn.lock +++ b/client/yarn.lock @@ -1950,6 +1950,32 @@ __metadata: languageName: node linkType: hard +"@radix-ui/react-dropdown-menu@npm:^2.0.6": + version: 2.0.6 + resolution: "@radix-ui/react-dropdown-menu@npm:2.0.6" + dependencies: + "@babel/runtime": ^7.13.10 + "@radix-ui/primitive": 1.0.1 + "@radix-ui/react-compose-refs": 1.0.1 + "@radix-ui/react-context": 1.0.1 + "@radix-ui/react-id": 1.0.1 + "@radix-ui/react-menu": 2.0.6 + "@radix-ui/react-primitive": 1.0.3 + "@radix-ui/react-use-controllable-state": 1.0.1 + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: 1433e04234c29ae688b1d50b4a5ad0fd67e2627a5ea2e5f60fec6e4307e673ef35a703672eae0d61d96156c59084bbb19de9f9b9936b3fc351917dfe41dcf403 + languageName: node + linkType: hard + "@radix-ui/react-focus-guards@npm:1.0.1": version: 1.0.1 resolution: "@radix-ui/react-focus-guards@npm:1.0.1" @@ -2023,6 +2049,77 @@ __metadata: languageName: node linkType: hard +"@radix-ui/react-menu@npm:2.0.6": + version: 2.0.6 + resolution: "@radix-ui/react-menu@npm:2.0.6" + dependencies: + "@babel/runtime": ^7.13.10 + "@radix-ui/primitive": 1.0.1 + "@radix-ui/react-collection": 1.0.3 + "@radix-ui/react-compose-refs": 1.0.1 + "@radix-ui/react-context": 1.0.1 + "@radix-ui/react-direction": 1.0.1 + "@radix-ui/react-dismissable-layer": 1.0.5 + "@radix-ui/react-focus-guards": 1.0.1 + "@radix-ui/react-focus-scope": 1.0.4 + "@radix-ui/react-id": 1.0.1 + "@radix-ui/react-popper": 1.1.3 + "@radix-ui/react-portal": 1.0.4 + "@radix-ui/react-presence": 1.0.1 + "@radix-ui/react-primitive": 1.0.3 + "@radix-ui/react-roving-focus": 1.0.4 + "@radix-ui/react-slot": 1.0.2 + "@radix-ui/react-use-callback-ref": 1.0.1 + aria-hidden: ^1.1.1 + react-remove-scroll: 2.5.5 + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: a43fb560dbb5a4ddc43ea4e2434a9f517bbbcbf8b12e1e74c1e36666ad321aef7e39f91770140c106fe6f34e237102be8a02f3bc5588e6c06a709e20580c5e82 + languageName: node + linkType: hard + +"@radix-ui/react-popover@npm:^1.0.7": + version: 1.0.7 + resolution: "@radix-ui/react-popover@npm:1.0.7" + dependencies: + "@babel/runtime": ^7.13.10 + "@radix-ui/primitive": 1.0.1 + "@radix-ui/react-compose-refs": 1.0.1 + "@radix-ui/react-context": 1.0.1 + "@radix-ui/react-dismissable-layer": 1.0.5 + "@radix-ui/react-focus-guards": 1.0.1 + "@radix-ui/react-focus-scope": 1.0.4 + "@radix-ui/react-id": 1.0.1 + "@radix-ui/react-popper": 1.1.3 + "@radix-ui/react-portal": 1.0.4 + "@radix-ui/react-presence": 1.0.1 + "@radix-ui/react-primitive": 1.0.3 + "@radix-ui/react-slot": 1.0.2 + "@radix-ui/react-use-controllable-state": 1.0.1 + aria-hidden: ^1.1.1 + react-remove-scroll: 2.5.5 + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: 3ec15c0923ea457f586aa34f77e17fabffa02dffeab622951560ec21c38df2f43718ff088d24bf9fd1d9cd0db62436fc19cae5b122d90f72de4945a1f508dc59 + languageName: node + linkType: hard + "@radix-ui/react-popper@npm:1.1.3": version: 1.1.3 resolution: "@radix-ui/react-popper@npm:1.1.3" @@ -7677,7 +7774,9 @@ __metadata: "@loaders.gl/core": 3.3.1 "@luma.gl/constants": 8.5.18 "@radix-ui/react-collapsible": 1.0.3 + "@radix-ui/react-dropdown-menu": ^2.0.6 "@radix-ui/react-label": 2.0.2 + "@radix-ui/react-popover": ^1.0.7 "@radix-ui/react-radio-group": 1.1.3 "@radix-ui/react-select": 2.0.0 "@radix-ui/react-slot": 1.0.2 From 18ba59997e4e168a09375715264c04d35396eb4a Mon Sep 17 00:00:00 2001 From: David Inga Date: Thu, 7 Mar 2024 10:25:20 +0100 Subject: [PATCH 3/4] added legend styles --- client/src/components/ui/popover.tsx | 22 ++++---- .../analysis-eudr/map/component.tsx | 4 +- .../analysis-eudr/map/legend/component.tsx | 51 +++++++++++++++++-- .../analysis-eudr/map/legend/item.tsx | 33 ++++++++++++ 4 files changed, 94 insertions(+), 16 deletions(-) create mode 100644 client/src/containers/analysis-eudr/map/legend/item.tsx diff --git a/client/src/components/ui/popover.tsx b/client/src/components/ui/popover.tsx index bbba7e0eb..325d7b703 100644 --- a/client/src/components/ui/popover.tsx +++ b/client/src/components/ui/popover.tsx @@ -1,29 +1,29 @@ -import * as React from "react" -import * as PopoverPrimitive from "@radix-ui/react-popover" +import * as React from 'react'; +import * as PopoverPrimitive from '@radix-ui/react-popover'; -import { cn } from "@/lib/utils" +import { cn } from '@/lib/utils'; -const Popover = PopoverPrimitive.Root +const Popover = PopoverPrimitive.Root; -const PopoverTrigger = PopoverPrimitive.Trigger +const PopoverTrigger = PopoverPrimitive.Trigger; const PopoverContent = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef ->(({ className, align = "center", sideOffset = 4, ...props }, ref) => ( +>(({ className, align = 'center', sideOffset = 4, ...props }, ref) => ( -)) -PopoverContent.displayName = PopoverPrimitive.Content.displayName +)); +PopoverContent.displayName = PopoverPrimitive.Content.displayName; -export { Popover, PopoverTrigger, PopoverContent } +export { Popover, PopoverTrigger, PopoverContent }; diff --git a/client/src/containers/analysis-eudr/map/component.tsx b/client/src/containers/analysis-eudr/map/component.tsx index 5aa2189c2..fc4ad8070 100644 --- a/client/src/containers/analysis-eudr/map/component.tsx +++ b/client/src/containers/analysis-eudr/map/component.tsx @@ -32,6 +32,8 @@ const EUDRMap = () => { autoHighlight: true, }); + const layers = [layer]; + const handleMapStyleChange = useCallback((newStyle: BasemapValue) => { setMapStyle(newStyle); }, []); @@ -52,7 +54,7 @@ const EUDRMap = () => { viewState={{ ...viewState }} onViewStateChange={({ viewState }) => setViewState(viewState as MapViewState)} controller={{ dragRotate: false }} - layers={[layer]} + layers={layers} > diff --git a/client/src/containers/analysis-eudr/map/legend/component.tsx b/client/src/containers/analysis-eudr/map/legend/component.tsx index 53c7d138e..54da03733 100644 --- a/client/src/containers/analysis-eudr/map/legend/component.tsx +++ b/client/src/containers/analysis-eudr/map/legend/component.tsx @@ -1,11 +1,16 @@ import { useState } from 'react'; import classNames from 'classnames'; +import { MinusIcon, PlusIcon } from '@heroicons/react/outline'; -import SandwichIcon from 'components/icons/sandwich'; +import LegendItem from './item'; + +import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible'; +import SandwichIcon from '@/components/icons/sandwich'; import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'; const EURDLegend = () => { const [isOpen, setIsOpen] = useState(false); + const [isExpanded, setIsExpanded] = useState(false); return (
@@ -14,14 +19,52 @@ const EURDLegend = () => { - - Place content for the popover here. + +
+

Legend

+
+ +
+ + +
+ +
+
+ + + + +
+
diff --git a/client/src/containers/analysis-eudr/map/legend/item.tsx b/client/src/containers/analysis-eudr/map/legend/item.tsx new file mode 100644 index 000000000..3946119f2 --- /dev/null +++ b/client/src/containers/analysis-eudr/map/legend/item.tsx @@ -0,0 +1,33 @@ +import classNames from 'classnames'; + +import type { FC, PropsWithChildren } from 'react'; + +type LegendItemProps = { title: string; description: string; iconClassName?: string }; + +const LegendItem: FC> = ({ + title, + description, + children, + iconClassName, +}) => { + return ( +
+
+
+
+

{title}

+
+
+

{description}

+ {children} +
+
+ ); +}; + +export default LegendItem; From d5949c0a14daa249efe7ad01969efa0773987341 Mon Sep 17 00:00:00 2001 From: David Inga Date: Thu, 7 Mar 2024 11:38:13 +0100 Subject: [PATCH 4/4] added plot geometries from api --- client/package.json | 1 + .../analysis-eudr/map/component.tsx | 56 ++++++++++++++++--- client/src/hooks/eudr/index.ts | 25 +++++++++ client/src/pages/eudr/index.tsx | 2 +- client/yarn.lock | 27 +++++++++ 5 files changed, 102 insertions(+), 9 deletions(-) diff --git a/client/package.json b/client/package.json index 2c05f2a00..370fc9ded 100644 --- a/client/package.json +++ b/client/package.json @@ -49,6 +49,7 @@ "@tanstack/react-query": "^4.2.1", "@tanstack/react-table": "8.13.2", "@tanstack/react-virtual": "3.0.1", + "@turf/bbox": "^6.5.0", "autoprefixer": "10.2.5", "axios": "1.3.4", "chroma-js": "2.1.2", diff --git a/client/src/containers/analysis-eudr/map/component.tsx b/client/src/containers/analysis-eudr/map/component.tsx index fc4ad8070..8c557d6ee 100644 --- a/client/src/containers/analysis-eudr/map/component.tsx +++ b/client/src/containers/analysis-eudr/map/component.tsx @@ -1,35 +1,40 @@ -import { useState, useCallback } from 'react'; +import { useEffect, useState, useCallback } from 'react'; import DeckGL from '@deck.gl/react/typed'; import { GeoJsonLayer } from '@deck.gl/layers/typed'; import Map from 'react-map-gl/maplibre'; -import { type MapViewState } from '@deck.gl/core/typed'; +import { WebMercatorViewport, type MapViewState } from '@deck.gl/core/typed'; +import bbox from '@turf/bbox'; import ZoomControl from './zoom'; import LegendControl from './legend'; import BasemapControl from '@/components/map/controls/basemap'; import { INITIAL_VIEW_STATE, MAP_STYLES } from '@/components/map'; +import { usePlotGeometries } from '@/hooks/eudr'; import type { BasemapValue } from '@/components/map/controls/basemap/types'; import type { MapStyle } from '@/components/map/types'; -const data = 'https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_10m_airports.geojson'; - const EUDRMap = () => { const [mapStyle, setMapStyle] = useState('terrain'); const [viewState, setViewState] = useState(INITIAL_VIEW_STATE); + const plotGeometries = usePlotGeometries(); + const layer: GeoJsonLayer = new GeoJsonLayer({ id: 'geojson-layer', - data, + data: plotGeometries.data, // Styles filled: true, - pointRadiusMinPixels: 2, - pointRadiusScale: 2000, - getFillColor: [200, 0, 80, 180], + getFillColor: [255, 176, 0, 84], + stroked: true, + getLineColor: [255, 176, 0, 255], + getLineWidth: 1, + lineWidthUnits: 'pixels', // Interactive props pickable: true, autoHighlight: true, + highlightColor: [255, 176, 0, 255], }); const layers = [layer]; @@ -48,6 +53,40 @@ const EUDRMap = () => { setViewState({ ...viewState, zoom }); }, [viewState]); + const fitToPlotBounds = useCallback(() => { + if (!plotGeometries.data) return; + const [minLng, minLat, maxLng, maxLat] = bbox(plotGeometries.data); + const newViewport = new WebMercatorViewport(viewState); + const { longitude, latitude, zoom } = newViewport.fitBounds( + [ + [minLng, minLat], + [maxLng, maxLat], + ], + { + padding: 10, + }, + ); + if ( + viewState.latitude !== latitude || + viewState.longitude !== longitude || + viewState.zoom !== zoom + ) { + setViewState({ ...viewState, longitude, latitude, zoom }); + } + }, [plotGeometries.data, viewState]); + + // Fit to bounds when data is loaded or changed + useEffect(() => { + if (plotGeometries.data) { + fitToPlotBounds(); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [plotGeometries.data]); + + const handleResize = useCallback(() => { + setTimeout(() => fitToPlotBounds(), 0); + }, [fitToPlotBounds]); + return ( <> { onViewStateChange={({ viewState }) => setViewState(viewState as MapViewState)} controller={{ dragRotate: false }} layers={layers} + onResize={handleResize} > diff --git a/client/src/hooks/eudr/index.ts b/client/src/hooks/eudr/index.ts index 5b369efa7..c39176d69 100644 --- a/client/src/hooks/eudr/index.ts +++ b/client/src/hooks/eudr/index.ts @@ -24,3 +24,28 @@ export const useEUDRSuppliers = ( }, ); }; + +export const usePlotGeometries = ( + params?: { + producersIds: string[]; + originsId: string[]; + materialsId: string[]; + geoRegionIds: string[]; + }, + options: UseQueryOptions = {}, +) => { + return useQuery( + ['eudr-geo-features-collection', params], + () => + apiService + .request<{ geojson }>({ + method: 'GET', + url: '/eudr/geo-features/collection', + params, + }) + .then((response) => response.data.geojson), + { + ...options, + }, + ); +}; diff --git a/client/src/pages/eudr/index.tsx b/client/src/pages/eudr/index.tsx index be4350cd2..8bffe7529 100644 --- a/client/src/pages/eudr/index.tsx +++ b/client/src/pages/eudr/index.tsx @@ -77,7 +77,7 @@ export const getServerSideProps: GetServerSideProps = async ({ req, res, query } } return { props: { query } }; } catch (error) { - if (error.response.status === 401) { + if (error.code === '401' || error.response.status === 401) { return { redirect: { permanent: false, diff --git a/client/yarn.lock b/client/yarn.lock index 47369494e..98c5d3880 100644 --- a/client/yarn.lock +++ b/client/yarn.lock @@ -2631,6 +2631,32 @@ __metadata: languageName: node linkType: hard +"@turf/bbox@npm:^6.5.0": + version: 6.5.0 + resolution: "@turf/bbox@npm:6.5.0" + dependencies: + "@turf/helpers": ^6.5.0 + "@turf/meta": ^6.5.0 + checksum: 537be56ae0c5ad44e71a691717b35745e947e19a6bd9f20fdac2ab4318caf98cd88472d7dbf576e8b32ead5da034d273ffb3f4559d6d386820ddcb88a1f7fedd + languageName: node + linkType: hard + +"@turf/helpers@npm:^6.5.0": + version: 6.5.0 + resolution: "@turf/helpers@npm:6.5.0" + checksum: d57f746351357838c654e0a9b98be3285a14b447504fd6d59753d90c6d437410bb24805d61c65b612827f07f6c2ade823bb7e56e41a1a946217abccfbd64c117 + languageName: node + linkType: hard + +"@turf/meta@npm:^6.5.0": + version: 6.5.0 + resolution: "@turf/meta@npm:6.5.0" + dependencies: + "@turf/helpers": ^6.5.0 + checksum: c6bb936aa92bf3365e87a50dc65f248e070c5767a36fac390754c00c89bf2d1583418686ab19a10332bfa9340b8cac6aaf2c55dad7f5fcf77f1a2dda75ccf363 + languageName: node + linkType: hard + "@types/chroma-js@npm:2.1.3": version: 2.1.3 resolution: "@types/chroma-js@npm:2.1.3" @@ -7786,6 +7812,7 @@ __metadata: "@tanstack/react-query": ^4.2.1 "@tanstack/react-table": 8.13.2 "@tanstack/react-virtual": 3.0.1 + "@turf/bbox": ^6.5.0 "@types/chroma-js": 2.1.3 "@types/d3-format": 3.0.1 "@types/d3-scale": 4.0.2