From 41aba97aab787e582faf6d5a16f73e25e74435cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?junh=5Feee=28=EC=9D=B4=EC=A4=80=ED=9D=AC=29?= Date: Thu, 7 Dec 2023 15:40:07 +0900 Subject: [PATCH] =?UTF-8?q?laanc=20=EB=B9=84=ED=96=89=EA=B5=AC=EC=97=AD=20?= =?UTF-8?q?=EC=A3=BC=EC=84=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/laanc/map/FlightArea.js | 237 ++++++------------- src/components/laanc/map/LaancAreaMap.js | 158 +++---------- src/components/laanc/map/LaancComn.js | 73 ++++++ src/components/laanc/map/LaancDrawControl.js | 64 ++--- src/utility/DrawUtil.js | 34 +-- 5 files changed, 222 insertions(+), 344 deletions(-) create mode 100644 src/components/laanc/map/LaancComn.js diff --git a/src/components/laanc/map/FlightArea.js b/src/components/laanc/map/FlightArea.js index 401dde8..c7bdfbf 100644 --- a/src/components/laanc/map/FlightArea.js +++ b/src/components/laanc/map/FlightArea.js @@ -1,6 +1,9 @@ +import { useEffect, useRef, useState } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; +import { Button, Modal, ModalHeader, ModalBody, ModalFooter } from 'reactstrap'; +// mapbox import 'mapbox-gl/dist/mapbox-gl.css'; import mapboxgl from 'mapbox-gl'; -import threebox from 'threebox-plugin'; import MapboxLanguage from '@mapbox/mapbox-gl-language'; import MapboxDraw from '@mapbox/mapbox-gl-draw'; import { @@ -10,18 +13,6 @@ import { SimpleSelectMode } from 'mapbox-gl-draw-circle'; import { MAPBOX_TOKEN } from '../../../configs/constants'; -import { useEffect, useRef, useState } from 'react'; -import { useDispatch, useSelector } from 'react-redux'; -import { Button, Modal, ModalHeader, ModalBody, ModalFooter } from 'reactstrap'; -import { - AREA_COORDINATE_LIST_SAVE, - AREA_DETAIL_LIST_SAVE -} from '../../../modules/basis/flight/actions/basisFlightAction'; -import { - drawTypeChangeAction, - mapInitAction -} from '../../../modules/control/map/actions/controlMapActions'; -import LaancAreaMap from './LaancAreaMap'; import { InitFeature, handlerCreatePoint, @@ -32,20 +23,26 @@ import { layerPolyline, layerWayPoint } from '../../../utility/DrawUtil'; -import flatGimpo from '../../map/geojson/flatGimpoAirportAirArea.json'; +// actions +import { + AREA_COORDINATE_LIST_SAVE, + AREA_DETAIL_LIST_SAVE +} from '../../../modules/basis/flight/actions/basisFlightAction'; +import { + drawTypeChangeAction, + mapInitAction +} from '../../../modules/control/map/actions/controlMapActions'; +import * as LaancAction from '../../../modules/laanc/actions/laancActions'; +// geojson import gimpo from '../../map/geojson/gimpoAirportAirArea.json'; -import geoJson from '../../map/geojson/airArea.json'; + +import threebox from 'threebox-plugin'; import { FeatureAirZone } from '../../map/mapbox/feature/FeatureAirZone'; import { WeatherContainer } from '../../../containers/basis/flight/plan/WeatherContainer'; import { initFlightBas } from '../../../modules/laanc/models/laancModels'; -import * as LaancAction from '../../../modules/laanc/actions/laancActions'; +import LaancAreaMap from './LaancAreaMap'; import LaancDrawModal from './LaancDrawModal'; - -const initialAddData = { - isAddable: false, - isViewAdd: false, - overAdd: false -}; +import { handlerCreateAirSpace } from './LaancComn'; export default function FlightArea({ centeredModal, @@ -61,40 +58,65 @@ export default function FlightArea({ >; const dispatch = useDispatch(); - const { areaCoordList } = useSelector(state => state.flightState); + // 비행구역 타입 및 공역 타입 const mapControl = useSelector(state => state.controlMapReducer); - const mapContainer = useRef(null); + // 비행구역 정보 저장 + const { areaCoordList } = useSelector(state => state.flightState); + + // 지도 const [mapObject, setMapObject] = useState(); - const [drawObj, setDrawObj] = useState(); + const mapContainer = useRef(null); + // 지도 로드 여부 const [isMapLoad, setIsMapLoad] = useState(false); + + // 비행구역 그리기 + const [drawObj, setDrawObj] = useState(); + + // 미니맵 레이어 const [previewLayer, setPreviewLayer] = useState(); + + // 날씨 모달 const [formModal, setFormModal] = useState(false); + // 비행구역 설정 관련 모달 const [modal, setModal] = useState({ title: '', desc: '', isOpen: false }); + // 비행구역 저장 가능 여부 const [isSaveable, setIsSaveable] = useState(false); - const [addData, setAddData] = useState(initialAddData); + // 비행구역 추가 가능 여부 판단 + const [addData, setAddData] = useState({ + isAddable: false, + isViewAdd: false, + overAdd: false + }); + + // 저장된 비행구역 데이터 const [saveData, setSaveData] = useState(); + + // 비행구역 고도 const [saveElev, setSaveElev] = useState(); - //날씨 임시 데이터 + //날씨 위치 데이터 const [wheather, setWheather] = useState([]); + // 미니맵에 표출되는 비행구역 정보 const previewGeo = { type: 'FeatureCollection', features: [] }; + // 지도 초기 셋팅 useEffect(() => { handlerMapInit(); }, []); + // 미니맵에 비행구역 표출 및 날씨 정보 저장 useEffect(() => { if (areaCoordList) { const area = areaCoordList[0]; @@ -105,78 +127,12 @@ export default function FlightArea({ } }, [areaCoordList, centeredModal, previewLayer]); - const handlerCreateAirSpace = ( - map, - useGeoJson = { - ...geoJson, - ...flatGimpo, - features: [...geoJson.features, ...flatGimpo.features] - } - ) => { - if (map.getLayer('maine')) { - map.removeLayer('maine'); - map.removeSource('maine'); - } - let arrGeoJson = []; - useGeoJson.features.map(item => { - if (item.properties.type === '0001' && mapControl.area0001) { - arrGeoJson.push({ - ...item, - properties: { ...item.properties, color: '#FF3648' } - }); - } else if (item.properties.type === '0002' && mapControl.area0002) { - arrGeoJson.push({ - ...item, - properties: { ...item.properties, color: '#FFA1AA' } - }); - } else if (item.properties.type === '0003' && mapControl.area0003) { - arrGeoJson.push({ - ...item, - properties: { ...item.properties, color: '#FFA800' } - }); - } else if (item.properties.type === '0004' && mapControl.area0004) { - arrGeoJson.push({ - ...item, - properties: { ...item.properties, color: '#A16B00' } - }); - } else if (item.properties.type === '0005' && mapControl.area0005) { - arrGeoJson.push({ - ...item, - properties: { ...item.properties, color: '#AB40FF' } - }); - } else if (item.properties.type === '0006' && mapControl.area0006) { - arrGeoJson.push({ - ...item, - properties: { ...item.properties, color: '#009cad' } - }); - } - }); - useGeoJson.features = arrGeoJson.filter(i => i.geometry.type === 'Polygon'); - - // 공역 생성 start - map.addSource('maine', { - type: 'geojson', - data: { - ...useGeoJson - } - }); - map.addLayer({ - id: 'maine', - type: 'fill', - source: 'maine', - layout: {}, - paint: { - 'fill-color': ['get', 'color'], - // 'fill-extrusion-height': 3000, - 'fill-opacity': 0.5 - } - }); - }; - + // 비행구역 설정 관련 모달 표출 const handlerModal = () => { setModal(!modal); }; + // 비행구역 타입 변경 시 그리기 모드 상태일 때 에러 표출 const handlerDrawType = val => { if (drawObj.getMode().includes('draw')) { setModal({ @@ -195,6 +151,7 @@ export default function FlightArea({ } }; + // laanc계획서 비행구역 저장버튼 클릭 시 비행구역 정보 저장 const handlerSave = async () => { if (areaCoordList) { console.log('save'); @@ -208,29 +165,28 @@ export default function FlightArea({ setCenteredModal(false); dispatch(AREA_DETAIL_LIST_SAVE(resultAreaDetail)); - } else { - alert('아무것도 작성 안함'); } }; - // 날씨 handler + // 날씨 모달 표출 const handlerWeather = () => { setFormModal(!formModal); }; + // 지도 초기 셋팅 const handlerMapInit = () => { mapboxgl.accessToken = MAPBOX_TOKEN; const map = new mapboxgl.Map({ - container: 'preview', // container ID - style: 'mapbox://styles/mapbox/streets-v12', // style URL - center: [126.612647, 37.519893], // starting position [lng, lat] - // zoom: !areaCoordList ? 14 : bufferZoom.bufferzoom, // starting zoom + container: 'preview', + style: 'mapbox://styles/mapbox/streets-v12', + center: [126.612647, 37.519893], zoom: 15, antialias: true, attributionControl: false }); + // 비행구역 상세맵 draw 정보 셋팅 const draw = new MapboxDraw({ displayControlsDefault: false, userProperties: true, @@ -243,16 +199,14 @@ export default function FlightArea({ simple_select: SimpleSelectMode }, styles: [ - // line stroke { + // polyline id: 'gl-draw-line', type: 'line', filter: [ 'all', ['==', '$type', 'LineString'], ['!=', 'mode', 'static'] - // ['==', 'meta', 'feature'], - // ['==', 'active', 'false'] ], layout: { 'line-cap': 'round', @@ -264,28 +218,8 @@ export default function FlightArea({ 'line-width': 2 } }, - // direct line stroke - // { - // id: 'gl-draw-line-active', - // type: 'line', - // filter: [ - // 'all', - // ['==', '$type', 'LineString'], - // ['==', 'meta', 'feature'], - // ['==', 'active', 'true'] - // ], - // layout: { - // 'line-cap': 'round', - // 'line-join': 'round' - // }, - // paint: { - // 'line-color': '#000000', - // 'line-dasharray': [0.2, 2], - // 'line-width': 2 - // } - // }, - // polygon fill { + // polygon fill id: 'gl-draw-polygon-fill', type: 'fill', filter: ['all', ['==', '$type', 'Polygon'], ['!=', 'mode', 'static']], @@ -295,18 +229,7 @@ export default function FlightArea({ 'fill-opacity': 0.1 } }, - // polygon mid points - { - id: 'gl-draw-polygon-midpoint', - type: 'circle', - filter: ['all', ['==', '$type', 'Point'], ['==', 'meta', 'midpoint']], - paint: { - 'circle-radius': 4, - 'circle-color': '#8a1c05' - } - }, - // polygon outline stroke - // This doesn't style the first edge of the polygon, which uses the line stroke styling instead + // polygon outline { id: 'gl-draw-polygon-stroke-active', type: 'line', @@ -321,8 +244,8 @@ export default function FlightArea({ 'line-width': 2 } }, - // vertex point halos { + // vertex point halos id: 'gl-draw-polygon-and-line-vertex-halo-active', type: 'circle', filter: [ @@ -333,11 +256,11 @@ export default function FlightArea({ ], paint: { 'circle-radius': 8, - 'circle-color': '#fff' + 'circle-color': '#ffffff' } }, - // vertex points { + // vertex points id: 'gl-draw-polygon-and-line-vertex-active', type: 'circle', filter: [ @@ -359,7 +282,6 @@ export default function FlightArea({ const language = new MapboxLanguage(); map.addControl(language); - // map.addControl(draw); const tb = (window.tb = new threebox.Threebox( map, @@ -396,7 +318,7 @@ export default function FlightArea({ } }); - handlerCreateAirSpace(map); + handlerCreateAirSpace(map, mapControl); // 미니맵 표출 map.addSource('preview', { @@ -417,6 +339,7 @@ export default function FlightArea({ dispatch(mapInitAction(map)); }; + // 저장된 비행구역 미니맵에 표출 const handlerPreviewDraw = () => { if (areaCoordList) { const areas = areaCoordList[0]; @@ -427,7 +350,6 @@ export default function FlightArea({ let fitZoomPaths = []; - // 기존 if (areas.areaType) { if (areas.areaType === 'CIRCLE') { const radius = areas.bufferZone; @@ -478,12 +400,8 @@ export default function FlightArea({ //지도 줌 좌표 설정 fitZoomPaths = paths.concat(); - - // 마커 삭제 - // const ele = document.getElementById('mapboxgl-popup'); - // const eleArr = Array.from(ele); - // eleArr?.forEach(marker => marker.remove()); } + handlerFitBounds(mapObject, fitZoomPaths, 50, areas.areaType); mapObject.setPaintProperty('waypoint', 'circle-radius', 10); @@ -491,12 +409,13 @@ export default function FlightArea({ } const coordValue = []; - const coord = paths?.map(coords => { + paths?.map(coords => { coordValue.push({ lat: coords[1], lon: coords[0] }); }); + if (page === 1) { naver.maps.Service.reverseGeocode( { @@ -527,7 +446,6 @@ export default function FlightArea({ name: 'latlon', value: coordValue }); - //스텝1에 반경도 글씨가 바뀌어야 함...!! handleChange({ type: 'area', name: 'bufferZone', @@ -537,38 +455,33 @@ export default function FlightArea({ } }; + // 비행구역 추가 버튼 클릭 시 const handlerAddClick = () => { if (!addData.isAddable || !addData.overAdd) { handlerAddChange('isAddable', true); - const obj = drawObj - .getAll() - .features.filter(obj => obj.properties.id !== 'BUFFER'); - // handlerDrawType(obj[0].properties.id); } }; + // 비행구역 추가 관련 상태 변경 const handlerAddChange = (key, val) => { - // const [addData, setAddData] = useState({ - // isAddalbe: false, - // isViewAdd: false, - // overAdd: false - // }) - setAddData(prev => ({ ...prev, [key]: val })); }; + // 비행구역 저장 가능 유무 체크 const handlerSaveCheck = save => { setIsSaveable(save); }; + // 비행구역 데이터 초기화 const handlerInitCoordinates = () => { const init = initFlightBas.initDetail.areaList.concat(); dispatch(AREA_COORDINATE_LIST_SAVE(init)); }; + // 비행구역 고도 저장 const handlerSaveElev = elev => { setSaveElev(elev); }; @@ -604,7 +517,6 @@ export default function FlightArea({ - {/* 닫기 */} 저장 diff --git a/src/components/laanc/map/LaancAreaMap.js b/src/components/laanc/map/LaancAreaMap.js index 039f91e..0901ba2 100644 --- a/src/components/laanc/map/LaancAreaMap.js +++ b/src/components/laanc/map/LaancAreaMap.js @@ -3,7 +3,7 @@ import mapboxgl from 'mapbox-gl'; import threebox from 'threebox-plugin'; import MapboxLanguage from '@mapbox/mapbox-gl-language'; import { MAPBOX_TOKEN } from '../../../configs/constants'; -import { useEffect, useMemo, useRef, useState } from 'react'; +import { useEffect, useRef, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { Card, CardBody } from 'reactstrap'; import { initFlightBas } from '../../../modules/basis/flight/models/basisFlightModel'; @@ -16,22 +16,15 @@ import { mapInitAction } from '../../../modules/control/map/actions/controlMapAc import { FormattingCoord, handlerFitBounds, - handlerGetCircleCoord, - layerBuffer, - layerGuideLine, - layerPolygon, - layerPolyline, - layerWayPoint + handlerGetCircleCoord } from '../../../utility/DrawUtil'; -import flatGimpo from '../../map/geojson/flatGimpoAirportAirArea.json'; import gimpo from '../../map/geojson/gimpoAirportAirArea.json'; -import geoJson from '../../map/geojson/airArea.json'; import { FeatureAirZone } from '../../map/mapbox/feature/FeatureAirZone'; import LaancMapSearch from './LaancMapSearch'; import { LaancDrawControl } from './LaancDrawControl'; +import { handlerCreateAirSpace } from './LaancComn'; export default function LaancAreaMap({ - centeredModal, mapContainer, drawObj, handlerSaveCheck, @@ -43,42 +36,38 @@ export default function LaancAreaMap({ setModal }) { const dispatch = useDispatch(); + // 비행구역 타입 및 공역 타입 const mapControl = useSelector(state => state.controlMapReducer); - const { areaCoordList } = useSelector(state => state.flightState); - const [mapObject, setMapObject] = useState(); - const [isMapLoad, setIsMapLoad] = useState(false); - const [mode, setMode] = useState(); + // 비행구역 정보 저장 + const { areaCoordList } = useSelector(state => state.flightState); + // 비행구역 초기값 포함 정보 저장 const [mapAreaCoordList, setMapAreaCoordList] = useState( initFlightBas.initDetail.areaList ); - const [number, setNumber] = useState(0); + // 지도 + const [mapObject, setMapObject] = useState(); + // 지도 로드 여부 + const [isMapLoad, setIsMapLoad] = useState(false); - // const [detailLayer, setDetailLayer] = useState(); + // 지도 렌더 횟수 + const [number, setNumber] = useState(0); + // 비행구역 좌표 카드에 표출될 좌표 정보 const [viewCoordObj, setViewCoordObj] = useState([]); - const detailGeo = useMemo(() => { - return { - type: 'FeatureCollection', - features: [] - }; - }, []); - // 좌표 정보 마우스 드래그 const scrollRef = useRef(null); const [isDrag, setIsDrag] = useState(false); const [startX, setStartX] = useState(); + // 지도 초기 셋팅 useEffect(() => { handlerMapInit(); }, []); - useEffect(() => { - setMode(mapControl.drawType); - }, [mapControl.drawType]); - + // 첫 비행구역 생성 or 저장했던 비행구역 다시 열기 시 비행구역에 화면 맞추어서 zoom useEffect(() => { if (areaCoordList && mapObject) { if ( @@ -111,75 +100,7 @@ export default function LaancAreaMap({ } }, [areaCoordList, mapObject, number]); - // 공역 생성 - const handlerCreateAirSpace = ( - map, - useGeoJson = { - ...geoJson, - ...flatGimpo, - features: [...geoJson.features, ...flatGimpo.features] - } - ) => { - if (map.getLayer('maine')) { - map.removeLayer('maine'); - map.removeSource('maine'); - } - let arrGeoJson = []; - useGeoJson.features.map(item => { - if (item.properties.type === '0001' && mapControl.area0001) { - arrGeoJson.push({ - ...item, - properties: { ...item.properties, color: '#FF3648' } - }); - } else if (item.properties.type === '0002' && mapControl.area0002) { - arrGeoJson.push({ - ...item, - properties: { ...item.properties, color: '#FFA1AA' } - }); - } else if (item.properties.type === '0003' && mapControl.area0003) { - arrGeoJson.push({ - ...item, - properties: { ...item.properties, color: '#FFA800' } - }); - } else if (item.properties.type === '0004' && mapControl.area0004) { - arrGeoJson.push({ - ...item, - properties: { ...item.properties, color: '#A16B00' } - }); - } else if (item.properties.type === '0005' && mapControl.area0005) { - arrGeoJson.push({ - ...item, - properties: { ...item.properties, color: '#AB40FF' } - }); - } else if (item.properties.type === '0006' && mapControl.area0006) { - arrGeoJson.push({ - ...item, - properties: { ...item.properties, color: '#009cad' } - }); - } - }); - useGeoJson.features = arrGeoJson.filter(i => i.geometry.type === 'Polygon'); - - // 공역 생성 start - map.addSource('maine', { - type: 'geojson', - data: { - ...useGeoJson - } - }); - map.addLayer({ - id: 'maine', - type: 'fill', - source: 'maine', - layout: {}, - paint: { - 'fill-color': ['get', 'color'], - // 'fill-extrusion-height': 3000, - 'fill-opacity': 0.5 - } - }); - }; - + // 맵박스 지도 초기 셋팅 const handlerMapInit = () => { mapboxgl.accessToken = MAPBOX_TOKEN; @@ -187,7 +108,6 @@ export default function LaancAreaMap({ container: 'detail', // container ID style: 'mapbox://styles/mapbox/streets-v12', // style URL center: [126.612647, 37.519893], // starting position [lng, lat] - // zoom: !areaCoordList ? 14 : bufferZoom.bufferzoom, // starting zoom zoom: 15, antialias: true, attributionControl: false @@ -238,31 +158,15 @@ export default function LaancAreaMap({ } }); - map.addSource('detail', { - type: 'geojson', - data: detailGeo - }); - map.addLayer(layerWayPoint('detail')); - map.addLayer(layerGuideLine('detail')); - map.addLayer(layerPolyline('detail')); - map.addLayer(layerPolygon('detail')); - map.addLayer(layerBuffer('detail')); - - handlerCreateAirSpace(map); + handlerCreateAirSpace(map, mapControl); setIsMapLoad(true); - - // const detail = map.getSource('detail'); - // if (detail) setDetailLayer(detail); }); + setMapObject(map); dispatch(mapInitAction(map)); }; - // const handlerInitCoordinates = () => { - // const init = initFlightBas.initDetail.areaList.concat(); - // dispatch(AREA_COORDINATE_LIST_SAVE(init)); - // }; - + // areaInfo를 areaList 형식으로 반환 const handlerAreaInfoToAreaList = areaInfo => { const initAreaList = initFlightBas.initDetail.areaList.concat(); const coordList = []; @@ -287,10 +191,10 @@ export default function LaancAreaMap({ return areaList; }; + // 비행관제구역 체크 및 버퍼 생성 const handlerCoordinates = areaInfo => { const areaList = handlerAreaInfoToAreaList(areaInfo); - // dispatch(LaancAction.LAANC_ALTITUDE.request(areaList)); dispatch(LaancAction.LAANC_VALID_AREA.request(areaList)); if (areaInfo.areaType === 'LINE' || areaInfo.areaType === 'POLYGON') { dispatch(FLIGHT_PLAN_AREA_BUFFER_LIST.request(areaList)); @@ -299,6 +203,7 @@ export default function LaancAreaMap({ } }; + // 비행구역 설정 후 저장 const handlerConfirm = areaList => { if (areaList === undefined) { alert('영역을 설정해 주세요.'); @@ -308,17 +213,14 @@ export default function LaancAreaMap({ dispatch(AREA_COORDINATE_LIST_SAVE(areaList)); }; - // const handlerModal = () => { - // setModal(!modal); - // }; - - // 좌표 정보 마우스 드래그 + // [좌표 정보] 마우스 다운 시 스크롤 준비 const onMouseDown = e => { e.preventDefault(); setIsDrag(true); setStartX(e.pageX + scrollRef.current.scrollLeft); }; + // [좌표 정보] 마우스 드래그로 스크롤 이동 const onMouseMove = e => { if (isDrag) { const { scrollWidth, clientWidth, scrollLeft } = scrollRef.current; @@ -333,6 +235,7 @@ export default function LaancAreaMap({ } }; + // [좌표 정보] onMouseMove 이벤트 빈도 조절 const throttle = (func, ms) => { let throttled = false; return (...args) => { @@ -346,11 +249,13 @@ export default function LaancAreaMap({ }; }; + // [좌표 정보] 마우스 업 시 스크롤 멈춤 const onMouseUp = e => { e.preventDefault(); setIsDrag(false); }; + // [좌표 정보] 마우스 벗어날 시 스크롤 멈춤 const onMouseLeave = () => { setIsDrag(false); }; @@ -455,21 +360,20 @@ export default function LaancAreaMap({ {isMapLoad && mapObject ? ( <> diff --git a/src/components/laanc/map/LaancComn.js b/src/components/laanc/map/LaancComn.js new file mode 100644 index 0000000..d8e30a8 --- /dev/null +++ b/src/components/laanc/map/LaancComn.js @@ -0,0 +1,73 @@ +import { useSelector } from 'react-redux'; +import geoJson from '../../map/geojson/airArea.json'; +import flatGimpo from '../../map/geojson/flatGimpoAirportAirArea.json'; + +// 공역 생성 +export const handlerCreateAirSpace = ( + map, + mapControl, + useGeoJson = { + ...geoJson, + ...flatGimpo, + features: [...geoJson.features, ...flatGimpo.features] + } +) => { + if (map.getLayer('maine')) { + map.removeLayer('maine'); + map.removeSource('maine'); + } + let arrGeoJson = []; + useGeoJson.features.map(item => { + if (item.properties.type === '0001' && mapControl.area0001) { + arrGeoJson.push({ + ...item, + properties: { ...item.properties, color: '#FF3648' } + }); + } else if (item.properties.type === '0002' && mapControl.area0002) { + arrGeoJson.push({ + ...item, + properties: { ...item.properties, color: '#FFA1AA' } + }); + } else if (item.properties.type === '0003' && mapControl.area0003) { + arrGeoJson.push({ + ...item, + properties: { ...item.properties, color: '#FFA800' } + }); + } else if (item.properties.type === '0004' && mapControl.area0004) { + arrGeoJson.push({ + ...item, + properties: { ...item.properties, color: '#A16B00' } + }); + } else if (item.properties.type === '0005' && mapControl.area0005) { + arrGeoJson.push({ + ...item, + properties: { ...item.properties, color: '#AB40FF' } + }); + } else if (item.properties.type === '0006' && mapControl.area0006) { + arrGeoJson.push({ + ...item, + properties: { ...item.properties, color: '#009cad' } + }); + } + }); + useGeoJson.features = arrGeoJson.filter(i => i.geometry.type === 'Polygon'); + + // 공역 생성 start + map.addSource('maine', { + type: 'geojson', + data: { + ...useGeoJson + } + }); + map.addLayer({ + id: 'maine', + type: 'fill', + source: 'maine', + layout: {}, + paint: { + 'fill-color': ['get', 'color'], + // 'fill-extrusion-height': 3000, + 'fill-opacity': 0.5 + } + }); +}; diff --git a/src/components/laanc/map/LaancDrawControl.js b/src/components/laanc/map/LaancDrawControl.js index 0dd2ef9..58990f2 100644 --- a/src/components/laanc/map/LaancDrawControl.js +++ b/src/components/laanc/map/LaancDrawControl.js @@ -1,5 +1,4 @@ import { useEffect, useRef, useState } from 'react'; -import { InfoModal } from '../../modal/InfoModal'; import { ErrorModal } from '../../modal/ErrorModal'; import { useDispatch, useSelector } from 'react-redux'; import { @@ -25,36 +24,42 @@ import Constants from 'mapbox-gl-draw-circle/node_modules/@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; + // 비행구역 타입 + const { drawType } = useSelector(state => state.controlMapReducer); + + // mapbox 기본 onClick 함수 저장 + const originClickRef = useRef(null); + + // 비행구역이 WayPoint일 때 bufferId const [bufferId, setBufferId] = useState(); + // 그리기모드 상태인지 유무 확인 const [isDrawDone, setIsDrawDone] = useState(false); - const [alertModal, setAlertModal] = useState({ - isOpen: false, - title: '', - desc: '' - }); + // 지도 렌더 횟수 + const [number, setNumber] = useState(0); + + // 에러 모달창 정보 const [isErrorModal, setIsErrorModal] = useState({ isOpen: false, title: '', desc: '' }); - const [number, setNumber] = useState(0); - + // 비행구역 타입 변경에 따른 그리기모드 셋팅 useEffect(() => { - if (mapControl.drawType === 'DONE') { - // 구역 생성 후 바로 directMode + if (drawType === 'DONE') { if (number !== 0) { const obj = drawObj .getAll() .features.filter(o => o.properties.id !== 'BUFFER'); + + // 구역 생성 후 바로 directMode if (obj.length > 0) { drawObj.changeMode('direct_select', { featureId: obj[obj.length - 1]?.id @@ -64,10 +69,9 @@ export const LaancDrawControl = props => { } else { drawInit(); } - }, [mapControl.drawType]); - - const originClickRef = useRef(null); + }, [drawType]); + // mapbox 기본 함수 오버라이드 및 함수 중복 등록 방지 useEffect(() => { if (mapObject) { const DrawLineStringMode = MapboxDraw.modes.draw_line_string; @@ -75,6 +79,7 @@ export const LaancDrawControl = props => { const DrawCircleMode = CircleMode; const modeArr = [DrawLineStringMode, DrawPolygonMode, DrawCircleMode]; + // 등록 함수 제거 const cleanUp = () => { modeArr.forEach(m => { m.onStop = null; @@ -154,6 +159,7 @@ export const LaancDrawControl = props => { setNumber(number + 1); } + // 컴포넌트 언마운트 시 return () => { dispatch(drawTypeChangeAction('DONE')); mapObject.off('draw.update', handlerUpdateSetting); @@ -162,10 +168,12 @@ export const LaancDrawControl = props => { } }, [mapObject]); + // 비행구역 데이터 지도에 다시 그려주기 useEffect(() => { handlerPastDraw(); }, [props.areaCoordList]); + // 비행구역 설정을 올바르게 마쳤을 때 좌표 저장 useEffect(() => { if (isDrawDone) { props.handlerConfirm(props.areaCoordList); @@ -173,7 +181,7 @@ export const LaancDrawControl = props => { } }, [isDrawDone]); - // 클릭할 때마다 마커 찍어줌 + // 클릭할 때마다 마커 표출 const handlerCustomOnClick = (state, e) => { const mode = handlerReturnMode(drawObj.getMode()); const obj = state[mode?.toLowerCase()]; @@ -181,7 +189,7 @@ export const LaancDrawControl = props => { if (mode && obj) { const feature = drawObj.get(obj.id); if (!feature) { - console.log('2222222222'); + // console.log('simple_select'); drawObj.changeMode('simple_select'); return; } @@ -220,7 +228,7 @@ export const LaancDrawControl = props => { } }; - // 도형 그리기 완료 시 + // 비행구역 그리기 완료 시 const handlerFinishDraw = state => { if (drawObj.getAll().features.length === 0) return; @@ -293,8 +301,7 @@ export const LaancDrawControl = props => { }); } } else { - console.log('333333333'); - // 좌표가 찍히기도 전에 틀만 생성된 도형들 삭제 + // console.log('좌표가 찍히기도 전에 틀만 생성된 도형들 삭제'); // if (mode === 'CIRCLE') { // const obj = state.polygon; // drawObj.delete(obj.id); @@ -307,7 +314,7 @@ export const LaancDrawControl = props => { // 모든 비정상상황 체크 const handlerAbnormalityCheck = async data => { - // radius도 있음 + // radius 존재함 const { coords, mode, id } = data; const areaInfo = handlerSettingAreaInfo(coords, mode); @@ -411,7 +418,7 @@ export const LaancDrawControl = props => { } }; - // 도형 수정 시 + // 비행구역 수정 시 const handlerUpdateSetting = e => { if (e.features[0]) { const { geometry, properties, id } = e.features[0]; @@ -482,7 +489,7 @@ export const LaancDrawControl = props => { ); props.setViewCoordObj(viewCoordObj); - // 계속 20개 미만이라 overAdd false처리(임시) + // 계속 20개 미만이라 overAdd false처리 props.handlerAddChange('overAdd', false); }; @@ -565,12 +572,12 @@ export const LaancDrawControl = props => { return true; }; + // 저장된 비행구역 데이터를 기반으로 지도에 다시 그려주기 const handlerPastDraw = () => { if (props.areaCoordList) { const objs = drawObj?.getAll().features; const areas = props.areaCoordList; if (areas.length > 0 && objs.length > 0) { - // areas -> 현재는 1개이지만 추후에 데이터가 바뀌면 여러개의 도형도 처리 가능! areas.map((area, idx) => { const paths = []; area.coordList.forEach(coord => paths.push([coord.lon, coord.lat])); @@ -639,7 +646,7 @@ export const LaancDrawControl = props => { } objId = polygonId; } - // 마커를 삭제하고 다시 그려주기 + // 마커를 삭제하고 다시 그려줌 const data = { coord: area.areaType === 'LINE' ? paths : [paths], id: objId @@ -754,8 +761,9 @@ export const LaancDrawControl = props => { return newObjId[0]; }; + // 비행구역 기본셋팅 const drawInit = () => { - const mode = mapControl.drawType; + const mode = drawType; if (mode !== 'DONE') { if (!mode || mode === 'RESET') { handlerResetMode(); @@ -790,6 +798,7 @@ export const LaancDrawControl = props => { drawObj.changeMode('simple_select'); }; + // 그리기모드 셋팅 const handlerStartMode = mode => { if (mode === 'LINE') { drawObj.changeMode('draw_line_string'); @@ -802,7 +811,6 @@ export const LaancDrawControl = props => { return ( <> - ); diff --git a/src/utility/DrawUtil.js b/src/utility/DrawUtil.js index 87553f1..19cb367 100644 --- a/src/utility/DrawUtil.js +++ b/src/utility/DrawUtil.js @@ -2,6 +2,7 @@ import * as turf from '@turf/turf'; import mapboxgl from 'mapbox-gl'; import 'mapbox-gl/dist/mapbox-gl.css'; +// geojson Feature 형식으로 반환 export const InitFeature = (type, id) => { return { type: 'Feature', @@ -43,6 +44,13 @@ export const CalculateDistance = (mouse, center) => { return distance; }; +// 미터 반환(m붙여서) +export const fromMetersToText = meters => { + meters = meters || 0; + const text = parseFloat(meters.toFixed(1)) + 'm'; + return text; +}; + // 두 좌표 간의 중간 지점 좌표 반환 export const handlerGetMidPoint = (dis1, dis2) => { return [(dis1[0] + dis2[0]) / 2, (dis1[1] + dis2[1]) / 2]; @@ -63,13 +71,6 @@ export const handlerGetHtmlContent = (distance, id) => { ); }; -// 미터 반환(m붙여서) -export const fromMetersToText = meters => { - meters = meters || 0; - const text = parseFloat(meters.toFixed(1)) + 'm'; - return text; -}; - // circle 360도 좌표 반환 export const handlerGetCircleCoord = (center, distance) => { const options = { @@ -183,25 +184,6 @@ export const layerWayPoint = source => { }; }; -export const layerGuideLine = source => { - return { - id: 'guideline', - type: 'line', - source: source, - layout: { - 'line-cap': 'round', - 'line-join': 'round' - }, - paint: { - 'line-color': '#283046', - 'line-width': 2, - 'line-opacity': 0.5, - 'line-dasharray': [5, 5] - }, - filter: ['==', ['get', 'id'], 'guideline'] - }; -}; - export const layerPolyline = source => { return { id: 'polyline',