diff --git "a/src/components/map/mapbox/draw/\bLaancModal.js" "b/src/components/map/mapbox/draw/\bLaancModal.js" new file mode 100644 index 0000000..7999946 --- /dev/null +++ "b/src/components/map/mapbox/draw/\bLaancModal.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 ( +
+ + 특별 비행 신청 + + 육안으로 기체를 확인할 수 없는 가시권 밖 범위는 특별비행 신청을 + 진행하셔야 합니다. 드론원스톱을 통해서 신청해 주시기 바랍니다. + + + + + + +
+ ); +} diff --git a/src/components/map/mapbox/draw/LaancDrawControl.js b/src/components/map/mapbox/draw/LaancDrawControl.js index 75411c7..d0b26d2 100644 --- a/src/components/map/mapbox/draw/LaancDrawControl.js +++ b/src/components/map/mapbox/draw/LaancDrawControl.js @@ -1,14 +1,18 @@ import { useEffect, useState } from 'react'; import { InfoModal } from '../../../modal/InfoModal'; -import { useSelector } from 'react-redux'; +import { useDispatch, useSelector } from 'react-redux'; import { CalculateDistance, handlerGetCircleCoord, handlerGetHtmlContent, handlerGetMidPoint } from '../../../../utility/DrawUtil'; +import { drawTypeChangeAction } from '../../../../modules/control/map/actions/controlMapActions'; +import MapboxDraw from '@mapbox/mapbox-gl-draw'; export const LaancDrawControl = props => { + const dispatch = useDispatch(); + const mapControl = useSelector(state => state.controlMapReducer); const drawObj = props.drawObj; const mapObject = props.mapObject; @@ -34,10 +38,22 @@ export const LaancDrawControl = props => { useEffect(() => { if (mapObject) { - mapObject.on('draw.create', handlerSetId); - mapObject.on('draw.update', handlerFormatAreaInfo); + mapObject.on('draw.update', handlerUpdateSetting); + + const DrawLineStringMode = MapboxDraw.modes.draw_line_string; + const DrawPolygonMode = MapboxDraw.modes.draw_polygon; + const modeArr = [DrawLineStringMode, DrawPolygonMode]; - mapObject.on('click', handlerOnClick); + modeArr.forEach(m => { + m.onStop = state => handlerDblClickFinish(state); + + // onClick 이벤트 오버라이드 + const origin = m.onClick; + m.onClick = function (state, e) { + origin.call(this, state, e); + handlerCustomOnClick(state, e); + }; + }); } }, [mapObject]); @@ -53,17 +69,15 @@ export const LaancDrawControl = props => { }, [isDrawDone]); // 클릭할 때마다 마커 찍어줌 - const handlerOnClick = e => { + const handlerCustomOnClick = (state, e) => { console.log('click'); - - const featureIds = drawObj.getFeatureIdsAt(e.point); - const feature = drawObj.get(featureIds[0]); const type = handlerReturnMode(drawObj.getMode()); + const obj = state[type?.toLowerCase()]; - if (type) { + if (type && obj) { if (type !== 'CIRCLE') { - if (feature) { - // 뒷 부분 + if (state.currentVertexPosition > 1) { + const feature = drawObj.get(obj.id); const coordinates = feature.geometry.coordinates; const coords = [ ...new Set( @@ -77,48 +91,110 @@ export const LaancDrawControl = props => { const lngLat = handlerGetMidPoint(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 { - // Start - if (type !== 'CIRCLE') - handlerCreateOneMarker( - [0, -10], - [e.lngLat.lng, e.lngLat.lat], - 'Start' - ); + handlerCreateOneMarker( + [0, -10], + [e.lngLat.lng, e.lngLat.lat], + 'Start', + obj.id + ); } } } }; - // 도형 첫 생성하면 properties.id에 현재 drawType 넣어줌 - const handlerSetId = e => { - console.log('create'); - const id = e.features[0].id; + const handlerDblClickFinish = state => { + console.log('dblclick'); const mode = handlerReturnMode(drawObj.getMode()); - if (mode) { - drawObj.setFeatureProperty(id, 'id', mode); - setDrawObjId(id); - handlerFormatAreaInfo(e); + + const obj = state[mode.toLowerCase()]; + console.log(obj, '>>>>>>obj'); + 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 handlerFormatAreaInfo = e => { - const coord = e.features[0].geometry.coordinates; - const mode = drawObj.get(e.features[0].id).properties.id; + // 변수들 이름 겹쳐서 헷갈리니까 정리하기 + const handlerAbnormalityCheck = (coord, id, mode) => { + console.log('check', coord, id, mode); + const isBreak = handlerIsSpecialFlight(coord, id, mode); + if (isBreak) return; - const data = - mode === 'LINE' - ? coord - : mode === 'POLYGON' - ? coord[0] - : mode === 'CIRCLE' - ? e.features[0].properties.center - : null; + const initCoord = coord; + const coords = + mode === 'LINE' ? initCoord : mode === 'POLYGON' ? initCoord[0] : null; + handlerSaveAreaInfo(coords, mode); + }; - handlerSaveAreaInfo(data, 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 handlerRemoveError = id => { + drawObj.delete(id); + handlerRemoveGroupMarker(id); + props.handlerSaveCheck(false); + }; + + // 도형 수정 시 + const handlerUpdateSetting = e => { + console.log('update'); + + 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) => { if (!coord || !mode) { alert('에러 발생. 다시 시도해 주세요.'); @@ -163,6 +239,10 @@ export const LaancDrawControl = props => { setIsDrawDone(true); }; + // 버퍼 및 기존 도형 재생성 + // 해당되는 도형 및 마커만 다시 그려지게 해야함(버퍼 포함) + // 해당 Id 마커 지우고 path만 받아서 다시 그려지도록... + // 근데 areaCoordList[0]이.. 도형을 하나만 받아오는걸로 알고 있어서 그거 확인해야함 const handlerPastDraw = () => { if (props.areaCoordList) { const areas = props.areaCoordList[0]; @@ -187,13 +267,13 @@ export const LaancDrawControl = props => { ); } else { if (areas.areaType === 'LINE') { - handlerCreateDrawObj( - drawObjId, - setDrawObjId, - 'LineString', - { path: paths }, - 'LINE' - ); + // handlerCreateDrawObj( + // drawObjId, + // setDrawObjId, + // 'LineString', + // { path: paths }, + // 'LINE' + // ); // 버퍼 생성 if (areas.bufferCoordList) { @@ -212,21 +292,21 @@ export const LaancDrawControl = props => { ); } } else if (areas.areaType === 'POLYGON') { - handlerCreateDrawObj( - drawObjId, - setDrawObjId, - 'Polygon', - { path: [paths] }, - 'POLYGON' - ); + // handlerCreateDrawObj( + // drawObjId, + // setDrawObjId, + // 'Polygon', + // { path: [paths] }, + // 'POLYGON' + // ); } } // 현재 그려진 도형 저장 setGeoJson(drawGeoJson); // 마커 재 생성 - handlerRemoveMarker(); - handlerCreateAllMarker(paths); + // handlerRemoveMarker(); + // handlerCreateAllMarker(paths); } } }; @@ -257,23 +337,35 @@ export const LaancDrawControl = props => { } }; + // 지도에 있는 모든 마커 삭제 const handlerRemoveMarker = () => { const ele = document.getElementsByClassName('mapboxgl-popup'); const eleArr = Array.from(ele); 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({ offset: anchor, closeButton: false, closeOnClick: false }) .setLngLat(lngLat) - .setHTML(handlerGetHtmlContent(text)) + .setHTML(handlerGetHtmlContent(text, id)) .addTo(mapObject); }; + // 모든 마커 생성 const handlerCreateAllMarker = coords => { const areas = props.areaCoordList[0]; @@ -293,15 +385,17 @@ export const LaancDrawControl = props => { }; const drawInit = () => { - // console.log('drawInit'); - drawObj.deleteAll(); - handlerRemoveMarker(); + // drawObj.deleteAll(); + // handlerRemoveMarker(); + props.handlerSaveCheck(false); setDrawObjId(); props.handlerInitCoordinates(); const mode = mapControl.drawType; if (!mode || mode === 'RESET') { + drawObj.deleteAll(); + handlerRemoveMarker(); return; } handlerStartMode(mode); diff --git a/src/utility/DrawUtil.js b/src/utility/DrawUtil.js index 5fa1d29..01fc17f 100644 --- a/src/utility/DrawUtil.js +++ b/src/utility/DrawUtil.js @@ -49,7 +49,7 @@ export const handlerGetMidPoint = (dis1, dis2) => { }; // html Content 반환 -export const handlerGetHtmlContent = distance => { +export const handlerGetHtmlContent = (distance, id) => { const text = typeof distance === 'number' ? '거리 ' + fromMetersToText(distance) @@ -57,6 +57,7 @@ export const handlerGetHtmlContent = distance => { return ( '
' + + `
` + text + '
' ); diff --git a/src/views/laanc/FlightArea.js b/src/views/laanc/FlightArea.js index 64811b1..98d087b 100644 --- a/src/views/laanc/FlightArea.js +++ b/src/views/laanc/FlightArea.js @@ -67,7 +67,8 @@ export default function FlightArea({ desc: '' }); - // console.log('>>>'); + const [isSaveable, setIsSaveable] = useState(false); + //날씨 임시 데이터 const [wheather, setWheather] = useState([]); @@ -507,6 +508,7 @@ export default function FlightArea({ centeredModal={centeredModal} mapContainer={mapContainer} drawObj={drawObj} + setIsSaveable={setIsSaveable} /> @@ -577,6 +579,7 @@ export default function FlightArea({