summaryrefslogblamecommitdiff
path: root/web/app/App.jsx
blob: a31545e38fe7e1b2369ede92a29f05a13df2e547 (plain) (tree)
































































































                                                                                                                                                                                                             
import React, { useState, useEffect } from "react"
import { Map, Marker, GeoJson, ZoomControl } from "pigeon-maps"
import useLocalState from "@phntms/use-local-state";
import moment from "moment";
import 'moment/min/locales';

export default () => {
    moment.locale('ru');
    const [point, setPoint] = useState({
        "id": "",
        "user_id": "",
        "lat": 0,
        "lon": 0,
        "time": "2024-08-15T09:54:00.666Z",
        "speed": 0,
        "direction": 0,
        "accuracy": 0,
    });
    const [selected, setSelected] = useState(null)
    const [points, setPoints] = useState([])
    const [loaded, setLoaded] = useState(false);
    const [zoom, setZoom] = useLocalState("zoom", 5);
    const [center, setCenter] = useState([])
    const [page, setPage] = useState(0)
    const updatePosition = () => {
        fetch("/api/points/last").then(x => x.json()).then((p) => {
            setPoint(p);
            setCenter([point.lat, point.lon])
            setLoaded(true);
        })
        fetch("/api/points").then(x => x.json()).then(p => {
            setPoints(p.reverse())
        })
    }
    useEffect(updatePosition, [])
    if (!loaded) {
        return <h1>Загрузка карты</h1>
    }
    const path = {
        type: "FeatureCollection",
        features: [
            {
                type: "Feature",
                geometry: {
                    type: "LineString",
                    coordinates: points.map((pp) => [pp.lon, pp.lat]),
                },
                properties: { prop0: "value0" },
            },
        ],
    };

    return (
        <div className="container">
            <div className="column">
                <Map height={'100vh'} center={center} defaultCenter={[point.lat, point.lon]} defaultZoom={zoom} onBoundsChanged={({ center, zoom, bounds, initial, }) => {setZoom(zoom); setCenter(center)}}>
                    <ZoomControl />
                    <GeoJson
                        data={path}
                        styleCallback={(feature, hover) => {
                            return { strokeWidth: "2", stroke: "red" };
                        }}
                    />
                    <Marker
                        width={32}
                        anchor={[point.lat, point.lon]}
                    />
                    {selected ? (<Marker
                        width={32}
                        anchor={[selected.lat, selected.lon]}
                    />):null}
                </Map>
            </div>
            <div className="column list">
                <div>Дата последней точки: <b>{moment(point.time).format("LTS L")}</b></div>
                <div>Точность: <b>{point.accuracy.toFixed(2)}м</b></div>
                <div>
                    <button onClick={updatePosition}>Обновить</button>
                    <button onClick={() => setCenter([point.lat, point.lon])}>Перейти к последней позиции</button>
                </div>
                <div>История перемещения:</div>
                <ul>
                    {points.slice(page*50, (page+1)*50).map(p => <li key={p.id}>
                        <a href="#" onClick={(ev) => {setSelected(p);setCenter([p.lat, p.lon]);ev.preventDefault(); }}>
                            {moment(p.time).format("LTS L")}&nbsp;—&nbsp;
                            {p.lat.toFixed(5)},
                            {p.lon.toFixed(5)}
                            &nbsp;(точность: {p.accuracy.toFixed(2)}м)
                        </a>
                    </li>)} 
                </ul>
                <button onClick={() => setPage(Math.max(0, page-1))}>←</button>
                <button onClick={() => setPage(Math.min(page+1, Math.floor(points.length / 50)))}>→</button>
            </div>
        </div >
    )
}