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, 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> { export class CancelDialog extends React.Component<Props, void> {
cancel = () => { cancel = () => {
@ -22,10 +22,8 @@ export class CancelDialog extends React.Component<Props, void> {
}; };
render() { render() {
const { width } = this.props;
return ( return (
<div className="control-dialog bottom right" style={{ width }}> <div className="control-dialog bottom right">
<div className="helper cancel-helper"> <div className="helper cancel-helper">
<div className="helper__text danger"> <div className="helper__text danger">
<Icon icon="icon-cancel-1" /> <Icon icon="icon-cancel-1" />

View file

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

View file

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

View file

@ -25,21 +25,19 @@ const TrashDialogUnconnected: FC<Props> = ({
<div className="control-dialog bottom right" style={{ width }}> <div className="control-dialog bottom right" style={{ width }}>
<div className="helper trash-helper desktop-only"> <div className="helper trash-helper desktop-only">
<div className="helper__text danger"> <div className="helper__text danger">
<div className="big upper desktop-only">Удалить:</div> <div className="big upper desktop-only">Все изменения будут удалены!</div>
</div> </div>
</div> </div>
<div className="helper trash-helper"> <div className="helper trash-helper">
<div className="helper__buttons flex_1 trash-buttons"> <div className="helper__buttons flex_1 trash-buttons">
<div className="button-group"> <div className="button router-helper__button" onClick={editorClearPoly}>
<div className="button router-helper__button" onClick={editorClearPoly}> Маршрут
Маршрут </div>
</div> <div className="button router-helper__button" onClick={editorClearStickers}>
<div className="button router-helper__button" onClick={editorClearStickers}> Стикеры
Стикеры </div>
</div> <div className="button router-helper__button" onClick={editorClearAll}>
<div className="button router-helper__button" onClick={editorClearAll}> ВСЕ
ВСЕ
</div>
</div> </div>
<div className="flex_1" /> <div className="flex_1" />
<div className="button primary router-helper__button" onClick={editorClearCancel}> <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 { export class MapContainer extends Map {
constructor(props) {
super(props);
this.routeLayer.addTo(this);
this.stickerLayer.addTo(this);
}
disableClicks = () => { disableClicks = () => {
this.clickable = false; this.clickable = false;
}; };
@ -9,10 +15,23 @@ export class MapContainer extends Map {
this.clickable = true; 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 clickable = true;
public routeLayer = new FeatureGroup();
public stickerLayer = new FeatureGroup();
} }
export const MainMap = new MapContainer(document.getElementById('canvas')).setView( export const MainMap = new MapContainer(document.getElementById('canvas')).setView(
[55.0153275, 82.9071235], [55.0153275, 82.9071235],
13 13
); );
console.log('MAP', MainMap);

View file

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

View file

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

View file

@ -48,7 +48,11 @@ export const editorResetSaveDialog = () => ({ type: EDITOR_ACTIONS.RESET_SAVE_DI
export const editorSetSave = (save: Partial<IEditorState['save']>) => ({ export const editorSetSave = (save: Partial<IEditorState['save']>) => ({
type: EDITOR_ACTIONS.SET_SAVE, type: EDITOR_ACTIONS.SET_SAVE,
save, save,
}) });
export const editorCancelSave = () => ({
type: EDITOR_ACTIONS.CANCEL_SAVE,
});
export const editorHideRenderer = () => ({ type: EDITOR_ACTIONS.HIDE_RENDERER }); export const editorHideRenderer = () => ({ type: EDITOR_ACTIONS.HIDE_RENDERER });
export const editorSetRenderer = payload => ({ type: EDITOR_ACTIONS.SET_RENDERER, payload }); 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`, SEND_SAVE_REQUEST: `${P}-SEND_SAVE_REQUEST`,
SET_SAVE_LOADING: `${P}-SET_SAVE_LOADING`, SET_SAVE_LOADING: `${P}-SET_SAVE_LOADING`,
CANCEL_SAVE_REQUEST: `${P}-CANCEL_SAVE_REQUEST`,
RESET_SAVE_DIALOG: `${P}-RESET_SAVE_DIALOG`, RESET_SAVE_DIALOG: `${P}-RESET_SAVE_DIALOG`,
CANCEL_SAVE: `${P}-CANCEL_SAVE`,
SET_SAVE: `${P}-SET_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, changed: false,
editing: false, editing: false,
ready: false, ready: false,

View file

@ -14,6 +14,7 @@ import {
editorSetFeature, editorSetFeature,
editorLocationChanged, editorLocationChanged,
editorKeyPressed, editorKeyPressed,
editorSetSave,
} from '~/redux/editor/actions'; } from '~/redux/editor/actions';
import { getUrlData, pushPath } from '~/utils/history'; import { getUrlData, pushPath } from '~/utils/history';
import { MODES } from '~/constants/modes'; import { MODES } from '~/constants/modes';
@ -45,6 +46,7 @@ import { MAP_ACTIONS } from '../map/constants';
import { OsrmRouter } from '~/utils/osrm'; import { OsrmRouter } from '~/utils/osrm';
import path from 'ramda/es/path'; import path from 'ramda/es/path';
import { MainMap } from '~/constants/map'; import { MainMap } from '~/constants/map';
import { EDITOR_INITIAL_STATE } from '.';
const hideLoader = () => { const hideLoader = () => {
document.getElementById('loader').style.opacity = String(0); document.getElementById('loader').style.opacity = String(0);
@ -181,6 +183,7 @@ function* locationChangeSaga({ location }: ReturnType<typeof editorLocationChang
if (!ready) return; if (!ready) return;
yield call(loadMapFromPath); yield call(loadMapFromPath);
MainMap.fitBounds(MainMap.getVisibleBounds(), { animate: true });
} }
function* keyPressedSaga({ key, target }: ReturnType<typeof editorKeyPressed>) { function* keyPressedSaga({ key, target }: ReturnType<typeof editorKeyPressed>) {
@ -248,6 +251,14 @@ function* routerSubmit() {
yield put(editorSetMode(MODES.NONE)); yield put(editorSetMode(MODES.NONE));
} }
function* cancelSave() {
yield put(
editorSetSave({
...EDITOR_INITIAL_STATE.save,
})
);
}
export function* editorSaga() { export function* editorSaga() {
yield takeEvery(EDITOR_ACTIONS.LOCATION_CHANGED, locationChangeSaga); yield takeEvery(EDITOR_ACTIONS.LOCATION_CHANGED, locationChangeSaga);
@ -259,4 +270,5 @@ export function* editorSaga() {
yield takeLatest(EDITOR_ACTIONS.ROUTER_CANCEL, routerCancel); yield takeLatest(EDITOR_ACTIONS.ROUTER_CANCEL, routerCancel);
yield takeLatest(MAP_ACTIONS.MAP_CLICKED, mapClick); yield takeLatest(MAP_ACTIONS.MAP_CLICKED, mapClick);
yield takeLatest(EDITOR_ACTIONS.ROUTER_SUBMIT, routerSubmit); 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 { setReadySaga } from '../editor/sagas';
import { selectEditor } from '../editor/selectors'; import { selectEditor } from '../editor/selectors';
import { EDITOR_ACTIONS } from '../editor/constants'; import { EDITOR_ACTIONS } from '../editor/constants';
import { MainMap } from '~/constants/map';
function* onMapClick({ latlng }: ReturnType<typeof mapClicked>) { function* onMapClick({ latlng }: ReturnType<typeof mapClicked>) {
const { const {
@ -149,6 +150,7 @@ export function* mapInitSaga() {
yield call(loadMapFromPath); yield call(loadMapFromPath);
yield call(setReadySaga); yield call(setReadySaga);
MainMap.fitBounds(MainMap.getVisibleBounds(), { animate: false });
pushLoaderState(100); pushLoaderState(100);
} }
@ -234,7 +236,7 @@ function* sendSaveRequestSaga({
const { distance }: ReturnType<typeof selectEditor> = yield select(selectEditor); const { distance }: ReturnType<typeof selectEditor> = yield select(selectEditor);
const { token }: ReturnType<typeof selectUserUser> = yield select(selectUserUser); 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 { const {
result, result,
@ -268,6 +270,7 @@ function* sendSaveRequestSaga({
if (result && result.data.code === 'already_exist') if (result && result.data.code === 'already_exist')
return yield put(editorSetSave({ overwriting: true })); return yield put(editorSetSave({ overwriting: true }));
if (result && result.data.code === 'conflict') if (result && result.data.code === 'conflict')
return yield put( return yield put(
editorSetSave({ editorSetSave({
@ -277,6 +280,7 @@ function* sendSaveRequestSaga({
finished: false, finished: false,
}) })
); );
if (timeout || !result || !result.data.route || !result.data.route.address) if (timeout || !result || !result.data.route || !result.data.route.address)
return yield put( return yield put(
editorSetSave({ editorSetSave({
@ -296,6 +300,10 @@ function* sendSaveRequestSaga({
}) })
); );
yield put(editorSetReady(false));
pushPath(`/${address}/edit`);
yield put(editorSetReady(true));
yield put( yield put(
editorSetSave({ editorSetSave({
error: TIPS.SAVE_SUCCESS, 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() { export function* mapSaga() {
// TODO: setChanged on set route, logo, provider, stickers // TODO: setChanged on set route, logo, provider, stickers
yield takeEvery(EDITOR_ACTIONS.START_EDITING, startEditingSaga); yield takeEvery(EDITOR_ACTIONS.START_EDITING, startEditingSaga);