@@ -6,11 +6,13 @@ import {
66 type LatLngExpression ,
77 type LeafletMouseEvent ,
88} from 'leaflet' ;
9+ import { Trans , useTranslation } from 'react-i18next' ;
910import { PopupTable } from './PopupTable' ;
1011import { createRoot } from 'react-dom/client' ;
1112import { useTheme } from '@mui/material/styles' ;
1213import { ThemeModeEnum } from '../Theme' ;
13- import { Box } from '@mui/material' ;
14+ import { Box , Typography , Tooltip } from '@mui/material' ;
15+ import InfoOutlinedIcon from '@mui/icons-material/InfoOutlined' ;
1416
1517export interface GeoJSONData {
1618 type : 'FeatureCollection' | 'Feature' | 'GeometryCollection' ;
@@ -33,6 +35,16 @@ export const MapGeoJSON = (
3335 props : React . PropsWithChildren < MapProps > ,
3436) : JSX . Element => {
3537 const theme = useTheme ( ) ;
38+ const { t } = useTranslation ( 'feeds' ) ;
39+ const { geoJSONData } = props ;
40+ const bounds = React . useMemo ( ( ) => {
41+ return props . polygon . length > 0
42+ ? ( props . polygon as LatLngBoundsExpression )
43+ : ( [
44+ [ 0 , 0 ] ,
45+ [ 0 , 0 ] ,
46+ ] as LatLngBoundsExpression ) ;
47+ } , [ props . polygon ] ) ;
3648
3749 const handleFeatureClick = (
3850 e : LeafletMouseEvent ,
@@ -64,20 +76,86 @@ export const MapGeoJSON = (
6476 } }
6577 >
6678 < MapContainer
67- bounds = { props . polygon as LatLngBoundsExpression }
79+ bounds = { bounds }
6880 zoom = { 8 }
69- style = { {
70- height : '100%' ,
71- } }
81+ style = { { minHeight : '400px' , height : '100%' } }
7282 data-testid = 'geojson-map'
7383 >
7484 < TileLayer
7585 attribution = '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
7686 url = { mapTiles }
7787 />
7888 { props . geoJSONData !== null && (
89+ < Box
90+ sx = { {
91+ position : 'absolute' ,
92+ bottom : 20 ,
93+ right : 16 ,
94+ background : theme . palette . background . paper ,
95+ padding : 1 ,
96+ borderRadius : 2 ,
97+ boxShadow : 3 ,
98+ maxWidth : 175 ,
99+ zIndex : 1000 ,
100+ } }
101+ >
102+ < Box sx = { { display : 'flex' , alignItems : 'center' , gap : 0.5 } } >
103+ < Typography style = { { fontSize : '0.85rem' , fontWeight : 800 } } >
104+ { t ( 'heatmapIntensity' ) }
105+ </ Typography >
106+ < Tooltip
107+ title = {
108+ < React . Fragment >
109+ < Typography sx = { { fontWeight : 800 } } >
110+ < strong > { t ( 'heatmapExplanationTitle' ) } </ strong >
111+ </ Typography >
112+ < div >
113+ { ' ' }
114+ < Trans
115+ i18nKey = { t ( 'heatmapExplanationContent' ) }
116+ components = { { code : < code /> } }
117+ />
118+ </ div >
119+ </ React . Fragment >
120+ }
121+ >
122+ < InfoOutlinedIcon
123+ sx = { {
124+ fontSize : '16px' ,
125+ color : theme . palette . text . secondary ,
126+ cursor : 'pointer' ,
127+ } }
128+ />
129+ </ Tooltip >
130+ </ Box >
131+ < Box
132+ sx = { {
133+ width : '100%' ,
134+ height : '16px' ,
135+ background : `linear-gradient(to right, #fb8c58, #7f0000)` ,
136+ marginTop : 2 ,
137+ marginBottom : 1 ,
138+ borderRadius : 1 ,
139+ } }
140+ />
141+ < Box
142+ sx = { {
143+ display : 'flex' ,
144+ justifyContent : 'space-between' ,
145+ fontSize : '0.75rem' ,
146+ gap : 2 ,
147+ color : theme . palette . text . secondary ,
148+ } }
149+ >
150+ < span > { t ( 'heatmapLower' ) } </ span >
151+ < span > { t ( 'heatmapHigher' ) } </ span >
152+ </ Box >
153+ </ Box >
154+ ) }
155+
156+ { geoJSONData !== null && (
79157 < GeoJSON
80- data = { props . geoJSONData }
158+ data = { geoJSONData }
81159 onEachFeature = { ( feature , layer ) => {
82160 const container = document . createElement ( 'div' ) ;
83161 container . style . background = theme . palette . background . default ;
0 commit comments