Browse Source

laanc 비행구역 다수 설정 및 비가시권 모달 표출

pull/2/head
junh_eee(이준희) 11 months ago
parent
commit
4980b06a3b
  1. 32
      src/components/map/mapbox/draw/LaancModal.js
  2. 206
      src/components/map/mapbox/draw/LaancDrawControl.js
  3. 3
      src/utility/DrawUtil.js
  4. 5
      src/views/laanc/FlightArea.js
  5. 26
      src/views/laanc/LaancAreaMap.js

32
src/components/map/mapbox/draw/LaancModal.js

@ -0,0 +1,32 @@
import { Button, Modal, ModalHeader, ModalBody, ModalFooter } from 'reactstrap';
export default function LaancModal({ modal, handler }) {
const handlerDroneOneStop = () => {
window.open('https://drone.onestop.go.kr/', '드론원스탑');
handler();
};
return (
<div className='vertically-centered-modal'>
<Modal
isOpen={modal}
toggle={handler}
modalClassName={'modal-primary'}
className='modal-dialog-centered'
>
<ModalHeader toggle={handler}>특별 비행 신청</ModalHeader>
<ModalBody>
육안으로 기체를 확인할 없는 가시권 범위는 특별비행 신청을
진행하셔야 합니다. 드론원스톱을 통해서 신청해 주시기 바랍니다.
</ModalBody>
<ModalFooter>
<Button color='secondary' onClick={handler}>
취소
</Button>
<Button color='primary' onClick={handlerDroneOneStop}>
드론원스톱 바로가기
</Button>
</ModalFooter>
</Modal>
</div>
);
}

206
src/components/map/mapbox/draw/LaancDrawControl.js

