added map fitting

This commit is contained in:
Fedor Katurov 2020-01-13 17:43:38 +07:00
parent 0314edd550
commit bc34cf3876
12 changed files with 93 additions and 78 deletions

View file

@ -10,7 +10,7 @@ const mapDispatchToProps = {
editorStopEditing,
};
type Props = ReturnType<typeof mapStateToProps> & typeof mapDispatchToProps & { width?: number };
type Props = ReturnType<typeof mapStateToProps> & typeof mapDispatchToProps & { };
export class CancelDialog extends React.Component<Props, void> {
cancel = () => {
@ -22,10 +22,8 @@ export class CancelDialog extends React.Component<Props, void> {
};
render() {
const { width } = this.props;
return (
<div className="control-dialog bottom right" style={{ width }}>
<div className="control-dialog bottom right">
<div className="helper cancel-helper">
<div className="helper__text danger">
<Icon icon="icon-cancel-1" />

View file

@ -89,7 +89,7 @@ const mapDispatchToProps = {
editorRouterSubmit: EDITOR_ACTIONS.editorRouterSubmit,
};
type Props = ReturnType<typeof mapStateToProps> & typeof mapDispatchToProps & { width?: number };
type Props = ReturnType<typeof mapStateToProps> & typeof mapDispatchToProps & { };
const RouterDialogUnconnected: FC<Props> = ({
editor: {
@ -98,9 +98,8 @@ const RouterDialogUnconnected: FC<Props> = ({
},
editorRouterCancel,
editorRouterSubmit,
width,
}) => (
<div className="control-dialog bottom right" style={{ width }}>
<div className="control-dialog bottom right">
<div className={classnames('save-loader', { active: is_routing })} />
{!waypoints.length && noPoints({ editorRouterCancel })}

View file

@ -2,7 +2,6 @@ import React from 'react';
import { copyToClipboard, getUrlData } from '~/utils/history';
import { toTranslit, parseDesc } from '~/utils/format';
import { TIPS } from '~/constants/tips';
import { MODES } from '~/constants/modes';
import { Icon } from '~/components/panels/Icon';
import { Switch } from '~/components/Switch';
@ -12,6 +11,7 @@ import { connect } from 'react-redux';
import { selectMap } from '~/redux/map/selectors';
import * as EDITOR_ACTIONS from '~/redux/editor/actions';
import { selectEditorSave } from '~/redux/editor/selectors';
import { MODES } from '~/constants/modes';
const mapStateToProps = state => ({
map: selectMap(state),
@ -19,11 +19,12 @@ const mapStateToProps = state => ({
});
const mapDispatchToProps = {
editorCancelSave: EDITOR_ACTIONS.editorCancelSave,
editorSetMode: EDITOR_ACTIONS.editorSetMode,
editorSendSaveRequest: EDITOR_ACTIONS.editorSendSaveRequest,
};
type Props = ReturnType<typeof mapStateToProps> & typeof mapDispatchToProps & { width: number };
type Props = ReturnType<typeof mapStateToProps> & typeof mapDispatchToProps & { };
interface State {
address: string;
@ -91,16 +92,19 @@ class SaveDialogUnconnected extends React.Component<Props, State> {
this.setState({ is_public: !this.state.is_public });
};
componentWillUnmount = () => {
this.props.editorCancelSave()
};
render() {
const { title, is_public, description } = this.state;
const {
save: { error, finished, overwriting, loading },
width,
} = this.props;
const { host, protocol } = getUrlData();
return (
<div className="control-dialog control-dialog-medium" style={{ width }}>
<div className="control-dialog bottom right">
<div className="helper save-helper">
<div className={classnames('save-loader', { active: loading })} />

View file

@ -25,12 +25,11 @@ const TrashDialogUnconnected: FC<Props> = ({
<div className="control-dialog bottom right" style={{ width }}>
<div className="helper trash-helper desktop-only">
<div className="helper__text danger">
<div className="big upper desktop-only">Удалить:</div>
<div className="big upper desktop-only">Все изменения будут удалены!</div>
</div>
</div>
<div className="helper trash-helper">
<div className="helper__buttons flex_1 trash-buttons">
<div className="button-group">
<div className="button router-helper__button" onClick={editorClearPoly}>
Маршрут
</div>
@ -40,7 +39,6 @@ const TrashDialogUnconnected: FC<Props> = ({
<div className="button router-helper__button" onClick={editorClearAll}>
ВСЕ
</div>
</div>
<div className="flex_1" />
<div className="button primary router-helper__button" onClick={editorClearCancel}>
Отмена

View file

@ -1,6 +1,12 @@
import { Map } from 'leaflet';
import { Map, LayerGroup, Layer, FeatureGroup } from 'leaflet';
export class MapContainer extends Map {
constructor(props) {
super(props);
this.routeLayer.addTo(this);
this.stickerLayer.addTo(this);
}
disableClicks = () => {
this.clickable = false;
};
@ -9,10 +15,23 @@ export class MapContainer extends Map {
this.clickable = true;
};
getVisibleBounds = () => {
const layers = [this.routeLayer, this.stickerLayer];
for (let i = 0; i < layers.length; i += 1) {
const bounds = layers[i].getBounds();
if (Object.keys(bounds).length == 2) return bounds;
}
};
public clickable = true;
public routeLayer = new FeatureGroup();
public stickerLayer = new FeatureGroup();
}
export const MainMap = new MapContainer(document.getElementById('canvas')).setView(
[55.0153275, 82.9071235],
13
);
console.log('MAP', MainMap);

View file

@ -48,7 +48,7 @@ const RouteUnconnected: FC<Props> = memo(
maxMarkers: isMobile() ? 50 : 150,
smoothFactor: 3,
})
.addTo(MainMap)
.addTo(MainMap.routeLayer)
.on('distancechange', onDistanceChange)
.on('vertexdragstart', MainMap.disableClicks)
.on('vertexdragend', MainMap.enableClicks)
@ -60,7 +60,7 @@ const RouteUnconnected: FC<Props> = memo(
setLayer(interactive);
return () => {
interactive.removeFrom(MainMap);
MainMap.routeLayer.removeLayer(interactive);
};
}, [MainMap, onDistanceChange]);

View file

@ -54,7 +54,8 @@ const Sticker: React.FC<IProps> = ({
setDragging(true);
}, [setDragging, layer, map]);
const onDragStop = React.useCallback(event => {
const onDragStop = React.useCallback(
event => {
event.stopPropagation();
event.preventDefault();
@ -70,7 +71,9 @@ const Sticker: React.FC<IProps> = ({
map.dragging.enable();
setTimeout(map.enableClicks, 100);
}, [setDragging, layer, map, sticker, angle]);
},
[setDragging, layer, map, sticker, angle]
);
const onMoveStarted = React.useCallback(() => {
map.disableClicks();
@ -159,7 +162,7 @@ const Sticker: React.FC<IProps> = ({
className: 'sticker-container',
});
const item = marker(sticker.latlng, { icon, draggable: true })
const item = marker(sticker.latlng, { icon, draggable: true });
setLayer(item);
@ -171,9 +174,9 @@ const Sticker: React.FC<IProps> = ({
useEffect(() => {
if (!layer) return;
layer.addTo(MainMap);
layer.addTo(MainMap.stickerLayer);
return () => layer.removeFrom(MainMap)
return () => MainMap.stickerLayer.removeLayer(layer);
}, [layer]);
React.useEffect(() => {

View file

@ -48,7 +48,11 @@ export const editorResetSaveDialog = () => ({ type: EDITOR_ACTIONS.RESET_SAVE_DI
export const editorSetSave = (save: Partial<IEditorState['save']>) => ({
type: EDITOR_ACTIONS.SET_SAVE,
save,
})
});
export const editorCancelSave = () => ({
type: EDITOR_ACTIONS.CANCEL_SAVE,
});
export const editorHideRenderer = () => ({ type: EDITOR_ACTIONS.HIDE_RENDERER });
export const editorSetRenderer = payload => ({ type: EDITOR_ACTIONS.SET_RENDERER, payload });

View file

@ -20,8 +20,8 @@ export const EDITOR_ACTIONS = {
SEND_SAVE_REQUEST: `${P}-SEND_SAVE_REQUEST`,
SET_SAVE_LOADING: `${P}-SET_SAVE_LOADING`,
CANCEL_SAVE_REQUEST: `${P}-CANCEL_SAVE_REQUEST`,
RESET_SAVE_DIALOG: `${P}-RESET_SAVE_DIALOG`,
CANCEL_SAVE: `${P}-CANCEL_SAVE`,
SET_SAVE: `${P}-SET_SAVE`,

View file

@ -51,7 +51,7 @@ export interface IEditorState {
};
}
const EDITOR_INITIAL_STATE = {
export const EDITOR_INITIAL_STATE = {
changed: false,
editing: false,
ready: false,

View file

@ -14,6 +14,7 @@ import {
editorSetFeature,
editorLocationChanged,
editorKeyPressed,
editorSetSave,
} from '~/redux/editor/actions';
import { getUrlData, pushPath } from '~/utils/history';
import { MODES } from '~/constants/modes';
@ -45,6 +46,7 @@ import { MAP_ACTIONS } from '../map/constants';
import { OsrmRouter } from '~/utils/osrm';
import path from 'ramda/es/path';
import { MainMap } from '~/constants/map';
import { EDITOR_INITIAL_STATE } from '.';
const hideLoader = () => {
document.getElementById('loader').style.opacity = String(0);
@ -181,6 +183,7 @@ function* locationChangeSaga({ location }: ReturnType<typeof editorLocationChang
if (!ready) return;
yield call(loadMapFromPath);
MainMap.fitBounds(MainMap.getVisibleBounds(), { animate: true });
}
function* keyPressedSaga({ key, target }: ReturnType<typeof editorKeyPressed>) {
@ -248,6 +251,14 @@ function* routerSubmit() {
yield put(editorSetMode(MODES.NONE));
}
function* cancelSave() {
yield put(
editorSetSave({
...EDITOR_INITIAL_STATE.save,
})
);
}
export function* editorSaga() {
yield takeEvery(EDITOR_ACTIONS.LOCATION_CHANGED, locationChangeSaga);
@ -259,4 +270,5 @@ export function* editorSaga() {
yield takeLatest(EDITOR_ACTIONS.ROUTER_CANCEL, routerCancel);
yield takeLatest(MAP_ACTIONS.MAP_CLICKED, mapClick);
yield takeLatest(EDITOR_ACTIONS.ROUTER_SUBMIT, routerSubmit);
yield takeLatest(EDITOR_ACTIONS.CANCEL_SAVE, cancelSave);
}

View file

@ -39,6 +39,7 @@ import { delay } from 'redux-saga';
import { setReadySaga } from '../editor/sagas';
import { selectEditor } from '../editor/selectors';
import { EDITOR_ACTIONS } from '../editor/constants';
import { MainMap } from '~/constants/map';
function* onMapClick({ latlng }: ReturnType<typeof mapClicked>) {
const {
@ -149,6 +150,7 @@ export function* mapInitSaga() {
yield call(loadMapFromPath);
yield call(setReadySaga);
MainMap.fitBounds(MainMap.getVisibleBounds(), { animate: false });
pushLoaderState(100);
}
@ -234,7 +236,7 @@ function* sendSaveRequestSaga({
const { distance }: ReturnType<typeof selectEditor> = yield select(selectEditor);
const { token }: ReturnType<typeof selectUserUser> = yield select(selectUserUser);
yield put(editorSetSave({ loading: true }));
yield put(editorSetSave({ loading: true, overwriting: false, finished: false, error: null }));
const {
result,
@ -268,6 +270,7 @@ function* sendSaveRequestSaga({
if (result && result.data.code === 'already_exist')
return yield put(editorSetSave({ overwriting: true }));
if (result && result.data.code === 'conflict')
return yield put(
editorSetSave({
@ -277,6 +280,7 @@ function* sendSaveRequestSaga({
finished: false,
})
);
if (timeout || !result || !result.data.route || !result.data.route.address)
return yield put(
editorSetSave({
@ -296,6 +300,10 @@ function* sendSaveRequestSaga({
})
);
yield put(editorSetReady(false));
pushPath(`/${address}/edit`);
yield put(editorSetReady(true));
yield put(
editorSetSave({
error: TIPS.SAVE_SUCCESS,
@ -306,36 +314,6 @@ function* sendSaveRequestSaga({
);
}
// function* setSaveSuccessSaga({
// address,
// title,
// is_public,
// description,
// }: ReturnType<typeof editorSetSaveSuccess>) {
// const { id }: ReturnType<typeof selectUserUser> = yield select(selectUserUser);
// const { dialog_active }: ReturnType<typeof selectEditor> = yield select(selectEditor);
// replacePath(`/${address}/edit`);
// yield put(
// mapSet({
// title,
// address,
// is_public,
// description,
// owner: { id },
// })
// );
// yield put(editorSetChanged(false));
// if (dialog_active) {
// yield call(searchSetSagaWorker);
// }
// return;
// }
export function* mapSaga() {
// TODO: setChanged on set route, logo, provider, stickers
yield takeEvery(EDITOR_ACTIONS.START_EDITING, startEditingSaga);