Browse Source

거리측정 되돌리기 기능 작업 중간커밋

master
김장현 2 months ago
parent
commit
31a85a867c
  1. 59
      src/components/map/mapbox/MapBoxMap.js
  2. 74
      src/components/map/mapbox/feature/FeatureAirZone.js
  3. 121
      src/containers/flight/OperationApprovalsContainer.js
  4. 157
      src/utility/MapUtils.js

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

@ -95,7 +95,7 @@ export default function MapBoxMap({ handlerDrawObjInit }) {
// 노탐 정보 모달 // 노탐 정보 모달
const [centeredModal, setCenteredModal] = useState(false); const [centeredModal, setCenteredModal] = useState(false);
let popup;
// 거리 측정 // 거리 측정
// 비행예상경로 geoJson 정보 // 비행예상경로 geoJson 정보
@ -419,7 +419,6 @@ export default function MapBoxMap({ handlerDrawObjInit }) {
type: 'custom', type: 'custom',
renderingMode: '3d', renderingMode: '3d',
onAdd: function () { onAdd: function () {
console.log(mapState.mapType);
for (let i = 0; i < gimPo.features.length; i++) { for (let i = 0; i < gimPo.features.length; i++) {
let line; let line;
const options = { const options = {
@ -572,11 +571,65 @@ export default function MapBoxMap({ handlerDrawObjInit }) {
setMapLoaded(true); setMapLoaded(true);
}); });
handlerDrawObjInit(drawObj); map.on('click', 'maine', e => {
let isMaine = false;
let isOperation = false;
map.queryRenderedFeatures(e.point).map(feature => {
if (feature.source === 'operationLayer') isOperation = true;
if (feature.source === 'maine') isMaine = true;
});
if (isMaine && !isOperation) {
map.getCanvas().style.cursor = 'pointer';
const feature = e.features[0];
const data = feature.properties;
data.coord = e.lngLat;
data.title = feature.properties.name;
infowindowOpen(data, map);
}
});
handlerDrawObjInit(drawObj, map);
setMapObject(map); setMapObject(map);
dispatch(clientMapInit(map)); dispatch(clientMapInit(map));
}; };
const infowindowOpen = (data, map) => {
const content =
'<div class="tooltip-box">' +
'<div class="tooltip-txt">' +
'<span>' +
data.title +
'</span>' +
'</div>' +
// '<div class="tooltip-txt">' +
// '<div class="tooltip-txt-list">' +
// '<span>' +
// data.description +
// '</span>' +
// '</div>' +
// '</div>' +
'</div>';
if (popup) {
popup.remove();
}
// Create a popup element
popup = new mapboxgl.Popup({
offset: [0, 0],
closeButton: false,
closeOnClick: true,
closeOnMove: false
})
.setLngLat(data.coord)
.setHTML(content)
.addTo(map);
};
return ( return (
<> <>
<div <div

74
src/components/map/mapbox/feature/FeatureAirZone.js

@ -95,26 +95,26 @@ export default function FeatureAirZone(props) {
}); });
}); });
props.map.on('click', 'maine', e => { // props.map.on('click', 'maine', e => {
let isMaine = false; // let isMaine = false;
let isOperation = false; // let isOperation = false;
props.map.queryRenderedFeatures(e.point).map(feature => { // props.map.queryRenderedFeatures(e.point).map(feature => {
if (feature.source === 'operationLayer') isOperation = true; // if (feature.source === 'operationLayer') isOperation = true;
if (feature.source === 'maine') isMaine = true; // if (feature.source === 'maine') isMaine = true;
}); // });
if (isMaine && !isOperation) { // if (isMaine && !isOperation) {
props.map.getCanvas().style.cursor = 'pointer'; // props.map.getCanvas().style.cursor = 'pointer';
const feature = e.features[0]; // const feature = e.features[0];
const data = feature.properties; // const data = feature.properties;
data.coord = e.lngLat; // data.coord = e.lngLat;
data.title = feature.properties.name; // data.title = feature.properties.name;
infowindowOpen(data); // infowindowOpen(data);
} // }
}); // });
// props.map.on('mouseover', 'maine', e => { // props.map.on('mouseover', 'maine', e => {
// props.map.getCanvas().style.cursor = 'pointer'; // props.map.getCanvas().style.cursor = 'pointer';
@ -133,27 +133,27 @@ export default function FeatureAirZone(props) {
// } // }
// }); // });
const buildingsLayer = props.map.getLayer('add-3d-buildings'); // const buildingsLayer = props.map.getLayer('add-3d-buildings');
if (buildingsLayer) { // if (buildingsLayer) {
props.map.on('click', e => { // props.map.on('click', e => {
// 클릭한 지점의 피처들을 얻어옵니다. // // 클릭한 지점의 피처들을 얻어옵니다.
const features = props.map.queryRenderedFeatures(e.point, { // const features = props.map.queryRenderedFeatures(e.point, {
layers: ['add-3d-buildings'] // 빌딩 레이어의 ID를 지정합니다. // layers: ['add-3d-buildings'] // 빌딩 레이어의 ID를 지정합니다.
}); // });
// 빌딩 피처가 있는 경우 // // 빌딩 피처가 있는 경우
if (features.length > 0) { // if (features.length > 0) {
// 첫 번째 빌딩 피처의 높이 값을 얻어옵니다. // // 첫 번째 빌딩 피처의 높이 값을 얻어옵니다.
const height = features[0].properties.height; // const height = features[0].properties.height;
// 팝업을 생성하고 지도에 추가합니다. // // 팝업을 생성하고 지도에 추가합니다.
new props.mapboxgl.Popup() // new props.mapboxgl.Popup()
.setLngLat(e.lngLat) // .setLngLat(e.lngLat)
.setHTML(`Building height: ${height}m`) // .setHTML(`Building height: ${height}m`)
.addTo(props.map); // .addTo(props.map);
} // }
}); // });
} // }
}; };
// 이착륙장 마커 이벤트 로직 // 이착륙장 마커 이벤트 로직

