From fafde7b8314d9bc63b683d8ef62c5fed25271106 Mon Sep 17 00:00:00 2001 From: evlist Date: Mon, 26 Sep 2022 01:46:19 +0200 Subject: [PATCH] Starting to refactor to store track points independently from their tracks (WIP) (#3) --- src/components/map/gpx-import.tsx | 8 ++--- src/components/map/gpx-record.tsx | 4 +-- src/components/map/gpx.tsx | 38 ++++++++++++++++++++ src/components/map/gpxes.tsx | 20 +++++++++++ src/components/map/map.tsx | 9 +++-- src/components/map/track.tsx | 23 ------------ src/components/map/tracks.tsx | 20 ----------- src/db/{tracks.ts => gpx.ts} | 59 +++++++++++++++++++++++-------- src/db/index.ts | 58 ++++++++++++++++++++++++++++++ src/lib/background-geolocation.ts | 2 +- 10 files changed, 172 insertions(+), 69 deletions(-) create mode 100644 src/components/map/gpx.tsx create mode 100644 src/components/map/gpxes.tsx delete mode 100644 src/components/map/track.tsx delete mode 100644 src/components/map/tracks.tsx rename src/db/{tracks.ts => gpx.ts} (67%) create mode 100644 src/db/index.ts diff --git a/src/components/map/gpx-import.tsx b/src/components/map/gpx-import.tsx index 724262a..21733a8 100644 --- a/src/components/map/gpx-import.tsx +++ b/src/components/map/gpx-import.tsx @@ -7,7 +7,7 @@ import GPX from '../../lib/gpx-parser-builder'; import '../../theme/get-location.css'; import { IonIcon, IonItem } from '@ionic/react'; import { downloadSharp } from 'ionicons/icons'; -import { pushTrack } from '../../db/tracks'; +import { pushGpx } from '../../db/gpx'; const GpxImport: React.FC<{}> = () => { const db = useDB(); @@ -23,9 +23,9 @@ const GpxImport: React.FC<{}> = () => { () => { // this will then display a text file console.log(fileReader.result); - const track = GPX.parse(fileReader.result); - pushTrack(db, { - track: JSON.parse(JSON.stringify(track)), + const gpx = GPX.parse(fileReader.result); + pushGpx(db, { + gpx, metadata: { lastModified: new Date(file.lastModified).toISOString(), importDate: new Date().toISOString(), diff --git a/src/components/map/gpx-record.tsx b/src/components/map/gpx-record.tsx index 14e5fae..f172970 100644 --- a/src/components/map/gpx-record.tsx +++ b/src/components/map/gpx-record.tsx @@ -2,12 +2,10 @@ import React, { useState } from 'react'; import { useDB } from 'react-pouchdb'; -import GPX from '../../lib/gpx-parser-builder'; import '../../theme/get-location.css'; -import { IonButton, IonIcon, IonItem } from '@ionic/react'; +import { IonButton, IonIcon } from '@ionic/react'; import { recordingOutline, recording } from 'ionicons/icons'; -import { pushTrack } from '../../db/tracks'; import { startBackgroundGeolocation, stopBackgroundGeolocation, diff --git a/src/components/map/gpx.tsx b/src/components/map/gpx.tsx new file mode 100644 index 0000000..41439d6 --- /dev/null +++ b/src/components/map/gpx.tsx @@ -0,0 +1,38 @@ +import React from 'react'; + +import { useFind } from 'react-pouchdb'; + +import { lat2tile, lon2tile } from '../../lib/geo'; +import { zoom0 } from '../../store/map'; + +const Gpx: React.FC<{ gpx: any }> = (props) => { + console.log('gpx'); + + var gpxes: any[] = []; + + gpxes = useFind({ + selector: { + type: 'trkpt', + gpx: props.gpx._id, + }, + // sort: ['trkpt.time'], + // use_index: 'type-trkpt-gpx-time3', + }); + + gpxes.sort((first: any, second: any) => + first.trkpt.time.localeCompare(second.trkpt.time) + ); + + const d = gpxes.reduce((previous: string, current: any, index: number) => { + const action = index === 0 ? 'M' : index === 1 ? 'L' : ''; + const trkpt = current.trkpt; + return `${previous} ${action} ${lon2tile(trkpt.$.lon, zoom0)}, ${lat2tile( + trkpt.$.lat, + zoom0 + )}`; + }, ''); + + return ; +}; + +export default Gpx; diff --git a/src/components/map/gpxes.tsx b/src/components/map/gpxes.tsx new file mode 100644 index 0000000..a4cc08f --- /dev/null +++ b/src/components/map/gpxes.tsx @@ -0,0 +1,20 @@ +import React, { Suspense } from 'react'; + +import { useFind } from 'react-pouchdb'; + +import Gpx from './gpx'; + +const Gpxes: React.FC<{}> = () => { + const gpxes = useFind({ + selector: { + type: 'gpx', + }, + }); + + return gpxes.map((gpx: any) => { + console.log('doc'); + return ; + }); +}; + +export default Gpxes; diff --git a/src/components/map/map.tsx b/src/components/map/map.tsx index 272b15b..7efe2a7 100644 --- a/src/components/map/map.tsx +++ b/src/components/map/map.tsx @@ -2,6 +2,7 @@ import react, { useMemo, useEffect } from 'react'; import { useDispatch } from 'react-redux'; import { mapActions } from '../../store/map'; import _ from 'lodash'; +import { useDB } from 'react-pouchdb'; import Layer from '../slippy/layer'; import Slippy from '../slippy/slippy'; @@ -19,8 +20,9 @@ import { } from '@ionic/react'; import GpxImport from './gpx-import'; -import Tracks from './tracks'; +import Gpxes from './gpxes'; import GpxRecord from './gpx-record'; +import { initDb } from '../../db'; const Map: react.FC<{}> = (props: {}) => { const dispatch = useDispatch(); @@ -33,9 +35,10 @@ const Map: react.FC<{}> = (props: {}) => { [] ); + const db = useDB(); useEffect(() => { window.addEventListener('resize', debouncedResizeHandler); - // dispatch(mapActions.shift({ x: -50, y: 0 })); + initDb(db); }, []); return ( @@ -45,7 +48,7 @@ const Map: react.FC<{}> = (props: {}) => { - + diff --git a/src/components/map/track.tsx b/src/components/map/track.tsx deleted file mode 100644 index 80d6f82..0000000 --- a/src/components/map/track.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import React from 'react'; - -import { lat2tile, lon2tile } from '../../lib/geo'; -import { zoom0 } from '../../store/map'; - -const Track: React.FC<{ track: any }> = (props) => { - console.log('track'); - const trkseg = props.track.track.trk[0].trkseg[0]; - const d = trkseg.trkpt.reduce( - (previous: string, current: any, index: number) => { - const action = index === 0 ? 'M' : index === 1 ? 'L' : ''; - return `${previous} ${action} ${lon2tile( - current.$.lon, - zoom0 - )}, ${lat2tile(current.$.lat, zoom0)}`; - }, - '' - ); - - return ; -}; - -export default Track; diff --git a/src/components/map/tracks.tsx b/src/components/map/tracks.tsx deleted file mode 100644 index 13595f0..0000000 --- a/src/components/map/tracks.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import React from 'react'; - -import { useFind } from 'react-pouchdb'; - -import Track from './track'; - -const Tracks: React.FC<{}> = () => { - const tracks = useFind({ - selector: { - type: 'Track', - }, - }); - - return tracks.map((track: any) => { - console.log('doc'); - return ; - }); -}; - -export default Tracks; diff --git a/src/db/tracks.ts b/src/db/gpx.ts similarity index 67% rename from src/db/tracks.ts rename to src/db/gpx.ts index 884fd0a..c94107e 100644 --- a/src/db/tracks.ts +++ b/src/db/gpx.ts @@ -1,16 +1,13 @@ import { Sha256, - Sha512, string_to_bytes, bytes_to_base64, } from '@openpgp/asmcrypto.js'; -import { DBWrapper } from 'workbox-core/_private'; -export const pushTrack = (db: any, payload: any) => { +export const pushGpx = async (db: any, payload: any) => { + const gpxString = JSON.stringify(payload.gpx); const sha = new Sha256(); - const result = sha - .process(string_to_bytes(JSON.stringify(payload.track))) - .finish().result; + const result = sha.process(string_to_bytes(gpxString)).finish().result; var _id; if (result === null) { console.log(`Can't hash`); @@ -19,16 +16,48 @@ export const pushTrack = (db: any, payload: any) => { _id = bytes_to_base64(result); console.log(`Digest: ${_id}`); } - const doc = { _id, type: 'Track', ...payload }; - // console.log(JSON.stringify(doc)); - db.put(doc); + + try { + await db.get(_id); + alert('This file has alerady been imported.'); + return; + } catch {} + + var gpx = JSON.parse(gpxString); + var points: any[] = []; + + const prune = (object: any) => { + for (var key in object) { + if (key === 'trkpt') { + points.push(...object[key]); + object[key] = []; + } else { + if (typeof object[key] === 'object') { + prune(object[key]); + } + } + } + }; + + prune(gpx); + + const doc = { ...payload, _id, type: 'gpx', gpx }; + console.log(JSON.stringify(doc)); + await db.put(doc); + + for (var point in points) { + const docPoint = { type: 'trkpt', gpx: _id, trkpt: points[point] }; + console.log(JSON.stringify(docPoint)); + const response = await db.post(docPoint); + console.log(JSON.stringify(docPoint)); + } }; -const CURRENT_TRACK = '---current track---'; +const CURRENT_GPX = '---current gpx---'; const initialTrack = { - _id: CURRENT_TRACK, - type: 'Track', + _id: CURRENT_GPX, + type: 'GPX', track: { $: { version: '1.1', @@ -65,18 +94,18 @@ const initialTrack = { export const appendTrkpt = async (db: any, trkpt: any) => { var track: any; await db - .get(CURRENT_TRACK) + .get(CURRENT_GPX) .then((result: any) => { track = result; }) .catch((error: any) => { - if (error.status='404') { + if ((error.status = '404')) { track = initialTrack; } else { console.log(`db.get(CURRENT_TRACK), ERROR: ${JSON.stringify(error)}`); alert(`db.get(CURRENT_TRACK), ERROR: ${JSON.stringify(error)}`); } - }); + }); track.metadata.lastModified = trkpt.time; const currentTrkseg = track.track.trk.at(-1).trkseg.at(-1); currentTrkseg.trkpt.push(trkpt); diff --git a/src/db/index.ts b/src/db/index.ts new file mode 100644 index 0000000..58ac9b7 --- /dev/null +++ b/src/db/index.ts @@ -0,0 +1,58 @@ +const DBDEFINITION = '--db-definition--'; + +const dbDefinition = { + _id: DBDEFINITION, + type: DBDEFINITION, + version: '0.000001', +}; + +export const initDb = async (db: any) => { + try { + await db.get(DBDEFINITION); + // TODO: support migrations + } catch (error: any) { + if (error.status !== 404) { + console.log( + `Unexpected error fetching db definition: ${JSON.stringify(error)}` + ); + return; + } + } + + await db.createIndex({ + index: { + name: 'type', + fields: ['type'], + }, + }); + + await db.createIndex({ + index: { + name: 'trkpt-time', + fields: ['trkpt.time'], + partial_filter_selector: { + type: 'trkpt', + }, + }, + }); + + await db.createIndex({ + index: { + name: 'type-trkpt-gpx-time3', + fields: ['type', 'gpx', 'trkpt.time'], + }, + }); + + const indexes = await db.getIndexes(); + console.log(`indexes: ${JSON.stringify(indexes)}`); + + const explain = await db.explain({ + selector: { + type: 'trkpt', + gpx: 'xxxx', + }, + // sort: ['trkpt.time'], + // use_index: 'type-trkpt-gpx-time', + }); + console.log(`explain: ${JSON.stringify(explain)}`); +}; diff --git a/src/lib/background-geolocation.ts b/src/lib/background-geolocation.ts index 99791df..1c46ea9 100644 --- a/src/lib/background-geolocation.ts +++ b/src/lib/background-geolocation.ts @@ -1,6 +1,6 @@ import { BackgroundGeolocationPlugin } from '@capacitor-community/background-geolocation'; import { registerPlugin } from '@capacitor/core'; -import { appendTrkpt } from '../db/tracks'; +import { appendTrkpt } from '../db/gpx'; const BackgroundGeolocation = registerPlugin( 'BackgroundGeolocation'