mirror of
https://github.com/muerwre/orchidmap-front.git
synced 2025-04-25 19:16:41 +07:00
InteractivePoly: working marker dragging
This commit is contained in:
parent
4dfba4839d
commit
edbd911de6
6 changed files with 277 additions and 370 deletions
|
@ -358,7 +358,8 @@ export class Editor {
|
||||||
this.setInitialData();
|
this.setInitialData();
|
||||||
this.owner = { id };
|
this.owner = { id };
|
||||||
|
|
||||||
if (this.poly.latlngs && this.poly.latlngs.length > 1) this.poly.poly.editor.enable();
|
// todo: implement
|
||||||
|
// if (this.poly.latlngs && this.poly.latlngs.length > 1) this.poly.poly.editor.enable();
|
||||||
this.stickers.startEditing();
|
this.stickers.startEditing();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
191
src/modules/InteractivePoly.ts
Normal file
191
src/modules/InteractivePoly.ts
Normal file
|
@ -0,0 +1,191 @@
|
||||||
|
import { LatLngExpression, Marker, Polyline, PolylineOptions, marker, divIcon, LayerGroup, LatLng } from 'leaflet';
|
||||||
|
|
||||||
|
interface InteractivePolylineOptions extends PolylineOptions {
|
||||||
|
maxMarkers?: number,
|
||||||
|
constraintsStyle?: PolylineOptions,
|
||||||
|
}
|
||||||
|
|
||||||
|
export class InteractivePoly extends Polyline {
|
||||||
|
constructor(latlngs: LatLngExpression[] | LatLngExpression[][], options?: InteractivePolylineOptions) {
|
||||||
|
super(latlngs, options);
|
||||||
|
|
||||||
|
this.constraintsStyle = { ...this.constraintsStyle, ...options.constraintsStyle };
|
||||||
|
this.maxMarkers = options.maxMarkers || this.maxMarkers;
|
||||||
|
|
||||||
|
this.constr1 = new Polyline([], this.constraintsStyle).addTo(this.constraintsLayer);
|
||||||
|
this.constr2 = new Polyline([], this.constraintsStyle).addTo(this.constraintsLayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
setPoints = (latlngs: LatLng[]) => {
|
||||||
|
this.setLatLngs(latlngs);
|
||||||
|
this.recreateMarkers();
|
||||||
|
};
|
||||||
|
|
||||||
|
createMarker = (latlng: LatLng): Marker => marker(latlng, {
|
||||||
|
draggable: true,
|
||||||
|
icon: divIcon({
|
||||||
|
className: 'leaflet-vertex-icon',
|
||||||
|
iconSize: [11, 11],
|
||||||
|
iconAnchor: [6, 6]
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.on('drag', this.onMarkerDrag)
|
||||||
|
.on('dragstart', this.onMarkerDragStart)
|
||||||
|
.on('dragend', this.onMarkerDragEnd)
|
||||||
|
.addTo(this.markerLayer);
|
||||||
|
|
||||||
|
recreateMarkers = () => {
|
||||||
|
this.clearAllMarkers();
|
||||||
|
const latlngs = this.getLatLngs();
|
||||||
|
|
||||||
|
if (!latlngs || latlngs.length === 0) return;
|
||||||
|
|
||||||
|
latlngs.forEach(latlng => this.markers.push(this.createMarker(latlng)));
|
||||||
|
|
||||||
|
this.updateMarkers();
|
||||||
|
};
|
||||||
|
|
||||||
|
clearAllMarkers = (): void => {
|
||||||
|
this.markerLayer.clearLayers();
|
||||||
|
this.markers = [];
|
||||||
|
};
|
||||||
|
|
||||||
|
updateMarkers = (): void => {
|
||||||
|
this.showVisibleMarkers();
|
||||||
|
};
|
||||||
|
|
||||||
|
showAllMarkers = (): void => {
|
||||||
|
if (this._map.hasLayer(this.markerLayer)) return;
|
||||||
|
|
||||||
|
this._map.addLayer(this.markerLayer);
|
||||||
|
this.fire('allvertexshow');
|
||||||
|
};
|
||||||
|
|
||||||
|
hideAllMarkers = (): void => {
|
||||||
|
if (!this._map.hasLayer(this.markerLayer)) return;
|
||||||
|
|
||||||
|
this._map.removeLayer(this.markerLayer);
|
||||||
|
this.fire('allvertexhide');
|
||||||
|
};
|
||||||
|
|
||||||
|
showVisibleMarkers = (): void => {
|
||||||
|
const northEast = this._map.getBounds().getNorthEast();
|
||||||
|
const southWest = this._map.getBounds().getSouthWest();
|
||||||
|
|
||||||
|
const { visible, hidden } = this.markers.reduce((obj, marker) => {
|
||||||
|
const { lat, lng } = marker.getLatLng();
|
||||||
|
const is_hidden = (lat > northEast.lat || lng > northEast.lng || lat < southWest.lat || lng < southWest.lng);
|
||||||
|
|
||||||
|
return is_hidden
|
||||||
|
? { ...obj, hidden: [...obj.hidden, marker] }
|
||||||
|
: { ...obj, visible: [...obj.visible, marker] }
|
||||||
|
|
||||||
|
},
|
||||||
|
{ visible: [], hidden: [] }
|
||||||
|
);
|
||||||
|
|
||||||
|
if (visible.length > this.maxMarkers) return this.hideAllMarkers();
|
||||||
|
|
||||||
|
this.showAllMarkers();
|
||||||
|
|
||||||
|
visible.forEach(marker => {
|
||||||
|
if (!this.markerLayer.hasLayer(marker)) this.markerLayer.addLayer(marker);
|
||||||
|
});
|
||||||
|
|
||||||
|
hidden.forEach(marker => {
|
||||||
|
if (this.markerLayer.hasLayer(marker)) this.markerLayer.removeLayer(marker);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
editor = {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
onMarkerDrag = ({ target }: { target: Marker}) => {
|
||||||
|
console.log(this.vertex_index, this.markers.length);
|
||||||
|
|
||||||
|
this.setConstraints(
|
||||||
|
this.vertex_index > 0 && this.markers[this.vertex_index - 1].getLatLng(),
|
||||||
|
target.getLatLng(),
|
||||||
|
this.vertex_index < (this.markers.length - 1) && this.markers[this.vertex_index + 1].getLatLng(),
|
||||||
|
);
|
||||||
|
|
||||||
|
this.fire('vertexdrag', { index: this.vertex_index, vertex: target });
|
||||||
|
};
|
||||||
|
|
||||||
|
onMarkerDragStart = ({ target }: { target: Marker}) => {
|
||||||
|
this.vertex_index = this.markers.indexOf(target);
|
||||||
|
|
||||||
|
this.is_dragging = true;
|
||||||
|
this.constraintsLayer.addTo(this._map);
|
||||||
|
|
||||||
|
this.fire('vertexdragstart', { index: this.vertex_index, vertex: target });
|
||||||
|
};
|
||||||
|
|
||||||
|
onMarkerDragEnd = ({ target }: { target: Marker}): void => {
|
||||||
|
this.replaceLatlng(target.getLatLng(), this.vertex_index);
|
||||||
|
|
||||||
|
this.is_dragging = false;
|
||||||
|
this.constraintsLayer.removeFrom(this._map);
|
||||||
|
|
||||||
|
this.fire('vertexdragend', { index: this.vertex_index, vertex: target });
|
||||||
|
this.vertex_index = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
replaceLatlng = (latlng: LatLng, index: number): void => {
|
||||||
|
const latlngs = this.getLatLngs();
|
||||||
|
latlngs.splice(index, 1, latlng);
|
||||||
|
this.setLatLngs(latlngs);
|
||||||
|
};
|
||||||
|
|
||||||
|
setConstraints = (prev?: LatLng, marker?: LatLng, next?: LatLng) => {
|
||||||
|
if (prev) this.constr1.setLatLngs([prev, marker]);
|
||||||
|
if (next) this.constr2.setLatLngs([next, marker]);
|
||||||
|
};
|
||||||
|
|
||||||
|
markers: Marker[] = [];
|
||||||
|
maxMarkers: InteractivePolylineOptions['maxMarkers'] = 2;
|
||||||
|
markerLayer: LayerGroup = new LayerGroup();
|
||||||
|
constraintsLayer: LayerGroup = new LayerGroup();
|
||||||
|
constraintsStyle: InteractivePolylineOptions['constraintsStyle'] = {
|
||||||
|
weight: 6,
|
||||||
|
color: 'red',
|
||||||
|
dashArray: '2, 10',
|
||||||
|
opacity: 0.5,
|
||||||
|
};
|
||||||
|
|
||||||
|
constr1: Polyline;
|
||||||
|
constr2: Polyline;
|
||||||
|
|
||||||
|
is_dragging: boolean = false;
|
||||||
|
vertex_index?: number = null;
|
||||||
|
markers_visible: boolean = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
InteractivePoly.addInitHook(function () {
|
||||||
|
this.once('add', (event) => {
|
||||||
|
if (event.target instanceof InteractivePoly) {
|
||||||
|
this.map = event.target._map;
|
||||||
|
this.markerLayer.addTo(event.target._map);
|
||||||
|
|
||||||
|
this.map.on('moveend', this.updateMarkers);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.once('remove', () => {
|
||||||
|
if (event.target instanceof InteractivePoly) {
|
||||||
|
this.markerLayer.removeFrom(this.map);
|
||||||
|
this.map.off('moveend', this.updateMarkers);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
events:
|
||||||
|
vertexdragstart,
|
||||||
|
vertexdragend,
|
||||||
|
vertexdrag,
|
||||||
|
|
||||||
|
allvertexhide
|
||||||
|
allvertexshow
|
||||||
|
*/
|
|
@ -1,12 +1,12 @@
|
||||||
import { Map, LayerGroup } from 'leaflet';
|
import { Map, LayerGroup, Polyline } from 'leaflet';
|
||||||
import 'leaflet-geometryutil';
|
|
||||||
import { EditablePolyline } from '$utils/EditablePolyline';
|
import { EditablePolyline } from '$utils/EditablePolyline';
|
||||||
import { simplify } from '$utils/simplify';
|
import { simplify } from '$utils/simplify';
|
||||||
import { findDistance, middleCoord } from '$utils/geom';
|
import { findDistance, getPolyLength, middleCoord } from '$utils/geom';
|
||||||
import { CLIENT } from '$config/frontend';
|
import { CLIENT } from '$config/frontend';
|
||||||
import { MODES } from '$constants/modes';
|
import { MODES } from '$constants/modes';
|
||||||
import { editor, Editor } from "$modules/Editor";
|
import { editor, Editor } from "$modules/Editor";
|
||||||
import { ILatLng } from "$modules/Stickers";
|
import { ILatLng } from "$modules/Stickers";
|
||||||
|
import { InteractivePoly } from "$modules/InteractivePoly";
|
||||||
|
|
||||||
const polyStyle = {
|
const polyStyle = {
|
||||||
color: 'url(#activePathGradient)',
|
color: 'url(#activePathGradient)',
|
||||||
|
@ -27,22 +27,28 @@ export class Poly {
|
||||||
constructor({
|
constructor({
|
||||||
map, routerMoveStart, lockMapClicks, setDistance, triggerOnChange, editor,
|
map, routerMoveStart, lockMapClicks, setDistance, triggerOnChange, editor,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
this.poly = new EditablePolyline([], {
|
this.poly = new InteractivePoly([], {
|
||||||
...polyStyle,
|
color: 'url(#activePathGradient)',
|
||||||
maxMarkers: 100,
|
weight: 6,
|
||||||
|
maxMarkers: 300,
|
||||||
onPointsSet: this.updateMarks,
|
});
|
||||||
onMarkerDragEnd: this.updateMarks,
|
// this.poly = new EditablePolyline([], {
|
||||||
onPointAdded: this.updateMarks,
|
// ...polyStyle,
|
||||||
onPointDropped: this.updateMarks,
|
// maxMarkers: 100,
|
||||||
onContinueDrawing: this.setModeOnDrawing,
|
//
|
||||||
|
// onPointsSet: this.updateMarks,
|
||||||
onMarkersHide: () => editor.setMarkersShown(false),
|
// onMarkerDragEnd: this.updateMarks,
|
||||||
onMarkersShow: () => editor.setMarkersShown(true),
|
// onPointAdded: this.updateMarks,
|
||||||
}).addTo(map);
|
// onPointDropped: this.updateMarks,
|
||||||
|
// onContinueDrawing: this.setModeOnDrawing,
|
||||||
|
//
|
||||||
|
// onMarkersHide: () => editor.setMarkersShown(false),
|
||||||
|
// onMarkersShow: () => editor.setMarkersShown(true),
|
||||||
|
// }).addTo(map);
|
||||||
|
|
||||||
this.poly.addTo(map);
|
this.poly.addTo(map);
|
||||||
this.poly._reloadPolyline();
|
// todo: uncomment
|
||||||
|
// this.poly._reloadPolyline();
|
||||||
this.editor = editor;
|
this.editor = editor;
|
||||||
|
|
||||||
this.map = map;
|
this.map = map;
|
||||||
|
@ -61,45 +67,46 @@ export class Poly {
|
||||||
|
|
||||||
drawArrows = () => {
|
drawArrows = () => {
|
||||||
// todo: fix this
|
// todo: fix this
|
||||||
// this.arrows.clearLayers();
|
this.arrows.clearLayers();
|
||||||
// const { latlngs } = this;
|
const { latlngs } = this;
|
||||||
//
|
|
||||||
// if (!latlngs || latlngs.length <= 1) return;
|
if (!latlngs || latlngs.length <= 1) return;
|
||||||
//
|
|
||||||
// latlngs.forEach((latlng, i) => {
|
latlngs.forEach((latlng, i) => {
|
||||||
// if (i === 0) return;
|
if (i === 0) return;
|
||||||
//
|
|
||||||
// const mid = middleCoord(latlngs[i], latlngs[i - 1]);
|
const mid = middleCoord(latlngs[i], latlngs[i - 1]);
|
||||||
// const dist = findDistance(latlngs[i - 1].lat, latlngs[i - 1].lng, latlngs[i].lat, latlngs[i].lng);
|
const dist = findDistance(latlngs[i - 1].lat, latlngs[i - 1].lng, latlngs[i].lat, latlngs[i].lng);
|
||||||
//
|
|
||||||
// if (dist <= 1) return;
|
if (dist <= 1) return;
|
||||||
//
|
|
||||||
// const slide = new Polyline(
|
const slide = new Polyline(
|
||||||
// [
|
[
|
||||||
// latlngs[i - 1],
|
latlngs[i - 1],
|
||||||
// [mid.lat, mid.lng]
|
[mid.lat, mid.lng]
|
||||||
// ],
|
],
|
||||||
// { color: 'none', weight: CLIENT.STROKE_WIDTH }
|
{ color: 'none', weight: CLIENT.STROKE_WIDTH }
|
||||||
// ).addTo(this.arrows);
|
).addTo(this.arrows) as any;
|
||||||
//
|
|
||||||
// // todo: uncomment and fix this:
|
// todo: uncomment and fix this:
|
||||||
// // slide._path.setAttribute('marker-end', 'url(#long-arrow)');
|
slide._path.setAttribute('marker-end', 'url(#long-arrow)');
|
||||||
// });
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
updateMarks = () => {
|
updateMarks = () => {
|
||||||
// todo: fix this
|
const coords = this.poly.toGeoJSON().geometry.coordinates;
|
||||||
// const coords = this.poly.toGeoJSON().geometry.coordinates;
|
|
||||||
//
|
// const meters = (this.latlngs && this.latlngs.length > 1 && getPolyLength(this.latlngs)) || 0;
|
||||||
// const meters = (this.poly && (L.GeometryUtil.length(this.poly) / 1000)) || 0;
|
// const kilometers = (meters && Number(meters.toFixed(1))) || 0;
|
||||||
// const kilometers = (meters && meters.toFixed(1)) || 0;
|
|
||||||
//
|
const kilometers = ((this.latlngs && this.latlngs.length > 1 && getPolyLength(this.latlngs)) || 0);
|
||||||
// this.setTotalDist(kilometers);
|
|
||||||
// this.routerMoveStart();
|
this.setDistance(parseFloat(kilometers.toFixed(2)));
|
||||||
//
|
this.routerMoveStart();
|
||||||
// this.drawArrows(); // <-- uncomment
|
|
||||||
//
|
this.drawArrows(); // <-- uncomment
|
||||||
// if (coords.length > 1) this.triggerOnChange();
|
|
||||||
|
if (coords.length > 1) this.triggerOnChange();
|
||||||
};
|
};
|
||||||
|
|
||||||
preventMissClicks = (e): void => {
|
preventMissClicks = (e): void => {
|
||||||
|
@ -113,15 +120,18 @@ export class Poly {
|
||||||
};
|
};
|
||||||
|
|
||||||
continue = (): void => {
|
continue = (): void => {
|
||||||
this.poly.editor.continueForward();
|
// todo: implement
|
||||||
|
// this.poly.editor.continueForward();
|
||||||
};
|
};
|
||||||
|
|
||||||
stop = (): void => {
|
stop = (): void => {
|
||||||
if (this.poly) this.poly.editor.stopDrawing();
|
// todo: implement
|
||||||
|
// if (this.poly) this.poly.editor.stopDrawing();
|
||||||
};
|
};
|
||||||
|
|
||||||
continueForward = (): void => {
|
continueForward = (): void => {
|
||||||
this.poly.continueForward();
|
// todo: implement
|
||||||
|
// this.poly.continueForward();
|
||||||
};
|
};
|
||||||
|
|
||||||
lockMap = (): void => {
|
lockMap = (): void => {
|
||||||
|
@ -129,7 +139,10 @@ export class Poly {
|
||||||
};
|
};
|
||||||
|
|
||||||
setPoints = (latlngs: Array<ILatLng>): void => {
|
setPoints = (latlngs: Array<ILatLng>): void => {
|
||||||
|
console.log('setP');
|
||||||
|
|
||||||
if (!latlngs || latlngs.length <= 1) return;
|
if (!latlngs || latlngs.length <= 1) return;
|
||||||
|
// todo: implement
|
||||||
this.poly.setPoints(latlngs);
|
this.poly.setPoints(latlngs);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -141,15 +154,15 @@ export class Poly {
|
||||||
...simplified,
|
...simplified,
|
||||||
];
|
];
|
||||||
|
|
||||||
this.poly.setLatLngs(summary);
|
this.poly.setPoints(summary);
|
||||||
this.poly.editor.enable();
|
|
||||||
this.poly.editor.reset();
|
|
||||||
this.updateMarks();
|
this.updateMarks();
|
||||||
};
|
};
|
||||||
|
|
||||||
clearAll = (): void => {
|
clearAll = (): void => {
|
||||||
// this.poly.setLatLngs([]);
|
// this.poly.setLatLngs([]);
|
||||||
this.poly.editor.clear();
|
// todo: implement
|
||||||
|
// this.poly.editor.clear();
|
||||||
|
this.poly.setPoints([]);
|
||||||
this.updateMarks();
|
this.updateMarks();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,81 +0,0 @@
|
||||||
import L from 'leaflet';
|
|
||||||
|
|
||||||
// import 'leaflet-editable';
|
|
||||||
// import 'leaflet.markercluster';
|
|
||||||
// import 'leaflet.markercluster.webpack';
|
|
||||||
import 'leaflet-geometryutil';
|
|
||||||
|
|
||||||
import { mapStyles } from '$constants/mapStyles';
|
|
||||||
|
|
||||||
import { stickers } from '$constants/stickers';
|
|
||||||
|
|
||||||
import { updateMarks } from '$utils/updater';
|
|
||||||
import { bindPolyEvents, preparePoly } from '$utils/poly';
|
|
||||||
|
|
||||||
// В этой штуке мы храним точки и выноски, их связки и всё такое
|
|
||||||
const point_array = {
|
|
||||||
points: L.layerGroup(),
|
|
||||||
vectors: L.layerGroup(),
|
|
||||||
handles: L.layerGroup(),
|
|
||||||
pairs: {},
|
|
||||||
point_to_id: {},
|
|
||||||
id_to_point: {},
|
|
||||||
savedata: {}
|
|
||||||
};
|
|
||||||
|
|
||||||
const points = L.layerGroup();
|
|
||||||
|
|
||||||
// let mode = 'none';
|
|
||||||
const current_map_style = 'dgis';
|
|
||||||
|
|
||||||
// Интересные места;
|
|
||||||
// const places_layer;
|
|
||||||
|
|
||||||
export const map = L.map('map', {
|
|
||||||
editable: true,
|
|
||||||
layers: [points, point_array.points, point_array.vectors, stickers.layers]
|
|
||||||
}).setView([55.0153275, 82.9071235], 13);
|
|
||||||
|
|
||||||
map.editTools.skipMiddleMarkers = true;
|
|
||||||
|
|
||||||
// Слой с интересными местами
|
|
||||||
// const places_layer = L.markerClusterGroup({maxClusterRadius: 20});
|
|
||||||
|
|
||||||
// const poly = preparePoly(map); // начинаем новую полилинию
|
|
||||||
|
|
||||||
// const updateOverlays = () => updateMarks({ map, poly, km_marks });
|
|
||||||
const updateOverlays = e => console.log();
|
|
||||||
|
|
||||||
const prepareMapLayer = provider => {
|
|
||||||
L.tileLayer(provider, {
|
|
||||||
attribution: 'Независимое Велосообщество',
|
|
||||||
maxNativeZoom: 18,
|
|
||||||
maxZoom: 18,
|
|
||||||
// minZoom: 11
|
|
||||||
}).addTo(map);
|
|
||||||
};
|
|
||||||
|
|
||||||
const bindMapEvents = () => {
|
|
||||||
// при масштабировании карты масштабировать стрелки
|
|
||||||
// map.on('zoom', function (e) {
|
|
||||||
// $('.arr_mark > div').css('transform', 'scale(' + (map.getZoom()/13) + ')');
|
|
||||||
// });
|
|
||||||
|
|
||||||
map.on('click', updateOverlays);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const setMode = variant => {
|
|
||||||
mode = variant;
|
|
||||||
};
|
|
||||||
|
|
||||||
// prepareMap();
|
|
||||||
|
|
||||||
export const prepareMap = () => {
|
|
||||||
// Эта функция создаёт саму карту и наносит на неё маршруты в самом начале работы
|
|
||||||
// создаём объект с картой
|
|
||||||
map.doubleClickZoom.disable();
|
|
||||||
prepareMapLayer(mapStyles[current_map_style]);
|
|
||||||
|
|
||||||
bindMapEvents();
|
|
||||||
// bindPolyEvents({ poly, map, updateOverlays, clearKmMarks });
|
|
||||||
};
|
|
|
@ -1,228 +0,0 @@
|
||||||
import L from "leaflet";
|
|
||||||
import { map } from "$utils/map";
|
|
||||||
import { findDistance, middle_latlng } from "../js/common";
|
|
||||||
|
|
||||||
let poly = null;
|
|
||||||
export const km_marks = L.layerGroup();
|
|
||||||
|
|
||||||
// const updateOverlays = () => updateMarks({ map, poly, km_marks });
|
|
||||||
|
|
||||||
const getRouteArray = poly => poly.toGeoJSON().geometry.coordinates;
|
|
||||||
|
|
||||||
|
|
||||||
export const writeReduxData = ({ e, updatePolyCoords }) => {
|
|
||||||
const route = getRouteArray(poly);
|
|
||||||
const latlngs = route.map(([lng, lat]) => ({lat, lng}));
|
|
||||||
|
|
||||||
updatePolyCoords({ latlngs });
|
|
||||||
};
|
|
||||||
|
|
||||||
const endMarker = ({ end_latlng, length }) => L.marker(
|
|
||||||
[end_latlng[1], end_latlng[0]],
|
|
||||||
{
|
|
||||||
icon: L.divIcon(
|
|
||||||
{
|
|
||||||
html: `${length} км`,
|
|
||||||
className: 'end_mark'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const startMarker = ({ start_latlng, map }) => L.marker(
|
|
||||||
[start_latlng[1], start_latlng[0]],
|
|
||||||
{
|
|
||||||
icon: L.divIcon({
|
|
||||||
html: `<div style="transform: scale(${(map.getZoom() / 13)});"><div class="arr_start"></div></div>`,
|
|
||||||
className: 'arr_mark'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
export const updateMarks = () => {
|
|
||||||
km_marks.clearLayers();
|
|
||||||
const route = getRouteArray(poly);
|
|
||||||
const latlngs = poly.getLatLngs();
|
|
||||||
let start_latlng;
|
|
||||||
let end_latlng;
|
|
||||||
let i;
|
|
||||||
let rotation;
|
|
||||||
let middle;
|
|
||||||
let distance;
|
|
||||||
|
|
||||||
if (route.length > 0) {
|
|
||||||
start_latlng = route[0];
|
|
||||||
end_latlng = route[route.length - 1];
|
|
||||||
km_marks.addLayer(startMarker({ start_latlng, map }));
|
|
||||||
if (route.length > 1) {
|
|
||||||
const segs = L.GeometryUtil.accumulatedLengths(poly);
|
|
||||||
const length = Math.round(segs[segs.length - 1] / 1000);
|
|
||||||
// end mark
|
|
||||||
km_marks.addLayer(endMarker({ end_latlng, length }));
|
|
||||||
|
|
||||||
//and also length to panel:
|
|
||||||
// $('#text_route_length').text(length + 'км');
|
|
||||||
|
|
||||||
for (i = 1; i < latlngs.length; i += 1) {
|
|
||||||
rotation = L.GeometryUtil.bearing(latlngs[i - 1], latlngs[i]);
|
|
||||||
middle = middle_latlng(latlngs[i], latlngs[i - 1]);
|
|
||||||
distance = findDistance(latlngs[i - 1].lat, latlngs[i - 1].lng, latlngs[i].lat, latlngs[i].lng);
|
|
||||||
|
|
||||||
if (distance > 1) {
|
|
||||||
km_marks.addLayer(L.marker([middle.lat, middle.lng], { icon: L.divIcon({ html: '<div style="transform: scale(' + (map.getZoom() / 13) + ');"><img src="misc/arr.png" style="transform: translateX(-4px) translateY(-4px) rotate(' + (270 + rotation) + 'deg);"></div>', className: 'arr_mark' }) }));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// $('#text_route_length').text('0 км');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// updatePolyCoords({ latlngs: route });
|
|
||||||
// local_store_data();
|
|
||||||
};
|
|
||||||
|
|
||||||
const clearKmMarks = () => km_marks.clearLayers();
|
|
||||||
|
|
||||||
const insertVertex = ({ e, updatePolyCoords }) => {
|
|
||||||
// Добавляет редактирующую ручку по щелчку
|
|
||||||
// если щелчок по кривой, а не по ручке И если ломаная в режиме редактирования. Иначе - перейти к редактированию
|
|
||||||
if (e.originalEvent.target.tagName === 'path' && poly.editor._enabled) {
|
|
||||||
// если щелкнуть по кривой во время редактирования, editable не должно рисовать новую точку
|
|
||||||
if (e.type === 'editable:drawing:click') e.cancel();
|
|
||||||
|
|
||||||
let latlngs = poly.getLatLngs(); // набор точек ломанной
|
|
||||||
let best = 10000;
|
|
||||||
let pos = []; // переменные для определения принадлежности точки отрезку на ломанной
|
|
||||||
|
|
||||||
for(let i=0; i<latlngs.length-1; i++) {
|
|
||||||
// Дальше определяем, лежит ли точка на отрезке ломаной перебором этих отрезков
|
|
||||||
const x = e.latlng['lat'];
|
|
||||||
const x1 = latlngs[i]['lat'];
|
|
||||||
const x2 = latlngs[i+1]['lat'];
|
|
||||||
const y = e.latlng['lng'];
|
|
||||||
const y1 = latlngs[i]['lng'];
|
|
||||||
const y2 = latlngs[i+1]['lng'];
|
|
||||||
|
|
||||||
// эта странная конструкция определяет, лежит ли вообще точка между двумя соседями на отрезке
|
|
||||||
if ((
|
|
||||||
(x1<x2 && (x>x1 && x<x2))
|
|
||||||
||
|
|
||||||
(x1>x2 && (x<x1 && x>x2))
|
|
||||||
||
|
|
||||||
(x1 === x2 && Math.abs(x-x1)>0.001)
|
|
||||||
) && (
|
|
||||||
(y1<y2 && (y>y1 && y<y2))
|
|
||||||
||
|
|
||||||
(y1>y2 && (y<y1 && y>y2))
|
|
||||||
||
|
|
||||||
(y1 === y2 && Math.abs(y-y1)>0.001)
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
// если да, то проверяем, далеко ли точка от самого отрезка между двумя точками
|
|
||||||
let dx1 = x2 - x1;
|
|
||||||
let dy1 = y2 - y1;
|
|
||||||
let dx = x - x1;
|
|
||||||
let dy = y - y1;
|
|
||||||
let result = Math.abs((dx1 * dy) - (dx * dy1));
|
|
||||||
if (result < best) {
|
|
||||||
// это - не очень-то точная функция. Но по клику она определяет, по какому отрезку мы кликнули
|
|
||||||
best = result;
|
|
||||||
pos = [i, i+1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// если точка найдена, добавляем её в отрезок
|
|
||||||
if (pos.length>1) {
|
|
||||||
// poly.editor.disable();
|
|
||||||
latlngs.splice(pos[1],0,e.latlng);
|
|
||||||
poly.setLatLngs(latlngs);
|
|
||||||
poly.editor.initVertexMarkers();
|
|
||||||
poly.editor.enable();
|
|
||||||
poly.editor.continueForward();
|
|
||||||
|
|
||||||
writeReduxData({ e, updatePolyCoords });
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Рисование! Очистим буфер отмен :-)
|
|
||||||
// redoBuffer = [];
|
|
||||||
// если ломаная не в режиме редактирования или если мы, всё-таки, кликнули по ручке, просто активируем редактор
|
|
||||||
// route_state('active');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const bindPolyEvents = ({ updatePolyCoords }) => {
|
|
||||||
// Если на карте что-то меняется, пересчитать километражи
|
|
||||||
map.editTools.addEventListener('editable:drawing:mouseup', updateMarks);
|
|
||||||
map.editTools.addEventListener('editable:vertex:dragend', updateMarks);
|
|
||||||
|
|
||||||
map.editTools.addEventListener('editable:vertex:dragend', e => writeReduxData({ e, updatePolyCoords }));
|
|
||||||
map.editTools.addEventListener('editable:vertex:new', e => writeReduxData({ e, updatePolyCoords }));
|
|
||||||
map.editTools.addEventListener('editable:vertex:deleted', e => writeReduxData({ e, updatePolyCoords }));
|
|
||||||
|
|
||||||
// Продолжить рисование после удаления точки
|
|
||||||
map.editTools.addEventListener('editable:vertex:deleted', e => {
|
|
||||||
poly.editor.continueForward();
|
|
||||||
updateMarks();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Добавлять точек в полилинию по щелчку
|
|
||||||
map.editTools.addEventListener('editable:drawing:click', e => insertVertex({ e, updatePolyCoords }));
|
|
||||||
map.editTools.addEventListener('editable:drawing:clicked', () => updateMarks({ updatePolyCoords }));
|
|
||||||
|
|
||||||
// Это для точек. При перетаскивании конца указателя тащим точку
|
|
||||||
// map.editTools.addEventListener('editable:vertex:drag', on_vertex_drag);
|
|
||||||
|
|
||||||
// при перетаскивании ручек убирать все отметки километров
|
|
||||||
map.editTools.addEventListener('editable:vertex:dragstart', clearKmMarks);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const updatePoly = (latlngs) => {
|
|
||||||
// const route = latlngs.map(([lat, lng]) => new L.latLng(lat, lng));
|
|
||||||
if (!latlngs || latlngs.length < 2) return;
|
|
||||||
|
|
||||||
poly.setLatLngs(createLatLngs(latlngs));
|
|
||||||
poly.addTo(map);
|
|
||||||
poly.setStyle({ color: '#ff3333', weight: '5' });
|
|
||||||
poly.editor.options.skipMiddleMarkers = true;
|
|
||||||
poly.editor.disable().enable();
|
|
||||||
poly.editor.continueForward();
|
|
||||||
//
|
|
||||||
};
|
|
||||||
|
|
||||||
export const createLatLngs = latlngs => latlngs.map(({ lat, lng }) => new L.LatLng(lat, lng));
|
|
||||||
|
|
||||||
const createPoly = () => {
|
|
||||||
const result = map.editTools.startPolyline();
|
|
||||||
|
|
||||||
result.editor.enable();
|
|
||||||
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
const restorePoly = latlngs => {
|
|
||||||
const result = L.polyline(createLatLngs(latlngs), { color: 'red' }).addTo(map);
|
|
||||||
|
|
||||||
result.enableEdit().continueForward();
|
|
||||||
result.editor.options.skipMiddleMarkers = true;
|
|
||||||
|
|
||||||
result.editor.reset();
|
|
||||||
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const preparePoly = ({ updatePolyCoords, latlngs }) => {
|
|
||||||
map.addLayer(km_marks);
|
|
||||||
|
|
||||||
poly = (latlngs && latlngs.length)
|
|
||||||
? restorePoly(latlngs)
|
|
||||||
: createPoly();
|
|
||||||
|
|
||||||
updateMarks();
|
|
||||||
|
|
||||||
poly.setStyle({ color: '#ff3333', weight: '5' });
|
|
||||||
|
|
||||||
bindPolyEvents({ updatePolyCoords });
|
|
||||||
|
|
||||||
return poly;
|
|
||||||
};
|
|
||||||
|
|
|
@ -34,3 +34,14 @@ export const findDistance = (t1: number, n1: number, t2: number, n2: number): nu
|
||||||
export const getLabelDirection = (angle: number): 'left' | 'right' => (
|
export const getLabelDirection = (angle: number): 'left' | 'right' => (
|
||||||
((angle % Math.PI) >= -(Math.PI / 2) && (angle % Math.PI) <= (Math.PI / 2)) ? 'left' : 'right'
|
((angle % Math.PI) >= -(Math.PI / 2) && (angle % Math.PI) <= (Math.PI / 2)) ? 'left' : 'right'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// export const getPolyLength = (latlngs: ILatLng[]): number => latlngs.reduce((distance, latlng, i) => (
|
||||||
|
// i < latlngs.length
|
||||||
|
// ? distance + findDistance(latlng.lat, latlng.lng, latlngs[i + 1].lat, latlngs[i + 1].lng)
|
||||||
|
// : distance
|
||||||
|
// ), 0);
|
||||||
|
export const getPolyLength = (latlngs: ILatLng[]): number => {
|
||||||
|
console.log('latlngs', latlngs);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue