Skip to content

Commit fc46dea

Browse files
committed
Add footprint point hover/click actions
1 parent e03a1ab commit fc46dea

7 files changed

Lines changed: 139 additions & 14 deletions

File tree

demo/app/src/components/Map/DynamicMap.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { useEffect } from 'react';
22
import Leaflet from 'leaflet';
33
import * as ReactLeaflet from 'react-leaflet';
44
import 'leaflet/dist/leaflet.css';
5+
import Footprint from './Footprint';
56

67
import styles from './Map.module.scss';
78

@@ -27,6 +28,7 @@ const Map = ({ children, className, width, height, ...rest }) => {
2728

2829
return (
2930
<MapContainer className={mapClassName} {...rest}>
31+
<Footprint />
3032
{children(ReactLeaflet, Leaflet)}
3133
</MapContainer>
3234
)
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import { useMap } from 'react-leaflet';
2+
import { useEffect, useState } from 'react';
3+
import { useAppContext } from 'src/context/appContext';
4+
5+
import styles from './Map.module.scss';
6+
7+
8+
function getCoords(geojson){
9+
return [geojson.geometry.coordinates[1], geojson.geometry.coordinates[0]]
10+
}
11+
12+
export default function Footprint() {
13+
const map = useMap();
14+
const [activeMarkerHover, setActiveMarkerHover] = useState(null);
15+
const [previousMarkerHover, setPreviousMarkerHover] = useState(null);
16+
const [activeMarkerClick, setActiveMarkerClick] = useState(null);
17+
const [previousMarkerClick, setPreviousMarkerClick] = useState(null);
18+
const { selectedOpportunity, hoveredOpportunity } = useAppContext();
19+
const footprintIcon = new L.divIcon({className: styles.footprintCircle});
20+
21+
useEffect(() => {
22+
if (!activeMarkerClick && previousMarkerClick){
23+
map.removeLayer(previousMarkerClick);
24+
setPreviousMarkerClick(null);
25+
}
26+
if (!activeMarkerHover && previousMarkerHover){
27+
map.removeLayer(previousMarkerHover);
28+
setPreviousMarkerHover(null);
29+
}
30+
if (activeMarkerClick && previousMarkerClick && (activeMarkerClick !== previousMarkerClick)){
31+
map.removeLayer(previousMarkerClick);
32+
setPreviousMarkerClick(activeMarkerClick);
33+
}
34+
previousMarkerHover && map.removeLayer(previousMarkerHover);
35+
activeMarkerHover && map.addLayer(activeMarkerHover);
36+
activeMarkerClick && map.addLayer(activeMarkerClick) && map.flyTo(getCoords(selectedOpportunity), 9);
37+
},[activeMarkerHover, previousMarkerHover, activeMarkerClick, previousMarkerClick]);
38+
39+
useEffect(() => {
40+
activeMarkerHover && setPreviousMarkerHover(activeMarkerHover);
41+
activeMarkerClick && setPreviousMarkerClick(activeMarkerClick);
42+
if (hoveredOpportunity){
43+
setActiveMarkerHover(new L.Marker(getCoords(hoveredOpportunity), {
44+
icon: footprintIcon
45+
}));
46+
}
47+
else {
48+
setActiveMarkerHover(null);
49+
}
50+
51+
if(selectedOpportunity) {
52+
setActiveMarkerClick(new L.Marker(getCoords(selectedOpportunity), {
53+
icon: footprintIcon
54+
}));
55+
setActiveMarkerHover(null);
56+
}
57+
else {
58+
setActiveMarkerClick(null);
59+
}
60+
}, [hoveredOpportunity, selectedOpportunity]);
61+
62+
return null;
63+
}
Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,26 @@
11
.map {
22
width: 100%;
33
height: 100%;
4-
}
4+
}
5+
6+
.footprintCircle {
7+
display: table-cell;
8+
text-align: center;
9+
vertical-align: middle;
10+
border-radius: 50%;
11+
border: 2px solid #FA00FF;
12+
width: 24px !important;
13+
height: 24px !important;
14+
15+
&:before{
16+
display: table-cell;
17+
position: absolute;
18+
top: 6px;
19+
left: 6px;
20+
content: "";
21+
border-radius: 50%;
22+
background-color: #FA00FF;
23+
width: 10px;
24+
height: 10px;
25+
}
26+
}

