mirror of
https://github.com/muerwre/orchidmap-front.git
synced 2025-04-25 02:56:41 +07:00
dist and time
finishing route
This commit is contained in:
parent
102328a1b2
commit
b8545105c8
15 changed files with 195 additions and 37 deletions
8
package-lock.json
generated
8
package-lock.json
generated
|
@ -7629,6 +7629,14 @@
|
|||
"resolved": "https://registry.npmjs.org/leaflet-editable/-/leaflet-editable-1.1.0.tgz",
|
||||
"integrity": "sha1-93dZekCoGic/KHtIn9D+XM1gyNA="
|
||||
},
|
||||
"leaflet-geometryutil": {
|
||||
"version": "0.9.0",
|
||||
"resolved": "https://registry.npmjs.org/leaflet-geometryutil/-/leaflet-geometryutil-0.9.0.tgz",
|
||||
"integrity": "sha512-xlie+JCF+zJKc8fujgIUFnob5roEz4GTiZ8GaDR6O24g3I2nsOcCc4GQUgKGpnDMOV4BKa7QavKxy/d92bLyYw==",
|
||||
"requires": {
|
||||
"leaflet": ">=0.7.0"
|
||||
}
|
||||
},
|
||||
"leaflet-routing-machine": {
|
||||
"version": "github:muerwre/leaflet-routing-machine#4be3c24db31b7c2e9750f5894e538969e953a093",
|
||||
"from": "github:muerwre/leaflet-routing-machine#no-osrm-text",
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
"history": "^4.7.2",
|
||||
"leaflet": "^1.3.3",
|
||||
"leaflet-editable": "^1.1.0",
|
||||
"leaflet-geometryutil": "^0.9.0",
|
||||
"leaflet-routing-machine": "muerwre/leaflet-routing-machine#no-osrm-text",
|
||||
"less": "^3.8.1",
|
||||
"lodash": "^4.17.10",
|
||||
|
|
|
@ -3,12 +3,13 @@ import { MODES } from '$constants/modes';
|
|||
|
||||
import { RouterHelper } from '$components/router/RouterHelper';
|
||||
|
||||
export const EditorDialog = ({ mode, routerPoints }) => {
|
||||
export const EditorDialog = ({ mode, routerPoints, editor }) => {
|
||||
const showDialog = (mode === MODES.ROUTER);
|
||||
|
||||
return (
|
||||
showDialog &&
|
||||
<div id="control-dialog">
|
||||
{ mode === MODES.ROUTER && <RouterHelper routerPoints={routerPoints} /> }
|
||||
{ mode === MODES.ROUTER && <RouterHelper routerPoints={routerPoints} editor={editor} /> }
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -2,6 +2,8 @@ import React from 'react';
|
|||
import { MODES } from '$constants/modes';
|
||||
import classnames from 'classnames';
|
||||
|
||||
import { toHours } from '$utils/time';
|
||||
|
||||
import { Icon } from '$components/panels/Icon';
|
||||
import { EditorDialog } from '$components/panels/EditorDialog';
|
||||
|
||||
|
@ -15,7 +17,9 @@ export class EditorPanel extends React.PureComponent {
|
|||
startShotterMode = () => this.props.editor.changeMode(MODES.SHOTTER);
|
||||
|
||||
render() {
|
||||
const { mode, routerPoints } = this.props;
|
||||
const {
|
||||
mode, routerPoints, editor, totalDistance, estimateTime
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<div>
|
||||
|
@ -23,6 +27,7 @@ export class EditorPanel extends React.PureComponent {
|
|||
<EditorDialog
|
||||
mode={mode}
|
||||
routerPoints={routerPoints}
|
||||
editor={editor}
|
||||
/>
|
||||
|
||||
<div className="panel">
|
||||
|
@ -36,6 +41,12 @@ export class EditorPanel extends React.PureComponent {
|
|||
</div>
|
||||
|
||||
<div className="panel right">
|
||||
<div className="control-dist">
|
||||
{totalDistance} км
|
||||
{
|
||||
(estimateTime > 0) && (estimateTime > 0) && <span>{toHours(estimateTime)}</span>
|
||||
}
|
||||
</div>
|
||||
<div className="control-bar">
|
||||
<button
|
||||
className={classnames({ active: mode === MODES.ROUTER })}
|
||||
|
@ -69,11 +80,18 @@ export class EditorPanel extends React.PureComponent {
|
|||
</button>
|
||||
|
||||
<button
|
||||
className={classnames('highlighted', { active: mode === MODES.SHOTTER })}
|
||||
className={classnames({ active: mode === MODES.TRASH })}
|
||||
onClick={this.startShotterMode}
|
||||
>
|
||||
<Icon icon="icon-trash" />
|
||||
</button>
|
||||
|
||||
<button
|
||||
className="highlighted"
|
||||
onClick={this.startShotterMode}
|
||||
>
|
||||
<span>СХОРОНИТЬ</span>
|
||||
<Icon icon="icon-shooter" />
|
||||
<Icon icon="icon-save" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
@ -81,4 +99,4 @@ export class EditorPanel extends React.PureComponent {
|
|||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,54 +1,68 @@
|
|||
import React from 'react';
|
||||
|
||||
const noPoints = () => (
|
||||
const noPoints = ({ cancelDrawing }) => (
|
||||
<div className="router-helper">
|
||||
<div className="router-helper__text">
|
||||
<div className="big white">Укажите на карте первую точку маршрута</div>
|
||||
<div className="small gray">Путь прокладывается по улицам, тротуарам и тропинкам</div>
|
||||
</div>
|
||||
<div className="router-helper__buttons">
|
||||
<div className="button router-helper__button">
|
||||
<div className="button router-helper__button" onClick={cancelDrawing}>
|
||||
Отмена
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
const firstPoint = () => (
|
||||
const firstPoint = ({ cancelDrawing }) => (
|
||||
<div className="router-helper">
|
||||
<div className="router-helper__text">
|
||||
<div className="big white">Укажите на карте конечную точку маршрута</div>
|
||||
<div className="small gray"> Вы сможете добавить уточняющие точки</div>
|
||||
</div>
|
||||
<div className="router-helper__buttons">
|
||||
<div className="button router-helper__button">
|
||||
<div className="button router-helper__button" onClick={cancelDrawing}>
|
||||
Отмена
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
const draggablePoints = () => (
|
||||
const draggablePoints = ({ cancelDrawing, submitDrawing }) => (
|
||||
<div className="router-helper">
|
||||
<div className="router-helper__text">
|
||||
<div className="big white">Продолжите маршрут, щелкая по карте</div>
|
||||
<div className="small gray">Потяните линию, чтобы указать промежуточные точки</div>
|
||||
</div>
|
||||
<div className="router-helper__buttons button-group">
|
||||
<div className="button button_red router-helper__button">
|
||||
<div className="button button_red router-helper__button" onClick={cancelDrawing}>
|
||||
Отмена
|
||||
</div>
|
||||
<div className="button primary router-helper__button">
|
||||
<div className="button primary router-helper__button" onClick={submitDrawing}>
|
||||
Применить
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
export const RouterHelper = ({ routerPoints }) => (
|
||||
export class RouterHelper extends React.Component {
|
||||
cancelDrawing = () => {
|
||||
this.props.editor.router.cancelDrawing();
|
||||
};
|
||||
|
||||
submitDrawing = () => {
|
||||
this.props.editor.router.submitDrawing();
|
||||
};
|
||||
|
||||
render() {
|
||||
const { routerPoints, editor } = this.props;
|
||||
const { cancelDrawing, submitDrawing } = this;
|
||||
return (
|
||||
<div>
|
||||
{ !routerPoints && noPoints() }
|
||||
{ routerPoints === 1 && firstPoint() }
|
||||
{ routerPoints >= 2 && draggablePoints() }
|
||||
{!routerPoints && noPoints({ cancelDrawing })}
|
||||
{routerPoints === 1 && firstPoint({ cancelDrawing })}
|
||||
{routerPoints >= 2 && draggablePoints({ cancelDrawing, submitDrawing })}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,5 +3,6 @@ export const MODES = {
|
|||
STICKERS: 'STICKERS',
|
||||
ROUTER: 'ROUTER',
|
||||
SHOTTER: 'SHOTTER',
|
||||
TRASH: 'TRASH',
|
||||
NONE: 'NONE',
|
||||
};
|
||||
|
|
|
@ -8,26 +8,36 @@ export class App extends React.Component {
|
|||
state = {
|
||||
mode: 'none',
|
||||
routerPoints: 0,
|
||||
totalDistance: 0,
|
||||
estimateTime: 0,
|
||||
};
|
||||
|
||||
setMode = mode => {
|
||||
this.setState({ mode });
|
||||
};
|
||||
|
||||
setRouterPoints = routerPoints => {
|
||||
this.setState({ routerPoints });
|
||||
};
|
||||
|
||||
setTotalDist = totalDistance => {
|
||||
const time = (totalDistance && (totalDistance / 15)) || 0;
|
||||
const estimateTime = (time && parseFloat(time.toFixed(1)));
|
||||
this.setState({ totalDistance, estimateTime });
|
||||
};
|
||||
|
||||
editor = new Editor({
|
||||
container: 'map',
|
||||
mode: this.state.mode,
|
||||
setMode: this.setMode,
|
||||
setRouterPoints: this.setRouterPoints,
|
||||
setTotalDist: this.setTotalDist,
|
||||
});
|
||||
|
||||
render() {
|
||||
const {
|
||||
editor,
|
||||
state: { mode, routerPoints },
|
||||
state: { mode, routerPoints, totalDistance, estimateTime },
|
||||
} = this;
|
||||
|
||||
|
||||
|
@ -38,6 +48,8 @@ export class App extends React.Component {
|
|||
editor={editor}
|
||||
mode={mode}
|
||||
routerPoints={routerPoints}
|
||||
totalDistance={totalDistance}
|
||||
estimateTime={estimateTime}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -11,14 +11,19 @@ export class Editor {
|
|||
mode,
|
||||
setMode,
|
||||
setRouterPoints,
|
||||
setTotalDist,
|
||||
}) {
|
||||
this.map = new Map({ container });
|
||||
|
||||
const { lockMapClicks, routerMoveStart, map: { map } } = this;
|
||||
const {
|
||||
lockMapClicks, routerMoveStart, changeMode, pushPolyPoints, map: { map }
|
||||
} = this;
|
||||
|
||||
this.poly = new Poly({ map, routerMoveStart, lockMapClicks });
|
||||
this.poly = new Poly({ map, routerMoveStart, lockMapClicks, setTotalDist });
|
||||
this.stickers = new Stickers({ map, lockMapClicks });
|
||||
this.router = new Router({ map, lockMapClicks, setRouterPoints });
|
||||
this.router = new Router({
|
||||
map, lockMapClicks, setRouterPoints, changeMode, pushPolyPoints
|
||||
});
|
||||
this.shotter = new Shotter({ map });
|
||||
|
||||
this.setMode = setMode;
|
||||
|
@ -99,5 +104,9 @@ export class Editor {
|
|||
const { _latlngs } = this.poly.poly;
|
||||
|
||||
if (_latlngs) this.router.moveStart(_latlngs[_latlngs.length - 1]);
|
||||
};
|
||||
|
||||
pushPolyPoints = latlngs => {
|
||||
this.poly.pushPoints(latlngs);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,16 +1,21 @@
|
|||
import { polyline } from "leaflet";
|
||||
import L from 'leaflet';
|
||||
import 'leaflet-geometryutil';
|
||||
import { simplify } from '$utils/simplify';
|
||||
|
||||
const polyStyle = { color: 'url(#activePathGradient)', weight: '6' };
|
||||
// const polyStyle = { color: '#ff3344', weight: '5' };
|
||||
|
||||
export class Poly {
|
||||
constructor({ map, routerMoveStart, lockMapClicks }) {
|
||||
this.poly = polyline([], polyStyle);
|
||||
constructor({
|
||||
map, routerMoveStart, lockMapClicks, setTotalDist
|
||||
}) {
|
||||
this.poly = L.polyline([], polyStyle);
|
||||
this.latlngs = [];
|
||||
this.poly.addTo(map);
|
||||
this.map = map;
|
||||
|
||||
this.routerMoveStart = routerMoveStart;
|
||||
this.setTotalDist = setTotalDist;
|
||||
this.lockMapClicks = lockMapClicks;
|
||||
this.bindEvents();
|
||||
}
|
||||
|
@ -19,7 +24,10 @@ export class Poly {
|
|||
console.log('upd');
|
||||
const coords = this.poly.toGeoJSON().geometry.coordinates;
|
||||
this.latlngs = (coords && coords.length && coords.map(([lng, lat]) => ({ lng, lat }))) || [];
|
||||
const meters = (this.poly && (L.GeometryUtil.length(this.poly) / 1000)) || 0;
|
||||
const kilometers = (meters && parseFloat(meters.toFixed(1))) || 0;
|
||||
|
||||
this.setTotalDist(kilometers);
|
||||
this.routerMoveStart();
|
||||
};
|
||||
|
||||
|
@ -59,9 +67,11 @@ export class Poly {
|
|||
|
||||
continue = () => {
|
||||
if (this.latlngs && this.latlngs.length) {
|
||||
console.log('continue?');
|
||||
this.poly.enableEdit().continueForward();
|
||||
this.poly.editor.reset();
|
||||
} else {
|
||||
console.log('start over');
|
||||
this.poly = this.map.editTools.startPolyline();
|
||||
this.poly.setStyle(polyStyle);
|
||||
}
|
||||
|
@ -78,5 +88,17 @@ export class Poly {
|
|||
|
||||
lockMap = () => {
|
||||
this.lockMapClicks(true);
|
||||
};
|
||||
|
||||
pushPoints = latlngs => {
|
||||
const { map } = this;
|
||||
const simplified = simplify({ map, latlngs });
|
||||
const summary = [
|
||||
...this.poly.getLatLngs(),
|
||||
...simplified,
|
||||
];
|
||||
|
||||
this.poly.setLatLngs(summary);
|
||||
this.updateMarks();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,9 +2,16 @@ import L from 'leaflet';
|
|||
import Routing from 'leaflet-routing-machine/src/index';
|
||||
import { CONFIG } from '$config';
|
||||
import { DomMarker } from '$utils/DomMarker';
|
||||
import { MODES } from '$constants/modes';
|
||||
|
||||
export class Router {
|
||||
constructor({ map, lockMapClicks, setRouterPoints }) {
|
||||
constructor({ map, lockMapClicks, setRouterPoints, changeMode, pushPolyPoints }) {
|
||||
this.waypoints = [];
|
||||
this.lockMapClicks = lockMapClicks;
|
||||
this.setRouterPoints = setRouterPoints;
|
||||
this.changeMode = changeMode;
|
||||
this.pushPolyPoints = pushPolyPoints;
|
||||
|
||||
const routeLine = r => Routing.line(r, {
|
||||
styles: [
|
||||
{ color: 'white', opacity: 0.8, weight: 6 },
|
||||
|
@ -36,9 +43,6 @@ export class Router {
|
|||
|
||||
this.router.addTo(map);
|
||||
|
||||
this.waypoints = [];
|
||||
this.lockMapClicks = lockMapClicks;
|
||||
this.setRouterPoints = setRouterPoints;
|
||||
// this.router._line.on('mousedown', console.log);
|
||||
}
|
||||
//
|
||||
|
@ -109,5 +113,20 @@ export class Router {
|
|||
updateWaypointsCount = () => {
|
||||
const waypoints = this.router.getWaypoints().filter(({ latLng }) => !!latLng);
|
||||
this.setRouterPoints(waypoints.length);
|
||||
}
|
||||
};
|
||||
|
||||
cancelDrawing = () => {
|
||||
this.router.setWaypoints([]);
|
||||
this.changeMode(MODES.NONE);
|
||||
};
|
||||
|
||||
submitDrawing = () => {
|
||||
const [route] = this.router._routes;
|
||||
if (!route) return;
|
||||
|
||||
const { coordinates, summary: { totalDistance } } = route;
|
||||
this.pushPolyPoints(coordinates);
|
||||
this.router.setWaypoints([]);
|
||||
this.changeMode(MODES.POLY);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -38,5 +38,23 @@
|
|||
</g>
|
||||
</g>
|
||||
|
||||
<g id="icon-trash">
|
||||
<g transform="matrix(4.2 0 0 4.2 -3 -2 )" stroke="none">
|
||||
<path fill="white" d="M2.783 3.626h2.923v2.923H2.783z"/>
|
||||
<path fill="white" d="M2.479 2.597h3.508v.748H2.479z"/>
|
||||
<path fill="white" d="M3.438 1.919h1.473v.865H3.438z"/>
|
||||
<path fill="black" d="M3.859 2.25h.631v.386h-.631z"/>
|
||||
<path fill="black" d="M3.134 3.906h.468v2.315h-.468z"/>
|
||||
<path fill="black" d="M-4.537 3.906h.444v2.315h-.444z" transform="scale(-1 1)"/>
|
||||
<path fill="black" d="M4.958 3.906h.444v2.315h-.444z"/>
|
||||
</g>
|
||||
</g>
|
||||
|
||||
<g id="icon-save" stroke="none">
|
||||
<path fill="black" d="M0 0h32v32H0z"/>
|
||||
<path fill="white" d="M6.844 8.459V24h18.312V11.375H14.031V8.459z"/>
|
||||
<rect fill="black" width="2.74" height="5.038" x="14.63" y="14.411" stroke-width="3.603" />
|
||||
<path fill="black" d="M16.866 19.73l-4.315-.06-4.314.06 2.209-3.707 2.105-3.766 2.106 3.766z" transform="matrix(.45903 -.40628 .79506 .23456 -3.467 21.088)"/>
|
||||
</g>
|
||||
</defs>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
@ -5,6 +5,15 @@
|
|||
box-shadow: rgba(0,0,0,0.3) 0 2px 0, inset rgba(255, 255, 255, 0.05) 1px 1px;
|
||||
}
|
||||
|
||||
.control-dist {
|
||||
height: 44px;
|
||||
background: #222222;
|
||||
padding: 0 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-radius: 3px 0 0 3px;
|
||||
}
|
||||
|
||||
.control-sep {
|
||||
height: 44px;
|
||||
background: #222222;
|
||||
|
|
21
src/utils/simplify.js
Normal file
21
src/utils/simplify.js
Normal file
|
@ -0,0 +1,21 @@
|
|||
import L from 'leaflet';
|
||||
|
||||
export const simplify = ({ map, latlngs }) => {
|
||||
const points = [];
|
||||
const target = [];
|
||||
const zoom = 12;
|
||||
const mul = 0.7; // 0 - not simplifying, 1 - very rude.
|
||||
// its better to estimate mul value by route length
|
||||
|
||||
for (let i = 0; i < latlngs.length; i += 1) {
|
||||
points.push(map.project({ lat: latlngs[i].lat, lng: latlngs[i].lng }, zoom));
|
||||
}
|
||||
|
||||
const simplified = L.LineUtil.simplify(points, mul);
|
||||
|
||||
for (let i = 0; i < simplified.length; i += 1) {
|
||||
target.push(map.unproject(simplified[i], zoom));
|
||||
}
|
||||
|
||||
return target;
|
||||
};
|
5
src/utils/time.js
Normal file
5
src/utils/time.js
Normal file
|
@ -0,0 +1,5 @@
|
|||
export const toHours = (info) => {
|
||||
const hrs = parseInt(Number(info));
|
||||
const min = Math.round((Number(info)-hrs) * 60);
|
||||
return hrs+':'+min;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue