svelte-local-gpx-viewer
Version:
Local-first GPX routes viewer. Svelte-based components. Useable in Svelte projects and standalone (vanilla JS).
80 lines (79 loc) • 3.3 kB
JavaScript
import { db, liveGeoJSONRoutes } from './localDB';
import { get } from 'svelte/store';
import { SvelteSet } from 'svelte/reactivity';
import GeoJsonToGpx from '@dwayneparton/geojson-to-gpx';
import JSZip from 'jszip';
let uiRoutes = $state.raw(get(liveGeoJSONRoutes));
const selectedRoutesIds = new SvelteSet();
const selectedRoutesInfo = $derived.by(() => {
const selectedRoutes = Array.from(selectedRoutesIds).map((id) => uiRoutes.filter((route) => route.id === id)[0]);
return selectedRoutes.reduce((acc, route) => {
acc.distance += route.distance;
acc.elevation.positive += route.elevation?.positive || 0;
acc.elevation.negative += route.elevation?.negative || 0;
return acc;
}, { distance: 0, elevation: { positive: 0, negative: 0 } });
});
// subscribe to the DexieJS liveQuery store
liveGeoJSONRoutes.subscribe((routes) => {
//console.log('liveGeoJSONRoutes', routes);
// When the store updates, update the runed signal
uiRoutes = routes;
});
export const getUIRoutes = () => {
return {
get routes() {
return uiRoutes;
},
get selectedRoutesIds() {
return selectedRoutesIds;
},
get selectedRoutesInfo() {
return selectedRoutesInfo;
},
async updateRouteColor(id, color) {
await db.geoJSONRoutes.update(id, { color: color });
},
async deleteRoute(id) {
selectedRoutesIds.delete(id);
await db.geoJSONRoutes.delete(id);
},
async updateRouteVisibility(id, visibility) {
await db.geoJSONRoutes.update(id, { visible: visibility });
},
async getRoute(id) {
return (await db.geoJSONRoutes.get(id));
},
async createRoute(obj) {
await db.geoJSONRoutes.add(obj);
},
async downloadAllRoutesArchive() {
const zip = new JSZip();
const routes = uiRoutes;
for (const route of routes) {
// Add GPX file
let gpxData = route.originalGPXData;
if (!gpxData) {
const gpx = GeoJsonToGpx(route.data);
gpxData = new XMLSerializer().serializeToString(gpx);
}
zip.file(`${route.name}.gpx`, gpxData);
// Add GeoJSON file
const geoJSONData = JSON.stringify(route.data, null, 2);
zip.file(`${route.name}.geojson`, geoJSONData);
}
// Generate the ZIP file
const content = await zip.generateAsync({ type: 'blob' });
const url = URL.createObjectURL(content);
// Generate a timestamp for the filename
const now = new Date();
const timestamp = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')}_${String(now.getHours()).padStart(2, '0')}-${String(now.getMinutes()).padStart(2, '0')}-${String(now.getSeconds()).padStart(2, '0')}`;
// Trigger download
const a = document.createElement('a');
a.href = url;
a.download = `routes-archive_${timestamp}.zip`;
a.click();
URL.revokeObjectURL(url);
}
};
};