121
src/containers/flight/OperationApprovalsContainer.js

@ -62,7 +62,6 @@ export default function OperationApprovalsContainer({ mode }) {
// 비행구역 그리기 // 비행구역 그리기
const [drawObj, setDrawObj] = useState(); const [drawObj, setDrawObj] = useState();
const [filter, setFilter] = useState(''); const [filter, setFilter] = useState('');
const mouseCursorRef = useRef(null);
// 지도 // 지도
const [mapObject, setMapObject] = useState(); const [mapObject, setMapObject] = useState();
@ -95,6 +94,12 @@ export default function OperationApprovalsContainer({ mode }) {
// 비행구역 데이터블록 // 비행구역 데이터블록
const [dataBlocks, setDataBlocks] = useState([]); const [dataBlocks, setDataBlocks] = useState([]);
// 거리측정
const [isDistanceStartPoint, setIsDistanceStartPoint] = useState(false);
const totalDistanceRef = useRef(null);
const mouseCursorRef = useRef(null);
const distanceBoxRef = useRef(null);
// 비행구역 (운항과) 레이어 // 비행구역 (운항과) 레이어
const operationLayer = { const operationLayer = {
type: 'FeatureCollection', type: 'FeatureCollection',
@ -135,7 +140,6 @@ export default function OperationApprovalsContainer({ mode }) {
window._mapbox = map; window._mapbox = map;
let mapInstance = mode === 'container' ? map : window.opener._mapbox; let mapInstance = mode === 'container' ? map : window.opener._mapbox;
setMapObject(mapInstance); setMapObject(mapInstance);
handlerOnClickDrawLineString(mapInstance, handlerDrawMarker);
} }
}, [map]); }, [map]);
@ -461,46 +465,78 @@ export default function OperationApprovalsContainer({ mode }) {
const handlerDrawTypeChange = (e, val) => { const handlerDrawTypeChange = (e, val) => {
drawObj.deleteAll(); drawObj.deleteAll();
distanceMarkers.map(i => i.remove()); distanceMarkers.map(i => i.remove());
distanceBoxRef.current.style.display = 'block';
dispatch(clientChangeDrawType(val)); dispatch(clientChangeDrawType(val));
handlerStartMode(val, drawObj); handlerStartMode(val, drawObj);
}; };
const handlerDrawObjInit = obj => { const handlerDrawObjInit = (obj, mapInstance) => {
setDrawObj(obj); setDrawObj(obj);
handlerOnClickDrawLineString(
mapInstance,
handlerDrawPopup,
{
totalDistanceRef,
mouseCursorRef,
distanceBoxRef
},
obj
);
}; };
const handlerMapTypeChange = val => { const handlerMapTypeChange = val => {
dispatch(clientChangeDrawType('')); // dispatch(clientChangeDrawType(''));
drawObj.changeMode('simple_select');
setMapType(val); setMapType(val);
}; };
const handlerDistanceClose = () => { const handlerDistanceClose = () => {
drawObj.deleteAll(); drawObj.deleteAll();
dispatch(clientChangeDrawType('')); dispatch(clientChangeDrawType('simple_select'));
document.getElementById('distance_box').style.display = 'none'; drawObj.changeMode('simple_select');
mouseCursorRef.current.style.display = 'none';
distanceBoxRef.current.style.display = 'none';
}; };
const handlerDrawMarker = (mapInstance, markerList, startPoint) => { const handlerDistanceRevert = () => {
const marker = markerList.filter(i => { if (drawObj.getMode() === 'draw_line_string') {
return i.coord[0][0] === startPoint.lng; const allFeatures = drawObj.getAll();
});
if (marker.length > 0) { if (allFeatures.features.length > 0) {
let distanceMarker = new mapboxgl.Popup({ allFeatures.features[0].geometry.coordinates.pop(); // 마지막 좌표 제거
closeButton: false, allFeatures.features[0].geometry.coordinates.pop();
closeOnClick: false, allFeatures.features[0].geometry.coordinates.push(
anchor: 'bottom', allFeatures.features[0].geometry.coordinates[
focusAfterOpen: false allFeatures.features[0].geometry.coordinates.length - 1
}) ]
.setLngLat([ );
marker[0].coord[0][0].toFixed(6),
marker[0].coord[0][1].toFixed(6) drawObj.set(allFeatures);
]) }
.setHTML( }
`<div style="color:#000000;font-weight:400;">${marker[0].text}</div>` };
)
.addTo(mapInstance); const handlerDrawPopup = (mapInstance, popupList) => {
// setIsDistanceStartPoint(true);
distanceMarkers.push(distanceMarker); if (distanceMarkers.length > 0) {
distanceMarkers.map(i => i.remove());
}
if (popupList.length > 0) {
popupList.map(i => {
let distanceMarker = new mapboxgl.Popup({
closeButton: false,
closeOnClick: false,
anchor: 'bottom',
focusAfterOpen: false
})
.setLngLat([i.coord[0][0].toFixed(6), i.coord[0][1].toFixed(6)])
.setHTML(
`<div style="color:#000000;font-weight:400;">${i.text}</div>`
)
.addTo(mapInstance);
distanceMarkers.push(distanceMarker);
});
} }
}; };
@ -517,18 +553,6 @@ export default function OperationApprovalsContainer({ mode }) {
return ( return (
<> <>
<div className='map' style={{ width: '100%' }}> <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'> <div className='test_modal'>
<Button <Button
color='primary' color='primary'
@ -807,7 +831,7 @@ export default function OperationApprovalsContainer({ mode }) {
</div> </div>
</div> </div>
<div <div
id='distance_box' ref={distanceBoxRef}
className='data-box-btn-list' className='data-box-btn-list'
style={{ display: 'none' }} style={{ display: 'none' }}
> >
@ -822,8 +846,9 @@ export default function OperationApprovalsContainer({ mode }) {
<FiRotateCw size={16} /> <FiRotateCw size={16} />
</Button> </Button>
<Button <Button
onClick={handlerDistanceRevert}
className='btn-icon rounded-circle' className='btn-icon rounded-circle'
color='primary' color={isDistanceStartPoint ? 'primary' : ''}
size='sm' size='sm'
> >
<FiCornerUpLeft size={16} /> <FiCornerUpLeft size={16} />
@ -841,7 +866,7 @@ export default function OperationApprovalsContainer({ mode }) {
<p> <p>
지도에서 지점을 클릭하여 거리를 측정하세요. 지도에서 지점을 클릭하여 거리를 측정하세요.
<span <span
id='total_distance' ref={totalDistanceRef}
className='finish' className='finish'
style={{ display: 'none' }} style={{ display: 'none' }}
> >
@ -903,6 +928,18 @@ export default function OperationApprovalsContainer({ mode }) {
</div> </div>
</div> </div>
)} )}
<div
ref={mouseCursorRef}
style={{
position: 'absolute',
display: 'none',
background: '#8a1c05',
color: '#fff',
padding: '5px',
borderRadius: '5px',
fontWeight: 500
}}
></div>
</> </>
); );
} }

