diff --git a/client/src/components/flightplan/FlightPlan.tsx b/client/src/components/flightplan/FlightPlan.tsx index 7ef7375c..6fce8100 100644 --- a/client/src/components/flightplan/FlightPlan.tsx +++ b/client/src/components/flightplan/FlightPlan.tsx @@ -1,5 +1,6 @@ import { Flight } from "../../api/flight"; import { Polyline } from "react-leaflet"; +import WaypointMarker from "../waypointmarker"; const BLUE_PATH = "#0084ff"; const RED_PATH = "#c85050"; @@ -35,10 +36,33 @@ function FlightPlanPath(props: FlightPlanProps) { ); } +const WaypointMarkers = (props: FlightPlanProps) => { + if (!props.selected || props.flight.waypoints == null) { + return <>; + } + + return ( + <> + {props.flight.waypoints + .filter((p) => p.should_mark) + .map((p, idx) => { + return ( + + ); + })} + + ); +}; + export default function FlightPlan(props: FlightPlanProps) { return ( <> + ); } diff --git a/client/src/components/waypointmarker/WaypointMarker.tsx b/client/src/components/waypointmarker/WaypointMarker.tsx new file mode 100644 index 00000000..c85f5eac --- /dev/null +++ b/client/src/components/waypointmarker/WaypointMarker.tsx @@ -0,0 +1,76 @@ +import { Marker, Tooltip, useMap, useMapEvent } from "react-leaflet"; +import { MutableRefObject, useCallback, useEffect, useRef } from "react"; + +import { Icon } from "leaflet"; +import { Marker as LMarker } from "leaflet"; +import { Waypoint } from "../../api/waypoint"; +import icon from "leaflet/dist/images/marker-icon.png"; +import iconShadow from "leaflet/dist/images/marker-shadow.png"; + +const WAYPOINT_ICON = new Icon({ + iconUrl: icon, + shadowUrl: iconShadow, + iconAnchor: [12, 41], +}); + +interface WaypointMarkerProps { + number: number; + waypoint: Waypoint; +} + +const WaypointMarker = (props: WaypointMarkerProps) => { + // Most props of react-leaflet types are immutable and components will not + // update to account for changes, so we can't simply use the `permanent` + // property of the tooltip to control tooltip visibility based on the zoom + // level. + // + // On top of that, listening for zoom changes and opening/closing is not + // sufficient because clicking anywhere will close any opened tooltips (even + // if they are permanent; once openTooltip has been called that seems to no + // longer have any effect). + // + // Instead, listen for zoom changes and rebind the tooltip when the zoom level + // changes. + const map = useMap(); + const marker: MutableRefObject = useRef(); + + const rebindTooltip = useCallback(() => { + if (marker.current === undefined) { + return; + } + + const tooltip = marker.current.getTooltip(); + if (tooltip === undefined) { + return; + } + + const permanent = map.getZoom() >= 9; + marker.current + .unbindTooltip() + .bindTooltip(tooltip, { permanent: permanent }); + }, [map]); + useMapEvent("zoomend", rebindTooltip); + + const waypoint = props.waypoint; + return ( + { + if (ref != null) { + marker.current = ref; + } + }} + > + + {`${props.number} ${waypoint.name}`} +
+ {`${waypoint.altitude_ft} ft ${waypoint.altitude_reference}`} +
+ TODO: Timing info +
+
+ ); +}; + +export default WaypointMarker; diff --git a/client/src/components/waypointmarker/index.ts b/client/src/components/waypointmarker/index.ts new file mode 100644 index 00000000..e0797a71 --- /dev/null +++ b/client/src/components/waypointmarker/index.ts @@ -0,0 +1,3 @@ +import WaypointMarker from "./WaypointMarker"; + +export default WaypointMarker;