mirror of
https://github.com/muerwre/orchidmap-front.git
synced 2025-04-25 02:56:41 +07:00
228 lines
8.1 KiB
JavaScript
228 lines
8.1 KiB
JavaScript
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;
|
||
};
|
||
|