Skip to content
Snippets Groups Projects
Commit 3142fd1c authored by mateusz-winiarczyk's avatar mateusz-winiarczyk
Browse files

feat(pins): add possibility to center map to pins

parent 6cce9291
No related branches found
No related tags found
1 merge request!131feat(map): Center map on pin after click on pin icon in search drawer (MIN-216)
import { twMerge } from 'tailwind-merge';
import { Icon } from '@/shared/Icon';
import { BioEntity } from '@/types/models';
import { useAppDispatch } from '@/redux/hooks/useAppDispatch';
import { setMapPosition } from '@/redux/map/map.slice';
import { DEFAULT_MAX_ZOOM } from '@/constants/map';
import { getPinColor } from '../../../ResultsList/PinsList/PinsListItem/PinsListItem.component.utils';
interface BioEntitiesPinsListItemProps {
......@@ -12,10 +14,27 @@ export const BioEntitiesPinsListItem = ({
name,
pin,
}: BioEntitiesPinsListItemProps): JSX.Element => {
const dispatch = useAppDispatch();
const handleCenterMapToPin = (): void => {
dispatch(
setMapPosition({
x: pin.x,
y: pin.y,
z: DEFAULT_MAX_ZOOM,
}),
);
};
return (
<div className="mb-4 flex w-full flex-col gap-3 rounded-lg border-[1px] border-solid border-greyscale-500 p-4">
<div
id="el"
className="mb-4 flex w-full flex-col gap-3 rounded-lg border-[1px] border-solid border-greyscale-500 p-4"
>
<div className="flex w-full flex-row items-center gap-2">
<Icon name="pin" className={twMerge('mr-2 shrink-0', getPinColor('bioEntity'))} />
<button type="button" onClick={handleCenterMapToPin} className="mr-2 shrink-0">
<Icon name="pin" className={getPinColor('bioEntity')} />
</button>
<p>
{pin.stringType}: <span className="w-full font-bold">{name}</span>
</p>
......
import { Icon } from '@/shared/Icon';
import { PinDetailsItem } from '@/types/models';
import { twMerge } from 'tailwind-merge';
import { useAppSelector } from '@/redux/hooks/useAppSelector';
import { modelsDataSelector } from '@/redux/models/models.selectors';
import { SIZE_OF_EMPTY_ARRAY } from '@/constants/common';
import { useAppDispatch } from '@/redux/hooks/useAppDispatch';
import { openMapAndSetActive, setActiveMap } from '@/redux/map/map.slice';
import { mapOpenedMapsSelector } from '@/redux/map/map.selectors';
import { useSetBounds } from '@/utils/map/useSetBounds';
import { getListOfAvailableSubmaps, getPinColor } from './PinsListItem.component.utils';
import { AvailableSubmaps, PinTypeWithNone } from '../PinsList.types';
import { useVisiblePinsPolygonCoordinates } from './hooks/useVisiblePinsPolygonCoordinates';
interface PinsListItemProps {
name: string;
......@@ -21,6 +22,8 @@ export const PinsListItem = ({ name, type, pin }: PinsListItemProps): JSX.Elemen
const openedMaps = useAppSelector(mapOpenedMapsSelector);
const models = useAppSelector(modelsDataSelector);
const availableSubmaps = getListOfAvailableSubmaps(pin, models);
const coordinates = useVisiblePinsPolygonCoordinates(pin.targetElements);
const setBounds = useSetBounds();
const isMapAlreadyOpened = (modelId: number): boolean =>
openedMaps.some(map => map.modelId === modelId);
......@@ -33,10 +36,17 @@ export const PinsListItem = ({ name, type, pin }: PinsListItemProps): JSX.Elemen
}
};
const handleCenterMapToPin = (): void => {
if (!coordinates) return;
setBounds(coordinates);
};
return (
<div className="mb-4 flex w-full flex-col gap-3 rounded-lg border-[1px] border-solid border-greyscale-500 p-4">
<div className="flex w-full flex-row items-center gap-2">
<Icon name="pin" className={twMerge('mr-2 shrink-0', getPinColor(type))} />
<button type="button" className="mr-2 shrink-0" onClick={handleCenterMapToPin}>
<Icon name="pin" className={getPinColor(type)} />
</button>
<p>
Full name: <span className="w-full font-bold">{name}</span>
</p>
......
import { useAppSelector } from '@/redux/hooks/useAppSelector';
import { mapModelIdSelector } from '@/redux/map/map.selectors';
import { Point } from '@/types/map';
import { PinDetailsItem } from '@/types/models';
import { usePointToProjection } from '@/utils/map/usePointToProjection';
import { isPointValid } from '@/utils/point/isPointValid';
import { Coordinate } from 'ol/coordinate';
import { useMemo } from 'react';
const VALID_POLYGON_COORDINATES_LENGTH = 2;
export const useVisiblePinsPolygonCoordinates = (
pinTargetElements: PinDetailsItem['targetElements'],
): Coordinate[] | undefined => {
const pointToProjection = usePointToProjection();
const currentModelId = useAppSelector(mapModelIdSelector);
const currentMapPinElements = useMemo(
() => pinTargetElements.filter(el => el.model === currentModelId),
[currentModelId, pinTargetElements],
);
const polygonPoints = useMemo((): Point[] => {
const allX = currentMapPinElements.map(({ x }) => x);
const allY = currentMapPinElements.map(({ y }) => y);
const minX = Math.min(...allX);
const maxX = Math.max(...allX);
const minY = Math.min(...allY);
const maxY = Math.max(...allY);
const points = [
{
x: minX,
y: maxY,
},
{
x: maxX,
y: minY,
},
];
return points.filter(isPointValid);
}, [currentMapPinElements]);
const polygonCoordinates = useMemo(
() => polygonPoints.map(point => pointToProjection(point)),
[polygonPoints, pointToProjection],
);
if (polygonCoordinates.length !== VALID_POLYGON_COORDINATES_LENGTH) {
return undefined;
}
return polygonCoordinates;
};
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment