feat: adds better gpx track views
This commit is contained in:
@@ -427,6 +427,10 @@ function runMigrations(db: Database.Database): void {
|
||||
db.prepare("UPDATE addons SET type = 'integration' WHERE id = 'mcp'").run();
|
||||
} catch {}
|
||||
},
|
||||
() => {
|
||||
// GPX full route geometry stored as JSON array of [lat,lng] pairs
|
||||
try { db.exec('ALTER TABLE places ADD COLUMN route_geometry TEXT'); } catch {}
|
||||
},
|
||||
];
|
||||
|
||||
if (currentVersion < migrations.length) {
|
||||
|
||||
@@ -115,7 +115,7 @@ router.post('/', authenticate, requireTripAccess, validateStringLengths({ name:
|
||||
broadcast(tripId, 'place:created', { place }, req.headers['x-socket-id'] as string);
|
||||
});
|
||||
|
||||
// Import places from GPX file (must be before /:id)
|
||||
// Import places from GPX file with full track geometry (must be before /:id)
|
||||
router.post('/import/gpx', authenticate, requireTripAccess, gpxUpload.single('file'), (req: Request, res: Response) => {
|
||||
const { tripId } = req.params;
|
||||
const file = (req as any).file;
|
||||
@@ -136,7 +136,7 @@ router.post('/import/gpx', authenticate, requireTripAccess, gpxUpload.single('fi
|
||||
const extractName = (body: string) => { const m = body.match(/<name[^>]*>([\s\S]*?)<\/name>/i); return m ? stripCdata(m[1]) : null };
|
||||
const extractDesc = (body: string) => { const m = body.match(/<desc[^>]*>([\s\S]*?)<\/desc>/i); return m ? stripCdata(m[1]) : null };
|
||||
|
||||
const waypoints: { name: string; lat: number; lng: number; description: string | null }[] = [];
|
||||
const waypoints: { name: string; lat: number; lng: number; description: string | null; routeGeometry?: string }[] = [];
|
||||
|
||||
// 1) Parse <wpt> elements (named waypoints / POIs)
|
||||
const wptRegex = /<wpt\s([^>]+)>([\s\S]*?)<\/wpt>/gi;
|
||||
@@ -159,23 +159,25 @@ router.post('/import/gpx', authenticate, requireTripAccess, gpxUpload.single('fi
|
||||
}
|
||||
}
|
||||
|
||||
// 3) If still nothing, extract track name + start/end points from <trkpt>
|
||||
// 3) If still nothing, extract full track geometry from <trkpt>
|
||||
if (waypoints.length === 0) {
|
||||
const trackNameMatch = xml.match(/<trk[^>]*>[\s\S]*?<name[^>]*>([\s\S]*?)<\/name>/i);
|
||||
const trackName = trackNameMatch?.[1]?.trim() || 'GPX Track';
|
||||
const trackDesc = (() => { const m = xml.match(/<trk[^>]*>[\s\S]*?<desc[^>]*>([\s\S]*?)<\/desc>/i); return m ? stripCdata(m[1]) : null })();
|
||||
const trkptRegex = /<trkpt\s([^>]*?)(?:\/>|>([\s\S]*?)<\/trkpt>)/gi;
|
||||
const trackPoints: { lat: number; lng: number }[] = [];
|
||||
const trackPoints: { lat: number; lng: number; ele: number | null }[] = [];
|
||||
while ((match = trkptRegex.exec(xml)) !== null) {
|
||||
const coords = parseCoords(match[1]);
|
||||
if (coords) trackPoints.push(coords);
|
||||
if (!coords) continue;
|
||||
const eleMatch = match[2]?.match(/<ele[^>]*>([\s\S]*?)<\/ele>/i);
|
||||
const ele = eleMatch ? parseFloat(eleMatch[1]) : null;
|
||||
trackPoints.push({ ...coords, ele: (ele !== null && !isNaN(ele)) ? ele : null });
|
||||
}
|
||||
if (trackPoints.length > 0) {
|
||||
const start = trackPoints[0];
|
||||
waypoints.push({ ...start, name: `${trackName} — Start`, description: null });
|
||||
if (trackPoints.length > 1) {
|
||||
const end = trackPoints[trackPoints.length - 1];
|
||||
waypoints.push({ ...end, name: `${trackName} — End`, description: null });
|
||||
}
|
||||
const hasAllEle = trackPoints.every(p => p.ele !== null);
|
||||
const routeGeometry = trackPoints.map(p => hasAllEle ? [p.lat, p.lng, p.ele] : [p.lat, p.lng]);
|
||||
waypoints.push({ ...start, name: trackName, description: trackDesc, routeGeometry: JSON.stringify(routeGeometry) });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,13 +186,13 @@ router.post('/import/gpx', authenticate, requireTripAccess, gpxUpload.single('fi
|
||||
}
|
||||
|
||||
const insertStmt = db.prepare(`
|
||||
INSERT INTO places (trip_id, name, description, lat, lng, transport_mode)
|
||||
VALUES (?, ?, ?, ?, ?, 'walking')
|
||||
INSERT INTO places (trip_id, name, description, lat, lng, transport_mode, route_geometry)
|
||||
VALUES (?, ?, ?, ?, ?, 'walking', ?)
|
||||
`);
|
||||
const created: any[] = [];
|
||||
const insertAll = db.transaction(() => {
|
||||
for (const wp of waypoints) {
|
||||
const result = insertStmt.run(tripId, wp.name, wp.description, wp.lat, wp.lng);
|
||||
const result = insertStmt.run(tripId, wp.name, wp.description, wp.lat, wp.lng, wp.routeGeometry || null);
|
||||
const place = getPlaceWithTags(Number(result.lastInsertRowid));
|
||||
created.push(place);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user