Skip to content

Commit

Permalink
Add waypoints
Browse files Browse the repository at this point in the history
  • Loading branch information
OlliV committed Oct 27, 2023
1 parent f8d60e4 commit b37f1c3
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 11 deletions.
5 changes: 5 additions & 0 deletions components/map/Course.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { useEffect, useMemo } from 'react';
import { CircleMarker } from 'react-leaflet';
import AntPath from '../../components/map/AntPath';
import MapWaypoint from './Waypoint';
import { CourseData } from '../../lib/gpx_parser';

export default function MapCourse({ map, course }: { map: any; course: CourseData }) {
const { trackpoints } = course?.tracks[0]?.segments[0] || { trackpoints: [] };
const waypoints = course?.waypoints || [];
const polyline = useMemo<[number, number][]>(() => trackpoints.map(({ lat, lon }) => [lat, lon]), [trackpoints]);
const first = polyline[0];
const last = polyline[polyline.length - 1];
Expand All @@ -22,6 +24,9 @@ export default function MapCourse({ map, course }: { map: any; course: CourseDat
{/* @ts-ignore */}
{last ? <CircleMarker center={last} radius={20} pathOptions={{ color: 'red' }} /> : null}
<AntPath positions={polyline} options={{ hardwareAccelerated: true, delay: 2000 }} />
<>
{waypoints.map(({lat, lon, name}, i: number) => <MapWaypoint key={i} position={[lat, lon]}>{name}</MapWaypoint>)}
</>
</>
);
}
28 changes: 28 additions & 0 deletions components/map/Waypoint.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
'use client';
import L from 'leaflet';
import { Marker, Popup } from 'react-leaflet';
import MarkerIcon from '../../node_modules/leaflet/dist/images/marker-icon.png';
import MarkerShadow from '../../node_modules/leaflet/dist/images/marker-shadow.png';
import { ReactNode } from 'react';

export default function MapWaypoint({ position, children }: { position: [number, number]; children?: ReactNode }) {
return (
<Marker
position={position}
// @ts-ignore
icon={
new L.Icon({
iconUrl: MarkerIcon.src,
iconRetinaUrl: MarkerIcon.src,
iconSize: [25, 41],
iconAnchor: [12.5, 41],
popupAnchor: [0, -41],
shadowUrl: MarkerShadow.src,
shadowSize: [41, 41],
})
}
>
<Popup>{children}</Popup>
</Marker>
);
}
66 changes: 55 additions & 11 deletions lib/gpx_parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ type Coord = {
lon: number;
};
type Trackpoint = Coord & {
ele: number;
ele?: number;
};
type Segment = {
trackpoints: Trackpoint[];
Expand All @@ -13,10 +13,17 @@ type Track = {
segments: Segment[];
};
type Routepoint = Coord;
type Waypoint = Coord;
type Route = {
name?: string;
routepoints: Routepoint[];
};
type Waypoint = Coord & {
name?: string;
ele?: number;
};
export type CourseData = {
tracks: Track[];
routePoints: Routepoint[];
routes: Route[];
waypoints: Waypoint[];
};

Expand Down Expand Up @@ -47,13 +54,22 @@ function getElValue(el: HTMLCollectionOf<Element>) {
return el[0].childNodes[0].nodeValue;
}

function parseTrackpoint(el: Element): Trackpoint {
const trackpoint: Trackpoint = {
lat: parseFloat(el.getAttribute('lat')),
lon: parseFloat(el.getAttribute('lon')),
};
const ele = parseFloat(getElValue(el.getElementsByTagName('ele')));
if (!Number.isNaN(ele)) {
trackpoint.ele = ele;
}

return trackpoint;
}

function parseTrackpoints(trackpoints: HTMLCollectionOf<Element>): Trackpoint[] {
return [
...elIter<Trackpoint>(trackpoints, (trackpoint) => ({
lat: parseFloat(trackpoint.getAttribute('lat')),
lon: parseFloat(trackpoint.getAttribute('lon')),
ele: parseFloat(getElValue(trackpoint.getElementsByTagName('ele'))),
})),
...elIter<Trackpoint>(trackpoints, parseTrackpoint),
];
}

Expand All @@ -74,17 +90,45 @@ function parseTracks(tracks: HTMLCollectionOf<Element>): Track[] {
];
}

function parseRoutepoints(routepoints: HTMLCollectionOf<Element>): Routepoint[] {
return [
...elIter<Routepoint>(routepoints, (routepoint) => ({
lat: parseFloat(routepoint.getAttribute('lat')),
lon: parseFloat(routepoint.getAttribute('lon')),
})),
];
}

function parseRoutes(routes: HTMLCollectionOf<Element>): Route[] {
return [
...elIter<Route>(routes, (route) => ({
name: getElValue(route.getElementsByTagName('name')),
routepoints: parseRoutepoints(route.getElementsByTagName('rtept')),
})),
];
}

function parseWaypoints(waypoints: HTMLCollectionOf<Element>): Waypoint[] {
return [
...elIter<Waypoint>(waypoints, (waypoint) => ({
name: getElValue(waypoint.getElementsByTagName('name')),
lat: parseFloat(waypoint.getAttribute('lat')),
lon: parseFloat(waypoint.getAttribute('lon')),
})),
];
}

export function gpxDocument2obj(doc: Document): CourseData {
return {
tracks: parseTracks(doc.documentElement.getElementsByTagName('trk')),
routePoints: [],
waypoints: [],
routes: parseRoutes(doc.documentElement.getElementsByTagName('rte')),
waypoints: parseWaypoints(doc.documentElement.getElementsByTagName('wpt')),
};
}

export function getMapBounds(obj: CourseData) {
// TODO support all tracks and segments
const points = [...obj.tracks[0].segments[0].trackpoints, ...obj.routePoints, ...obj.waypoints];
const points = [...obj.tracks[0].segments[0].trackpoints, ...obj.routes[0].routepoints, ...obj.waypoints];
const lats = points.map(({ lat }) => lat);
const lons = points.map(({ lon }) => lon);
return {
Expand Down

1 comment on commit b37f1c3

@vercel
Copy link

@vercel vercel bot commented on b37f1c3 Oct 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

bfree – ./

bfree-git-master-olliv.vercel.app
bfree-olliv.vercel.app
bfree.vercel.app

Please sign in to comment.