106 lines
2.7 KiB
TypeScript
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>
|
|
);
|
|
}
|