Browse Source

거리측정 피처 이동 제한 기능 및 draw 관련 함수 작성

master
김장현 2 months ago
parent
commit
5892ad8660
  1. 5
      package-lock.json
  2. 1
      package.json
  3. 75
      src/components/map/mapbox/MapBoxMap.js
  4. 72
      src/containers/flight/OperationApprovalsContainer.js
  5. 101
      src/utility/MapUtils.js

5
package-lock.json generated

@ -14305,6 +14305,11 @@
}
}
},
"mapbox-gl-draw-waypoint": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/mapbox-gl-draw-waypoint/-/mapbox-gl-draw-waypoint-1.2.3.tgz",
"integrity": "sha512-O6vAAKjPTcTyPth0Y4DI/QDLljFitRYM5f3iGgTNNgJa/KKPd1MrqbM0h5HPQ6EfTWpUGG878dsIsMq8agOUsw=="
},
"marker-clusterer-plus": {
"version": "2.1.4",
"resolved": "https://registry.npmjs.org/marker-clusterer-plus/-/marker-clusterer-plus-2.1.4.tgz",

1
package.json

@ -60,6 +60,7 @@
"leaflet": "1.6.0",
"mapbox-gl": "^2.15.0",
"mapbox-gl-draw-circle": "1.1.2",
"mapbox-gl-draw-waypoint": "1.2.3",
"nouislider": "14.6.2",
"nouislider-react": "3.3.8",
"postcss-rtl": "1.5.0",

75
src/components/map/mapbox/MapBoxMap.js

@ -96,7 +96,7 @@ export default function MapBoxMap({ handlerDrawObjInit }) {
// 노탐 정보 모달
const [centeredModal, setCenteredModal] = useState(false);
const mouseCursorRef = useRef(null);
// 거리 측정
// 비행예상경로 geoJson 정보
const [planGeo, setPlanGeo] = useState({
@ -572,72 +572,11 @@ export default function MapBoxMap({ handlerDrawObjInit }) {
setMapLoaded(true);
});
map.on('click', e => {
console.log(drawObj.getMode());
if (drawObj.getMode() === 'draw_line_string') {
startPoint = e.lngLat;
}
});
map.on('mousemove', e => {
let distance = 0;
if (startPoint) {
// console.log(drawObj.getAll());
const feature = [];
drawObj
.getAll()
.features[0].geometry.coordinates.map(i => feature.push(i));
const obj = {
geometry: {
coordinates: [...feature],
type: 'LineString'
},
type: 'Feature'
};
distance = turf.length(obj, { units: 'kilometers' });
distance = distance * 1000;
distance = distance.toFixed(2);
mouseCursorRef.current.style.left = e.originalEvent.pageX + 'px';
mouseCursorRef.current.style.top = e.originalEvent.pageY + 45 + 'px';
mouseCursorRef.current.innerText = `${distance.toLocaleString()}m`;
// const endPoint = e.lngLat;
// const distance = calculateDistance(startPoint, endPoint);
// mouseCursorRef.current.innerText = `Distance from start point: ${distance.toFixed(
// 2
// )} meters`;
if (drawObj.getMode() === 'simple_select') {
// startPoint = null;
const box = document.getElementById('distance_box');
box.innerText = `${distance.toLocaleString()}m`;
box.style.display = 'block';
mouseCursorRef.current.style.display = 'none';
mouseCursorRef.current.style.innerText = '';
}
if (drawObj.getMode() === 'direct_select') {
const box = document.getElementById('distance_box');
box.innerText = `${distance.toLocaleString()}km`;
}
} else {
if (drawObj.getMode() === 'draw_line_string') {
mouseCursorRef.current.style.display = 'block';
mouseCursorRef.current.style.left = e.originalEvent.pageX + 'px';
mouseCursorRef.current.style.top = e.originalEvent.pageY + 45 + 'px';
mouseCursorRef.current.innerText = '시작점 선택';
}
}
});
handlerDrawObjInit(drawObj);
setMapObject(map);
dispatch(clientMapInit(map));
};
function calculateDistance(point1, point2) {
return mapboxgl.MercatorCoordinate.fromLngLat(point1).distanceTo(
mapboxgl.MercatorCoordinate.fromLngLat(point2)
);
}
return (
<>
<div
@ -645,18 +584,6 @@ export default function MapBoxMap({ handlerDrawObjInit }) {
ref={mapContainer}
style={{ width: '100%', height: '100vh' }}
></div>
<div
ref={mouseCursorRef}
style={{
position: 'absolute',
display: 'none',
background: '#8a1c05',
color: '#fff',
padding: '5px',
borderRadius: '5px',
fontWeight: 500
}}
></div>
{isMapLoaded && mapObject ? (
<>

72
src/containers/flight/OperationApprovalsContainer.js

@ -9,7 +9,8 @@ import {
flightlayerPolyline,
flightlayerPolygon,
flightlayerBuffer,
handlerStartMode
handlerStartMode,
handlerOnClickDrawLineString
} from '../../utility/MapUtils';
import { useHistory } from 'react-router-dom';
import useMapType from '@hooks/useMapType';
@ -48,6 +49,7 @@ import { X } from 'react-feather';
import mapboxgl from 'mapbox-gl';
import * as turf from '@turf/turf';
let distanceMarkers = [];
export default function OperationApprovalsContainer({ mode }) {
const dispatch = useDispatch();
const history = useHistory();
@ -62,6 +64,7 @@ export default function OperationApprovalsContainer({ mode }) {
// 비행구역 그리기
const [drawObj, setDrawObj] = useState();
const [filter, setFilter] = useState('');
const mouseCursorRef = useRef(null);
// 지도
const [mapObject, setMapObject] = useState();
@ -133,6 +136,7 @@ export default function OperationApprovalsContainer({ mode }) {
window._mapbox = map;
let mapInstance = mode === 'container' ? map : window.opener._mapbox;
setMapObject(mapInstance);
handlerOnClickDrawLineString(mapInstance, handlerDrawMarker);
}
}, [map]);
@ -462,11 +466,8 @@ export default function OperationApprovalsContainer({ mode }) {
};
const handlerDrawTypeChange = (e, val) => {
// const cursor = document.getElementById('distance_cursor');
// cursor.style.display = 'block';
// cursor.style.left = e.clientX + 'px';
// cursor.style.top = e.clientY + 45 + 'px';
// cursor.innerText = '시작점 선택';
drawObj.deleteAll();
distanceMarkers.map(i => i.remove());
dispatch(clientChangeDrawType(val));
handlerStartMode(val, drawObj);
};
@ -480,6 +481,36 @@ export default function OperationApprovalsContainer({ mode }) {
setMapType(val);
};
const handlerDistanceClose = () => {
drawObj.deleteAll();
dispatch(clientChangeDrawType(''));
document.getElementById('distance_box').style.display = 'none';
};
const handlerDrawMarker = (mapInstance, markerList, startPoint) => {
const marker = markerList.filter(i => {
return i.coord[0][0] === startPoint.lng;
});
if (marker.length > 0) {
let distanceMarker = new mapboxgl.Popup({
closeButton: false,
closeOnClick: false,
anchor: 'bottom',
focusAfterOpen: false
})
.setLngLat([
marker[0].coord[0][0].toFixed(6),
marker[0].coord[0][1].toFixed(6)
])
.setHTML(
`<div style="color:#000000;font-weight:400;">${marker[0].text}</div>`
)
.addTo(mapInstance);
distanceMarkers.push(distanceMarker);
}
};
const handlerLogout = async () => {
const { payload } = await dispatch(setLogout());
@ -493,6 +524,18 @@ export default function OperationApprovalsContainer({ mode }) {
return (
<>
<div className='map' style={{ width: '100%' }}>
<div
ref={mouseCursorRef}
style={{
position: 'absolute',
display: 'none',
background: '#8a1c05',
color: '#fff',
padding: '5px',
borderRadius: '5px',
fontWeight: 500
}}
></div>
<div className='test_modal'>
<Button
color='primary'
@ -770,10 +813,14 @@ export default function OperationApprovalsContainer({ mode }) {
</ButtonGroup>
</div>
</div>
<div className='data-box-btn-list'>
<div
id='distance_box'
className='data-box-btn-list'
style={{ display: 'none' }}
>
<h4>측정</h4>
<div className='distance-check'>
<div class='btn-box'>
<div className='btn-box'>
<Button
className='btn-icon rounded-circle'
color='primary'
@ -792,6 +839,7 @@ export default function OperationApprovalsContainer({ mode }) {
className='btn-icon rounded-circle'
color='dark'
size='sm'
onClick={handlerDistanceClose}
>
<X size={16} />
</Button>
@ -799,7 +847,13 @@ export default function OperationApprovalsContainer({ mode }) {
<div className='text'>
<p>
지도에서 지점을 클릭하여 거리를 측정하세요.
<span className='finish'> 거리 : 1050.24m</span>
<span
id='total_distance'
className='finish'
style={{ display: 'none' }}
>
거리 : 1050.24m
</span>
</p>
</div>
</div>

101
src/utility/MapUtils.js

@ -1,6 +1,7 @@
import * as turf from '@turf/turf';
import mapboxgl from 'mapbox-gl';
import MapboxDraw from '@mapbox/mapbox-gl-draw';
import * as MapboxDrawWaypoint from 'mapbox-gl-draw-waypoint';
import {
CircleMode,
DragCircleMode,
@ -477,8 +478,9 @@ export const flightlayerBuffer = source => {
// 비행구역 상세맵 draw 정보 셋팅
export const getDraw = mode => {
let drawObj = null;
if (mode === 'laanc') {
return new MapboxDraw({
drawObj = new MapboxDraw({
displayControlsDefault: false,
userProperties: true,
boxSelect: false,
@ -568,16 +570,17 @@ export const getDraw = mode => {
]
});
} else {
return new MapboxDraw({
let modes = MapboxDraw.modes;
modes = MapboxDrawWaypoint.enable(modes);
drawObj = new MapboxDraw({
displayControlsDefault: false,
userProperties: true,
boxSelect: false,
modes: {
...MapboxDraw.modes,
...modes,
draw_circle: CircleMode,
drag_circle: DragCircleMode,
direct_select: DirectMode,
simple_select: SimpleSelectMode
drag_circle: DragCircleMode
},
styles: [
{
@ -643,6 +646,7 @@ export const getDraw = mode => {
// vertex points
id: 'gl-draw-polygon-and-line-vertex-active',
type: 'circle',
filter: ['all', ['==', '$type', 'Point']],
paint: {
'circle-radius': 6,
'circle-color': '#8a1c05'
@ -651,6 +655,8 @@ export const getDraw = mode => {
]
});
}
return drawObj;
};
/**
@ -666,3 +672,86 @@ export const handlerStartMode = (mode, drawObj) => {
drawObj.changeMode('draw_circle', { initialRadiusInKm: 100 / 1000 });
}
};
export const handlerOnClickDrawLineString = (mapInstance, callback) => {
const originClickHandler = MapboxDraw.modes.draw_line_string.onClick;
const originMouseMoveHandler = MapboxDraw.modes.draw_line_string.onMouseMove;
let startPoint;
let markerList = [];
MapboxDraw.modes.draw_line_string.onClick = function (state, e) {
originClickHandler.call(this, state, e);
startPoint = e.lngLat;
state.line.coordinates.map((i, idx) => {
if (
i[0] !== state.line.coordinates[state.line.coordinates.length - 1][0]
) {
const obj = {
geometry: {
coordinates: [i, state.line.coordinates[idx + 1]],
type: 'LineString'
},
type: 'Feature'
};
let distance = turf.length(obj, { units: 'kilometers' });
distance = distance * 1000;
distance = distance.toFixed(2);
markerList.push({
text: `${distance.toLocaleString()}m`,
coord: [state.line.coordinates[idx + 1]]
});
}
});
callback(mapInstance, markerList, startPoint);
};
MapboxDraw.modes.draw_line_string.onMouseMove = function (state, e) {
originMouseMoveHandler.call(this, state, e);
let distance = 0;
console.log;
if (startPoint) {
console.log(state);
const drawGeometry = state.line.coordinates;
if (drawGeometry) {
const feature = [];
drawGeometry.map(i => feature.push(i));
const obj = {
geometry: {
coordinates: [...feature],
type: 'LineString'
},
type: 'Feature'
};
distance = turf.length(obj, { units: 'kilometers' });
distance = distance * 1000;
distance = distance.toFixed(2);
// mouseCursorRef.current.style.display = 'none';
}
// if (drawObj.getMode() === 'simple_select') {
// // startPoint = null;
// const totalDistance = document.getElementById('total_distance');
// totalDistance.style.display = 'block';
// totalDistance.innerText = `총 거리 : ${distance.toLocaleString()}m`;
// mouseCursorRef.current.style.display = 'none';
// mouseCursorRef.current.style.innerText = '';
// }
// if (drawObj.getMode() === 'direct_select') {
// distanceMarkers.map(i => i.remove());
// distanceMarkers = [];
// const totalDistance = document.getElementById('total_distance');
// totalDistance.innerText = `총 거리 : ${distance.toLocaleString()}m`;
// }
}
// else {
// if (drawObj.getMode() === 'draw_line_string') {
// document.getElementById('distance_box').style.display = 'block';
// mouseCursorRef.current.style.display = 'block';
// mouseCursorRef.current.style.left = e.originalEvent.pageX + 'px';
// mouseCursorRef.current.style.top = e.originalEvent.pageY + 45 + 'px';
// mouseCursorRef.current.innerText = '시작점 선택';
// }
// }
};
};

Loading…
Cancel
Save