Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AA storm feature / revisit landfall popup display #1410

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
954eeee
report the change from PR #1384
Jan 10, 2025
5fa8df2
permanently show last analysed time point popup
Jan 10, 2025
103eb85
Merge branch 'feature/add-new-AA-storm' into feature/permanently-show…
ericboucher Jan 12, 2025
a8966e4
Merge branch 'feature/add-new-AA-storm' into improve-style-of-windpoi…
ericboucher Jan 12, 2025
84e7856
refacto types
Jan 13, 2025
f938589
remove unused types, more refacto
Jan 13, 2025
f9f46a8
Merge branch 'feature/permanently-show-last-analysed-date-tooltip' of…
Jan 13, 2025
53fca9f
improve timeline tooltip arrow
Jan 14, 2025
57c3b52
update landfall popup
Jan 14, 2025
da8d19d
fix test
Jan 14, 2025
19015fb
Merge branch 'feature/permanently-show-last-analysed-date-tooltip' in…
Jan 14, 2025
1635a2c
show small landfall popup
Jan 14, 2025
6eddfab
move popup of the right
Jan 15, 2025
edd7cda
Merge branch 'feature/add-new-AA-storm' into aa-storm-feature/revisit…
ericboucher Jan 15, 2025
57cbbc9
Fix lint
ericboucher Jan 15, 2025
e395922
Update index.tsx
ericboucher Jan 15, 2025
977735c
Update index.tsx
ericboucher Jan 15, 2025
1f2d078
Cleanup PR
ericboucher Jan 15, 2025
98ab91f
remove usage of unknown keyword
Jan 16, 2025
7a4a9b5
Merge branch 'aa-storm-feature/revisit-landfall-popup-display' of ssh…
Jan 16, 2025
7dd24d9
fix tooltip behaviour when clicking on it several times
Jan 16, 2025
e76f601
redefine how landfall marker is displayed
Jan 17, 2025
92a3f97
display landfall marker based on report date instead of current date
Jan 17, 2025
32845f0
Update AAStormLandfallMarker.tsx
ericboucher Jan 17, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { MapLayerMouseEvent, Popup } from 'react-map-gl/maplibre';
import _React, { useCallback, useState } from 'react';
import { createStyles, makeStyles, Typography } from '@material-ui/core';
import { useMapCallback } from 'utils/map-utils';
import { formatInUTC, getDateInUTC } from '../utils';
import { formatWindPointDate } from '../utils';
import {
FeaturePropertyDataType,
TimeSeries,
Expand Down Expand Up @@ -48,16 +48,6 @@ function AAStormDatePopup({ timeSeries }: AAStormDatePopupProps) {
onMouseLeave,
);

function getDayAndTime(time: string) {
const dateInUTC = getDateInUTC(time);

if (!dateInUTC) {
return '';
}

return formatInUTC(dateInUTC, 'dd - Kaaa');
}

const lastAnalyzedTimePoint: TimeSeriesFeature | undefined =
// eslint-disable-next-line fp/no-mutating-methods
timeSeries?.features
Expand All @@ -73,8 +63,8 @@ function AAStormDatePopup({ timeSeries }: AAStormDatePopupProps) {
return null;
}

const lng = feature.geometry.coordinates[0];
const lat = feature.geometry.coordinates[1];
const [lng, lat] = feature.geometry.coordinates;

const { time } = feature.properties;

return (
Expand All @@ -90,7 +80,7 @@ function AAStormDatePopup({ timeSeries }: AAStormDatePopupProps) {
className={classes.popup}
>
<Typography className={classes.toolTipDate} variant="body1">
{getDayAndTime(time)}
{formatWindPointDate(time)}
</Typography>
</Popup>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { Popup } from 'react-map-gl/maplibre';
import { ParsedStormData } from 'context/anticipatoryAction/AAStormStateSlice/parsedStormDataTypes';
import _React from 'react';
import { createStyles, makeStyles, Typography } from '@material-ui/core';
import { findLandfallWindPoint, hasLandfallOccured } from '../utils';
import { formatWindPointDate } from '../../utils';

function AAStormLandfallMarker({ stormData }: AAStormLandfallPopupProps) {
const classes = useStyles();

const windpoint = findLandfallWindPoint(stormData);

if (!windpoint) {
return null;
}

const isVisible = !hasLandfallOccured(stormData);

if (!isVisible) {
return null;
}

const [lng, lat] = windpoint.geometry.coordinates;

return (
<Popup
longitude={lng}
latitude={lat}
anchor="bottom"
offset={25}
closeButton={false}
closeOnClick={false}
className={classes.popup}
>
<Typography className={classes.tooltipText} variant="body1">
LF: {formatWindPointDate(windpoint.properties.time)}
</Typography>
</Popup>
);
}

interface AAStormLandfallPopupProps {
stormData: ParsedStormData;
}

const useStyles = makeStyles(() =>
createStyles({
tooltipText: {
fontSize: '14px',
fontWeight: 600,
lineHeight: '14px',
paddingBottom: '2px',
},

popup: {
'& > .maplibregl-popup-content': {
border: 'none',
padding: '4px',
borderRadius: '4px',
background: 'white',
boxShadow: 'inset 0px 0px 0px 1px #A4A4A4',
position: 'relative',
},

'& > .maplibregl-popup-tip': {
display: 'none',
},

// hack to display the popup tip without overlapping border
'&::after': {
content: '""',
position: 'absolute',
left: '50%',
bottom: '-5px',
width: '10px',
height: '10px',
background: 'white',
transform: 'translateX(-50%) rotate(45deg)',
borderWidth: '0px 1px 1px 0px',
borderColor: '#A4A4A4',
borderStyle: 'solid',
},
},
}),
);

export default AAStormLandfallMarker;
Original file line number Diff line number Diff line change
@@ -1,26 +1,42 @@
import { createStyles, makeStyles } from '@material-ui/core';
import { Point } from 'geojson';
import { Offset } from 'maplibre-gl';
import { Popup } from 'react-map-gl/maplibre';
import { LandfallInfo } from 'context/anticipatoryAction/AAStormStateSlice/parsedStormDataTypes';
import { AAStormTimeSeriesFeature } from 'context/anticipatoryAction/AAStormStateSlice/rawStormDataTypes';
import PopupContent from './PopupContent';
import { isFeatureAtLandfallEstimateTime } from './utils';

const verticalLandfallPopupOffset = -50;
const horizontalLandfallPopupOffset = 25;

function AAStormLandfallPopup({
point,
feature,
onClose,
landfallInfo,
reportDate,
}: AAStormLandfallPopupProps) {
const classes = useStyles();

const lng = point.coordinates[0];
const lat = point.coordinates[1];
if (!landfallInfo) {
return null;
}

const isVisible = isFeatureAtLandfallEstimateTime(feature, landfallInfo.time);

if (!isVisible) {
return null;
}

const [lng, lat] = feature.geometry.coordinates;

return (
<Popup
longitude={lng}
latitude={lat}
anchor="top"
offset={15}
anchor="top-left"
offset={
[verticalLandfallPopupOffset, horizontalLandfallPopupOffset] as Offset
}
closeButton={false}
onClose={onClose}
closeOnClick
Expand All @@ -33,8 +49,8 @@ function AAStormLandfallPopup({
}

interface AAStormLandfallPopupProps {
point: Point;
landfallInfo: LandfallInfo;
feature: AAStormTimeSeriesFeature;
landfallInfo: LandfallInfo | undefined;
reportDate: string;
onClose: () => void;
}
Expand All @@ -43,15 +59,31 @@ const useStyles = makeStyles(() =>
createStyles({
popup: {
width: '280px',

'& > .maplibregl-popup-content': {
background: '#F1F1F1',
padding: '0px 2px 0px 2px',
border: 'none',
borderRadius: '4px',
boxShadow: 'inset 0px 1px 0px 0px #A4A4A4',
position: 'relative',
},

'& > .maplibregl-popup-tip': {
borderBottomColor: '#F1F1F1',
borderLeftWidth: '8px',
borderRightWidth: '8px',
display: 'none',
},

// hack to display the popup tip without overlapping border
'&::after': {
background: '#F1F1F1',
content: '""',
position: 'absolute',
left: `${horizontalLandfallPopupOffset * 2}px`,
top: -5,
width: '10px',
height: '10px',

transform: 'translateX(-50%) rotate(45deg)',
boxShadow: 'inset 1px 1px 0px 0px #A4A4A4',
},
},
}),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { ParsedStormData } from 'context/anticipatoryAction/AAStormStateSlice/parsedStormDataTypes';
import { AAStormTimeSeriesFeature } from 'context/anticipatoryAction/AAStormStateSlice/rawStormDataTypes';
import { getDateInUTC } from '../utils';

function getLandfallEstimatedTime(stormData: ParsedStormData) {
const { landfall } = stormData;
if (!landfall) {
return null;
}

return landfall.time;
}

/* find the wind point which time corresponds to the landfall estimated time */
export function findLandfallWindPoint(stormData: ParsedStormData) {
const landfallEstimatedtime = getLandfallEstimatedTime(stormData);

const windpoints = stormData.timeSeries?.features;
const foundWindPoint = windpoints?.find(windpoint =>
isFeatureAtLandfallEstimateTime(windpoint, landfallEstimatedtime),
);

return foundWindPoint || null;
}

export function isFeatureAtLandfallEstimateTime(
feature: AAStormTimeSeriesFeature,
landfallEstimatedtime: string[] | null,
) {
return (
landfallEstimatedtime &&
feature.properties.time === landfallEstimatedtime[0]
);
}

export function hasLandfallOccured(stormData: ParsedStormData) {
const reportTime = stormData.forecastDetails?.reference_time;

const reportTimeDate = getDateInUTC(reportTime);

if (!reportTimeDate) {
return null;
}

const landfallEstimatedtimeRange = getLandfallEstimatedTime(stormData);

if (!landfallEstimatedtimeRange) {
return null;
}

const landfallEstimatedStartTime = getDateInUTC(
landfallEstimatedtimeRange[0],
);

if (!landfallEstimatedStartTime) {
return null;
}

return reportTimeDate?.valueOf() > landfallEstimatedStartTime.valueOf();
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,13 @@ import { useWindStatesByTime } from 'components/MapView/DateSelector/TimelineIte
import { getAAColor } from 'components/MapView/LeftPanel/AnticipatoryActionPanel/AnticipatoryActionStormPanel/utils';
import { AACategory } from 'context/anticipatoryAction/AAStormStateSlice/parsedStormDataTypes';
import anticipatoryActionIcons from 'components/Common/AnticipatoryAction/icons';
import { AAStormTimeSeriesFeature } from 'context/anticipatoryAction/AAStormStateSlice/rawStormDataTypes';
import AAStormDatePopup from './AAStormDatePopup';
import AAStormLandfallPopup from './AAStormLandfallPopup';

import { TimeSeries } from './types';
import AAStormLandfallMarker from './AAStormLandfallPopup/AAStormLandfallMarker/AAStormLandfallMarker';
import { parseGeoJsonFeature } from './utils';

interface AnticipatoryActionStormLayerProps {
layer: AnticipatoryActionLayerProps;
Expand Down Expand Up @@ -104,8 +107,10 @@ const AnticipatoryActionStormLayer = React.memo(
) as LayerData<BoundaryLayerProps> | undefined;
const { data: boundaryData } = boundaryLayerState || {};

const [selectedFeature, setSelectedFeature] =
useState<Feature<Point> | null>(null);
const [selectedFeature, setSelectedFeature] = useState<{
feature: AAStormTimeSeriesFeature | null;
hasBeenDeselected: boolean;
}>({ feature: null, hasBeenDeselected: false });

function enhanceTimeSeries(timeSeries: TimeSeries) {
const { features, ...timeSeriesRest } = timeSeries;
Expand Down Expand Up @@ -169,7 +174,7 @@ const AnticipatoryActionStormLayer = React.memo(
}

function landfallPopupCloseHandler() {
setSelectedFeature(null);
setSelectedFeature({ feature: null, hasBeenDeselected: true });
}

// Load all images from the mapping
Expand Down Expand Up @@ -227,7 +232,19 @@ const AnticipatoryActionStormLayer = React.memo(
e.preventDefault();
dispatch(hidePopup()); // hides the black tooltip containing the district names
const feature = e.features?.[0];
setSelectedFeature(feature as Feature<Point>);

if (!selectedFeature.feature) {
if (selectedFeature.hasBeenDeselected) {
setSelectedFeature({
feature: null,
hasBeenDeselected: false,
});
}
setSelectedFeature({
feature: parseGeoJsonFeature(feature),
hasBeenDeselected: false,
});
}
};

useMapCallback<'click', null>(
Expand Down Expand Up @@ -436,14 +453,16 @@ const AnticipatoryActionStormLayer = React.memo(

<AAStormDatePopup timeSeries={stormData.timeSeries} />

{selectedFeature && stormData.landfall?.time && (
{selectedFeature.feature && (
<AAStormLandfallPopup
point={selectedFeature.geometry}
feature={selectedFeature.feature}
reportDate={stormData.forecastDetails?.reference_time || ''}
landfallInfo={stormData.landfall}
onClose={() => landfallPopupCloseHandler()}
/>
)}

<AAStormLandfallMarker stormData={stormData} />
</>
);
},
Expand Down
Loading
Loading