Wpt editor: we can add waypoints (at last !)
This commit is contained in:
parent
6451b110b9
commit
55830251e0
|
@ -12,6 +12,7 @@ import Dialog from '../dialog';
|
||||||
import { getMap, getState } from '../map';
|
import { getMap, getState } from '../map';
|
||||||
import { Overlay } from 'ol';
|
import { Overlay } from 'ol';
|
||||||
import { fromLonLat } from 'ol/proj';
|
import { fromLonLat } from 'ol/proj';
|
||||||
|
import WptEditDialog from '../wpt/WptEditDialog';
|
||||||
|
|
||||||
interface Props {}
|
interface Props {}
|
||||||
|
|
||||||
|
@ -22,6 +23,7 @@ const Finder: Component<Props> = (props) => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [t, { add, locale, dict }] = useI18n();
|
const [t, { add, locale, dict }] = useI18n();
|
||||||
const [popup, setPopup] = createSignal<Overlay>();
|
const [popup, setPopup] = createSignal<Overlay>();
|
||||||
|
const [coordinate, setCoordinate] = createSignal<Coordinate>();
|
||||||
const searchStringChangeHandler = (event: any) => {
|
const searchStringChangeHandler = (event: any) => {
|
||||||
setSearchString(event.target.value);
|
setSearchString(event.target.value);
|
||||||
};
|
};
|
||||||
|
@ -33,38 +35,37 @@ const Finder: Component<Props> = (props) => {
|
||||||
let popupElement: HTMLElement;
|
let popupElement: HTMLElement;
|
||||||
|
|
||||||
const submitHandler = () => {
|
const submitHandler = () => {
|
||||||
let coordinates: Coordinate | undefined = undefined;
|
|
||||||
const latLonRegExp = /(-?[0-9]+.[0-9]+)\s*,\s*(-?[0-9]+.[0-9]+)/;
|
const latLonRegExp = /(-?[0-9]+.[0-9]+)\s*,\s*(-?[0-9]+.[0-9]+)/;
|
||||||
const latLonMatch = searchString().match(latLonRegExp);
|
const latLonMatch = searchString().match(latLonRegExp);
|
||||||
|
|
||||||
if (!!latLonMatch) {
|
if (!!latLonMatch) {
|
||||||
coordinates = [+latLonMatch[2], +latLonMatch[1]];
|
setCoordinate([+latLonMatch[2], +latLonMatch[1]]);
|
||||||
setPopupContent(<>{latLonMatch[0]}</>);
|
setPopupContent(<>{latLonMatch[0]}</>);
|
||||||
console.log({
|
console.log({
|
||||||
caller: 'Finder / submitHandler',
|
caller: 'Finder / submitHandler',
|
||||||
searchString: searchString(),
|
searchString: searchString(),
|
||||||
latLonMatch,
|
latLonMatch,
|
||||||
coordinates,
|
coordinate: coordinate(),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
const utmRegExp = /([0-6]?[0-9])\s*([C-X])\s*([0-9]+)\s*([0-9]+)/;
|
const utmRegExp = /([0-6]?[0-9])\s*([C-X])\s*([0-9]+)\s*([0-9]+)/;
|
||||||
const utmMatch = searchString().match(utmRegExp);
|
const utmMatch = searchString().match(utmRegExp);
|
||||||
if (!!utmMatch) {
|
if (!!utmMatch) {
|
||||||
const utm = `+proj=utm +zone=${utmMatch[1]}`;
|
const utm = `+proj=utm +zone=${utmMatch[1]}`;
|
||||||
coordinates = proj4(utm, 'EPSG:4326', [+utmMatch[3], +utmMatch[4]]);
|
setCoordinate(proj4(utm, 'EPSG:4326', [+utmMatch[3], +utmMatch[4]]));
|
||||||
setPopupContent(
|
setPopupContent(
|
||||||
<>{`${coordinates[0]}, ${coordinates[1]} (UTM ${utmMatch[0]})`}</>
|
<>{`${coordinate()[0]}, ${coordinate()[1]} (UTM ${utmMatch[0]})`}</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
console.log({
|
console.log({
|
||||||
caller: 'Finder / submitHandler',
|
caller: 'Finder / submitHandler',
|
||||||
searchString: searchString(),
|
searchString: searchString(),
|
||||||
utmMatch,
|
utmMatch,
|
||||||
coordinates,
|
coordinate: coordinate(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!!coordinates) {
|
if (!!coordinate()) {
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
if (popup() === undefined) {
|
if (popup() === undefined) {
|
||||||
setPopup(
|
setPopup(
|
||||||
|
@ -77,22 +78,29 @@ const Finder: Component<Props> = (props) => {
|
||||||
console.log({
|
console.log({
|
||||||
caller: 'Finder / submitHandler / popup',
|
caller: 'Finder / submitHandler / popup',
|
||||||
searchString: searchString(),
|
searchString: searchString(),
|
||||||
coordinates,
|
coordinate: coordinate(),
|
||||||
popup: popup(),
|
popup: popup(),
|
||||||
popupElement,
|
popupElement,
|
||||||
});
|
});
|
||||||
popup().setMap(getMap());
|
popup().setMap(getMap());
|
||||||
popup().setPosition(fromLonLat(coordinates));
|
popup().setPosition(fromLonLat(coordinate()));
|
||||||
getMap()?.addOverlay(popup());
|
getMap()?.addOverlay(popup());
|
||||||
|
|
||||||
navigate(
|
navigate(
|
||||||
`/map/${getState().provider}/${coordinates[0]}/${coordinates[1]}/16/${
|
`/map/${getState().provider}/${coordinate()[0]}/${coordinate()[1]}/16/${
|
||||||
getState().rotation
|
getState().rotation
|
||||||
}`
|
}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const [openCreateWptDialog, setOpenCreateWptDialog] = createSignal(false);
|
||||||
|
|
||||||
|
const createWptCloseHandler = () => {
|
||||||
|
setOpenCreateWptDialog(false);
|
||||||
|
popupCloseHandler();
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div class={style.control}>
|
<div class={style.control}>
|
||||||
|
@ -135,8 +143,19 @@ const Finder: Component<Props> = (props) => {
|
||||||
<div>
|
<div>
|
||||||
<div>{popupContent()}</div>
|
<div>{popupContent()}</div>
|
||||||
<div>
|
<div>
|
||||||
<Button>New waypoint</Button>
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
setOpenCreateWptDialog(true);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
New waypoint
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
<WptEditDialog
|
||||||
|
open={openCreateWptDialog}
|
||||||
|
closeHandler={createWptCloseHandler}
|
||||||
|
coordinate={coordinate}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -1,31 +1,65 @@
|
||||||
import { Box, Button, Stack, TextField } from '@suid/material';
|
import { Box, Button, Stack, TextField } from '@suid/material';
|
||||||
import { Component, createEffect, createSignal } from 'solid-js';
|
import { Component, createEffect, createSignal, Show } from 'solid-js';
|
||||||
import { useI18n } from '@solid-primitives/i18n';
|
import { useI18n } from '@solid-primitives/i18n';
|
||||||
|
|
||||||
import Dialog from '../dialog';
|
import Dialog from '../dialog';
|
||||||
import { peekCachedSignal } from '../../workers/cached-signals';
|
import {
|
||||||
|
cachedSignalValue,
|
||||||
|
peekCachedSignal,
|
||||||
|
} from '../../workers/cached-signals';
|
||||||
import dispatch from '../../workers/dispatcher-main';
|
import dispatch from '../../workers/dispatcher-main';
|
||||||
|
import { emptyWpt } from '../../db/wpt';
|
||||||
|
import GpxChooser from '../gpx-chooser';
|
||||||
|
import { currentGpxId } from '../gpx-dialog';
|
||||||
|
import { emptyGpx } from '../../db/gpx';
|
||||||
|
import getUri from '../../lib/ids';
|
||||||
|
import { Coordinate } from 'ol/coordinate';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
wptId: string;
|
wptId?: string;
|
||||||
|
coordinate?: () => Coordinate | undefined;
|
||||||
open: () => boolean;
|
open: () => boolean;
|
||||||
closeHandler?: () => vpod;
|
closeHandler?: () => vpod;
|
||||||
}
|
}
|
||||||
|
|
||||||
const WptEditDialog: Component<Props> = (props) => {
|
const WptEditDialog: Component<Props> = (props) => {
|
||||||
const { wptId, closeHandler, open } = props;
|
const { wptId, closeHandler, open, coordinate } = props;
|
||||||
const [t, { add, locale, dict }] = useI18n();
|
const [t, { add, locale, dict }] = useI18n();
|
||||||
|
|
||||||
const wpt = peekCachedSignal({ id: wptId, method: 'getWpt' });
|
const wpt = !!wptId
|
||||||
|
? peekCachedSignal({ id: wptId, method: 'getWpt' })
|
||||||
|
: () => emptyWpt;
|
||||||
|
|
||||||
|
const [gpxId, setGpxId] = !wptId
|
||||||
|
? createSignal<string>(currentGpxId())
|
||||||
|
: [() => '', () => {}];
|
||||||
|
|
||||||
|
createEffect(() => {
|
||||||
|
setGpxId(currentGpxId());
|
||||||
|
});
|
||||||
|
|
||||||
const [editedWpt, setEditedWpt] = createSignal<Wpt>();
|
const [editedWpt, setEditedWpt] = createSignal<Wpt>();
|
||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
console.log({
|
console.log({
|
||||||
caller: 'WptEditDialog / createEffect',
|
caller: 'WptEditDialog / createEffect',
|
||||||
wptId,
|
wptId,
|
||||||
|
gpxId: gpxId(),
|
||||||
wpt: wpt(),
|
wpt: wpt(),
|
||||||
});
|
});
|
||||||
setEditedWpt(wpt());
|
const newWpt = editedWpt() || wpt();
|
||||||
|
if (!!coordinate && !!coordinate()) {
|
||||||
|
newWpt.$.lon = coordinate()[0];
|
||||||
|
newWpt.$.lat = coordinate()[1];
|
||||||
|
}
|
||||||
|
console.log({
|
||||||
|
caller: 'WptEditDialog / createEffect',
|
||||||
|
wptId,
|
||||||
|
gpxId: gpxId(),
|
||||||
|
wpt: wpt(),
|
||||||
|
newWpt,
|
||||||
|
});
|
||||||
|
setEditedWpt(newWpt);
|
||||||
});
|
});
|
||||||
|
|
||||||
const _closeHandler = () => {
|
const _closeHandler = () => {
|
||||||
|
@ -34,13 +68,46 @@ const WptEditDialog: Component<Props> = (props) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const saveHandler = () => {
|
const saveHandler = async () => {
|
||||||
console.log({
|
console.log({
|
||||||
caller: 'WptEditDialog / saveHandler',
|
caller: 'WptEditDialog / saveHandler',
|
||||||
wptId,
|
wptId,
|
||||||
editedWpt: editedWpt(),
|
editedWpt: editedWpt(),
|
||||||
});
|
});
|
||||||
dispatch({ action: 'putWpt', params: { id: wptId, wpt: editedWpt() } });
|
let newWptId = wptId;
|
||||||
|
if (!newWptId) {
|
||||||
|
if (gpxId() === 'new') {
|
||||||
|
const id = (await dispatch({
|
||||||
|
action: 'putGpx',
|
||||||
|
params: {
|
||||||
|
id: 'new',
|
||||||
|
gpx: emptyGpx,
|
||||||
|
},
|
||||||
|
})) as string;
|
||||||
|
setGpxId(id);
|
||||||
|
}
|
||||||
|
const gpx = await cachedSignalValue({ method: 'getGpx', id: gpxId() });
|
||||||
|
const gpxIdObj = getUri('gpx', gpxId());
|
||||||
|
const lastWptId = gpx.wpt?.at(-1);
|
||||||
|
const lastWptIdObj = !!lastWptId
|
||||||
|
? getUri('wpt', lastWptId)
|
||||||
|
: {
|
||||||
|
gpx: gpxIdObj.gpx,
|
||||||
|
wpt: -1,
|
||||||
|
};
|
||||||
|
newWptId = getUri('wpt', { ...lastWptIdObj, wpt: lastWptIdObj.wpt + 1 });
|
||||||
|
}
|
||||||
|
console.log({
|
||||||
|
caller: 'WptEditDialog / saveHandler',
|
||||||
|
wptId,
|
||||||
|
editedWpt: editedWpt(),
|
||||||
|
newWptId,
|
||||||
|
});
|
||||||
|
dispatch({
|
||||||
|
action: 'putWpt',
|
||||||
|
params: { id: newWptId, wpt: editedWpt() },
|
||||||
|
});
|
||||||
|
|
||||||
_closeHandler();
|
_closeHandler();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -57,6 +124,10 @@ const WptEditDialog: Component<Props> = (props) => {
|
||||||
title={getTitle()}
|
title={getTitle()}
|
||||||
closeHandler={_closeHandler}
|
closeHandler={_closeHandler}
|
||||||
>
|
>
|
||||||
|
<Show when={!wptId}>
|
||||||
|
<GpxChooser gpxId={gpxId} setGpxId={setGpxId} />
|
||||||
|
</Show>
|
||||||
|
|
||||||
<Box
|
<Box
|
||||||
component='form'
|
component='form'
|
||||||
sx={{
|
sx={{
|
||||||
|
|
|
@ -427,11 +427,12 @@ export const putGpx = async (params: any) => {
|
||||||
let { id, gpx } = params;
|
let { id, gpx } = params;
|
||||||
|
|
||||||
if (id === 'new') {
|
if (id === 'new') {
|
||||||
|
const date = !!gpx.metadata.time ? new Date(gpx.metadata.time) : new Date();
|
||||||
id = getUri('gpx', {
|
id = getUri('gpx', {
|
||||||
gpx: intToGpxId(new Date(gpx.metadata.time).valueOf()),
|
gpx: intToGpxId(date.valueOf()),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
console.log({ caller: 'putGpx', params, id, gpx });
|
||||||
const extensions = gpx?.extensions;
|
const extensions = gpx?.extensions;
|
||||||
|
|
||||||
gpx.extensions = undefined;
|
gpx.extensions = undefined;
|
||||||
|
|
|
@ -49,6 +49,19 @@ export const peekCachedSignal = (params: any) => {
|
||||||
return signal;
|
return signal;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const cachedSignalValue = async (params: any) => {
|
||||||
|
const cachedSignal = cache.get({ cacheId: 'signals', key: params.id });
|
||||||
|
console.log({ caller: 'cachedSignalValue', params, cachedSignal });
|
||||||
|
if (cachedSignal !== null) {
|
||||||
|
const value = cachedSignal();
|
||||||
|
if (value != undefined) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const value = await dispatch({ action: params.method, params });
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
|
||||||
export const destroyCachedSignal = (params: any) => {
|
export const destroyCachedSignal = (params: any) => {
|
||||||
dispatch({
|
dispatch({
|
||||||
action: 'cancelWatch',
|
action: 'cancelWatch',
|
||||||
|
|
Loading…
Reference in New Issue