frontend/src/common/MapGL.tsx
2025-05-08 11:24:21 -06:00

106 lines
2.7 KiB
TypeScript

import { Tooltip } from "@mui/material";
import { Beenhere } from "@mui/icons-material";
import { useThemeType } from "hooks";
import moment from "moment";
import React, { useEffect, useState } from "react";
import Map, { Marker } from "react-map-gl/mapbox";
const MAPBOX_TOKEN = import.meta.env.VITE_MAPBOX_ACCESS_TOKEN;
export interface Coordinate {
latitude: number;
longitude: number;
timestamp: string;
}
interface Props {
paths: Map<string, Coordinate[]>;
}
export default function MapGL(props: Props) {
const themeType = useThemeType();
const { paths } = props;
const [viewport, setViewport] = useState({
latitude: 52.8118612,
longitude: -106.2459731,
zoom: 12
});
useEffect(() => {
let lat = 52.8118612;
let long = -106.2459731;
if (paths.size > 0) {
let first = Array.from(paths.values())[0][0];
if (first) {
lat = first.latitude;
long = first.longitude;
}
}
setViewport({
latitude: lat,
longitude: long,
zoom: 8
});
}, [paths]);
/*
const changeViewport = (vp: typeof viewport) => {
let transition: any = vp;
if (!transition || transition.width === 0 || transition.height === 0) return;
setViewport(vp);
};
*/
const markers = (): any[] => {
let elems: any[] = [];
paths.forEach((path: Coordinate[], name: string) => {
let num = path.length;
let step = 1;
if (num > 0) {
step = 1.0 / (num * 1.0);
}
path
.sort((a: Coordinate, b: Coordinate) => {
if (a.timestamp < b.timestamp) return 1;
else if (b.timestamp < a.timestamp) return -1;
return 0;
})
.forEach((coord: Coordinate, i: number) => {
let ts = moment(coord.timestamp);
let title = coord.latitude + ", " + coord.longitude;
if (ts.isValid()) {
title += " @ " + ts.format("lll");
}
elems.push(
<Marker key={name + i} latitude={coord.latitude} longitude={coord.longitude}>
<React.Fragment>
<Tooltip title={title}>
<Beenhere style={{ opacity: step * (num - i) }} />
</Tooltip>
</React.Fragment>
</Marker>
);
});
});
return elems;
};
let style =
themeType === "dark" ? "mapbox://styles/mapbox/dark-v10" : "mapbox://styles/mapbox/light-v10";
return (
<Map
mapStyle={style}
initialViewState={viewport}
mapboxAccessToken={MAPBOX_TOKEN}
{...viewport}
onMove={(e: any) => {
setViewport({
longitude: e.viewState.longitude,
latitude: e.viewState.latitude,
zoom: e.viewState.zoom,
});
}}
>
{markers()}
</Map>
);
}