demo/app/src/components/Sidebar/Opportunity.js

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,18 @@ export default function Opportunity({
55
title,
66
provider,
77
start,
8-
end
8+
end,
9+
onMouseEnter,
10+
onMouseLeave,
11+
onClick
912
}) {
1013
return (
11-
<div className={styles.opportunityPreview}>
14+
<div
15+
className={styles.opportunityPreview}
16+
onClick={onClick}
17+
onMouseEnter={onMouseEnter}
18+
onMouseLeave={onMouseLeave}
19+
>
1220
<h1>{title}</h1>
1321
<h2>{provider}</h2>
1422
<div className={styles.previewStartDate}>
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import styles from './Sidebar.module.scss'
2+
import { useAppContext } from 'src/context/appContext';
3+
import Button from '@components/Button';
4+
5+
export default function OpportunityDetail() {
6+
const { selectedOpportunity, setSelectedOpportunity, setHoveredOpportunity } = useAppContext();
7+
8+
return (
9+
<div className={styles.opportunityDetail}>
10+
<div className={styles.topBar}>
11+
<h3 className={styles.heading}>Detail</h3>
12+
<Button
13+
onClick={() => {
14+
setSelectedOpportunity(null);
15+
setHoveredOpportunity(null);
16+
}}
17+
>
18+
x
19+
</Button>
20+
</div>
21+
<div>{selectedOpportunity.id}</div>
22+
</div>
23+
);
24+
}

demo/app/src/components/Sidebar/OpportunityList.js

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { useAppContext } from 'src/context/appContext';
44
import { parseStacDatetime } from 'src/utils';
55

66
export default function OpportunityList() {
7-
const { opportunities, setHoveredOpportunity, setSelectedOpportunity } = useAppContext();
7+
const { opportunities, selectedOpportunity, setHoveredOpportunity, setSelectedOpportunity } = useAppContext();
88

99
function mouseInStyleChange(e) {
1010
e.target.style.outline = 'red';
@@ -25,13 +25,17 @@ function mouseOutStyleChange(e) {
2525
provider={provider}
2626
start={start}
2727
end={end}
28-
// onMouseEnter={(e) => {
29-
// mouseInStyleChange(e);
30-
// setHoveredOpportunity(index)}}
31-
// onMouseLeave={(e) => {
32-
// mouseOutStyleChange(e);
33-
// setHoveredOpportunity(null)}}
34-
// onClick={(e) => setSelectedOpportunity(index)}
28+
onMouseEnter={(e) => {
29+
if(!selectedOpportunity){
30+
mouseInStyleChange(e);
31+
setHoveredOpportunity(opportunities[provider][index])}}
32+
}
33+
onMouseLeave={(e) => {
34+
if(!selectedOpportunity){
35+
mouseOutStyleChange(e);
36+
setHoveredOpportunity(null)}}
37+
}
38+
onClick={(e) => setSelectedOpportunity(opportunities[provider][index])}
3539
/>
3640
})
3741
})

demo/app/src/components/Sidebar/Sidebar.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,16 @@ import { useAppContext } from 'src/context/appContext';
1111
import OpportunityList from './OpportunityList';
1212
import { useEffect, useState } from 'react';
1313
import { ALL_PROVIDERS as providers } from 'src/utils/constants';
14+
import OpportunityDetail from './OpportunityDetail';
1415

1516
export default function Sidebar(props) {
1617
const {
17-
opportunities,
18+
selectedOpportunity,
1819
isLoadingOpps,
1920
errorOpps,
2021
openFilters,
2122
setOpenFilters,
2223
products,
23-
isLoadingProducts,
24-
isErrorProducts,
2524
userParams,
2625
setUserParams
2726
} = useAppContext();
@@ -151,6 +150,9 @@ export default function Sidebar(props) {
151150
<RingLoader color="#5fbb9d" />
152151
</div>
153152
)}
153+
{!!selectedOpportunity && (
154+
<OpportunityDetail />
155+
)}
154156
</div>
155157
);
156158
}

0 commit comments

Comments
 (0)