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: `
`, 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: '
', 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; ix1 && xx2 && (xx2)) || (x1 === x2 && Math.abs(x-x1)>0.001) ) && ( (y1y1 && yy2 && (yy2)) || (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; };