@ -1,14 +1,18 @@
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { InfoModal } from '../../../modal/InfoModal'; import { InfoModal } from '../../../modal/InfoModal';
import { useSelector } from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
import { import {
CalculateDistance, CalculateDistance,
handlerGetCircleCoord, handlerGetCircleCoord,
handlerGetHtmlContent, handlerGetHtmlContent,
handlerGetMidPoint handlerGetMidPoint
} from '../../../../utility/DrawUtil'; } from '../../../../utility/DrawUtil';
import { drawTypeChangeAction } from '../../../../modules/control/map/actions/controlMapActions';
import MapboxDraw from '@mapbox/mapbox-gl-draw';
export const LaancDrawControl = props => { export const LaancDrawControl = props => {
const dispatch = useDispatch();
const mapControl = useSelector(state => state.controlMapReducer); const mapControl = useSelector(state => state.controlMapReducer);
const drawObj = props.drawObj; const drawObj = props.drawObj;
const mapObject = props.mapObject; const mapObject = props.mapObject;
@ -34,10 +38,22 @@ export const LaancDrawControl = props => {
useEffect(() => { useEffect(() => {
if (mapObject) { if (mapObject) {
mapObject.on('draw.create', handlerSetId); mapObject.on('draw.update', handlerUpdateSetting);
mapObject.on('draw.update', handlerFormatAreaInfo);
const DrawLineStringMode = MapboxDraw.modes.draw_line_string;
const DrawPolygonMode = MapboxDraw.modes.draw_polygon;
const modeArr = [DrawLineStringMode, DrawPolygonMode];
modeArr.forEach(m => {
m.onStop = state => handlerDblClickFinish(state);
mapObject.on('click', handlerOnClick); // onClick 이벤트 오버라이드
const origin = m.onClick;
m.onClick = function (state, e) {
origin.call(this, state, e);
handlerCustomOnClick(state, e);
};
});
} }
}, [mapObject]); }, [mapObject]);
@ -53,17 +69,15 @@ export const LaancDrawControl = props => {
}, [isDrawDone]); }, [isDrawDone]);
// 클릭할 때마다 마커 찍어줌 // 클릭할 때마다 마커 찍어줌
const handlerOnClick = e => { const handlerCustomOnClick = (state, e) => {
console.log('click'); console.log('click');
const featureIds = drawObj.getFeatureIdsAt(e.point);
const feature = drawObj.get(featureIds[0]);
const type = handlerReturnMode(drawObj.getMode()); const type = handlerReturnMode(drawObj.getMode());
const obj = state[type?.toLowerCase()];
if (type) { if (type && obj) {
if (type !== 'CIRCLE') { if (type !== 'CIRCLE') {
if (feature) { if (state.currentVertexPosition > 1) {
// 뒷 부분 const feature = drawObj.get(obj.id);
const coordinates = feature.geometry.coordinates; const coordinates = feature.geometry.coordinates;
const coords = [ const coords = [
...new Set( ...new Set(
@ -77,48 +91,110 @@ export const LaancDrawControl = props => {
const lngLat = handlerGetMidPoint(coords[len - 2], coords[len - 1]); const lngLat = handlerGetMidPoint(coords[len - 2], coords[len - 1]);
const text = CalculateDistance(coords[len - 2], coords[len - 1]); const text = CalculateDistance(coords[len - 2], coords[len - 1]);
handlerCreateOneMarker([0, 0], lngLat, text); handlerCreateOneMarker([0, 0], lngLat, text, obj.id);
} else { } else {
// Start
if (type !== 'CIRCLE')
handlerCreateOneMarker( handlerCreateOneMarker(
[0, -10], [0, -10],
[e.lngLat.lng, e.lngLat.lat], [e.lngLat.lng, e.lngLat.lat],
'Start' 'Start',
obj.id
); );
} }
} }
} }
}; };
// 도형 첫 생성하면 properties.id에 현재 drawType 넣어줌 const handlerDblClickFinish = state => {
const handlerSetId = e => { console.log('dblclick');
console.log('create');
const id = e.features[0].id;
const mode = handlerReturnMode(drawObj.getMode()); const mode = handlerReturnMode(drawObj.getMode());
if (mode) {
drawObj.setFeatureProperty(id, 'id', mode); const obj = state[mode.toLowerCase()];
setDrawObjId(id); console.log(obj, '>>>>>>obj');
handlerFormatAreaInfo(e); const length = state.currentVertexPosition;
drawObj.setFeatureProperty(obj.id, 'id', mode);
// dbl클릭이 click 두번으로 인식돼서, 마지막 값을 없애버리기로 함
if (mode === 'LINE') {
obj.coordinates.splice(-1);
if (length < 1) {
setAlertModal({
isOpen: true,
title: '좌표 최소 개수',
desc: '좌표를 두 개 점으로 이어주세요.'
});
handlerRemoveError(obj.id);
}
} else if (mode === 'POLYGON') {
obj.coordinates[0].splice(-1);
if (length < 2) {
setAlertModal({
isOpen: true,
title: '좌표 최소 개수',
desc: '좌표를 세 개 점으로 이어주세요.'
});
handlerRemoveError(obj.id);
}
}
handlerAbnormalityCheck(obj.coordinates, obj.id, mode);
};
// 변수들 이름 겹쳐서 헷갈리니까 정리하기
const handlerAbnormalityCheck = (coord, id, mode) => {
console.log('check', coord, id, mode);
const isBreak = handlerIsSpecialFlight(coord, id, mode);
if (isBreak) return;
const initCoord = coord;
const coords =
mode === 'LINE' ? initCoord : mode === 'POLYGON' ? initCoord[0] : null;
handlerSaveAreaInfo(coords, mode);
};
// 현재 그려진 모든 도형에 대한 비가시권 검사
const handlerIsSpecialFlight = (coord, id, mode) => {
// console.log(obj, 'specialFlight');
console.log('specialFlight');
let isBreak = false;
const coords = mode === 'LINE' ? coord : coord[0];
for (let point = 0; point < coords.length - 1; point++) {
const distance = CalculateDistance(coords[point], coords[point + 1]);
if (distance > 1000) {
isBreak = true;
break;
}
}
if (isBreak) {
props.setModal(true);
handlerRemoveError(id);
return true;
} else {
props.handlerSaveCheck(true);
return false;
} }
}; };
const handlerFormatAreaInfo = e => { // 비정상 감지 시 해당 도형, 마커 삭제
const coord = e.features[0].geometry.coordinates; const handlerRemoveError = id => {
const mode = drawObj.get(e.features[0].id).properties.id; drawObj.delete(id);
handlerRemoveGroupMarker(id);
props.handlerSaveCheck(false);
};
const data = // 도형 수정 시
mode === 'LINE' const handlerUpdateSetting = e => {
? coord console.log('update');
: mode === 'POLYGON'
? coord[0]
: mode === 'CIRCLE'
? e.features[0].properties.center
: null;
handlerSaveAreaInfo(data, mode); if (e.features[0]) {
const obj = e.features[0];
const mode = obj.properties.id;
const initCoord = obj.geometry.coordinates;
const coords = mode === 'LINE' ? initCoord : initCoord[0];
handlerAbnormalityCheck(coords, obj.id, mode);
}
}; };
// areaInfo 셋팅
const handlerSaveAreaInfo = (coord, mode) => { const handlerSaveAreaInfo = (coord, mode) => {
if (!coord || !mode) { if (!coord || !mode) {
alert('에러 발생. 다시 시도해 주세요.'); alert('에러 발생. 다시 시도해 주세요.');
@ -163,6 +239,10 @@ export const LaancDrawControl = props => {
setIsDrawDone(true); setIsDrawDone(true);
}; };
// 버퍼 및 기존 도형 재생성
// 해당되는 도형 및 마커만 다시 그려지게 해야함(버퍼 포함)
// 해당 Id 마커 지우고 path만 받아서 다시 그려지도록...
// 근데 areaCoordList[0]이.. 도형을 하나만 받아오는걸로 알고 있어서 그거 확인해야함
const handlerPastDraw = () => { const handlerPastDraw = () => {
if (props.areaCoordList) { if (props.areaCoordList) {
const areas = props.areaCoordList[0]; const areas = props.areaCoordList[0];
@ -187,13 +267,13 @@ export const LaancDrawControl = props => {
); );
} else { } else {
if (areas.areaType === 'LINE') { if (areas.areaType === 'LINE') {
handlerCreateDrawObj( // handlerCreateDrawObj(
drawObjId, // drawObjId,
setDrawObjId, // setDrawObjId,
'LineString', // 'LineString',
{ path: paths }, // { path: paths },
'LINE' // 'LINE'
); // );
// 버퍼 생성 // 버퍼 생성
if (areas.bufferCoordList) { if (areas.bufferCoordList) {
@ -212,21 +292,21 @@ export const LaancDrawControl = props => {
); );
} }
} else if (areas.areaType === 'POLYGON') { } else if (areas.areaType === 'POLYGON') {
handlerCreateDrawObj( // handlerCreateDrawObj(
drawObjId, // drawObjId,
setDrawObjId, // setDrawObjId,
'Polygon', // 'Polygon',
{ path: [paths] }, // { path: [paths] },
'POLYGON' // 'POLYGON'
); // );
} }
} }
// 현재 그려진 도형 저장 // 현재 그려진 도형 저장
setGeoJson(drawGeoJson); setGeoJson(drawGeoJson);
// 마커 재 생성 // 마커 재 생성
handlerRemoveMarker(); // handlerRemoveMarker();
handlerCreateAllMarker(paths); // handlerCreateAllMarker(paths);
} }
} }
}; };
@ -257,23 +337,35 @@ export const LaancDrawControl = props => {
} }
}; };
// 지도에 있는 모든 마커 삭제
const handlerRemoveMarker = () => { const handlerRemoveMarker = () => {
const ele = document.getElementsByClassName('mapboxgl-popup'); const ele = document.getElementsByClassName('mapboxgl-popup');
const eleArr = Array.from(ele); const eleArr = Array.from(ele);
eleArr?.forEach(marker => marker.remove()); eleArr?.forEach(marker => marker.remove());
}; };
const handlerCreateOneMarker = (anchor, lngLat, text) => { // 해당되는 id의 마커 삭제
const handlerRemoveGroupMarker = id => {
const ele = document.getElementsByClassName('mapboxgl-popup');
const eleArr = Array.from(ele);
eleArr?.forEach(marker => {
if (marker.innerHTML.includes(id)) marker.remove();
});
};
// 개별 마커 생성
const handlerCreateOneMarker = (anchor, lngLat, text, id) => {
const popup = new props.mapboxgl.Popup({ const popup = new props.mapboxgl.Popup({
offset: anchor, offset: anchor,
closeButton: false, closeButton: false,
closeOnClick: false closeOnClick: false
}) })
.setLngLat(lngLat) .setLngLat(lngLat)
.setHTML(handlerGetHtmlContent(text)) .setHTML(handlerGetHtmlContent(text, id))
.addTo(mapObject); .addTo(mapObject);
}; };
// 모든 마커 생성
const handlerCreateAllMarker = coords => { const handlerCreateAllMarker = coords => {
const areas = props.areaCoordList[0]; const areas = props.areaCoordList[0];
@ -293,15 +385,17 @@ export const LaancDrawControl = props => {
}; };
const drawInit = () => { const drawInit = () => {
// console.log('drawInit'); // drawObj.deleteAll();
drawObj.deleteAll(); // handlerRemoveMarker();
handlerRemoveMarker(); props.handlerSaveCheck(false);
setDrawObjId(); setDrawObjId();
props.handlerInitCoordinates(); props.handlerInitCoordinates();
const mode = mapControl.drawType; const mode = mapControl.drawType;
if (!mode || mode === 'RESET') { if (!mode || mode === 'RESET') {
drawObj.deleteAll();
handlerRemoveMarker();
return; return;
} }
handlerStartMode(mode); handlerStartMode(mode);

3
src/utility/DrawUtil.js

@ -49,7 +49,7 @@ export const handlerGetMidPoint = (dis1, dis2) => {
}; };
// html Content 반환 // html Content 반환
export const handlerGetHtmlContent = distance => { export const handlerGetHtmlContent = (distance, id) => {
const text = const text =
typeof distance === 'number' typeof distance === 'number'
? '거리 ' + fromMetersToText(distance) ? '거리 ' + fromMetersToText(distance)
@ -57,6 +57,7 @@ export const handlerGetHtmlContent = distance => {
return ( return (
'<div style="display:inline-block;padding:5px;text-align:center;background-color:#fff;border:1px solid #000;font-size:13px;color:#ff0000;"><span>' + '<div style="display:inline-block;padding:5px;text-align:center;background-color:#fff;border:1px solid #000;font-size:13px;color:#ff0000;"><span>' +
`<div style="display:hidden;" className=${id}></div>` +
text + text +
'</span></div>' '</span></div>'
); );

5
src/views/laanc/FlightArea.js

@ -67,7 +67,8 @@ export default function FlightArea({
desc: '' desc: ''
}); });
// console.log('>>>'); const [isSaveable, setIsSaveable] = useState(false);
//날씨 임시 데이터 //날씨 임시 데이터
const [wheather, setWheather] = useState([]); const [wheather, setWheather] = useState([]);
@ -507,6 +508,7 @@ export default function FlightArea({
centeredModal={centeredModal} centeredModal={centeredModal}
mapContainer={mapContainer} mapContainer={mapContainer}
drawObj={drawObj} drawObj={drawObj}
setIsSaveable={setIsSaveable}
/> />
</ModalBody> </ModalBody>
<ModalFooter> <ModalFooter>
@ -577,6 +579,7 @@ export default function FlightArea({
<div> <div>
<Button <Button
color='primary' color='primary'
disabled={!isSaveable}
onClick={() => { onClick={() => {
handlerSave(); handlerSave();
}} }}

26
src/views/laanc/LaancAreaMap.js

@ -11,8 +11,6 @@ import {
AREA_COORDINATE_LIST_SAVE, AREA_COORDINATE_LIST_SAVE,
FLIGHT_PLAN_AREA_BUFFER_LIST FLIGHT_PLAN_AREA_BUFFER_LIST
} from '../../modules/basis/flight/actions/basisFlightAction'; } from '../../modules/basis/flight/actions/basisFlightAction';
import { LaancDraw } from '../../components/map/mapbox/draw/LaancDraw';
import { LaancDrawRe } from '../../components/map/mapbox/draw/LaancDrawRe';
import { import {
drawTypeChangeAction, drawTypeChangeAction,
mapInitAction mapInitAction
@ -33,8 +31,14 @@ import geoJson from '../../components/map/geojson/airArea.json';
import { FeatureAirZone } from '../../components/map/mapbox/feature/FeatureAirZone'; import { FeatureAirZone } from '../../components/map/mapbox/feature/FeatureAirZone';
import LaancMapSearch from '../../components/map/mapbox/draw/LaancMapSearch'; import LaancMapSearch from '../../components/map/mapbox/draw/LaancMapSearch';
import { LaancDrawControl } from '../../components/map/mapbox/draw/LaancDrawControl'; import { LaancDrawControl } from '../../components/map/mapbox/draw/LaancDrawControl';
import LaancModal from '../../components/map/mapbox/draw/\bLaancModal';
export default function LaancAreaMap({ centeredModal, mapContainer, drawObj }) {
export default function LaancAreaMap({
centeredModal,
mapContainer,
drawObj,
setIsSaveable
}) {
const dispatch = useDispatch(); const dispatch = useDispatch();
const mapControl = useSelector(state => state.controlMapReducer); const mapControl = useSelector(state => state.controlMapReducer);
const { areaCoordList } = useSelector(state => state.flightState); const { areaCoordList } = useSelector(state => state.flightState);
@ -47,6 +51,7 @@ export default function LaancAreaMap({ centeredModal, mapContainer, drawObj }) {
); );
const [number, setNumber] = useState(0); const [number, setNumber] = useState(0);
const [modal, setModal] = useState(false);
const [detailLayer, setDetailLayer] = useState(); const [detailLayer, setDetailLayer] = useState();
@ -294,6 +299,14 @@ export default function LaancAreaMap({ centeredModal, mapContainer, drawObj }) {
dispatch(AREA_COORDINATE_LIST_SAVE(areaList)); dispatch(AREA_COORDINATE_LIST_SAVE(areaList));
}; };
const handlerModal = () => {
setModal(!modal);
};
const handlerSaveCheck = save => {
setIsSaveable(save);
};
return ( return (
<Card className='mb-0'> <Card className='mb-0'>
<CardBody> <CardBody>
@ -331,14 +344,19 @@ export default function LaancAreaMap({ centeredModal, mapContainer, drawObj }) {
/> */} /> */}
<LaancDrawControl <LaancDrawControl
drawObj={drawObj} drawObj={drawObj}
setModal={setModal}
mapboxgl={mapboxgl} mapboxgl={mapboxgl}
mapObject={mapObject} mapObject={mapObject}
areaCoordList={mapAreaCoordList} areaCoordList={mapAreaCoordList}
handlerConfirm={handlerConfirm} handlerConfirm={handlerConfirm}
handlerSaveCheck={handlerSaveCheck}
handlerCoordinates={handlerCoordinates} handlerCoordinates={handlerCoordinates}
handlerInitCoordinates={handlerInitCoordinates} handlerInitCoordinates={handlerInitCoordinates}
/> />
<FeatureAirZone map={mapObject} mapboxgl={mapboxgl} /> <FeatureAirZone map={mapObject} mapboxgl={mapboxgl} />
{modal ? (
<LaancModal modal={modal} handler={handlerModal} />
) : null}
</> </>
) : null} ) : null}
</div> </div>

Loading…
Cancel
Save