157
src/utility/MapUtils.js

@ -578,9 +578,7 @@ export const getDraw = mode => {
userProperties: true, userProperties: true,
boxSelect: false, boxSelect: false,
modes: { modes: {
...modes, ...modes
draw_circle: CircleMode,
drag_circle: DragCircleMode
}, },
styles: [ styles: [
{ {
@ -673,22 +671,106 @@ export const handlerStartMode = (mode, drawObj) => {
} }
}; };
export const handlerOnClickDrawLineString = (mapInstance, callback) => { export const handlerOnClickDrawLineString = (
const originClickHandler = MapboxDraw.modes.draw_line_string.onClick; mapInstance,
const originMouseMoveHandler = MapboxDraw.modes.draw_line_string.onMouseMove; callback,
refObj,
drawObj
) => {
const originLineClickHandler = MapboxDraw.modes.draw_line_string.onClick;
const { totalDistanceRef, mouseCursorRef, distanceBoxRef } = refObj;
let startPoint; let startPoint;
let markerList = []; let markerList = [];
let distance = 0;
MapboxDraw.modes.draw_line_string.onClick = function (state, e) { MapboxDraw.modes.draw_line_string.onClick = function (state, e) {
originClickHandler.call(this, state, e); originLineClickHandler.call(this, state, e);
startPoint = e.lngLat; startPoint = e.lngLat;
state.line.coordinates.map((i, idx) => {
const markerList = getDintancePointPopupList(drawObj);
callback(mapInstance, markerList);
};
mapInstance.on('mousemove', e => {
if (startPoint) {
mouseCursorRef.current.style.display = 'none';
if (drawObj.getMode() === 'direct_select') {
// distanceMarkers.map(i => i.remove());
const distance = getDrawDistance(drawObj);
totalDistanceRef.current.innerText = `총 거리 : ${distance.toLocaleString()}m`;
}
} else {
if (drawObj.getMode() === 'draw_line_string') {
console.log('@@@@');
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 = '시작점 선택';
}
}
});
mapInstance.on('draw.modechange', obj => {
if (obj.mode === 'simple_select') {
totalDistanceRef.current.style.display = 'block';
const distance = getDrawDistance(drawObj);
totalDistanceRef.current.innerText = `총 거리 : ${distance.toLocaleString()}m`;
mouseCursorRef.current.style.display = 'none';
mouseCursorRef.current.style.innerText = '';
const markerList = getDintancePointPopupList(drawObj);
callback(mapInstance, markerList);
} else if (obj.mode === 'direct_select') {
}
});
};
/**
*
* @param {MapboxDraw} drawObj
* @returns 거리 : number
*/
export const getDrawDistance = drawObj => {
const drawGeometry = drawObj.getAll().features[0];
let distance = 0;
if (drawGeometry) {
const feature = [];
drawGeometry.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);
}
return distance;
};
/**
*
* @param {MapboxDraw} drawObj
* @returns Draw 포인트 거리 팝업 리스트
*/
export const getDintancePointPopupList = drawObj => {
const drawGeometry = drawObj.getAll().features[0];
console.log(drawObj.getAll().features[0]);
let markerList = [];
if (drawGeometry?.geometry) {
drawGeometry.geometry.coordinates.map((i, idx) => {
if ( if (
i[0] !== state.line.coordinates[state.line.coordinates.length - 1][0] i[0] !==
drawGeometry.geometry.coordinates[
drawGeometry.geometry.coordinates.length - 1
][0]
) { ) {
const obj = { const obj = {
geometry: { geometry: {
coordinates: [i, state.line.coordinates[idx + 1]], coordinates: [i, drawGeometry.geometry.coordinates[idx + 1]],
type: 'LineString' type: 'LineString'
}, },
type: 'Feature' type: 'Feature'
@ -698,60 +780,11 @@ export const handlerOnClickDrawLineString = (mapInstance, callback) => {
distance = distance.toFixed(2); distance = distance.toFixed(2);
markerList.push({ markerList.push({
text: `${distance.toLocaleString()}m`, text: `${distance.toLocaleString()}m`,
coord: [state.line.coordinates[idx + 1]] coord: [drawGeometry.geometry.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') { return markerList;
// // 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