First version of the new importer (stiil needs to convert non timed tracks into routes).

This commit is contained in:
Eric van der Vlist 2022-12-13 12:41:13 +01:00
parent 102a2feddc
commit 90fb0e6944
4 changed files with 194 additions and 138 deletions

View File

@ -21,50 +21,6 @@ const GpxImport: Component = () => {
files: event.target.files, files: event.target.files,
}); });
setFilesToImport(event.target.files); setFilesToImport(event.target.files);
// for (const file of event.target.files) {
// const fileReader = new FileReader();
// fileReader.readAsText(file);
// fileReader.addEventListener(
// 'load',
// async () => {
// // this will then display a text file
// console.log({
// caller: 'GpxImport / XML',
// file,
// result: fileReader.result,
// });
// const gpx = GPX.parse(fileReader.result);
// console.log({ caller: 'GpxImport / JSON', file, gpx });
// if (gpx) {
// const startTime = new Date(findStartTime(gpx)!);
// await dispatch({
// action: 'pruneAndSaveImportedGpx',
// params: {
// id: { gpx: intToGpxId(startTime.valueOf()) },
// gpx: gpx,
// tech: {
// lastModified: new Date(file.lastModified).toISOString(),
// importDate: new Date().toISOString(),
// name: file.name,
// size: file.size,
// type: file.type,
// },
// },
// });
// console.log({ caller: 'GpxImport / JSON / done', file, gpx });
// } else {
// console.error({
// message: "can't parse GPX file",
// file,
// xml: fileReader.result,
// });
// }
// // TODO: error handling
// },
// false
// );
// }
}; };
const handleClose = (event: any, reason?: string) => { const handleClose = (event: any, reason?: string) => {

View File

@ -12,6 +12,7 @@ import {
import { Component, createEffect, createSignal, Show } from 'solid-js'; import { Component, createEffect, createSignal, Show } from 'solid-js';
import { findStartTime } from '../../lib/gpx'; import { findStartTime } from '../../lib/gpx';
import GPX from '../../lib/gpx-parser-builder/src/gpx'; import GPX from '../../lib/gpx-parser-builder/src/gpx';
import dispatch from '../../workers/dispatcher-main';
import GpxChooser from '../gpx-chooser'; import GpxChooser from '../gpx-chooser';
import { currentGpxId } from '../gpx-dialog'; import { currentGpxId } from '../gpx-dialog';
@ -76,8 +77,58 @@ const GpxImportSingleFile: Component<Props> = ({ gpxFile }) => {
false false
); );
const doImport = () => { const doImport = async () => {
setState('importing'); setState('importing');
// for (const file of event.target.files) {
// const fileReader = new FileReader();
// fileReader.readAsText(file);
// fileReader.addEventListener(
// 'load',
// async () => {
// // this will then display a text file
// console.log({
// caller: 'GpxImport / XML',
// file,
// result: fileReader.result,
// });
// const gpx = GPX.parse(fileReader.result);
// console.log({ caller: 'GpxImport / JSON', file, gpx });
// if (gpx) {
// const startTime = new Date(findStartTime(gpx)!);
await dispatch({
action: 'pruneAndSaveImportedGpx',
params: {
id: gpxId(),
gpx: statsAndGpx()?.gpx,
tech: {
lastModified: new Date(gpxFile.lastModified).toISOString(),
importDate: new Date().toISOString(),
name: gpxFile.name,
size: gpxFile.size,
type: gpxFile.type,
},
},
});
console.log({
caller: 'GpxImport / JSON / done',
gpxFile,
gpx: statsAndGpx()?.gpx,
});
setState('done');
// } else {
// console.error({
// message: "can't parse GPX file",
// file,
// xml: fileReader.result,
// });
// }
// // TODO: error handling
// },
// false
// );
// }
}; };
const [selectedTrkTransform, setSelectedTrkTransform] = createSignal( const [selectedTrkTransform, setSelectedTrkTransform] = createSignal(
@ -139,7 +190,11 @@ const GpxImportSingleFile: Component<Props> = ({ gpxFile }) => {
<LinearProgress /> <LinearProgress />
</Show> </Show>
<CardActions> <CardActions>
<GpxChooser gpxId={gpxId} setGpxId={setGpxId} disabled={state() != 'init'} /> <GpxChooser
gpxId={gpxId}
setGpxId={setGpxId}
disabled={state() != 'init'}
/>
<Button <Button
variant='contained' variant='contained'
disabled={state() != 'init'} disabled={state() != 'init'}

View File

@ -1,7 +1,9 @@
import { cloneDeep } from 'lodash'; import { cloneDeep } from 'lodash';
import { PureComponent } from 'react'; import { PureComponent } from 'react';
import { $DEVCOMP } from 'solid-js';
import { Point, Rectangle } from '../components/map/types'; import { Point, Rectangle } from '../components/map/types';
import { lat2tile, lon2tile, rectanglesIntersect } from '../lib/geo'; import { lat2tile, lon2tile, rectanglesIntersect } from '../lib/geo';
import { findStartTime } from '../lib/gpx';
import getUri, { intToGpxId, intToTrkptId } from '../lib/ids'; import getUri, { intToGpxId, intToTrkptId } from '../lib/ids';
import { get, getDocsByType, getFamily, put, putAll } from './lib'; import { get, getDocsByType, getFamily, put, putAll } from './lib';
@ -61,7 +63,13 @@ export const existsGpx = async (id: IdGpx) => {
} }
}; };
const prune = (id: any, object: any, docs: any[]) => { const prune = (
id: any,
object: any,
previousGpx: Gpx | null,
extensions: any,
docs: any[]
) => {
if (typeof object === 'object') { if (typeof object === 'object') {
for (const key in object) { for (const key in object) {
if ( if (
@ -74,6 +82,10 @@ const prune = (id: any, object: any, docs: any[]) => {
) { ) {
const subObjects = object[key]; const subObjects = object[key];
let previousId = 0; let previousId = 0;
let nbPreviousObjects = 0;
if (previousGpx !== null && key in previousGpx) {
nbPreviousObjects = previousGpx[key].length;
}
for (const index in subObjects) { for (const index in subObjects) {
const subId = { ...id }; const subId = { ...id };
if (key === 'trkpt') { if (key === 'trkpt') {
@ -85,7 +97,7 @@ const prune = (id: any, object: any, docs: any[]) => {
subId[key] = id; subId[key] = id;
previousId = id; previousId = id;
} else { } else {
subId[key] = index; subId[key] = index + nbPreviousObjects;
} }
// console.log({ // console.log({
// caller: 'prune', // caller: 'prune',
@ -95,113 +107,146 @@ const prune = (id: any, object: any, docs: any[]) => {
// object: object[key][index], // object: object[key][index],
// time: object[key][index].time, // time: object[key][index].time,
// }); // });
subObjects[index].extensions = {
...extensions,
...subObjects[index].extensions,
};
docs.push({ docs.push({
_id: getUri(key, subId), _id: getUri(key, subId),
type: key, type: key,
doc: subObjects[index], doc: subObjects[index],
}); });
prune(subId, subObjects[index], docs); prune(subId, subObjects[index], previousGpx, extensions, docs);
} }
object[key] = undefined; object[key] = undefined;
} else prune(id, object[key], docs); } else prune(id, object[key], previousGpx, extensions, docs);
} }
} }
}; };
const extensionsFromObject = ( // const extensionsFromObject = (
object: any, // object: any,
extensions = { // extensions = {
viewport: { topLeft: <Point>{}, bottomRight: <Point>{} }, // viewport: { topLeft: <Point>{}, bottomRight: <Point>{} },
bbox: { // bbox: {
minLon: <number | undefined>undefined, // minLon: <number | undefined>undefined,
minLat: <number | undefined>undefined, // minLat: <number | undefined>undefined,
maxLon: <number | undefined>undefined, // maxLon: <number | undefined>undefined,
maxLat: <number | undefined>undefined, // maxLat: <number | undefined>undefined,
}, // },
} // }
) => { // ) => {
if (typeof object === 'object') { // if (typeof object === 'object') {
if ('$' in object) { // if ('$' in object) {
const attributes = object.$; // const attributes = object.$;
if ('lat' in attributes) { // if ('lat' in attributes) {
const lat = +attributes.lat; // const lat = +attributes.lat;
if ( // if (
extensions.bbox.minLat === undefined || // extensions.bbox.minLat === undefined ||
lat < extensions.bbox.minLat // lat < extensions.bbox.minLat
) { // ) {
extensions.bbox.minLat = lat; // extensions.bbox.minLat = lat;
} // }
if ( // if (
extensions.bbox.maxLat === undefined || // extensions.bbox.maxLat === undefined ||
lat > extensions.bbox.maxLat // lat > extensions.bbox.maxLat
) { // ) {
extensions.bbox.maxLat = lat; // extensions.bbox.maxLat = lat;
} // }
} // }
if ('lon' in attributes) { // if ('lon' in attributes) {
const lon = +attributes.lon; // const lon = +attributes.lon;
if ( // if (
extensions.bbox.minLon === undefined || // extensions.bbox.minLon === undefined ||
lon < extensions.bbox.minLon // lon < extensions.bbox.minLon
) { // ) {
extensions.bbox.minLon = lon; // extensions.bbox.minLon = lon;
} // }
if ( // if (
extensions.bbox.maxLon === undefined || // extensions.bbox.maxLon === undefined ||
lon > extensions.bbox.maxLon // lon > extensions.bbox.maxLon
) { // ) {
extensions.bbox.maxLon = lon; // extensions.bbox.maxLon = lon;
} // }
} // }
} // }
for (const key in object) { // for (const key in object) {
extensionsFromObject(object[key], extensions); // extensionsFromObject(object[key], extensions);
} // }
} // }
return extensions; // return extensions;
}; // };
const extensionsFromGpx = (gpx: Gpx) => { // const extensionsFromGpx = (gpx: Gpx) => {
const extensions = { ...gpx.extensions, ...extensionsFromObject(gpx) }; // const extensions = { ...gpx.extensions, ...extensionsFromObject(gpx) };
gpx.extensions = undefined; // gpx.extensions = undefined;
if ( // if (
extensions.bbox.maxLat !== undefined && // extensions.bbox.maxLat !== undefined &&
extensions.bbox.minLon !== undefined // extensions.bbox.minLon !== undefined
) { // ) {
extensions.viewport.topLeft = { // extensions.viewport.topLeft = {
x: lon2tile(extensions.bbox.minLon, 0), // x: lon2tile(extensions.bbox.minLon, 0),
y: lat2tile(extensions.bbox.maxLat, 0), // y: lat2tile(extensions.bbox.maxLat, 0),
}; // };
} // }
if ( // if (
extensions.bbox.minLat !== undefined && // extensions.bbox.minLat !== undefined &&
extensions.bbox.maxLon !== undefined // extensions.bbox.maxLon !== undefined
) { // ) {
extensions.viewport.bottomRight = { // extensions.viewport.bottomRight = {
x: lon2tile(extensions.bbox.maxLon, 0), // x: lon2tile(extensions.bbox.maxLon, 0),
y: lat2tile(extensions.bbox.minLat, 0), // y: lat2tile(extensions.bbox.minLat, 0),
}; // };
} // }
return extensions; // return extensions;
}; // };
export const pruneAndSaveImportedGpx = async (params: any) => { export const pruneAndSaveImportedGpx = async (params: any) => {
console.log({ caller: 'pruneAndSaveImportedGpx', params }); console.log({ caller: 'pruneAndSaveImportedGpx', params });
const { id, gpx, extensions } = params; const { id, gpx, tech } = params;
let docs: any[] = [ let gpxId: IdGpx;
{ _id: getUri('gpx', id), type: 'gpx', doc: gpx }, let docs: any[] = [];
{ const extensions = {
_id: getUri('extensions', id), ...tech,
type: 'extensions', ...gpx.extensions,
doc: { ...extensions, ...extensionsFromGpx(gpx) }, gpx: {
creator: gpx?.$?.creator,
metadata: gpx.metadata,
extensions: gpx.extensions,
}, },
]; };
prune(id, gpx, docs); let previousGpx: Gpx | null = null;
if (id === 'new') {
const currentDateTime = new Date().toISOString();
const startTime = new Date(findStartTime(gpx, currentDateTime));
if (gpx.metadata === undefined) {
gpx.metadata = {};
}
if (gpx.metadata.time === undefined) {
gpx.metadata.time = startTime.toISOString();
}
gpxId = { gpx: intToGpxId(startTime.valueOf()) };
docs = [
{ _id: getUri('gpx', gpxId), type: 'gpx', doc: gpx },
{
_id: getUri('extensions', gpxId),
type: 'extensions',
doc: {},
},
];
} else {
gpxId = getUri('gpx', id);
previousGpx = (await getGpx(id)) ?? null;
}
prune(gpxId, gpx, previousGpx, extensions, docs);
console.log({ caller: 'pruneAndSaveImportedGpx / pruned', docs }); console.log({ caller: 'pruneAndSaveImportedGpx / pruned', docs });
try { try {
const result = await putAll(docs); const result = await putAll(docs);
console.log(JSON.stringify(result)); console.log(JSON.stringify(result));
if (id !== 'new') {
put(id, 'gpx', (doc) => doc, {});
}
} catch (err) { } catch (err) {
console.error(`error: ${err}`); console.error(`error: ${err}`);
} }

View File

@ -7,7 +7,7 @@ export default class Metadata {
constructor(object) { constructor(object) {
this.name = object.name; this.name = object.name;
this.desc = object.desc; this.desc = object.desc;
this.time = object.time ? new Date(object.time) : new Date(); this.time = object.time ? new Date(object.time) : undefined;
this.keywords = object.keywords; this.keywords = object.keywords;
this.extensions = object.extensions; this.extensions = object.extensions;
if (object.author) { if (object.author) {
@ -17,7 +17,7 @@ export default class Metadata {
if (!Array.isArray(object.link)) { if (!Array.isArray(object.link)) {
object.link = [object.link]; object.link = [object.link];
} }
this.link = object.link.map(l => new Link(l)); this.link = object.link.map((l) => new Link(l));
} }
if (object.bounds) { if (object.bounds) {
this.bounds = new Bounds(object.bounds); this.bounds = new Bounds(object.bounds);