Major update: storing trkpt and rtept inside trkseg and rte instead of independent documents.

This commit is contained in:
Eric van der Vlist 2023-02-08 20:44:28 +01:00
parent ecae9b4037
commit 92ffe42ab9
10 changed files with 90 additions and 94 deletions

View File

@ -1,11 +1,15 @@
# Dyomedea
## License
GPL 3.0.
## Branches
* master: dev branch (started as a React project; now using dolidjs)
* multi-layers: attempt to create a native React map components. Went pretty far but there was still so many things to implement that I switched to:
* openlayers: an attempt to use React with Openlayers. Wasn't that easy because Openlayers is heavily based on the DOM while React uses a "pseudo-dom". That has been one of the reasons why I switched (again) to:
* solid: a SolidJS / Openlayers implementation that has replaced the master branch on Feb 5th, 2023.
* master: dev (and only active) branch (started as a React project, now using solidjs)
* multi-layers: (deprecated) attempt to create a native React map components. Went pretty far but there was still so many things to implement that I switched to:
* openlayers: (deprecated) an attempt to use React with Openlayers. Wasn't that easy because Openlayers is heavily based on the DOM while React uses a "pseudo-dom". That has been one of the reasons why I switched (again) to:
* solid: (merged into master and deprecated) a SolidJS / Openlayers implementation that has replaced the master branch on Feb 5th, 2023.
## Hiking app.
@ -350,6 +354,9 @@ Requires esrun (`sudo npm i -g @digitak/esrun`)
### Patches
```
* suid: https://github.com/swordev/suid/issues/89
### NPM updates: use npm-check-updates !

View File

@ -1,6 +1,5 @@
import { Component, createEffect, createSignal, onCleanup } from 'solid-js';
import dispatch, { cancelDispatch } from '../../workers/dispatcher-main';
import VectorSource from 'ol/source/Vector';
import GeoJSON from 'ol/format/GeoJSON';
import {
@ -36,7 +35,7 @@ export const Rte: Component<Props> = ({ vectorSource, rteId, context }) => {
createEffect(() => {
console.log({ caller: 'Rte', vectorSource, rteId, rte: rte() });
if (rte()) {
if (rte() && rte().rtept && rte().rtept.length > 0) {
let geo: any = {
type: 'FeatureCollection',
features: [

View File

@ -1,4 +1,4 @@
import { Component, createSignal } from 'solid-js';
import { Component, createSignal, Show } from 'solid-js';
import { peekCachedSignal } from '../../workers/cached-signals';
import RteIcon from '../../icons/directions-svgrepo-com.svg?component-solid';
import { useI18n } from '@solid-primitives/i18n';
@ -74,11 +74,13 @@ const RteViewer: Component<Props> = ({ rteId }) => {
<>
<div>
{getFormatedLength(lineString)} {t('from')}{' '}
<Show when={false}>
<DisplayOrGetAddress
target={() => rte().rtept.at(0)}
putAction='putRtept'
putParamName='rtept'
/>{' '}
</Show>
{t('to')}{' '}
<DisplayOrGetAddress
target={() => rte().rtept.at(-1)}

View File

@ -49,7 +49,7 @@ export const Trkseg: Component<Props> = ({
createEffect(() => {
console.log({ caller: 'Trkseg', vectorSource, trksegId, trkseg: trkseg() });
if (trkseg()) {
if (trkseg() && trkseg().trkpt && trkseg().trkpt.length > 0) {
let geo: any = {
type: 'FeatureCollection',
features: [

View File

@ -84,15 +84,15 @@ const prune = (
if (
key === 'wpt' ||
key === 'rte' ||
key === 'rtept' ||
// key === 'rtept' ||
key === 'trk' ||
key === 'trkseg' ||
key === 'trkpt'
key === 'trkseg'
// key === 'trkpt'
) {
const subObjects = object[key];
for (const index in subObjects) {
const subId = { ...id };
if (key === 'trkpt') {
/* if (key === 'trkpt') {
// fix buggy times in GPX tracks
const normalId = intToTrkptId(
new Date(object[key][index].time).valueOf()
@ -101,10 +101,10 @@ const prune = (
normalId > previousIds.trk ? normalId : previousIds.trk + 1;
subId[key] = id;
previousIds.trk = id;
} else {
} else { */
previousIds[key] = previousIds[key] + 1;
subId[key] = previousIds[key];
}
/* } */
// console.log({
// caller: 'prune',
// id,

View File

@ -1,3 +1,5 @@
import { debounce, memoize, property, wrap } from 'lodash';
import { delay } from '../lib/delay';
import getUri from '../lib/ids';
import { appendToArray, putNewGpx } from './gpx';
import { getFamily, put } from './lib';
@ -32,9 +34,43 @@ export const putNewRte = async (id?: IdRte | IdGpx) => {
return finalId as IdRte;
};
export const getRte = async (params: any) => {
// See https://stackoverflow.com/questions/28787436/debounce-a-function-with-argument
const debounceByParam = (
targetFunc: (params: any) => any,
resolver: (params: any) => any,
...debounceParams: any
) =>
wrap(
memoize(() => debounce(targetFunc, ...debounceParams), resolver),
(getMemoizedFunc, ...params) => getMemoizedFunc(...params)(...params)
);
const compactRteOrTrkseg = (params: any) => {
const { getDocs } = params;
getDocs(params).then(({ docs }) => {
if (docs.rows.length > 1) {
const compactedDocs = docs.rows.map((row: any) => {
if (['rte', 'trkseg'].includes(row.doc.type)) {
return row.doc;
}
return { ...row.doc, doc: undefined, _deleted: true };
});
db.bulkDocs(compactedDocs);
}
console.log({ caller: 'compactRteOrTrkseg', params, compactedDocs });
});
};
export const compactRteOrTrksegDebounced = debounceByParam(
compactRteOrTrkseg,
property('id'),
3600000 * (1 + Math.random())
);
const getRteDocs = async (params: any) => {
const { id } = params;
const docs = await getFamily(id, { include_docs: true });
// console.log({ caller: 'getRte', id, docs });
let target: any[];
let rte: Rte | undefined = undefined;
docs.rows.every((row: any) => {
@ -56,12 +92,21 @@ export const getRte = async (params: any) => {
//level 1
if (row.doc.type === 'rtept') {
target.splice(1);
row.doc.doc.id = row.doc._id;
// row.doc.doc.id = row.doc._id;
appendToArray(target.at(-1), row.doc.type, row.doc.doc);
target.push(row.doc.doc);
}
return true;
});
return { docs, rte };
};
export const getRte = async (params: any) => {
const { id } = params;
const { docs, rte } = await getRteDocs(params);
if (docs.rows.length > 1) {
compactRteOrTrksegDebounced({ id, getDocs: getRteDocs });
}
return rte;
};

View File

@ -1,6 +1,3 @@
import getUri from '../lib/ids';
import { put } from './lib';
import { putNewRte } from './rte';
export const emptyRtept: Wpt = {
$: { lat: 0, lon: 0 },
@ -24,28 +21,3 @@ export const emptyRtept: Wpt = {
dgpsid: undefined,
extensions: undefined,
};
export const putNewRtept = async (id?: IdGpx | IdRte | IdRtept) => {
let finalId = { ...id };
if (!('rtept' in finalId)) {
const rteId = await putNewRte(id);
finalId = { ...rteId, rtept: 0 };
}
const uri = getUri('rtept', finalId);
await put(
uri,
'rtept',
(rtept) => {
return rtept;
},
emptyRtept
);
return finalId as IdRtept;
};
export const putRtept = async (params: any) => {
const { id, rtept } = params;
rtept.id = undefined;
await put(id, 'rtept', (doc) => rtept, rtept);
return rtept;
};

View File

@ -1,6 +1,5 @@
import getUri, { intToTrkptId } from '../lib/ids';
import { put } from './lib';
import { putNewTrkseg } from './trkseg';
const emptyTrkpt: Wpt = {
$: { lat: 0, lon: 0 },
@ -31,24 +30,6 @@ const emptyTrkpt: Wpt = {
},
};
export const putNewTrkpt = async (id?: IdTrk | IdGpx | IdTrkseg | IdTrkpt) => {
let finalId = { ...id };
if (!('trkpt' in finalId)) {
const trksegId = await putNewTrkseg(id);
finalId = { ...trksegId, trkpt: intToTrkptId(Date.now()) };
}
const uri = getUri('trkpt', finalId);
await put(
uri,
'trkpt',
(trkpt) => {
return trkpt;
},
emptyTrkpt
);
return finalId;
};
export const putTrkpt = async (params: any) => {
const { id, trkpt } = params;

View File

@ -1,6 +1,7 @@
import getUri, { intToTrkptId } from '../lib/ids';
import { appendToArray } from './gpx';
import { getFamily, put } from './lib';
import { compactRteOrTrksegDebounced } from './rte';
import { putNewTrk } from './trk';
import { emptyWpt } from './wpt';
@ -9,27 +10,10 @@ const emptyTrkseg: Trkseg = {
extensions: undefined,
};
export const putNewTrkseg = async (id?: IdTrk | IdGpx | IdTrkseg) => {
let finalId = { ...id };
if (!('trkseg' in finalId)) {
const trkId = await putNewTrk(id);
finalId = { ...trkId, trkseg: 0 };
}
const uri = getUri('trkseg', finalId);
await put(
uri,
'trkseg',
(trkseg) => {
return trkseg;
},
emptyTrkseg
);
return finalId as IdTrkseg;
};
export const getTrkseg = async (params: any) => {
const getTrksegDocs = async (params: any) => {
const { id } = params;
const docs = await getFamily(id, { include_docs: true });
console.log({ caller: 'getTrksegDocs', id, docs });
let target: any[];
let trkseg: Trkseg | undefined = undefined;
docs.rows.every((row: any) => {
@ -37,13 +21,12 @@ export const getTrkseg = async (params: any) => {
if (row.doc.type === 'trkseg') {
if (!!trkseg) {
console.error({
caller: 'getTrkseg',
caller: 'getTrksegDocs',
id,
row,
target,
trkseg,
});
return false; // Hack to stop if getFamily fails
}
target = [row.doc.doc];
@ -52,12 +35,21 @@ export const getTrkseg = async (params: any) => {
//level 1
if (row.doc.type === 'trkpt') {
target.splice(1);
row.doc.doc.id = row.doc._id;
// row.doc.doc.id = row.doc._id;
appendToArray(target.at(-1), row.doc.type, row.doc.doc);
target.push(row.doc.doc);
}
return true;
});
return { trkseg, docs };
};
export const getTrkseg = async (params: any) => {
const { id } = params;
const { docs, trkseg } = await getTrksegDocs(params);
if (docs.rows.length > 1) {
compactRteOrTrksegDebounced({ id, getDocs: getTrksegDocs });
}
return trkseg;
};

View File

@ -14,7 +14,6 @@ import {
} from '../db/gpx';
import { putOverlays } from '../db/overlays';
import { deleteRte, putRte } from '../db/rte';
import { putRtept } from '../db/rtept';
import { getSettings, putSettings } from '../db/settings';
import { getState, setState } from '../db/state';
import { deleteTrk, getTrk, putNewTrk } from '../db/trk';
@ -52,7 +51,6 @@ onmessage = async function (e) {
putWpt,
putRte,
putRtept,
putTrkpt,
deleteTrk,