mirror of
https://github.com/muerwre/orchidmap-front.git
synced 2025-04-25 02:56:41 +07:00
replacing gpx tracks
This commit is contained in:
parent
acca2aba14
commit
1d45e65434
5 changed files with 86 additions and 56 deletions
|
@ -1,9 +1,9 @@
|
||||||
import React, { FC, useCallback, ChangeEvent } from 'react';
|
import React, { FC, useCallback, ChangeEvent } from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import * as EDITOR_ACTIONS from '~/redux/editor/actions';
|
|
||||||
import { IState } from '~/redux/store';
|
import { IState } from '~/redux/store';
|
||||||
import { selectEditorGpx } from '~/redux/editor/selectors';
|
import { selectEditorGpx } from '~/redux/editor/selectors';
|
||||||
import { GpxDialogRow } from '~/components/gpx/GpxDialogRow';
|
import { GpxDialogRow } from '~/components/gpx/GpxDialogRow';
|
||||||
|
import { GpxConfirm } from '~/components/gpx/GpxConfirm';
|
||||||
import { MainMap } from '~/constants/map';
|
import { MainMap } from '~/constants/map';
|
||||||
import { latLngBounds } from 'leaflet';
|
import { latLngBounds } from 'leaflet';
|
||||||
import { Switch } from '../Switch';
|
import { Switch } from '../Switch';
|
||||||
|
@ -13,6 +13,10 @@ import uuid from 'uuid';
|
||||||
import { getUrlData } from '~/utils/history';
|
import { getUrlData } from '~/utils/history';
|
||||||
import { getRandomColor } from '~/utils/dom';
|
import { getRandomColor } from '~/utils/dom';
|
||||||
|
|
||||||
|
import * as EDITOR_ACTIONS from '~/redux/editor/actions';
|
||||||
|
import * as MAP_ACTIONS from '~/redux/map/actions';
|
||||||
|
import { simplify } from '~/utils/simplify';
|
||||||
|
|
||||||
const mapStateToProps = (state: IState) => ({
|
const mapStateToProps = (state: IState) => ({
|
||||||
gpx: selectEditorGpx(state),
|
gpx: selectEditorGpx(state),
|
||||||
route: selectMapRoute(state),
|
route: selectMapRoute(state),
|
||||||
|
@ -25,6 +29,7 @@ const mapDispatchToProps = {
|
||||||
editorUploadGpx: EDITOR_ACTIONS.editorUploadGpx,
|
editorUploadGpx: EDITOR_ACTIONS.editorUploadGpx,
|
||||||
editorSetGpx: EDITOR_ACTIONS.editorSetGpx,
|
editorSetGpx: EDITOR_ACTIONS.editorSetGpx,
|
||||||
editorGetGPXTrack: EDITOR_ACTIONS.editorGetGPXTrack,
|
editorGetGPXTrack: EDITOR_ACTIONS.editorGetGPXTrack,
|
||||||
|
mapSetRoute: MAP_ACTIONS.mapSetRoute,
|
||||||
};
|
};
|
||||||
|
|
||||||
type Props = ReturnType<typeof mapStateToProps> & typeof mapDispatchToProps & {};
|
type Props = ReturnType<typeof mapStateToProps> & typeof mapDispatchToProps & {};
|
||||||
|
@ -37,7 +42,12 @@ const GpxDialogUnconnected: FC<Props> = ({
|
||||||
editorGetGPXTrack,
|
editorGetGPXTrack,
|
||||||
editorSetGpx,
|
editorSetGpx,
|
||||||
editorUploadGpx,
|
editorUploadGpx,
|
||||||
|
mapSetRoute,
|
||||||
}) => {
|
}) => {
|
||||||
|
const toggleGpx = useCallback(() => {
|
||||||
|
editorSetGpx({ enabled: !gpx.enabled });
|
||||||
|
}, [gpx, editorSetGpx]);
|
||||||
|
|
||||||
const onGpxUpload = useCallback(
|
const onGpxUpload = useCallback(
|
||||||
(event: ChangeEvent<HTMLInputElement>) => {
|
(event: ChangeEvent<HTMLInputElement>) => {
|
||||||
if (!event.target || !event.target.files || event.target.files.length === 0) {
|
if (!event.target || !event.target.files || event.target.files.length === 0) {
|
||||||
|
@ -76,13 +86,10 @@ const GpxDialogUnconnected: FC<Props> = ({
|
||||||
[gpx, editorSetGpx]
|
[gpx, editorSetGpx]
|
||||||
);
|
);
|
||||||
|
|
||||||
const toggleGpx = useCallback(() => {
|
|
||||||
editorSetGpx({ enabled: !gpx.enabled });
|
|
||||||
}, [gpx, editorSetGpx]);
|
|
||||||
|
|
||||||
const onRouteToggle = useCallback(
|
const onRouteToggle = useCallback(
|
||||||
index => {
|
index => {
|
||||||
if (!gpx.enabled) return;
|
if (!gpx.enabled) return;
|
||||||
|
|
||||||
editorSetGpx({
|
editorSetGpx({
|
||||||
list: gpx.list.map((el, i) => (i !== index ? el : { ...el, enabled: !el.enabled })),
|
list: gpx.list.map((el, i) => (i !== index ? el : { ...el, enabled: !el.enabled })),
|
||||||
});
|
});
|
||||||
|
@ -109,22 +116,19 @@ const GpxDialogUnconnected: FC<Props> = ({
|
||||||
});
|
});
|
||||||
}, [route, gpx, editorSetGpx]);
|
}, [route, gpx, editorSetGpx]);
|
||||||
|
|
||||||
|
const onRouteReplace = useCallback(
|
||||||
|
(i: number) => {
|
||||||
|
mapSetRoute(simplify(gpx.list[i].latlngs));
|
||||||
|
|
||||||
|
editorSetGpx({
|
||||||
|
list: gpx.list.map((el, index) => (i !== index ? el : { ...el, enabled: false })),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[gpx, mapSetRoute, editorSetGpx]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="control-dialog control-dialog__left control-dialog__small">
|
<div className="control-dialog control-dialog__left control-dialog__small">
|
||||||
{false && (
|
|
||||||
<div className="gpx-confirm">
|
|
||||||
<div className="gpx-confirm__text">Маршрут уже нанесен. Что делаем?</div>
|
|
||||||
|
|
||||||
<div className="gpx-confirm__buttons">
|
|
||||||
<div className="button success">Соединить</div>
|
|
||||||
|
|
||||||
<div className="button danger">Переписать</div>
|
|
||||||
|
|
||||||
<div className="button primary">Отмена</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div className="gpx-title">
|
<div className="gpx-title">
|
||||||
<div className="flex_1 big white upper">Треки</div>
|
<div className="flex_1 big white upper">Треки</div>
|
||||||
<Switch active={gpx.enabled} onPress={toggleGpx} />
|
<Switch active={gpx.enabled} onPress={toggleGpx} />
|
||||||
|
@ -140,6 +144,7 @@ const GpxDialogUnconnected: FC<Props> = ({
|
||||||
onFocusRoute={onFocusRoute}
|
onFocusRoute={onFocusRoute}
|
||||||
onRouteToggle={onRouteToggle}
|
onRouteToggle={onRouteToggle}
|
||||||
onRouteColor={onRouteColor}
|
onRouteColor={onRouteColor}
|
||||||
|
onRouteReplace={onRouteReplace}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
|
|
21
src/components/gpx/GpxConfirm.tsx
Normal file
21
src/components/gpx/GpxConfirm.tsx
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
import React, { FC } from 'react';
|
||||||
|
|
||||||
|
interface IProps {}
|
||||||
|
|
||||||
|
const GpxConfirm: FC<IProps> = ({}) => {
|
||||||
|
return (
|
||||||
|
<div className="gpx-confirm">
|
||||||
|
<div className="gpx-confirm__text">Маршрут уже нанесен. Что делаем?</div>
|
||||||
|
|
||||||
|
<div className="gpx-confirm__buttons">
|
||||||
|
<div className="button success">Соединить</div>
|
||||||
|
|
||||||
|
<div className="button danger">Переписать</div>
|
||||||
|
|
||||||
|
<div className="button primary">Отмена</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export { GpxConfirm };
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { FC } from 'react';
|
import React, { FC, memo } from 'react';
|
||||||
import { IGpxRoute } from '~/redux/editor';
|
import { IGpxRoute } from '~/redux/editor';
|
||||||
import { Switch } from '../Switch';
|
import { Switch } from '../Switch';
|
||||||
import { Icon } from '../panels/Icon';
|
import { Icon } from '../panels/Icon';
|
||||||
|
@ -13,44 +13,48 @@ interface IProps {
|
||||||
onRouteDrop: (i: number) => void;
|
onRouteDrop: (i: number) => void;
|
||||||
onRouteToggle: (i: number) => void;
|
onRouteToggle: (i: number) => void;
|
||||||
onRouteColor: (i: number) => void;
|
onRouteColor: (i: number) => void;
|
||||||
|
onRouteReplace: (i: number) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const GpxDialogRow: FC<IProps> = ({
|
const GpxDialogRow: FC<IProps> = memo(
|
||||||
item,
|
({
|
||||||
index,
|
item,
|
||||||
enabled,
|
index,
|
||||||
onRouteToggle,
|
enabled,
|
||||||
onFocusRoute,
|
onRouteToggle,
|
||||||
onRouteDrop,
|
onFocusRoute,
|
||||||
onRouteColor,
|
onRouteDrop,
|
||||||
}) => {
|
onRouteColor,
|
||||||
return (
|
onRouteReplace,
|
||||||
<div className={classnames('gpx-row', { 'gpx-row_disabled': !enabled || !item.enabled })}>
|
}) => {
|
||||||
<div
|
return (
|
||||||
className="gpx-row__color"
|
<div className={classnames('gpx-row', { 'gpx-row_disabled': !enabled || !item.enabled })}>
|
||||||
style={{ backgroundColor: item.color }}
|
<div
|
||||||
onClick={() => onRouteColor(index)}
|
className="gpx-row__color"
|
||||||
/>
|
style={{ backgroundColor: item.color }}
|
||||||
|
onClick={() => onRouteColor(index)}
|
||||||
|
/>
|
||||||
|
|
||||||
<div className="gpx-row__title" onClick={() => onFocusRoute(index)}>
|
<div className="gpx-row__title" onClick={() => onFocusRoute(index)}>
|
||||||
{item.name}
|
{item.name}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="gpx-row__buttons">
|
<div className="gpx-row__buttons">
|
||||||
{false && (
|
<div onClick={() => onRouteReplace(index)}>
|
||||||
<div onClick={() => onRouteDrop(index)}>
|
|
||||||
<Icon icon="icon-to-poly" size={24} />
|
<Icon icon="icon-to-poly" size={24} />
|
||||||
</div>
|
</div>
|
||||||
)}
|
|
||||||
<div onClick={() => onRouteDrop(index)}>
|
<div onClick={() => onRouteDrop(index)}>
|
||||||
<Icon icon="icon-trash-6" size={24} />
|
<Icon icon="icon-trash-6" size={24} />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
|
||||||
<Switch active={item.enabled} onPress={() => onRouteToggle(index)} />
|
<div>
|
||||||
|
<Switch active={item.enabled} onPress={() => onRouteToggle(index)} />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
);
|
||||||
);
|
}
|
||||||
};
|
);
|
||||||
|
|
||||||
export { GpxDialogRow };
|
export { GpxDialogRow };
|
||||||
|
|
|
@ -294,7 +294,7 @@ function* routerSubmit() {
|
||||||
const route: ReturnType<typeof selectMapRoute> = yield select(selectMapRoute);
|
const route: ReturnType<typeof selectMapRoute> = yield select(selectMapRoute);
|
||||||
const latlngs: LatLng[] = path(['_routes', 0, 'coordinates'], OsrmRouter);
|
const latlngs: LatLng[] = path(['_routes', 0, 'coordinates'], OsrmRouter);
|
||||||
|
|
||||||
const coordinates = simplify({ map: MainMap, latlngs });
|
const coordinates = simplify(latlngs);
|
||||||
|
|
||||||
yield put(mapSetRoute([...route, ...coordinates]));
|
yield put(mapSetRoute([...route, ...coordinates]));
|
||||||
OsrmRouter.setWaypoints([]);
|
OsrmRouter.setWaypoints([]);
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import { Map, LineUtil, LatLng } from 'leaflet';
|
import { Map, LineUtil, LatLng } from 'leaflet';
|
||||||
// import { ILatLng } from "~/redux/map/types";
|
import { MainMap } from '~/constants/map';
|
||||||
|
|
||||||
export const simplify = ({ map, latlngs }: { map: Map, latlngs: LatLng[] }): LatLng[] => {
|
export const simplify = (latlngs: LatLng[]): LatLng[] => {
|
||||||
const zoom = 12;
|
const zoom = 12;
|
||||||
const mul = 0.7; // 0 - not simplifying, 1 - very rude.
|
const mul = 0.7; // 0 - not simplifying, 1 - very rude.
|
||||||
const points = latlngs.map(({ lat, lng }) => map.project({ lat, lng }, zoom));
|
const points = latlngs.map(({ lat, lng }) => MainMap.project({ lat, lng }, zoom));
|
||||||
return LineUtil.simplify(points, mul).map(item => map.unproject(item, zoom));
|
return LineUtil.simplify(points, mul).map(item => MainMap.unproject(item, zoom));
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue