diff --git a/package-lock.json b/package-lock.json
index 241d7ff..a16af5d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -689,6 +689,16 @@
"to-fast-properties": "^2.0.0"
}
},
+ "@mapbox/corslite": {
+ "version": "0.0.7",
+ "resolved": "https://registry.npmjs.org/@mapbox/corslite/-/corslite-0.0.7.tgz",
+ "integrity": "sha1-KfW2oYi6lG5RS98LZAHtT74To54="
+ },
+ "@mapbox/polyline": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/@mapbox/polyline/-/polyline-0.2.0.tgz",
+ "integrity": "sha1-biWYB0SqIjMflLZFpULALT/P7pc="
+ },
"@mrmlnc/readdir-enhanced": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz",
@@ -7418,6 +7428,16 @@
"resolved": "https://registry.npmjs.org/leaflet-editable/-/leaflet-editable-1.1.0.tgz",
"integrity": "sha1-93dZekCoGic/KHtIn9D+XM1gyNA="
},
+ "leaflet-routing-machine": {
+ "version": "3.2.8",
+ "resolved": "https://registry.npmjs.org/leaflet-routing-machine/-/leaflet-routing-machine-3.2.8.tgz",
+ "integrity": "sha512-cJPN//kMu6J7L7M/apfjx3SEAt7TFSFGj285To4vLTnq4h9uPo5u6Rd8JdIipyBJXED/UvUVG7LlpguQ+G7gqA==",
+ "requires": {
+ "@mapbox/corslite": "0.0.7",
+ "@mapbox/polyline": "^0.2.0",
+ "osrm-text-instructions": "^0.11.5"
+ }
+ },
"levn": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
@@ -8881,6 +8901,11 @@
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
"dev": true
},
+ "osrm-text-instructions": {
+ "version": "0.11.5",
+ "resolved": "https://registry.npmjs.org/osrm-text-instructions/-/osrm-text-instructions-0.11.5.tgz",
+ "integrity": "sha512-EKCfIXhJHsYQLcuctymvSVH7ulRXx5sGb2MdZL3NzD6XhRVZRkqwRicd9/QI27A5oXW4ojOEJ81RGay7bO6dbA=="
+ },
"output-file-sync": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/output-file-sync/-/output-file-sync-2.0.1.tgz",
diff --git a/package.json b/package.json
index d57b7dd..c453214 100644
--- a/package.json
+++ b/package.json
@@ -48,6 +48,7 @@
"history": "^4.7.2",
"leaflet": "^1.3.3",
"leaflet-editable": "^1.1.0",
+ "leaflet-routing-machine": "^3.2.8",
"react": "^16.3.2",
"react-dom": "^16.3.2",
"react-hot-loader": "^4.1.1",
diff --git a/src/config.js b/src/config.js
new file mode 100644
index 0000000..e1b5973
--- /dev/null
+++ b/src/config.js
@@ -0,0 +1,3 @@
+export const CONFIG = {
+ OSRM_URL: 'http://vault48.org:5000/route/v1',
+};
diff --git a/src/constants/modes.js b/src/constants/modes.js
index efa6a0c..4a65951 100644
--- a/src/constants/modes.js
+++ b/src/constants/modes.js
@@ -1,5 +1,6 @@
export const MODES = {
POLY: 'POLY',
STICKERS: 'STICKERS',
+ ROUTER: 'ROUTER',
NONE: 'NONE',
};
diff --git a/src/containers/App.jsx b/src/containers/App.jsx
index 0defa4e..42f41b0 100644
--- a/src/containers/App.jsx
+++ b/src/containers/App.jsx
@@ -30,6 +30,8 @@ export class App extends React.Component {
startStickerMode = () => this.editor.changeMode(MODES.STICKERS);
+ startRouterMode = () => this.editor.changeMode(MODES.ROUTER);
+
render() {
const { mode } = this.state;
@@ -43,6 +45,9 @@ export class App extends React.Component {
+
);
diff --git a/src/modules/Editor.js b/src/modules/Editor.js
index f02957e..714d96b 100644
--- a/src/modules/Editor.js
+++ b/src/modules/Editor.js
@@ -1,7 +1,8 @@
import { Map } from '$modules/Map';
-import { Poly } from "$modules/Poly";
+import { Poly } from '$modules/Poly';
import { MODES } from '$constants/modes';
import { Stickers } from '$modules/Stickers';
+import { Router } from '$modules/Router';
export class Editor {
constructor({
@@ -10,8 +11,12 @@ export class Editor {
setMode
}) {
this.map = new Map({ container });
+
+ const { lockMapClicks, map: { map } } = this;
+
this.poly = new Poly({ map: this.map.map });
- this.stickers = new Stickers({ map: this.map.map });
+ this.stickers = new Stickers({ map, lockMapClicks });
+ this.router = new Router({ map, lockMapClicks });
this.setMode = setMode;
this.mode = mode;
@@ -20,14 +25,20 @@ export class Editor {
[MODES.POLY]: {
start: this.poly.continue,
stop: this.poly.stop,
+ },
+ [MODES.ROUTER]: {
+ start: this.routerSetStart,
}
};
this.clickHandlers = {
- [MODES.STICKERS]: this.stickers.createOnClick
+ [MODES.STICKERS]: this.stickers.createOnClick,
+ [MODES.ROUTER]: this.router.pushWaypointOnClick,
};
- this.map.map.addEventListener('mousedown', this.onClick);
+ map.addEventListener('mouseup', this.onClick);
+ map.addEventListener('dragstart', () => lockMapClicks(true));
+ map.addEventListener('dragstop', () => lockMapClicks(false));
}
changeMode = mode => {
@@ -52,6 +63,29 @@ export class Editor {
};
onClick = e => {
+ if (e.originalEvent.which === 3) return; // skip right click
if (this.clickHandlers[this.mode]) this.clickHandlers[this.mode](e);
};
+
+ lockMapClicks = lock => {
+ if (lock) {
+ this.map.map.removeEventListener('mouseup', this.onClick);
+ this.map.map.addEventListener('mouseup', this.unlockMapClicks);
+ } else {
+ this.map.map.removeEventListener('mouseup', this.unlockMapClicks);
+ this.map.map.addEventListener('mouseup', this.onClick);
+ }
+ };
+
+ unlockMapClicks = () => {
+ this.lockMapClicks(false);
+ };
+
+ routerSetStart = () => {
+ const { latlngs } = this.poly;
+
+ if (!latlngs || !latlngs.length) return;
+
+ this.router.startFrom(latlngs.pop());
+ };
}
diff --git a/src/modules/Map.js b/src/modules/Map.js
index 6f92870..ee001d2 100644
--- a/src/modules/Map.js
+++ b/src/modules/Map.js
@@ -8,7 +8,7 @@ export class Map {
constructor({ container }) {
this.map = L.map(container, { editable: true }).setView([55.0153275, 82.9071235], 13);
- this.tileLayer = L.tileLayer(providers.dgis, {
+ this.tileLayer = L.tileLayer(providers.default, {
attribution: 'Независимое Велосообщество',
maxNativeZoom: 18,
maxZoom: 18,
diff --git a/src/modules/Router.js b/src/modules/Router.js
new file mode 100644
index 0000000..9a6d4a7
--- /dev/null
+++ b/src/modules/Router.js
@@ -0,0 +1,100 @@
+import L from 'leaflet';
+import 'leaflet-routing-machine';
+import { CONFIG } from '$config';
+import { DomMarker } from '$utils/DomMarker';
+
+export class Router {
+ constructor({ map, lockMapClicks }) {
+ const routeLine = r => L.Routing.line(r, {
+ styles: [
+ { color: 'white', opacity: 0.8, weight: 6 },
+ { color: '#4597d0', opacity: 1, weight: 4, dashArray: '15,10' }
+ ],
+ addWaypoints: true,
+ }).on('linetouched', this.lockPropagations);
+
+ this.router = L.Routing.control({
+ serviceUrl: CONFIG.OSRM_URL,
+ profile: 'bike',
+ fitSelectedRoutes: false,
+ routeLine,
+ altLineOptions: {
+ styles: [{ color: '#4597d0', opacity: 1, weight: 3 }]
+ },
+ show: false,
+ plan: L.Routing.plan([], {
+ createMarker: (i, wp) => L.marker(wp.latLng, {
+ draggable: true,
+ icon: this.createWaypointMarker(),
+ }),
+ routeWhileDragging: true,
+ }),
+ routeWhileDragging: true
+ });
+ // .on('waypointschanged', this.updateWaypointsByEvent);
+
+ this.router.addTo(map);
+
+ this.waypoints = [];
+ this.lockMapClicks = lockMapClicks;
+
+ console.log('router', this.router);
+ // this.router._line.on('mousedown', console.log);
+ console.log('map', map);
+ }
+ //
+ pushWaypointOnClick = ({ latlng: { lat, lng } }) => {
+ const waypoints = this.router.getWaypoints().filter(({ latLng }) => !!latLng);
+ console.log('push', waypoints);
+ this.router.setWaypoints([...waypoints, { lat, lng }]);
+ };
+ //
+ // pushWaypoint = latlng => {
+ // this.waypoints.push(latlng);
+ // this.updateWaypoints();
+ // };
+ //
+ // updateWaypointsByEvent = (e) => {
+ // console.log('upd', e);
+ // // this.waypoints = waypoints.map(({ latlng }) => latlng);
+ //
+ // };
+ //
+ // updateWaypoints = () => {
+ // this.router.setWaypoints(this.waypoints);
+ // };
+ //
+ createWaypointMarker = () => {
+ const element = document.createElement('div');
+
+ element.addEventListener('mousedown', this.lockPropagations);
+ element.addEventListener('mouseup', this.unlockPropagations);
+
+ return new DomMarker({
+ element,
+ className: 'router-waypoint',
+ });
+ };
+ //
+ lockPropagations = () => {
+ console.log('lock');
+ window.addEventListener('mouseup', this.unlockPropagations);
+ this.lockMapClicks(true);
+ };
+ //
+ unlockPropagations = e => {
+ console.log('unlock');
+ if (e && e.preventPropagations) {
+ console.log('stop');
+ e.preventDefault();
+ e.preventPropagations();
+ }
+
+ window.removeEventListener('mouseup', this.unlockPropagations);
+ setTimeout(() => this.lockMapClicks(false), 300);
+ };
+
+ startFrom = latlngs => {
+ this.router.setWaypoints([{ ...latlngs }]);
+ }
+}
diff --git a/src/modules/Sticker.js b/src/modules/Sticker.js
index fe7b1cc..e74e9cd 100644
--- a/src/modules/Sticker.js
+++ b/src/modules/Sticker.js
@@ -1,17 +1,18 @@
import L from 'leaflet';
import 'leaflet-editable';
-import { DomMarker } from '$utils/leafletDomMarkers';
+import { DomMarker } from '$utils/DomMarker';
export class Sticker {
constructor({
- latlng, deleteSticker, map
+ latlng, deleteSticker, map, lockMapClicks
}) {
this.angle = 2.2;
this.isDragging = false;
this.map = map;
this.deleteSticker = deleteSticker;
+ this.lockMapClicks = lockMapClicks;
this.element = document.createElement('div');
this.stickerImage = document.createElement('div');
@@ -34,14 +35,12 @@ export class Sticker {
this.sticker = L.marker(latlng, { icon: marker });
- this.stickerImage.addEventListener('mousedown', this.onDragStart);
- this.stickerImage.addEventListener('mouseup', this.onDragStop);
- this.stickerImage.addEventListener('click', this.preventPropagations);
-
- this.element.addEventListener('mousedown', this.preventPropagations);
-
this.setAngle(this.angle);
+ this.stickerImage.addEventListener('mousedown', this.onDragStart);
+ this.stickerImage.addEventListener('mouseup', this.onDragStop);
+
+ this.element.addEventListener('mouseup', this.preventPropagations);
this.stickerDelete.addEventListener('click', this.onDelete);
}
@@ -55,6 +54,8 @@ export class Sticker {
this.isDragging = true;
this.sticker.disableEdit();
+ this.lockMapClicks(true);
+
window.addEventListener('mousemove', this.onDrag);
window.addEventListener('mouseup', this.onDragStop);
};
@@ -74,6 +75,8 @@ export class Sticker {
window.removeEventListener('mousemove', this.onDrag);
window.removeEventListener('mouseup', this.onDragStop);
+
+ this.lockMapClicks(false);
};
onDrag = e => {
@@ -82,7 +85,6 @@ export class Sticker {
};
estimateAngle = e => {
- console.log('est');
const { x, y } = this.element.getBoundingClientRect();
const { pageX, pageY } = e;
this.angle = Math.atan2((y - pageY), (x - pageX));
diff --git a/src/modules/Stickers.js b/src/modules/Stickers.js
index 2edf735..e846bd8 100644
--- a/src/modules/Stickers.js
+++ b/src/modules/Stickers.js
@@ -2,10 +2,11 @@ import L from 'leaflet';
import { Sticker } from '$modules/Sticker';
export class Stickers {
- constructor({ map }) {
+ constructor({ map, lockMapClicks }) {
this.map = map;
this.layer = L.layerGroup();
+ this.lockMapClicks = lockMapClicks;
this.stickers = [];
this.layer.addTo(this.map);
@@ -23,6 +24,7 @@ export class Stickers {
latlng,
deleteSticker: this.deleteStickerByReference,
map: this.map,
+ lockMapClicks: this.lockMapClicks,
});
this.stickers.push(sticker);
diff --git a/src/styles/mapScreen.js b/src/styles/mapScreen.js
index 14a91c2..5f0cfb4 100644
--- a/src/styles/mapScreen.js
+++ b/src/styles/mapScreen.js
@@ -28,6 +28,32 @@ const vertexMixin = css`
}
`;
+const routerMixin = css`
+ .leaflet-control-container .leaflet-routing-container-hide {
+ display: none;
+ }
+
+ .router-waypoint {
+ width: 40px;
+ height: 40px;
+ margin-left: -20px;
+ margin-top: -20px;
+ outline: none;
+ z-index: 10001;
+
+ ::after {
+ content: ' ';
+ display: block;
+ width: 20px;
+ height: 20px;
+ border-radius: 10px;
+ box-shadow: 0 0 0 2px #4597d0;
+ margin-left: 10px;
+ margin-top: 10px;
+ }
+ }
+`;
+
const stickers = css`
.sticker-container {
outline: none;
@@ -132,4 +158,5 @@ export const MapScreen = styled.div.attrs({ id: 'map' })`
${vertexMixin}
${stickers}
+ ${routerMixin}
`;
diff --git a/src/utils/leafletDomMarkers.js b/src/utils/DomMarker.js
similarity index 100%
rename from src/utils/leafletDomMarkers.js
rename to src/utils/DomMarker.js