orchidmap-front/src/parts/poly.js
2018-12-20 18:51:10 +07:00

228 lines
8.1 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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;
};