Skip to content
This repository has been archived by the owner on May 4, 2024. It is now read-only.

Add road selection #107

Merged
merged 1 commit into from
Nov 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
13 changes: 12 additions & 1 deletion frontend/src/Components/Conditions/ConditionsMap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ import {
IRInew,
KPI,
Mu,
YearMonth,
MultiMode,
YearMonth,
} from '../../models/conditions';
import { getAllConditions } from '../../queries/conditions';

Expand Down Expand Up @@ -56,6 +56,8 @@ const getTypeColor = (type: string): string => {
* @param y otherwise the color is yellow if value <= y
* @param o otherwise the color is orange if value <= o. Otherwise, the color is red
* @returns {string} the color
*
* @author Kerbourc'h
*/
const getColorForValue = (
value: number,
Expand All @@ -75,6 +77,13 @@ const getColorForValue = (
: '#FF0000';
};

/**
* The gradient color for each indicator
*
* @param properties the type and value of the GeoJSON being drawn
*
* @author Kerbourc'h
*/
const getConditionColor = (properties: GeoJSON.GeoJsonProperties): string => {
if (properties !== null) {
const type = properties.type;
Expand Down Expand Up @@ -111,6 +120,8 @@ interface ConditionsMapProps {

/**
* Component rendering the map with the conditions
*
* @author Hansen, Kerbourc'h
*/
const ConditionsMap: FC<ConditionsMapProps> = ({
children,
Expand Down
24 changes: 24 additions & 0 deletions frontend/src/Components/Map/DetectMapClick.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { useMapEvents } from 'react-leaflet';
import { LatLng } from 'leaflet';
import { FC } from 'react';

interface Props {
/** The callback function */
onClick: (latLng: LatLng) => void;
}

/**
* A component that detects a click on the map and calls the callback function
*
* @author Kerbourc'h
*/
const DetectMapClick: FC<Props> = ({ onClick }) => {
useMapEvents({
click: (e) => {
onClick(e.latlng);
},
});
return null;
};

export default DetectMapClick;
3 changes: 3 additions & 0 deletions frontend/src/Components/Map/ForceMapUpdate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ interface Props {

/**
* This component is used to force an update of the map. It is used in conjunction with the useMap hook.
*
* @author Kerbourc'h
*/
const ForceMapUpdate: React.FC<Props> = ({ triggerUpdate, position }) => {
const map = useMap();
Expand All @@ -19,6 +21,7 @@ const ForceMapUpdate: React.FC<Props> = ({ triggerUpdate, position }) => {
map.invalidateSize();
}, [triggerUpdate]);

// TODO: not working when moving too little
useEffect(() => {
if (position) {
map.flyTo(position);
Expand Down
11 changes: 7 additions & 4 deletions frontend/src/Components/Map/Road.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { IRoad } from '../../models/path';
import { LatLng, LatLngLiteral } from 'leaflet';
import L, { LatLng, LatLngLiteral } from 'leaflet';
import { Polyline } from 'react-leaflet';
import React, { ReactElement, useEffect } from 'react';

Expand All @@ -12,6 +12,8 @@ interface Props {

/**
* A components that renders a road on the map
*
* @author Kerbourc'h
*/
const Road: React.FC<Props> = ({ road, onClick }) => {
const [lines, setLines] = React.useState<ReactElement[]>([]);
Expand Down Expand Up @@ -47,11 +49,12 @@ const Road: React.FC<Props> = ({ road, onClick }) => {
pathOptions={{ weight: 5, opacity: opacity }}
positions={data}
eventHandlers={{
click: ({ latlng }) => {
if (onClick) onClick(latlng);
click: (e) => {
L.DomEvent.stopPropagation(e); // used to prevent the map to detect the click
if (onClick) onClick(e.latlng);
},
mouseover: () => {
setOpacity(0.8);
setOpacity(0.9);
},
mouseout: () => {
setOpacity(0.2);
Expand Down
37 changes: 23 additions & 14 deletions frontend/src/Components/Map/Roads.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,47 @@ import React from 'react';
import { IRoad } from '../../models/path';
import Road from './Road';
import { LatLng } from '../../models/models';
import { useNavigate } from 'react-router-dom';

interface Props {
/** The roads */
roads?: IRoad[];
/** The selected road index */
selectedRoadIdx?: number;
/** The event handlers, when a road is selected */
onSelectedRoad?: (road: IRoad, position: LatLng) => void;
onSelectedRoad?: (index: number, road: IRoad, position: LatLng) => void;
}

/**
* A components that renders the roads on the map
*
* @author Kerbourc'h
*/
const Roads: React.FC<Props> = ({ roads, onSelectedRoad }) => {
const navigate = useNavigate();

const Roads: React.FC<Props> = ({ roads, selectedRoadIdx, onSelectedRoad }) => {
return (
<>
{roads?.map((road) => (
{selectedRoadIdx === undefined || selectedRoadIdx === -1 || !roads ? (
roads?.map((road, index) => (
<Road
key={road.way_name}
road={road}
onClick={(position) => {
if (onSelectedRoad) {
onSelectedRoad(index, road, position);
}
}}
/>
))
) : (
<Road
key={road.way_name}
road={road}
key={roads[selectedRoadIdx].way_name}
road={roads[selectedRoadIdx]}
onClick={(position) => {
console.log(road, position);
// TODO: remove when possible to select a road
navigate('/inspect');

if (onSelectedRoad) {
onSelectedRoad(road, position);
onSelectedRoad(selectedRoadIdx, roads[selectedRoadIdx], position);
}
}}
/>
))}
)}
</>
);
};
Expand Down
31 changes: 15 additions & 16 deletions frontend/src/css/navbar.css
Original file line number Diff line number Diff line change
Expand Up @@ -20,29 +20,19 @@
position: relative;
width: 15%;
min-width: fit-content;
height: 100%;
margin-top: 13px;
margin-left: 0.4%;
align-self: flex-start;
}

.picker-container {
position: relative;
width: 15%;
min-width: fit-content;
height: 100%;
margin-top: 10px;
align-self: flex-start;
height: 38px;
}

.filter-container {
position: relative;
width: 6%;
min-width: fit-content;
height: 100%;
margin-top: 13px;
align-self: flex-start;
flex-basis: auto;
}

.nav-tab {
Expand All @@ -64,11 +54,20 @@
white-space: nowrap;
}

.nav-tab:hover {
color: var(--highlight-text);
.inspect-button-div {
position: relative;
width: 6%;
min-width: fit-content;
margin-left: auto;
margin-right: 20px;
}

.nav-tab.active {
color: var(--highlight-text);
background: var(--highlight-background);
.inspect-button {
font-size: inherit; /* Inherit font size */
color: inherit; /* Inherit text color */
cursor: pointer; /* Add a pointer cursor on hover */
text-decoration: none; /* Remove underlines on hover */
background: #7f6fe9;
border-radius: 2px;
padding: 7px 20px 7px 20px;
}
60 changes: 53 additions & 7 deletions frontend/src/pages/Main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,29 @@ import ForceMapUpdate from '../Components/Map/ForceMapUpdate';
import Roads from '../Components/Map/Roads';
import {
ConditionTypeOptions,
SeverityOptions,
DateRange,
YearMonth,
MultiMode,
DefaultMode,
MultiMode,
SeverityOptions,
YearMonth,
} from '../models/conditions';
import MonthFilter from '../Components/Map/Inputs/MonthFilter';
import MultiSelector from '../Components/Map/Inputs/MultiSelector';
import '../css/navbar.css';
import DetectMapClick from '../Components/Map/DetectMapClick';
import { Link } from 'react-router-dom';

/**
* Component rendering the main page
*
* @author Hansen, Kerbourc'h
*/
const Main: FC = () => {
// The roads loaded from the database
const [roads, setRoads] = useState<IRoad[]>();
// Select road index
const [selectedRoadIdx, setSelectedRoadIdx] = useState<number>(-1);

// The position to move too (used by the Search component)
const [moveToPosition, setMoveToPosition] = useState<LatLng>();
// The indicator(s) to display on the map
Expand All @@ -43,7 +50,7 @@ const Main: FC = () => {
function dateChange(date: any) {
const YearMonth: YearMonth = {
year: date.getFullYear(),
month: date.getMonth() + 1,
month: date.getMonth() + 1, // january = 0
};

return YearMonth;
Expand Down Expand Up @@ -84,7 +91,7 @@ const Main: FC = () => {

const multiModeSet = useCallback((value: string[]) => {
const outputMode: MultiMode = {
count: value.length + 0,
count: value.length,
mode: value
.map((e: any) => e.label)
.toString()
Expand All @@ -108,7 +115,20 @@ const Main: FC = () => {
<div className="nav-container">
<Search
onPlaceSelect={(value: any) => {
console.log(value);
const osm_id = value?.properties?.datasource?.raw?.osm_id;
if (osm_id && roads) {
console.debug(osm_id, roads.length);
for (let idx = 0; idx < roads.length; idx++) {
if (
Object.keys(roads[idx].geometries).includes(String(osm_id))
) {
console.debug('Found road', idx);
setSelectedRoadIdx(idx);
break;
}
}
}

const coordinates = value?.geometry?.coordinates;
if (coordinates) {
const position = {
Expand Down Expand Up @@ -147,9 +167,35 @@ const Main: FC = () => {
/>
<p className="labelling"> Start Date → End Date</p>
</div>
<div className="inspect-button-div">
<Link
to="/inspect/survey/65d62536-d3af-4184-9c6b-6fedd97de15c"
hidden={selectedRoadIdx === -1}
className="inspect-button"
>
Inspect
</Link>
</div>
</div>
<ConditionsMap multiMode={multiMode!} rangeSelected={rangeSelected}>
<Roads roads={roads} />
<Roads
roads={roads}
selectedRoadIdx={selectedRoadIdx}
onSelectedRoad={(index, _road, position) => {
// If no road is selected, select the road
if (selectedRoadIdx === -1) {
setSelectedRoadIdx(index);
}
setMoveToPosition(position);
}}
/>
<DetectMapClick
onClick={() => {
if (selectedRoadIdx !== -1) {
setSelectedRoadIdx(-1);
}
}}
/>
<ForceMapUpdate position={moveToPosition} />
</ConditionsMap>
</div>
Expand Down