Skip to content

Commit

Permalink
Directions: Add markers to directions
Browse files Browse the repository at this point in the history
  • Loading branch information
jvaclavik committed Nov 13, 2024
1 parent 7125f59 commit fda55fc
Show file tree
Hide file tree
Showing 6 changed files with 257 additions and 43 deletions.
61 changes: 47 additions & 14 deletions src/components/Directions/DirectionsAutocomplete.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { MapClickOverride, useMapStateContext } from '../utils/MapStateContext';
import { useStarsContext } from '../utils/StarsContext';
import React, { useEffect, useRef, useState } from 'react';
import React, { useEffect, useMemo, useRef, useState } from 'react';
import { abortFetch } from '../../services/fetch';
import {
fetchGeocoderOptions,
Expand All @@ -13,14 +13,15 @@ import { Autocomplete, InputAdornment, TextField } from '@mui/material';
import { useMapCenter } from '../SearchBox/utils';
import { useUserThemeContext } from '../../helpers/theme';
import { renderOptionFactory } from '../SearchBox/renderOptionFactory';
import PlaceIcon from '@mui/icons-material/Place';
import { Option } from '../SearchBox/types';
import { getOptionLabel } from '../SearchBox/getOptionLabel';
import { useUserSettingsContext } from '../utils/UserSettingsContext';
import { getCoordsOption } from '../SearchBox/options/coords';
import { LonLat } from '../../services/types';
import { getGlobalMap } from '../../services/mapStorage';
import maplibregl, { LngLatLike } from 'maplibre-gl';
import maplibregl, { LngLatLike, PointLike } from 'maplibre-gl';
import ReactDOMServer from 'react-dom/server';
import { AlphabeticalMarker } from './TextMarker';

const StyledTextField = styled(TextField)`
input::placeholder {
Expand All @@ -35,6 +36,7 @@ const DirectionsInput = ({
label,
onFocus,
onBlur,
pointIndex,
}) => {
const { InputLabelProps, InputProps, ...restParams } = params;

Expand All @@ -59,8 +61,11 @@ const DirectionsInput = ({
fullWidth
InputProps={{
startAdornment: (
<InputAdornment position="start">
<PlaceIcon fontSize="small" />
<InputAdornment
position="start"
sx={{ position: 'relative', top: 5, left: 5 }}
>
<AlphabeticalMarker hasPin={false} index={pointIndex} height={32} />
</InputAdornment>
),
}}
Expand Down Expand Up @@ -137,14 +142,15 @@ type Props = {
label: string;
value: Option;
setValue: (value: Option) => void;
pointIndex: number;
};

const PREVIEW_MARKER = {
color: 'salmon',
draggable: false,
};

export const DirectionsAutocomplete = ({ label, value, setValue }: Props) => {
export const DirectionsAutocomplete = ({
label,
value,
setValue,
pointIndex,
}: Props) => {
const autocompleteRef = useRef();
const { inputValue, setInputValue } = useInputValueState();
const selectedOptionInputValue = useRef<string | null>(null);
Expand All @@ -153,19 +159,45 @@ export const DirectionsAutocomplete = ({ label, value, setValue }: Props) => {
const { userSettings } = useUserSettingsContext();
const { isImperial } = userSettings;

const ALPHABETICAL_MARKER = useMemo(() => {
let svgElement;
if (typeof window !== 'undefined' && typeof document !== 'undefined') {
svgElement = document.createElement('div');
svgElement.innerHTML = ReactDOMServer.renderToStaticMarkup(
<AlphabeticalMarker index={pointIndex} hasShadow width={27} />,
);
} else svgElement = undefined;

return {
color: 'salmon',
draggable: true,
element: svgElement,
offset: [0, -10] as PointLike,
};
}, [pointIndex]);

const markerRef = useRef<maplibregl.Marker>();

useEffect(() => {
console.log('___', value);
const map = getGlobalMap();
if (value?.type === 'coords') {
markerRef.current = new maplibregl.Marker(PREVIEW_MARKER)
markerRef.current = new maplibregl.Marker(ALPHABETICAL_MARKER)
.setLngLat(value.coords.center as LngLatLike)
.addTo(map);
}
return () => {
markerRef.current?.remove();
};
}, [value]);
}, [ALPHABETICAL_MARKER, value]);

const onDragEnd = () => {
const lngLat = markerRef.current?.getLngLat();
if (lngLat) {
setValue(getCoordsOption([lngLat.lng, lngLat.lat]));
}
};

markerRef.current?.on('dragend', onDragEnd);

const options = useOptions(inputValue);

Expand Down Expand Up @@ -224,6 +256,7 @@ export const DirectionsAutocomplete = ({ label, value, setValue }: Props) => {
label={label}
onFocus={onInputFocus}
onBlur={handleBlur}
pointIndex={pointIndex}
/>
)}
renderOption={renderOptionFactory(
Expand Down
2 changes: 2 additions & 0 deletions src/components/Directions/DirectionsForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -165,11 +165,13 @@ export const DirectionsForm = ({ setResult, hideForm }: Props) => {
value={from}
setValue={setFrom}
label={t('directions.form.start_or_click')}
pointIndex={0}
/>
<DirectionsAutocomplete
value={to}
setValue={setTo}
label={t('directions.form.destination')}
pointIndex={1}
/>
</Stack>

Expand Down
51 changes: 31 additions & 20 deletions src/components/Directions/Instructions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import { icon, Sign } from './routing/instructions';
import { RoutingResult } from './routing/types';
import { useUserSettingsContext } from '../utils/UserSettingsContext';
import { toHumanDistance } from './helpers';
import { Stack, Typography } from '@mui/material';
import { Box, Divider, Grid2, Stack, Typography } from '@mui/material';
import { useTheme } from '@emotion/react';

type Instruction = RoutingResult['instructions'][number];

Expand All @@ -25,27 +26,37 @@ const StyledListItem = styled.li`
gap: 0.25rem;
`;

const Instruction = ({ instruction }: { instruction: Instruction }) => (
<StyledListItem>
<Stack direction="row" alignItems="center">
<Icon sign={instruction.sign} />
{instruction.street_name || instruction.text}
</Stack>
{instruction.distance > 0 && (
<Stack direction="row" alignItems="center" spacing={0.5}>
<Typography
noWrap
color="textSecondary"
variant="body1"
style={{ overflow: 'visible' }}
>
<Distance distance={instruction.distance} />
const Instruction = ({ instruction }: { instruction: Instruction }) => {
const theme = useTheme();

return (
<StyledListItem>
<Stack direction="row" alignItems="center">
<Box width={theme.spacing(6)}>
<Icon sign={instruction.sign} />
</Box>
<Typography variant="subtitle1" fontWeight={700}>
{instruction.street_name || instruction.text}
</Typography>
<hr style={{ width: '100%' }} />
</Stack>
)}
</StyledListItem>
);
{instruction.distance > 0 && (
<Stack direction="row" alignItems="center" spacing={2} ml={6}>
<Typography
noWrap
color="textSecondary"
variant="body2"
style={{ overflow: 'visible' }}
>
<Distance distance={instruction.distance} />
</Typography>
<Stack flex={1}>
<Divider />
</Stack>
</Stack>
)}
</StyledListItem>
);
};

const StyledList = styled.ul`
list-style: none;
Expand Down
41 changes: 33 additions & 8 deletions src/components/Directions/Result.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useMobileMode } from '../helpers';
import { Button, Paper, Stack, Typography } from '@mui/material';
import { Button, Divider, Paper, Stack, Typography } from '@mui/material';
import React from 'react';
import styled from '@emotion/styled';
import { convertHexToRgba } from '../utils/colorUtils';
Expand Down Expand Up @@ -126,13 +126,38 @@ export const Result = ({ result, revealForm }: Props) => {

return (
<StyledPaper elevation={3} $height="100%" $overflow="auto">
{t('directions.result.time')}: <strong>{time}</strong>
<br />
{t('directions.result.distance')}: <strong>{distance}</strong>
<br />
{t('directions.result.ascent')}: <strong>{ascent}</strong>
<br />
<br />
<Stack
direction="row"
spacing={2}
width="100%"
justifyContent="space-between"
>
<div>
<Typography variant="caption">
{t('directions.result.time')}
</Typography>
<Typography fontWeight={900} variant="h6">
{time}
</Typography>
</div>
<div>
<Typography variant="caption">
{t('directions.result.distance')}
</Typography>
<Typography fontWeight={900} variant="h6">
{distance}
</Typography>
</div>
<div>
<Typography variant="caption">
{t('directions.result.ascent')}
</Typography>
<Typography fontWeight={900} variant="h6">
{ascent}
</Typography>
</div>
</Stack>
<Divider sx={{ mt: 2, mb: 3 }} />
{result.instructions && (
<Instructions instructions={result.instructions} />
)}
Expand Down
Loading

0 comments on commit fda55fc

Please sign in to comment.