junh_eee(이준희)
10 months ago
10 changed files with 0 additions and 2495 deletions
@ -1,543 +0,0 @@
|
||||
import { useEffect, useRef, useState } from 'react'; |
||||
import 'mapbox-gl/dist/mapbox-gl.css'; |
||||
import mapboxgl from 'mapbox-gl'; |
||||
import MapboxLanguage from '@mapbox/mapbox-gl-language'; |
||||
import { MAPBOX_TOKEN } from '../../../../configs/constants'; |
||||
import { |
||||
Card, |
||||
CardBody, |
||||
Button, |
||||
ButtonGroup, |
||||
Input, |
||||
InputGroup, |
||||
InputGroupAddon, |
||||
InputGroupText, |
||||
Modal, |
||||
ModalHeader, |
||||
ModalBody, |
||||
ModalFooter |
||||
} from 'reactstrap'; |
||||
import { useDispatch, useSelector } from 'react-redux'; |
||||
import { initFlightBas } from '../../../../modules/basis/flight/models/basisFlightModel'; |
||||
import { |
||||
AREA_COORDINATE_LIST_SAVE, |
||||
AREA_DETAIL_INIT, |
||||
FLIGHT_PLAN_AREA_BUFFER_LIST |
||||
} from '../../../../modules/basis/flight/actions/basisFlightAction'; |
||||
import { flightPlanAPI } from '../../../../modules/basis/flight/apis/basisFlightApi'; |
||||
import { Search } from 'react-feather'; |
||||
import { FeatureAirZone } from '../../../map/mapbox/feature/FeatureAirZone'; |
||||
import { drawTypeChangeAction } from '../../../../modules/control/map/actions/controlMapActions'; |
||||
import { MapBoxDraw } from '../../../map/mapbox/draw/MapBoxDraw'; |
||||
import { WeatherContainer } from '../../../../containers/basis/flight/plan/WeatherContainer'; |
||||
|
||||
export const FlightPlanAreaMapBox = props => { |
||||
const dispatch = useDispatch(); |
||||
const mapControl = useSelector(state => state.controlMapReducer); |
||||
const { areaCoordList } = useSelector(state => state.flightState); |
||||
|
||||
const mapContainer = useRef(null); |
||||
const [mapObject, setMapObject] = useState(); |
||||
const [isMapLoad, setIsMapLoad] = useState(false); |
||||
const [mode, setMode] = useState(); |
||||
const [mapAreaCoordList, setMapAreaCoordList] = useState( |
||||
initFlightBas.initDetail.areaList |
||||
); |
||||
|
||||
const [query, setQuery] = useState(''); |
||||
const [searchRes, setSearchRes] = useState([]); |
||||
const [isSearch, setIsSearch] = useState(false); |
||||
|
||||
const [number, setNumber] = useState(0); |
||||
|
||||
const [formModal, setFormModal] = useState(false); |
||||
|
||||
const [layerId, setLayerId] = useState(); |
||||
const buildingLayer = { |
||||
id: 'add-3d-buildings', |
||||
source: 'composite', |
||||
'source-layer': 'building', |
||||
filter: ['==', 'extrude', 'true'], |
||||
type: 'fill-extrusion', |
||||
minzoom: 15, |
||||
paint: { |
||||
'fill-extrusion-color': '#aaa', |
||||
|
||||
// Use an 'interpolate' expression to
|
||||
// add a smooth transition effect to
|
||||
// the buildings as the user zooms in.
|
||||
'fill-extrusion-height': [ |
||||
'interpolate', |
||||
['linear'], |
||||
['zoom'], |
||||
15, |
||||
0, |
||||
15.05, |
||||
['get', 'height'] |
||||
], |
||||
'fill-extrusion-base': [ |
||||
'interpolate', |
||||
['linear'], |
||||
['zoom'], |
||||
15, |
||||
0, |
||||
15.05, |
||||
['get', 'min_height'] |
||||
], |
||||
'fill-extrusion-opacity': 0.6 |
||||
} |
||||
}; |
||||
const terrainLayer = { |
||||
type: 'raster-dem', |
||||
url: 'mapbox://mapbox.mapbox-terrain-dem-v1' |
||||
// url: 'mapbox://mapbox.mapbox-street-v1',
|
||||
// tileSize: 512,
|
||||
// maxZoom: 16,
|
||||
}; |
||||
|
||||
const geojson = { |
||||
type: 'FeatureCollection', |
||||
features: [] |
||||
}; |
||||
|
||||
useEffect(() => { |
||||
mapBoxMapInit(); |
||||
|
||||
return () => { |
||||
dispatch(AREA_DETAIL_INIT()); |
||||
}; |
||||
}, []); |
||||
|
||||
useEffect(() => { |
||||
setMode(mapControl.drawType); |
||||
}, [mapControl.drawType]); |
||||
|
||||
useEffect(() => { |
||||
if (areaCoordList && mapObject) { |
||||
if ( |
||||
areaCoordList[0].coordList[0].lat !== 0 && |
||||
areaCoordList[0].coordList[0].lon !== 0 |
||||
) { |
||||
if (number === 0) { |
||||
mapObject.setCenter([ |
||||
areaCoordList[0].coordList[0].lon, |
||||
areaCoordList[0].coordList[0].lat |
||||
]); |
||||
setNumber(number + 1); |
||||
} |
||||
} |
||||
setMapAreaCoordList(areaCoordList); |
||||
} |
||||
}, [areaCoordList, mapObject, number]); |
||||
|
||||
const mapBoxMapInit = () => { |
||||
const bufferZoom = {}; |
||||
if (areaCoordList) { |
||||
if ( |
||||
areaCoordList[0].bufferZone >= 0 && |
||||
areaCoordList[0].bufferZone < 2000 |
||||
) { |
||||
bufferZoom.bufferzoom = 13; |
||||
} else if ( |
||||
areaCoordList[0].bufferZone >= 2000 && |
||||
areaCoordList[0].bufferZone < 5000 |
||||
) { |
||||
bufferZoom.bufferzoom = 12; |
||||
} else if ( |
||||
areaCoordList[0].bufferZone >= 5000 && |
||||
areaCoordList[0].bufferZone <= 9000 |
||||
) { |
||||
bufferZoom.bufferzoom = 11; |
||||
} else { |
||||
bufferZoom.bufferzoom = 10; |
||||
} |
||||
} |
||||
|
||||
mapboxgl.accessToken = MAPBOX_TOKEN; |
||||
|
||||
const map = new mapboxgl.Map({ |
||||
container: 'map', // 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 |
||||
}); |
||||
|
||||
const language = new MapboxLanguage(); |
||||
map.addControl(language); |
||||
|
||||
map.on('load', () => { |
||||
const layers = map.getStyle().layers; |
||||
|
||||
const labelLayerId = layers.find( |
||||
layer => layer.type === 'symbol' && layer.layout['text-field'] |
||||
).id; |
||||
setLayerId(labelLayerId); |
||||
|
||||
// 지형 3d start
|
||||
map.addSource('mapbox-dem', terrainLayer); |
||||
map.setTerrain({ source: 'mapbox-dem', exaggeration: 1.5 }); |
||||
|
||||
map.addLayer(buildingLayer, labelLayerId); |
||||
|
||||
//mapDraw layer
|
||||
map.addSource('geojson', { |
||||
type: 'geojson', |
||||
data: geojson |
||||
}); |
||||
map.addLayer({ |
||||
id: 'waypoint', |
||||
type: 'circle', |
||||
source: 'geojson', |
||||
paint: { |
||||
'circle-radius': 5, |
||||
'circle-color': '#ffffff', |
||||
'circle-stroke-color': '#000000', |
||||
'circle-stroke-width': 1 |
||||
}, |
||||
filter: ['in', '$type', 'Point'] |
||||
}); |
||||
map.addLayer({ |
||||
id: 'guideline', |
||||
type: 'line', |
||||
source: 'geojson', |
||||
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'] |
||||
}); |
||||
map.addLayer({ |
||||
id: 'polyline', |
||||
type: 'line', |
||||
source: 'geojson', |
||||
layout: { |
||||
'line-cap': 'round', |
||||
'line-join': 'round' |
||||
}, |
||||
paint: { |
||||
'line-color': '#283046', |
||||
'line-width': 2 |
||||
}, |
||||
filter: ['in', ['get', 'id'], ['literal', ['polyline', 'outline']]] |
||||
}); |
||||
map.addLayer({ |
||||
id: 'polygon', |
||||
type: 'fill', |
||||
source: 'geojson', |
||||
layout: {}, |
||||
paint: { |
||||
'fill-color': '#8a1c05', |
||||
'fill-opacity': 0.5, |
||||
'fill-outline-color': '#000000' |
||||
}, |
||||
//polygon, circle에 사용
|
||||
filter: ['in', '$type', 'Polygon'] |
||||
}); |
||||
map.addLayer({ |
||||
id: 'buffer', |
||||
type: 'line', |
||||
source: 'geojson', |
||||
layout: { |
||||
'line-cap': 'round', |
||||
'line-join': 'round' |
||||
}, |
||||
paint: { |
||||
'line-color': '#283046', |
||||
'line-width': 1, |
||||
'line-dasharray': [5, 5] |
||||
}, |
||||
filter: ['==', ['get', 'id'], 'buffer'] |
||||
}); |
||||
setMapObject(map); |
||||
setIsMapLoad(true); |
||||
}); |
||||
}; |
||||
|
||||
const handlerMapTypeSwitch = type => { |
||||
if (type === '2d') { |
||||
mapObject.dragRotate.disable(); |
||||
if (mapObject.getLayer('add-3d-buildings')) { |
||||
mapObject.removeLayer('add-3d-buildings'); |
||||
|
||||
mapObject.setTerrain(); |
||||
mapObject.removeSource('mapbox-dem'); |
||||
mapObject.flyTo({ |
||||
pitch: 0, |
||||
bearing: 0 |
||||
}); |
||||
} |
||||
} else if (type === '3d') { |
||||
mapObject.dragRotate.enable(); |
||||
if (!mapObject.getLayer('add-3d-buildings')) { |
||||
mapObject.addLayer(buildingLayer, layerId); |
||||
|
||||
mapObject.addSource('mapbox-dem', terrainLayer); |
||||
mapObject.setTerrain({ source: 'mapbox-dem', exaggeration: 1.5 }); |
||||
} |
||||
} |
||||
}; |
||||
|
||||
//지역 검색
|
||||
const handlerSearch = async () => { |
||||
const res = await flightPlanAPI.searchArea({ query: query }); |
||||
setIsSearch(true); |
||||
setSearchRes(res.data.items); |
||||
}; |
||||
|
||||
const handlerChange = e => { |
||||
const { name, value } = e.target; |
||||
|
||||
if (name == 'searchInput') { |
||||
setQuery(value); |
||||
} |
||||
}; |
||||
|
||||
const handlerEnter = e => { |
||||
if (e.key == 'Enter') { |
||||
handlerSearch(); |
||||
} |
||||
}; |
||||
|
||||
const handlerCoord = (mapx, mapy) => { |
||||
const numberString = [mapx, mapy]; |
||||
const latlng = []; |
||||
|
||||
numberString.map(coord => { |
||||
let digits = coord.split(''); |
||||
|
||||
if (digits[0] !== '1') { |
||||
digits.splice(2, 0, '.'); |
||||
} else { |
||||
digits.splice(3, 0, '.'); |
||||
} |
||||
|
||||
latlng.push(Number(digits.join(''))); |
||||
}); |
||||
|
||||
setIsSearch(false); |
||||
mapObject.setCenter(latlng); |
||||
mapObject.setZoom(15); |
||||
}; |
||||
|
||||
const handler = () => { |
||||
setFormModal(!formModal); |
||||
}; |
||||
|
||||
const handlerDrawType = val => { |
||||
dispatch(drawTypeChangeAction(val)); |
||||
}; |
||||
|
||||
const handlerInitCoordinates = () => { |
||||
const init = initFlightBas.initDetail.areaList.concat(); |
||||
dispatch(AREA_COORDINATE_LIST_SAVE(init)); |
||||
}; |
||||
|
||||
const handlerCoordinates = areaInfo => { |
||||
const initAreaList = initFlightBas.initDetail.areaList.concat(); |
||||
const coordList = []; |
||||
|
||||
areaInfo.coordinates.forEach((c, idx) => { |
||||
const coord = Object.assign({}, initFlightBas['coord']); |
||||
coord.lat = c.lat; |
||||
coord.lon = c.lon; |
||||
|
||||
coordList.push(coord); |
||||
}); |
||||
|
||||
const areaList = initAreaList.map((area, idx) => { |
||||
return { |
||||
...area, |
||||
bufferZone: areaInfo.bufferZone, |
||||
areaType: areaInfo.areaType, |
||||
coordList: coordList |
||||
}; |
||||
}); |
||||
|
||||
if (areaInfo.areaType === 'LINE' || areaInfo.areaType === 'POLYGON') { |
||||
dispatch(FLIGHT_PLAN_AREA_BUFFER_LIST.request(areaList)); |
||||
} else { |
||||
setMapAreaCoordList(areaList); |
||||
} |
||||
}; |
||||
|
||||
const handlerConfirm = areaList => { |
||||
if (areaList === undefined) { |
||||
alert('영역을 설정해 주세요.'); |
||||
return false; |
||||
} |
||||
|
||||
dispatch(AREA_COORDINATE_LIST_SAVE(areaList)); |
||||
}; |
||||
|
||||
return ( |
||||
<Card className='mb-0'> |
||||
<CardBody> |
||||
<div className='search-cont search-info pd-0'> |
||||
<div className='cont-ti mb-1 d-flex justify-content-between align-items-sm-center align-items-start flex-sm-row'> |
||||
<div> |
||||
<h4>지도 영역</h4> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
||||
<div style={{ position: 'relative' }}> |
||||
<div |
||||
id='map' |
||||
ref={mapContainer} |
||||
style={{ width: '100%', height: '60vh' }} |
||||
> |
||||
{isMapLoad && mapObject ? ( |
||||
<MapBoxDraw |
||||
mapObject={mapObject} |
||||
mapboxgl={mapboxgl} |
||||
mode={mode} |
||||
areaCoordList={mapAreaCoordList} |
||||
handlerCoordinates={handlerCoordinates} |
||||
handlerInitCoordinates={handlerInitCoordinates} |
||||
handlerConfirm={handlerConfirm} |
||||
isDone={props.isDone} |
||||
isDisabled={props.isDisabled} |
||||
geojson={geojson} |
||||
handlerDrawType={handlerDrawType} |
||||
/> |
||||
) : null} |
||||
<div className='d-flex search-comp absolute'> |
||||
<div className=''> |
||||
<InputGroup className='search-feather'> |
||||
<InputGroupAddon addonType='prepend'> |
||||
<InputGroupText> |
||||
<Search size={14} onClick={handlerSearch} /> |
||||
</InputGroupText> |
||||
</InputGroupAddon> |
||||
<Input |
||||
type='text' |
||||
id='searchInput' |
||||
name='searchInput' |
||||
bsSize='sm' |
||||
autoComplete='off' |
||||
placeholder='검색명을 입력하세요.' |
||||
onChange={handlerChange} |
||||
onKeyPress={handlerEnter} |
||||
/> |
||||
</InputGroup> |
||||
<div className='search-result-comp'> |
||||
<ul> |
||||
{searchRes?.length !== 0 && isSearch ? ( |
||||
searchRes?.map(search => { |
||||
const title = search.title |
||||
.replaceAll('<b>', '') |
||||
.replaceAll('</b>', ''); |
||||
|
||||
return ( |
||||
<li |
||||
key={search.mapx + search.mapy} |
||||
onClick={() => |
||||
handlerCoord(search.mapx, search.mapy) |
||||
} |
||||
> |
||||
<a> |
||||
<div className='search-result'> |
||||
<div className='title'> |
||||
<span> |
||||
<strong>{title}</strong> |
||||
</span> |
||||
</div> |
||||
<div className='address'> |
||||
<span>{search.roadAddress}</span> |
||||
</div> |
||||
</div> |
||||
</a> |
||||
</li> |
||||
); |
||||
}) |
||||
) : ( |
||||
<></> |
||||
)} |
||||
</ul> |
||||
</div> |
||||
</div> |
||||
<div> |
||||
<ButtonGroup> |
||||
<Button onClick={() => handlerMapTypeSwitch('2d')}>2D</Button> |
||||
<Button onClick={() => handlerMapTypeSwitch('3d')}>3D</Button> |
||||
</ButtonGroup> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
||||
{isMapLoad ? ( |
||||
<FeatureAirZone map={mapObject} mapboxgl={mapboxgl} /> |
||||
) : null} |
||||
|
||||
<div className='d-flex align-items-center mt-2'> |
||||
<Button.Ripple |
||||
className='mr-1' |
||||
color='primary' |
||||
onClick={e => handlerDrawType('LINE')} |
||||
disabled={props.isDisabled || props.isDone} |
||||
> |
||||
WayPoint |
||||
</Button.Ripple> |
||||
<Button.Ripple |
||||
className='mr-1' |
||||
color='primary' |
||||
onClick={e => handlerDrawType('CIRCLE')} |
||||
disabled={props.isDisabled || props.isDone} |
||||
> |
||||
Circle |
||||
</Button.Ripple> |
||||
<Button.Ripple |
||||
className='mr-1' |
||||
color='primary' |
||||
onClick={e => handlerDrawType('POLYGON')} |
||||
disabled={props.isDisabled || props.isDone} |
||||
> |
||||
Polygon |
||||
</Button.Ripple> |
||||
<Button.Ripple |
||||
color='primary' |
||||
className='mr-1' |
||||
onClick={e => handlerDrawType('RESET')} |
||||
disabled={props.isDisabled || props.isDone} |
||||
> |
||||
초기화 |
||||
</Button.Ripple> |
||||
{areaCoordList ? ( |
||||
areaCoordList[0].coordList[0].lat ? ( |
||||
<Button.Ripple color='primary' onClick={handler}> |
||||
날씨 |
||||
</Button.Ripple> |
||||
) : null |
||||
) : ( |
||||
<></> |
||||
)} |
||||
</div> |
||||
<Modal |
||||
isOpen={formModal} |
||||
toggle={handler} |
||||
className='modal-dialog-centered' |
||||
> |
||||
<ModalHeader toggle={handler}>날씨 정보</ModalHeader> |
||||
<ModalBody> |
||||
<WeatherContainer mapAreaCoordList={mapAreaCoordList} /> |
||||
</ModalBody> |
||||
<ModalFooter> |
||||
<Button color='primary' onClick={handler}> |
||||
확인 |
||||
</Button> |
||||
</ModalFooter> |
||||
</Modal> |
||||
</CardBody> |
||||
</Card> |
||||
); |
||||
}; |
@ -1,544 +0,0 @@
|
||||
import React, { useEffect, useState } from 'react'; |
||||
import { DronMarker } from './dron/DronMarker'; |
||||
import NaverMapControl from './NaverMapControl'; |
||||
import { FeatureAirZone } from './feature/FeatureAirZone'; |
||||
import geoJson from '../geojson/airArea.json'; |
||||
import gimPo from '../geojson/airportAirArea.json'; |
||||
import NewDronPlan from './dron/NewDronPlan'; |
||||
import DronToast from './dron/DronToast'; |
||||
import ControlDraw from './draw/ControlDraw'; |
||||
|
||||
export const NaverCustomMap = () => { |
||||
const naver = window.naver; |
||||
|
||||
const [mapObject, setMapObject] = useState(null); |
||||
const [arrPolyline, setArrPolyline] = useState([]); |
||||
|
||||
const [poly, setPoly] = useState([]); |
||||
const [coordCenter, setCoordCenter] = useState([]); |
||||
const airPort = [ |
||||
{ |
||||
title: '김포공항', |
||||
buffer: 9300, |
||||
center: new naver.maps.LatLng(37.558522, 126.793722), |
||||
reduce: [54.4, 218.6, 500, 905.4, 1459.8, 2195, 3173.5, 4552.5, 6952.5] |
||||
}, |
||||
{ |
||||
title: '인천공항', |
||||
buffer: 9300, |
||||
center: new naver.maps.LatLng(37.4588105, 126.4409428), |
||||
reduce: [54.4, 218.6, 500, 905.4, 1459.8, 2195, 3173.5, 4552.5, 6952.5] |
||||
}, |
||||
{ |
||||
title: '제주공항', |
||||
buffer: 9300, |
||||
center: new naver.maps.LatLng(33.506848, 126.4930205), |
||||
reduce: [54.4, 218.6, 500, 905.4, 1459.8, 2195, 3173.5, 4552.5, 6952.5] |
||||
}, |
||||
{ |
||||
title: '정석비행장', |
||||
buffer: 9300, |
||||
center: new naver.maps.LatLng(33.3943517, 126.7142598), |
||||
reduce: [54.4, 218.6, 500, 905.4, 1459.8, 2195, 3173.5, 4552.5, 6952.5] |
||||
} |
||||
]; |
||||
|
||||
const [squarePaths, setSquarePaths] = useState([]); |
||||
|
||||
const uamPosition = [ |
||||
{ |
||||
name: 'V1', |
||||
lat: 37.4797865, |
||||
lon: 126.540668 |
||||
}, |
||||
{ |
||||
name: 'V2', |
||||
|
||||
lat: 37.521245, |
||||
lon: 126.6107763 |
||||
}, |
||||
{ |
||||
name: 'V3', |
||||
lat: 37.5642352, |
||||
lon: 126.6243464 |
||||
}, |
||||
{ |
||||
name: 'V4', |
||||
lat: 37.3658236, |
||||
lon: 126.6650669 |
||||
}, |
||||
{ |
||||
name: 'V5', |
||||
lat: 37.4520753, |
||||
lon: 126.7074861 |
||||
}, |
||||
{ |
||||
name: 'R1', |
||||
lat: 37.492581, |
||||
lon: 126.5801572 |
||||
}, |
||||
{ |
||||
name: 'R2', |
||||
lat: 37.542031, |
||||
lon: 126.6036588 |
||||
}, |
||||
{ |
||||
name: 'R3', |
||||
lat: 37.5764269, |
||||
lon: 126.6005224 |
||||
}, |
||||
{ |
||||
name: 'R4', |
||||
lat: 37.5790407, |
||||
lon: 126.6600404 |
||||
}, |
||||
{ |
||||
name: 'R5', |
||||
lat: 37.524016, |
||||
lon: 126.649562 |
||||
}, |
||||
{ |
||||
name: 'R6', |
||||
lat: 37.5506488, |
||||
lon: 126.693722 |
||||
}, |
||||
{ |
||||
name: 'R7', |
||||
lat: 37.4712333, |
||||
lon: 126.6023981 |
||||
}, |
||||
{ |
||||
name: 'R8', |
||||
lat: 37.4046495, |
||||
lon: 126.6202759 |
||||
}, |
||||
{ |
||||
name: 'R9', |
||||
lat: 37.3450207, |
||||
lon: 126.6296542 |
||||
} |
||||
]; |
||||
|
||||
let airArea = geoJson.features; |
||||
let gimPofeatures = gimPo.features; |
||||
let features = airArea.concat(gimPofeatures); |
||||
const coords = []; |
||||
useEffect(() => { |
||||
NaverMapInit(); |
||||
airPort?.map((air, idx) => polyArea(air, idx)); |
||||
// airPort?.map((air, idx) => airlist(air, idx));
|
||||
// airPort?.map((air, idx) => polyArea(air, idx));
|
||||
airPort?.map((air, idx) => { |
||||
gridgrid(air, idx); |
||||
}); |
||||
gimPofeatures.map(air => { |
||||
coords.push({ |
||||
lat: |
||||
(Math.max( |
||||
air.geometry.coordinates[0][0][1], |
||||
air.geometry.coordinates[0][1][1], |
||||
air.geometry.coordinates[0][2][1], |
||||
air.geometry.coordinates[0][3][1] |
||||
) + |
||||
Math.min( |
||||
air.geometry.coordinates[0][0][1], |
||||
air.geometry.coordinates[0][1][1], |
||||
air.geometry.coordinates[0][2][1], |
||||
air.geometry.coordinates[0][3][1] |
||||
)) / |
||||
2, |
||||
lng: |
||||
(Math.max( |
||||
air.geometry.coordinates[0][0][0], |
||||
air.geometry.coordinates[0][1][0], |
||||
air.geometry.coordinates[0][2][0], |
||||
air.geometry.coordinates[0][3][0] |
||||
) + |
||||
Math.min( |
||||
air.geometry.coordinates[0][0][0], |
||||
air.geometry.coordinates[0][1][0], |
||||
air.geometry.coordinates[0][2][0], |
||||
air.geometry.coordinates[0][3][0] |
||||
)) / |
||||
2, |
||||
airspace: air.properties.airspace |
||||
}); |
||||
}); |
||||
setCoordCenter(coords); |
||||
}, []); |
||||
|
||||
useEffect(() => { |
||||
uamPosition.map(uam => { |
||||
const name = uam.name; |
||||
const position = new naver.maps.LatLng(uam.lat, uam.lon); |
||||
const cont = |
||||
name.substr(0, 1) == 'R' |
||||
? [ |
||||
'<div style="border-radius:50%; background:#429629; border: 4px solid #ffffff; padding:5px; width:40px; height:40px; text-align:center">', |
||||
`<span style="color:#ffffff">${name}</span>`, |
||||
'</div>' |
||||
] |
||||
: [ |
||||
'<div style="border-radius:50%; background:#ffffff; border: 4px solid #15298A; padding:5px; width:40px; height:40px; text-align:center ">', |
||||
`<span style="color:#000000">${name}</span>`, |
||||
'</div>' |
||||
]; |
||||
|
||||
new naver.maps.Marker({ |
||||
position: position, |
||||
map: mapObject, |
||||
icon: { |
||||
content: cont.join(''), |
||||
anchor: new naver.maps.Point(20, 20) |
||||
} |
||||
}); |
||||
}); |
||||
// coordCenter = new nl();
|
||||
coordCenter.map((val, idx) => { |
||||
const position = new naver.maps.LatLng( |
||||
val.lat.toFixed(6), |
||||
val.lng.toFixed(6) |
||||
); |
||||
|
||||
// const cont = `<div style=font-size:5px;color:#000000; text-align:center">${val.airspace}</div>`;
|
||||
const marker = new naver.maps.Marker({ |
||||
position: position, |
||||
map: mapObject, |
||||
icon: { |
||||
content: `<div style="color:#000000;font-size:5px;">${val.airspace}</div>`, |
||||
size: new naver.maps.Size(0, 0), |
||||
origin: new naver.maps.Point(0, 0), |
||||
anchor: new naver.maps.Point(5, 5), |
||||
align: 'center' |
||||
} |
||||
}); |
||||
}); |
||||
}, [mapObject, coordCenter]); |
||||
|
||||
// useEffect(() => {
|
||||
// if (squarePaths.length > 315) {
|
||||
// const arr = [];
|
||||
// squarePaths.map((path, idx) => {
|
||||
// const obj = {
|
||||
// type: 'Feature',
|
||||
// geometry: {
|
||||
// type: 'Polygon',
|
||||
// coordinates: [path]
|
||||
// },
|
||||
// properties: {
|
||||
// name: `${idx + 1}번째 영역`,
|
||||
// description: `${idx + 1}번째 영역 입니다.`,
|
||||
// type: '0001'
|
||||
// }
|
||||
// };
|
||||
// arr.push(obj);
|
||||
// });
|
||||
// console.log(arr, '>>>>>');
|
||||
// }
|
||||
// }, [squarePaths]);
|
||||
|
||||
const NaverMapInit = () => { |
||||
const mapOptions = { |
||||
center: new naver.maps.LatLng(37.558522, 126.793722), |
||||
// center: new naver.maps.LatLng(36.56793936069445, 127.85101412107547),
|
||||
// zoom: 10,
|
||||
zoom: 12, |
||||
zoomControl: true, |
||||
mapTypeId: naver.maps.MapTypeId.NORMAR, |
||||
zoomControlOptions: { |
||||
position: naver.maps.Position.TOP_LEFT, |
||||
|
||||
style: naver.maps.ZoomControlStyle.SMALL |
||||
} |
||||
}; |
||||
|
||||
setMapObject(new naver.maps.Map('map', mapOptions)); |
||||
}; |
||||
|
||||
const handleHistoryInit = line => { |
||||
setArrPolyline([...arrPolyline, line]); |
||||
}; |
||||
|
||||
//비행 공역 밖에 있는 값인지 확인하는 코드(추후 사용 할 수 있을 것 같아서 주석 걸어둠)
|
||||
// const incoords = [];
|
||||
// coords.map(coord => {
|
||||
// let centerLat = 37.558522;
|
||||
// let centerLng = 126.793722;
|
||||
// let radius = 9.3;
|
||||
// // let distance = Math.sqrt(
|
||||
// // (coord._lat - centerLat) ** 2 + (coord._lng - centerLng) ** 2
|
||||
// // );
|
||||
// const centerLatRad = (centerLat * Math.PI) / 180;
|
||||
// const centerLngRad = (centerLng * Math.PI) / 180;
|
||||
// const coordlat = (coord._lat.toFixed(6) * Math.PI) / 180;
|
||||
// const coordlng = (coord._lng.toFixed(6) * Math.PI) / 180;
|
||||
|
||||
// const R = 6371; // Radius of the earth in km
|
||||
// const dLat = coordlat - centerLatRad;
|
||||
// const dLon = coordlng - centerLngRad;
|
||||
// const a =
|
||||
// Math.sin(dLat / 2) * Math.sin(dLat / 2) +
|
||||
// Math.sin(dLon / 2) *
|
||||
// Math.sin(dLon / 2) *
|
||||
// Math.cos(centerLatRad) *
|
||||
// Math.cos(coordlat);
|
||||
// const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
|
||||
// const distance = R * c; // Distance in km
|
||||
|
||||
// if (distance <= radius) {
|
||||
// incoords.push(coord);
|
||||
// }
|
||||
// });
|
||||
// setCoordValue(incoords);
|
||||
|
||||
const polyArea = (air, idx) => { |
||||
if (idx === 0) return; |
||||
|
||||
const polyArr = []; |
||||
const radius = air.buffer; |
||||
const position = air.center; //공역 센터
|
||||
const color = '#000'; |
||||
const opacity = 0.7; |
||||
const coords = []; |
||||
|
||||
let angle = 0; |
||||
for (let i = 0; i < 4; i++) { |
||||
angle += 90; |
||||
let buffer = 0; |
||||
// for (let j = 0; j < 4; j++) {
|
||||
for (let j = 0; j < 9; j++) { |
||||
// buffer += 2000;
|
||||
buffer += 1000; |
||||
|
||||
//EPSG3857.getDestinationCoord
|
||||
//지정한 좌표에서 북쪽을 기준으로 각도와 거리만큼 떨어진 위치의 좌표 반환
|
||||
const coord = new naver.maps.EPSG3857.getDestinationCoord( |
||||
position, |
||||
angle, |
||||
buffer |
||||
); |
||||
// console.log('coord>>>>>', coord);
|
||||
// coords.push(coord);
|
||||
// setCoordValue(coords);
|
||||
let reduce = 0; |
||||
reduce = air.reduce[j]; |
||||
|
||||
// 2km reduce
|
||||
// [218.6, 905.4, 2195, 4560.2]
|
||||
|
||||
if (angle % 180 == 0) { |
||||
const polyEW = new naver.maps.Polyline({ |
||||
path: [ |
||||
new naver.maps.EPSG3857.getDestinationCoord( |
||||
coord, |
||||
90, |
||||
radius - reduce |
||||
), |
||||
new naver.maps.EPSG3857.getDestinationCoord( |
||||
coord, |
||||
270, |
||||
radius - reduce |
||||
) |
||||
], |
||||
strokeWeight: 0.8, |
||||
strokeOpacity: opacity, |
||||
strokeColor: color |
||||
// map: map
|
||||
}); |
||||
polyArr.push(polyEW); |
||||
} else { |
||||
const polyNS = new naver.maps.Polyline({ |
||||
path: [ |
||||
new naver.maps.EPSG3857.getDestinationCoord( |
||||
coord, |
||||
0, |
||||
radius - reduce |
||||
), |
||||
new naver.maps.EPSG3857.getDestinationCoord( |
||||
coord, |
||||
180, |
||||
radius - reduce |
||||
) |
||||
], |
||||
strokeWeight: 0.8, |
||||
strokeOpacity: opacity, |
||||
strokeColor: color |
||||
// map: props.map
|
||||
}); |
||||
polyArr.push(polyNS); |
||||
} |
||||
} |
||||
} |
||||
|
||||
const NS = new naver.maps.Polyline({ |
||||
path: [ |
||||
new naver.maps.EPSG3857.getDestinationCoord(position, 0, radius), |
||||
new naver.maps.EPSG3857.getDestinationCoord(position, 180, radius) |
||||
], |
||||
strokeWeight: 0.8, |
||||
strokeOpacity: opacity, |
||||
strokeColor: color |
||||
// map: props.map
|
||||
}); |
||||
polyArr.push(NS); |
||||
const EW = new naver.maps.Polyline({ |
||||
path: [ |
||||
new naver.maps.EPSG3857.getDestinationCoord(position, 90, radius), |
||||
new naver.maps.EPSG3857.getDestinationCoord(position, 270, radius) |
||||
], |
||||
strokeWeight: 0.8, |
||||
strokeOpacity: opacity, |
||||
strokeColor: color |
||||
// map: props.map
|
||||
}); |
||||
polyArr.push(EW); |
||||
|
||||
setPoly(m => [...m, polyArr]); |
||||
}; |
||||
|
||||
const gridgrid = (air, idx) => { |
||||
if (idx !== 0) return; |
||||
|
||||
const realCenter = air.center; |
||||
new naver.maps.Marker({ |
||||
position: realCenter, |
||||
map: mapObject |
||||
}); |
||||
|
||||
let westEastAngle = 270; |
||||
for (let we = 0; we < 2; we++) { |
||||
if (we === 1) westEastAngle = 90; |
||||
let westEastBuffer = 0; |
||||
for (let westEast = 0; westEast < 10; westEast++) { |
||||
westEastBuffer += 1000; |
||||
const coord = new naver.maps.EPSG3857.getDestinationCoord( |
||||
realCenter, |
||||
westEastAngle, |
||||
westEastBuffer |
||||
); |
||||
|
||||
let northSouthCoord = coord; |
||||
let notIncludes = 10; |
||||
if (westEast === 3 || westEast === 4) { |
||||
notIncludes = 9; |
||||
} else if (westEast === 5 || westEast === 6) { |
||||
notIncludes = 8; |
||||
} else if (westEast === 7) { |
||||
notIncludes = 7; |
||||
} else if (westEast === 8) { |
||||
notIncludes = 5; |
||||
} else if (westEast === 9) { |
||||
notIncludes = 3; |
||||
} |
||||
|
||||
for (let ns = 0; ns < 2; ns++) { |
||||
getNorthSouth(northSouthCoord, notIncludes, we, ns); |
||||
} |
||||
} |
||||
} |
||||
}; |
||||
|
||||
const getNorthSouth = (northSouthCoord, notIncludes, weType, nsType) => { |
||||
for (let i = 0; i < notIncludes; i++) { |
||||
getSquare(northSouthCoord, weType, nsType); |
||||
|
||||
const angle = nsType === 0 ? 0 : 180; |
||||
northSouthCoord = new naver.maps.EPSG3857.getDestinationCoord( |
||||
northSouthCoord, |
||||
angle, |
||||
1000 |
||||
); |
||||
} |
||||
}; |
||||
|
||||
const getSquare = (coord, weType, nsType) => { |
||||
const square = [coord]; |
||||
|
||||
let angle = 0; |
||||
|
||||
if (weType === 0 && nsType === 1) { |
||||
angle = 90; |
||||
} else if (weType === 1) { |
||||
if (nsType === 0) { |
||||
angle = 360; |
||||
} else if (nsType === 1) { |
||||
angle = 270; |
||||
} |
||||
} |
||||
for (let i = 2; i < 5; i++) { |
||||
const tt = new naver.maps.EPSG3857.getDestinationCoord( |
||||
square[i - 2], |
||||
angle, |
||||
1000 |
||||
); |
||||
if (weType === 0) { |
||||
angle += 90; |
||||
} else if (weType === 1) { |
||||
angle -= 90; |
||||
} |
||||
square.push(tt); |
||||
} |
||||
const polygon = new naver.maps.Polygon({ |
||||
strokeColor: '#283046', |
||||
strokeOpacity: 0.5, |
||||
// fillColor: '#8a1c05',
|
||||
fillOpacity: 0.1, |
||||
paths: square, |
||||
map: mapObject |
||||
}); |
||||
|
||||
const path = polygon.getPath()._array; |
||||
|
||||
const arr = []; |
||||
path.map(tt => { |
||||
const latlngJson = [tt.lng(), tt.lat(), 0]; |
||||
arr.push(latlngJson); |
||||
}); |
||||
arr.push([path[0].lng(), path[0].lat(), 0]); |
||||
setSquarePaths(prev => [...prev, arr]); |
||||
}; |
||||
|
||||
return ( |
||||
<> |
||||
<div id='map' style={{ width: '100%', height: '100vh' }}></div> |
||||
{mapObject != null ? ( |
||||
<> |
||||
<DronMarker map={mapObject} naver={naver} /> |
||||
|
||||
{/* <DronPlan map={mapObject} naver={naver} /> */} |
||||
<NewDronPlan map={mapObject} naver={naver} /> |
||||
|
||||
<NaverMapControl map={mapObject} /> |
||||
|
||||
{/* <DronHistory |
||||
map={mapObject} |
||||
naver={naver} |
||||
arrPolyline={arrPolyline} |
||||
handleHistoryInit={handleHistoryInit} |
||||
/> */} |
||||
{/* <NewDronHistory |
||||
map={mapObject} |
||||
naver={naver} |
||||
arrPolyline={arrPolyline} |
||||
handleHistoryInit={handleHistoryInit} |
||||
/> */} |
||||
|
||||
<ControlDraw map={mapObject} naver={naver} /> |
||||
|
||||
<DronToast /> |
||||
|
||||
<FeatureAirZone |
||||
map={mapObject} |
||||
naver={naver} |
||||
features={features} |
||||
poly={poly} |
||||
/> |
||||
{/* <NaverMapSearch map={mapObject} naver={naver} /> */} |
||||
{/* <SensorZone map={mapObject} naver={naver} /> */} |
||||
</> |
||||
) : null} |
||||
|
||||
{/* */} |
||||
</> |
||||
); |
||||
}; |
@ -1,89 +0,0 @@
|
||||
import { object } from 'prop-types'; |
||||
import { useEffect, useState } from 'react'; |
||||
import { useDispatch, useSelector } from 'react-redux'; |
||||
import { controlGpHisAction } from '../../../../modules/control/gp'; |
||||
|
||||
export const DronHistory = props => { |
||||
const { controlGpHistory } = useSelector(state => state.controlGpHisState); |
||||
const { controlGpList } = useSelector(state => state.controlGpState); |
||||
const { objectId, isClickObject } = useSelector(state => state.controlMapReducer);
|
||||
|
||||
const [arrHistory, setArrHistory] = useState([]); |
||||
|
||||
let naver = props.naver; |
||||
let polyline; |
||||
let polylinePath = [];
|
||||
|
||||
const dispatch = useDispatch(); |
||||
|
||||
useEffect(() => { |
||||
if(objectId && isClickObject) {
|
||||
if(arrHistory && arrHistory.length > 0) { |
||||
const gps = controlGpList.find((gps) => gps.controlId === objectId); |
||||
|
||||
if(gps) { |
||||
const addHistory = { |
||||
objectId: gps.objectId, |
||||
lat: gps.lat, |
||||
lng: gps.lng |
||||
} |
||||
|
||||
const history = [...arrHistory, addHistory]; |
||||
polylineInit(history); |
||||
|
||||
setArrHistory((his) => { |
||||
return [...his, addHistory]; |
||||
}); |
||||
}
|
||||
}
|
||||
} |
||||
}, [controlGpList]); |
||||
|
||||
useEffect(() => {
|
||||
polylineRemove();
|
||||
|
||||
setArrHistory(controlGpHistory); |
||||
polylineInit(controlGpHistory);
|
||||
|
||||
}, [controlGpHistory]); |
||||
|
||||
useEffect(() => { |
||||
if (isClickObject) { |
||||
dispatch(controlGpHisAction.request({ id: objectId })); |
||||
} else { |
||||
polylineRemove(); |
||||
} |
||||
}, [objectId, isClickObject]); |
||||
|
||||
const polylineRemove = () => {
|
||||
if (props.arrPolyline) { |
||||
props.arrPolyline.map(item => { |
||||
item.setMap(null); |
||||
}); |
||||
} |
||||
}; |
||||
const polylineInit = (history) => { |
||||
if (history) { |
||||
polyline = new naver.maps.Polyline({ |
||||
clickable: false, |
||||
strokeColor: '#ff4961', |
||||
strokeStyle: 'solid', |
||||
strokeOpacity: 5, |
||||
strokeWeight: 1.5 |
||||
}); |
||||
|
||||
history.map(item => { |
||||
if (item.lat > 0 && item.lng > 0) { |
||||
const position = new naver.maps.LatLng(item.lat, item.lng); |
||||
polylinePath.push(position); |
||||
}
|
||||
}); |
||||
|
||||
polyline.setPath(polylinePath); |
||||
polyline.setMap(props.map); |
||||
props.handleHistoryInit(polyline); |
||||
} |
||||
}; |
||||
|
||||
return null; |
||||
}; |
@ -1,630 +0,0 @@
|
||||
import $ from 'jquery'; |
||||
import { useEffect, useState } from 'react'; |
||||
import { useDispatch, useSelector, shallowEqual } from 'react-redux'; |
||||
import '../../../../assets/css/custom.css'; |
||||
import FlightIcon from '../../../../assets/images/airplan_org.svg'; |
||||
import FlightDetailIcon from '../../../../assets/images/airplan_pp.svg'; |
||||
import DronIcon from '../../../../assets/images/drone-marker-icon.png'; |
||||
import DronDetailIcon from '../../../../assets/images/drone-marker-icon-pulple.png'; |
||||
import DronUamIcon from '../../../../assets/images/uam_icon.png'; |
||||
import DronUamDetailIcon from '../../../../assets/images/uam_icon_purple.png'; |
||||
import { |
||||
controlGpDtlAction, |
||||
controlGpFlightPlanAction, |
||||
controlGpCountAction |
||||
} from '../../../../modules/control/gp'; |
||||
import { |
||||
objectClickAction, |
||||
objectUnClickAction |
||||
} from '../../../../modules/control/map/actions/controlMapActions'; |
||||
import { JOIN_LIST } from '../../../../modules/basis/group/actions/basisGroupAction'; |
||||
|
||||
export const DronMarker = props => { |
||||
const dispatch = useDispatch(); |
||||
|
||||
const { controlGpList, controlGroupAuthInfo } = useSelector( |
||||
state => state.controlGpState |
||||
); |
||||
const { objectId, isClickObject } = useSelector( |
||||
state => state.controlMapReducer, |
||||
shallowEqual |
||||
); |
||||
// const { controlGroupAuthInfo } = useSelector(
|
||||
// state => state.controlGroupAuthState
|
||||
// );
|
||||
const { controlGpArcrftWarnList } = useSelector( |
||||
state => state.controlGpLogState |
||||
); |
||||
|
||||
const { user } = useSelector(state => state.authState); |
||||
const { joinList } = useSelector(state => state.groupState); |
||||
|
||||
const [arrMarkers, setArrMarkers] = useState([]); |
||||
const [arrInfos, setArrInfos] = useState([]); |
||||
|
||||
const [count, setCount] = useState({ |
||||
drone: [], |
||||
flight: [] |
||||
}); |
||||
|
||||
let naver = props.naver; |
||||
let map = props.map; |
||||
let CustomOverlay; |
||||
let infoWindow; |
||||
// const infowindowOpen = data => {
|
||||
// const content = `
|
||||
// <div class="dblock-box">
|
||||
// <div class="dblock-ti">
|
||||
// <span>${data?.id}</span>
|
||||
// </div>
|
||||
// <div class="dblock-txt>
|
||||
// <div class="dblock-txt-list">
|
||||
// <div>
|
||||
// <span style="width: 250px; display: inline-block;">${
|
||||
// data?.speed
|
||||
// }${data?.speedType} | ${data?.elev}${data?.elevType} | ${
|
||||
// data?.heading
|
||||
// }</span>
|
||||
// <span style="width: 250px; display: inline-block;">${(data?.coord._lat).toFixed(
|
||||
// 6
|
||||
// )} | ${(data?.coord._lng).toFixed(6)}</span>
|
||||
// </div>
|
||||
// </div>
|
||||
// </div>
|
||||
// </div>
|
||||
// `;
|
||||
|
||||
// infoWindow = new naver.maps.InfoWindow({
|
||||
// class: 'tooltip-dblock',
|
||||
// content: content,
|
||||
// maxWidth: 160,
|
||||
// backgroundColor: '#283046', //박스안쪽영역 컬러
|
||||
// // borderColor: '#333', //테두리컬러
|
||||
// // borderWidth: 3, //테두리 굵기
|
||||
// // anchorSize: new naver.maps.Size(30, -10),
|
||||
// anchorSkew: false,
|
||||
// anchorColor: '#283046',
|
||||
|
||||
// pixelOffset: new naver.maps.Point(20, -20)
|
||||
// });
|
||||
|
||||
// infoWindow.open(props.map, data.coord);
|
||||
// };
|
||||
|
||||
// useLayoutEffect(() => {
|
||||
// dispatch(controlGroupAuthAction.request());
|
||||
// }, [controlGpList]);
|
||||
|
||||
useEffect(() => { |
||||
if (count.drone.length > 0 || count.flight.length > 0) { |
||||
dispatch( |
||||
controlGpCountAction.request({ |
||||
count |
||||
}) |
||||
); |
||||
} else { |
||||
const count = { |
||||
drone: [], |
||||
flight: [] |
||||
}; |
||||
dispatch( |
||||
controlGpCountAction.request({ |
||||
count |
||||
}) |
||||
); |
||||
} |
||||
}, [count]); |
||||
|
||||
useEffect(() => { |
||||
dispatch( |
||||
JOIN_LIST.request({ |
||||
cstmrSno: user?.cstmrSno |
||||
}) |
||||
); |
||||
}, []); |
||||
|
||||
useEffect(() => { |
||||
if (arrMarkers.length != 0) { |
||||
markerInfo(arrMarkers); |
||||
} |
||||
}, [arrMarkers]); |
||||
|
||||
useEffect(() => { |
||||
markerInit(); |
||||
}, [controlGpList]); |
||||
|
||||
useEffect(() => { |
||||
let imageUrl; |
||||
arrMarkers.map(clickMarker => { |
||||
if (objectId === clickMarker.controlId && isClickObject) { |
||||
// console.log(clickMarker.gps.objectId, '><><');
|
||||
imageUrl = |
||||
// clickMarker.type === 'DRONE' ? DronUamDetailIcon : FlightDetailIcon;
|
||||
clickMarker.type === 'DRONE' |
||||
? clickMarker.gps.objectId.includes('UAM') |
||||
? DronUamDetailIcon |
||||
: DronDetailIcon |
||||
: FlightDetailIcon; |
||||
clickMarker.setIcon({ |
||||
content: `<img src="${imageUrl}" alt="" style="transform: rotate(${clickMarker.gps.heading}deg)">`, |
||||
origin: new naver.maps.Point(0, 0), |
||||
anchor: new naver.maps.Point(15, 15) |
||||
}); |
||||
} else { |
||||
// imageUrl = clickMarker.type === 'DRONE' ? DronUamIcon : FlightIcon;
|
||||
imageUrl = |
||||
clickMarker.type === 'DRONE' |
||||
? clickMarker.gps.objectId.includes('UAM') |
||||
? DronUamIcon |
||||
: DronIcon |
||||
: FlightIcon; |
||||
clickMarker.setIcon({ |
||||
content: `<img src="${imageUrl}" alt="" style="transform: rotate(${clickMarker.gps.heading}deg)">`, |
||||
origin: new naver.maps.Point(0, 0), |
||||
anchor: new naver.maps.Point(15, 15) |
||||
}); |
||||
} |
||||
}); |
||||
}, [objectId, isClickObject]); |
||||
|
||||
useEffect(() => { |
||||
arrMarkers.map(clickMarker => { |
||||
if (objectId === clickMarker.controlId) { |
||||
dispatch(controlGpDtlAction.request(objectId)); |
||||
props.map.setCenter(clickMarker.getPosition()); |
||||
props.map.setZoom(13, true); |
||||
} |
||||
}); |
||||
}, [objectId]); |
||||
|
||||
//마커를 그린다.
|
||||
const addMarkers = (position, id, controlId, gps) => { |
||||
const gpsCnt = { |
||||
gps: gps, |
||||
type: '' |
||||
}; |
||||
|
||||
const markerOption = {}; |
||||
|
||||
if (id.substring(0, 2) === 'PA') { |
||||
const pal = controlGroupAuthInfo?.find( |
||||
prev => prev.idntfNum === gps.objectId |
||||
); |
||||
if (pal || !pal || id.includes('NAMWON')) { |
||||
if (id.includes('UAM')) { |
||||
markerOption.url = DronUamIcon; |
||||
} else { |
||||
markerOption.url = DronIcon; |
||||
} |
||||
|
||||
markerOption.type = 'DRONE'; |
||||
gpsCnt.type = 'drone'; |
||||
} else { |
||||
if (user?.authId === 'SUPER' || user?.authId === 'ADMIN') { |
||||
markerOption.url = FlightIcon; |
||||
markerOption.type = 'FLIGHT'; |
||||
gpsCnt.type = 'flight'; |
||||
} else { |
||||
const terminal = joinList?.find(prev => prev.trmnlId === gps.trmnlId); |
||||
if ( |
||||
terminal?.groupAuthCd === 'MASTER' || |
||||
terminal?.groupAuthCd === 'LEADER' |
||||
) { |
||||
markerOption.url = FlightIcon; |
||||
markerOption.type = 'FLIGHT'; |
||||
gpsCnt.type = 'flight'; |
||||
} |
||||
} |
||||
} |
||||
} else { |
||||
if (user?.authId === 'SUPER' || user?.authId === 'ADMIN') { |
||||
markerOption.url = FlightIcon; |
||||
markerOption.type = 'FLIGHT'; |
||||
gpsCnt.type = 'flight'; |
||||
} else { |
||||
const terminal = joinList?.find(prev => prev.trmnlId === gps.trmnlId); |
||||
if ( |
||||
terminal?.groupAuthCd === 'MASTER' || |
||||
terminal?.groupAuthCd === 'LEADER' |
||||
) { |
||||
markerOption.url = FlightIcon; |
||||
markerOption.type = 'FLIGHT'; |
||||
gpsCnt.type = 'flight'; |
||||
} |
||||
} |
||||
} |
||||
|
||||
if (gpsCnt.type === 'drone') { |
||||
setCount(prev => ({ |
||||
...prev, |
||||
drone: [...prev.drone, gpsCnt] |
||||
})); |
||||
} else if (gpsCnt.type === 'flight') { |
||||
setCount(prev => ({ |
||||
...prev, |
||||
flight: [...prev.flight, gpsCnt] |
||||
})); |
||||
} |
||||
|
||||
// if (id.substring(0, 2) === 'PA') {
|
||||
// const pal = controlGroupAuthInfo?.find(
|
||||
// prev => prev.idntfNum === gps.objectId
|
||||
// );
|
||||
// markerOption.url = pal ? DronIcon : FlightIcon;
|
||||
// markerOption.type = pal ? 'DRONE' : 'FLIGHT';
|
||||
// } else {
|
||||
// markerOption.url = FlightIcon;
|
||||
// markerOption.type = 'FLIGHT';
|
||||
// }
|
||||
|
||||
markerOption.origin = new naver.maps.Point(0, 0); |
||||
markerOption.anchor = new naver.maps.Point(15, 15); |
||||
|
||||
const marker = new naver.maps.Marker({ |
||||
position: position, |
||||
title: id, |
||||
id: id, |
||||
controlId: controlId, |
||||
type: markerOption.type, |
||||
icon: { |
||||
content: `<img id=${id} src="${markerOption.url}" alt="" style="transform: rotate(${gps.heading}deg);">`, |
||||
origin: markerOption.origin, |
||||
anchor: markerOption.anchor |
||||
}, |
||||
gps: gps |
||||
}); |
||||
marker.setMap(props.map); |
||||
|
||||
dispatch(controlGpFlightPlanAction.request(marker.id)); //예상경로
|
||||
// dispatch(controlGpHisAction.request({ id: marker.controlId })); //진행경로;
|
||||
|
||||
/** drone 상세보기 */ |
||||
naver.maps.Event.addListener(marker, 'click', function (e) { |
||||
handlerDronClick(marker.controlId, marker.id); |
||||
}); |
||||
|
||||
// naver.maps.Event.addListener(marker, 'mouseover', function (e) {
|
||||
// const data = {};
|
||||
// data.id = marker.id;
|
||||
// data.speed = marker.gps?.speed;
|
||||
// data.speedType = marker.gps?.speedType;
|
||||
// data.elev = marker.gps?.elev;
|
||||
// data.elevType = marker.gps?.elevType;
|
||||
// data.heading = marker.gps?.heading;
|
||||
// data.coord = marker.position;
|
||||
|
||||
// infowindowOpen(data);
|
||||
// });
|
||||
|
||||
naver.maps.Event.addListener(marker, 'mouseout', function (e) { |
||||
if (infoWindow) { |
||||
infoWindow.close(); |
||||
} |
||||
}); |
||||
|
||||
// naver.maps.Event.addListener(map, 'zoom_changed', function (zoom) {
|
||||
// const a = document.getElementsByClassName('dblock-box');
|
||||
|
||||
// for (let i = 0; i < a.length; i++) {
|
||||
// if (zoom <= 9) {
|
||||
// a[i].style.display = 'none';
|
||||
// } else {
|
||||
// a[i].style.display = 'block';
|
||||
// a[i].style.width = `${zoom * 10 + 20}px`;
|
||||
// a[i].style.fontSize = `${zoom}px`;
|
||||
// }
|
||||
// }
|
||||
// // console.log(document.getElementsByClassName('dblock-box'));
|
||||
// // document.querySelector('.dblock-box').style.width = `${zoom * 10}px`;
|
||||
// // document.querySelector('.dblock-box').style.fontSize = `${zoom}px`;
|
||||
// // document.querySelector('.dblock-ti').style.fontSize = `${zoom}px`;
|
||||
// });
|
||||
if (markerOption.url) { |
||||
setArrMarkers(m => [...m, marker]); |
||||
} |
||||
}; |
||||
|
||||
const handlerDronClick = (controlId, idntfNum) => { |
||||
// get detail, history, flight-plan
|
||||
dispatch(objectClickAction(controlId)); |
||||
// dispatch(controlGpDtlAction.request(controlId));
|
||||
// dispatch(controlGpFlightPlanAction.request(idntfNum));
|
||||
}; |
||||
|
||||
//마커를 삭제 한다.
|
||||
const removeMarkers = marker => { |
||||
marker.setMap(null); |
||||
}; |
||||
|
||||
const removeInfos = info => { |
||||
info.setMap(null); |
||||
}; |
||||
|
||||
//마커에 위치를 이동한다.
|
||||
const moveMarkers = (marker, position, gps) => { |
||||
const getIcon = marker.getIcon(); |
||||
|
||||
marker.setPosition(position); |
||||
const warnList = controlGpArcrftWarnList?.filter( |
||||
i => i.cntrlId === gps.controlId |
||||
); |
||||
if (warnList?.length > 0) { |
||||
if (warnList[0].controlWarnCd) { |
||||
marker.setIcon({ |
||||
content: `<img ${getIcon.content.substr( |
||||
getIcon.content.indexOf('src'), |
||||
getIcon.content.indexOf('alt') - 6 |
||||
)} alt="" style="transform: rotate(${ |
||||
gps.heading |
||||
}deg); filter: invert(16%) sepia(79%) saturate(4975%) hue-rotate(359deg) brightness(104%) contrast(129%)" />`,
|
||||
anchor: getIcon.anchor |
||||
}); |
||||
} else { |
||||
marker.setIcon({ |
||||
content: `<img ${getIcon.content.substr( |
||||
getIcon.content.indexOf('src'), |
||||
getIcon.content.indexOf('alt') - 6 |
||||
)} alt="" style="transform: rotate(${gps.heading}deg); " />`,
|
||||
anchor: getIcon.anchor |
||||
}); |
||||
} |
||||
return; |
||||
} |
||||
marker.setIcon({ |
||||
content: `<img ${getIcon.content.substr( |
||||
getIcon.content.indexOf('src'), |
||||
getIcon.content.indexOf('alt') - 6 |
||||
)} alt="" style="transform: rotate(${gps.heading}deg); " />`,
|
||||
anchor: getIcon.anchor |
||||
}); |
||||
}; |
||||
|
||||
const moveInfos = (info, position, item, idx) => { |
||||
if (info) { |
||||
info.setPosition(position, info); |
||||
// info._element.html(`<div class="dblock-ti"><span>${info?._id}</span>
|
||||
// <span>${item?.speed}${item?.speedType} | ${item?.elev}${item?.elevType} | ${item?.heading}</span></div>`);
|
||||
info._element.html(` |
||||
|
||||
<div class="dblock-ti"> |
||||
<span>${info?._id}</span> |
||||
</div> |
||||
<div class="dblock-txt"> |
||||
<div class="dblock-txt-list"> |
||||
<span>${item?.elev}M</span> |
||||
<span>${item?.speed}km</span> |
||||
${ |
||||
typeof item?.lat === 'number' && typeof item?.lng === 'number' |
||||
? ` |
||||
<span> |
||||
${(item?.lat).toFixed(6)} ${(item?.lng).toFixed(6)} |
||||
</span>` |
||||
: '' |
||||
} |
||||
</div> |
||||
</div> |
||||
|
||||
|
||||
`);
|
||||
} |
||||
}; |
||||
|
||||
//데이터가 없는 마커를 모두 삭제 한다.
|
||||
const allRemoveMarkers = () => { |
||||
let isUnClick = false; |
||||
if (arrMarkers && controlGpList) { |
||||
arrMarkers.map(marker => { |
||||
const isExists = controlGpList.find( |
||||
item => item.objectId === marker.id |
||||
); |
||||
if (!isExists) { |
||||
removeMarkers(marker); |
||||
const arrData = arrMarkers.filter(item => item.id != marker.id); |
||||
|
||||
const drone = count.drone.filter(d => d.gps.objectId != marker.id); |
||||
const flight = count.flight.filter(d => d.gps.objectId != marker.id); |
||||
|
||||
setCount({ |
||||
drone: drone, |
||||
flight: flight |
||||
}); |
||||
|
||||
removeArrMarkers(arrData); |
||||
if (marker.controlId === objectId) { |
||||
dispatch(objectUnClickAction()); |
||||
} |
||||
} |
||||
}); |
||||
arrInfos.map(info => { |
||||
const isExists = controlGpList.find(item => item.objectId === info._id); |
||||
if (!isExists) { |
||||
removeInfos(info); |
||||
const arrData = arrInfos.filter(item => item.id != info._id); |
||||
removeArrInfos(arrData); |
||||
} |
||||
}); |
||||
} |
||||
return isUnClick; |
||||
}; |
||||
|
||||
//마커를 셋팅 한다.
|
||||
const markerInit = () => { |
||||
if (controlGpList) { |
||||
allRemoveMarkers(); |
||||
controlGpList.map((item, idx) => { |
||||
let position = new naver.maps.LatLng(item.lat, item.lng); |
||||
|
||||
if (arrMarkers) { |
||||
const isExists = arrMarkers.find(ele => ele.id === item.objectId); |
||||
const isInfos = arrInfos.find(info => info._id === item.objectId); |
||||
if (isExists) { |
||||
moveMarkers(isExists, position, item); |
||||
moveInfos(isInfos, position, item, idx); |
||||
} else { |
||||
addMarkers(position, item.objectId, item.controlId, item); |
||||
} |
||||
} else { |
||||
addMarkers(position, item.objectId, item.controlId, item); |
||||
} |
||||
}); |
||||
} |
||||
}; |
||||
|
||||
//운항정보 창 셋팅
|
||||
const infoInit = (marker, gps, idx) => { |
||||
CustomOverlay = function (options) { |
||||
this._element = $(` |
||||
<div class="dblock-box"> |
||||
<div class="dblock-ti"> |
||||
<span>${marker?.id}</span> |
||||
</div> |
||||
<div class="dblock-txt"> |
||||
<div class="dblock-txt-list"> |
||||
<span>${gps?.elev}M</span> |
||||
<span>${gps?.speed}km</span> |
||||
${ |
||||
typeof gps?.lat === 'number' && typeof gps?.lng === 'number' |
||||
? ` |
||||
<span> |
||||
${(gps?.lat).toFixed(6)} ${(gps?.lng).toFixed(6)} |
||||
</span>` |
||||
: '' |
||||
} |
||||
</div> |
||||
</div> |
||||
</div> |
||||
`);
|
||||
|
||||
// this._element = $(`
|
||||
// <div class="tooltip-box" style="width: 150px;">
|
||||
// <div class="tooltip-ti">
|
||||
// <span>${marker?.id}</span>
|
||||
// </div>
|
||||
// <div class="tooltip-txt>
|
||||
// <div class="tooltip-txt-list">
|
||||
// <div>
|
||||
// <span style="width: 120px; display: inline-block;">속도: ${gps?.speed}${gps?.speedType}</span>
|
||||
// </div>
|
||||
// <div>
|
||||
// <span style="width: 120px; display: inline-block;">고도: ${gps?.elev}${gps?.elevType}</span>
|
||||
// </div>
|
||||
// <div>
|
||||
// <span style="width: 120px; display: inline-block;">헤딩방향: ${gps?.heading}</span>
|
||||
// </div>
|
||||
// </div>
|
||||
// </div>
|
||||
// </div>
|
||||
// `)
|
||||
|
||||
this.setPosition(options.position, idx); |
||||
this.setMap(options.map || null); |
||||
this.setId(options.id); |
||||
this.setIdx(idx); |
||||
this.setControlId(options.controlId); |
||||
}; |
||||
|
||||
CustomOverlay.prototype = new naver.maps.OverlayView(); |
||||
CustomOverlay.prototype.constructor = CustomOverlay; |
||||
|
||||
//메소드 재정의
|
||||
//필수
|
||||
CustomOverlay.prototype.onAdd = function () { |
||||
let overlayLayer = this.getPanes().overlayLayer; |
||||
|
||||
this._element.appendTo(overlayLayer); |
||||
}; |
||||
|
||||
CustomOverlay.prototype.draw = function (idx) { |
||||
if (!this.getMap()) { |
||||
return; |
||||
} |
||||
|
||||
let projection = this.getProjection(), |
||||
position = this.getPosition(), |
||||
pixelPosition = projection.fromCoordToOffset(position); |
||||
|
||||
// let cnt = 0;
|
||||
// let index = idx?._idx;
|
||||
// cnt = index * 98;
|
||||
this._element.css('left', pixelPosition.x); |
||||
this._element.css('top', pixelPosition.y); |
||||
// this._element.css('top', pixelPosition.y + -cnt)
|
||||
}; |
||||
|
||||
CustomOverlay.prototype.onRemove = function () { |
||||
let overlayLayer = this.getPanes().overlayLayer; |
||||
|
||||
this._element.remove(); |
||||
this._element.off(); |
||||
}; |
||||
|
||||
//속성
|
||||
CustomOverlay.prototype.setPosition = function (position, idx) { |
||||
this._position = position; |
||||
this.draw(idx); |
||||
}; |
||||
|
||||
CustomOverlay.prototype.getPosition = function () { |
||||
return this._position; |
||||
}; |
||||
|
||||
CustomOverlay.prototype.setId = function (id) { |
||||
this._id = id; |
||||
}; |
||||
|
||||
CustomOverlay.prototype.getId = function () { |
||||
return this._id; |
||||
}; |
||||
|
||||
CustomOverlay.prototype.setIdx = function (idx) { |
||||
this._idx = idx; |
||||
}; |
||||
|
||||
CustomOverlay.prototype.getIdx = function () { |
||||
return this._idx; |
||||
}; |
||||
|
||||
CustomOverlay.prototype.setControlId = function (controlId) { |
||||
this._controlId = controlId; |
||||
}; |
||||
|
||||
CustomOverlay.prototype.getControlId = function () { |
||||
return this._controlId; |
||||
}; |
||||
}; |
||||
|
||||
const removeArrMarkers = arrData => { |
||||
setArrMarkers(arrData); |
||||
}; |
||||
|
||||
const removeArrInfos = arrData => { |
||||
setArrInfos(arrData); |
||||
}; |
||||
|
||||
const markerInfo = arrMarkers => { |
||||
arrMarkers.forEach((marker, idx) => { |
||||
if (arrInfos.filter(i => i._controlId === marker.controlId).length > 0) { |
||||
return; |
||||
} |
||||
infoInit(marker, controlGpList[idx], idx); |
||||
|
||||
if (controlGpList.length != 0) { |
||||
const info = new CustomOverlay({ |
||||
position: new naver.maps.LatLng( |
||||
controlGpList[idx]?.lat, |
||||
controlGpList[idx]?.lng |
||||
), |
||||
// map: map,
|
||||
id: marker.id, |
||||
idx: idx, |
||||
controlId: marker.controlId |
||||
}); |
||||
info.setMap(map); |
||||
|
||||
setArrInfos(m => [...m, info]); |
||||
} |
||||
}); |
||||
}; |
||||
|
||||
return null; |
||||
}; |
@ -1,200 +0,0 @@
|
||||
import { useEffect, useState } from 'react'; |
||||
import { useSelector, useDispatch } from 'react-redux'; |
||||
import { controlGpFlightPlanInitAction } from '../../../../modules/control/gp'; |
||||
import DronToast from './DronToast'; |
||||
import { toast } from 'react-toastify'; |
||||
|
||||
|
||||
const DronPlan = ({ naver, map }) => { |
||||
const dispatch = useDispatch(); |
||||
|
||||
const { controlGpList } = useSelector(state => state.controlGpState); |
||||
const { controlGpFltPlanList } = useSelector(state => state.controlGpFltPlanState); |
||||
const { objectId, isClickObject } = useSelector(state => state.controlMapReducer); |
||||
|
||||
const [area, setArea] = useState(); // 비행 구역 관리
|
||||
const [buffer, setBuffer] = useState(); // 버퍼 구역 관리
|
||||
const [controlId, setControlId] = useState(); // 식별번호 저장
|
||||
|
||||
useEffect(() => { |
||||
if (controlGpFltPlanList) { |
||||
init(); |
||||
} |
||||
}, [controlGpFltPlanList]) |
||||
|
||||
useEffect(() => {
|
||||
if (!isClickObject) { |
||||
|
||||
// 관제 종료시 영역 초기화.
|
||||
clear(); |
||||
|
||||
} else { |
||||
setControlId(objectId); |
||||
} |
||||
|
||||
}, [objectId ,isClickObject]); |
||||
|
||||
useEffect(() => {
|
||||
// 구역 대상의 드론 데이터가 지도 상에 존재하고 있는지 체크해야 한다. (없을 경우 영역 제거)
|
||||
if (controlId && isClickObject) {
|
||||
if (controlGpList) {
|
||||
const isExist = controlGpList.find(data => data.controlId === controlId) |
||||
|
||||
if(!isExist) { |
||||
clear(); |
||||
} |
||||
}
|
||||
} |
||||
}, [controlGpList]) |
||||
|
||||
// useEffect(() => {
|
||||
// if (controlGpContains) {
|
||||
// if(!controlGpContains.contains) {
|
||||
// toast.info(<DronToast title={'비정상 상황 알림'} message={'경로 상에 비행 구역을 이탈하였습니다.'}/>, {
|
||||
// autoClose: 3000,
|
||||
// hideProgressBar: true,
|
||||
// position: toast.POSITION.BOTTOM_RIGHT,
|
||||
// })
|
||||
// }
|
||||
|
||||
// }
|
||||
// }, [controlGpContains])
|
||||
|
||||
|
||||
/* 비행 구역 그리기. */ |
||||
const init = () => { |
||||
if(area) { |
||||
area.setMap(null); |
||||
} |
||||
|
||||
/* 좌표 추출 */ |
||||
const planList = controlGpFltPlanList; |
||||
planList.forEach(plan => { |
||||
|
||||
const areaList = plan.areaList; |
||||
|
||||
// 구역 정보는 계획서당 1개만 존재
|
||||
areaList.forEach(area => { |
||||
const coordList = area.coordList; // 기초 좌표
|
||||
const bufferList = area.bufferCoordList; // 기초 좌표의 버퍼 좌표
|
||||
const bufferZone = area.bufferZone; // 반경 값
|
||||
const areaType = area.areaType; // 도형 타입
|
||||
|
||||
const paths = []; |
||||
coordList.forEach((coord) => { |
||||
const path = new naver.maps.LatLng(coord.lat, coord.lon) |
||||
|
||||
paths.push(path); |
||||
}); |
||||
|
||||
clear(); |
||||
|
||||
if (areaType === 'LINE') { |
||||
polyline(paths, bufferList); |
||||
} |
||||
|
||||
if (areaType === 'POLYGON') { |
||||
polygon(paths); |
||||
} |
||||
|
||||
if (areaType === 'CIRCLE') { |
||||
circle(paths, bufferZone); |
||||
} |
||||
|
||||
}); |
||||
}) |
||||
} |
||||
|
||||
/* Polyline Create */ |
||||
const polyline = (paths, bufferList) => {
|
||||
if (paths && paths.length > 1) { |
||||
const line = new naver.maps.Polyline({ |
||||
strokeLineCap: 'round', |
||||
strokeLineJoin: 'round', |
||||
strokeColor: '#283046', |
||||
strokeWeight: 1, |
||||
strokeOpacity: 0.5, |
||||
path: paths, |
||||
map: map |
||||
}); |
||||
|
||||
setArea(line); |
||||
}
|
||||
|
||||
if (bufferList && bufferList.length > 1) { |
||||
const paths = []; |
||||
bufferList.forEach((buffer) => { |
||||
const path = new naver.maps.LatLng(buffer.lat, buffer.lon) |
||||
|
||||
paths.push(path); |
||||
}); |
||||
|
||||
const lineBuffer = new naver.maps.Polygon({ |
||||
strokeColor: '#283046', |
||||
strokeOpacity: 1, |
||||
fillColor: '#8a1c05', |
||||
fillOpacity: 0.1, |
||||
paths: paths, |
||||
map: map |
||||
}); |
||||
|
||||
setBuffer(lineBuffer); |
||||
} |
||||
} |
||||
|
||||
/* Polygon Create */
|
||||
const polygon = (paths) => {
|
||||
if (paths && paths.length > 1) { |
||||
const poly = new naver.maps.Polygon({ |
||||
strokeColor: '#283046', |
||||
strokeOpacity: 1, |
||||
fillColor: '#8a1c05', |
||||
fillOpacity: 0.1, |
||||
paths: paths, |
||||
map: map |
||||
}); |
||||
|
||||
setArea(poly); |
||||
}
|
||||
} |
||||
|
||||
/* Circle Create */ |
||||
const circle = (paths, bufferZone) => { |
||||
|
||||
if (paths[0].lat !== 0 && paths[0].lon !== 0) { |
||||
const circle = new naver.maps.Circle({ |
||||
strokeColor: '#283046', |
||||
strokeOpacity: 1,
|
||||
fillColor: '#8a1c05', |
||||
fillOpacity: 0.1, |
||||
center: paths[0], |
||||
radius: bufferZone, |
||||
map: map, |
||||
clickable: true |
||||
}); |
||||
|
||||
setArea(circle); |
||||
} |
||||
} |
||||
|
||||
/* 구역 초기화 */ |
||||
const clear = () => { |
||||
|
||||
if(area) { |
||||
area.setMap(null); |
||||
|
||||
setArea(); |
||||
if(buffer) { |
||||
buffer.setMap(null); |
||||
setBuffer(); |
||||
} |
||||
|
||||
dispatch(controlGpFlightPlanInitAction()); |
||||
} |
||||
} |
||||
|
||||
|
||||
return null; |
||||
} |
||||
|
||||
export default DronPlan; |
@ -1,99 +0,0 @@
|
||||
import React, { useEffect, useState } from 'react'; |
||||
import { useSelector, useDispatch } from 'react-redux'; |
||||
import { Fragment } from 'react'; |
||||
import { toast } from 'react-toastify'; |
||||
import Avatar from '../../../../@core/components/avatar'; |
||||
import { Bell, Check, X, AlertTriangle, Info } from 'react-feather'; |
||||
import { |
||||
controlGpDtlAction, |
||||
controlGpFlightPlanAction |
||||
} from '../../../../modules/control/gp'; |
||||
import { |
||||
objectClickAction, |
||||
objectUnClickAction |
||||
} from '../../../../modules/control/map/actions/controlMapActions'; |
||||
import 'react-toastify/dist/ReactToastify.css'; |
||||
import useAudio from '../../../../utility/hooks/useAudio'; |
||||
import warning from '../../../../assets/sounds/warning.mp3'; |
||||
|
||||
const DronToast = () => { |
||||
const dispatch = useDispatch(); |
||||
const [playing, toggle] = useAudio(warning); |
||||
const { controlGpArcrftWarnList } = useSelector( |
||||
state => state.controlGpLogState |
||||
); |
||||
const [toastId, setToastId] = useState(); |
||||
|
||||
let warningList = []; |
||||
|
||||
useEffect(() => { |
||||
if (controlGpArcrftWarnList) { |
||||
if (!toastId) { |
||||
for (let i = 0; i < controlGpArcrftWarnList.length; i++) { |
||||
if (controlGpArcrftWarnList[i].controlWarnCd) { |
||||
const id = toast.info( |
||||
toastRender( |
||||
`${controlGpArcrftWarnList[i].idntfNum} 비정상 상황 알림`, |
||||
`경로 상에 비행 구역을 이탈했습니다.` |
||||
), |
||||
{ |
||||
autoClose: false, |
||||
hideProgressBar: true, |
||||
position: toast.POSITION.BOTTOM_RIGHT, |
||||
onClick: () => { |
||||
handleNotiClick( |
||||
controlGpArcrftWarnList[i].cntrlId, |
||||
controlGpArcrftWarnList[i].idntfNum |
||||
); |
||||
// setToastId(null);
|
||||
}, |
||||
onClose: () => { |
||||
// setIs(true);
|
||||
toggle(false); |
||||
setToastId(null); |
||||
} |
||||
} |
||||
); |
||||
|
||||
setToastId(id); |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
for (let i = 0; i < controlGpArcrftWarnList.length; i++) { |
||||
warningList.push(controlGpArcrftWarnList[i].controlWarnCd); |
||||
} |
||||
|
||||
warningList.find(i => i) ? toggle(true) : toggle(false); |
||||
} |
||||
}, [controlGpArcrftWarnList]); |
||||
|
||||
const handleNotiClick = (controlId, idntfNum) => { |
||||
dispatch(objectClickAction(controlId)); |
||||
dispatch(controlGpDtlAction.request(controlId)); |
||||
dispatch(controlGpFlightPlanAction.request(idntfNum)); |
||||
}; |
||||
|
||||
const toastRender = (title, message) => { |
||||
return ( |
||||
<Fragment> |
||||
<div className='toastify-header'> |
||||
<div className='title-wrapper'> |
||||
<Avatar size='sm' color='info' icon={<Info size={10} />} /> |
||||
<h6 className='text-info ml-50 mb-0' style={{ fontSize: 'small' }}> |
||||
{title} |
||||
</h6> |
||||
</div> |
||||
</div> |
||||
|
||||
<div className='toastify-body'> |
||||
<span>{message}</span> |
||||
</div> |
||||
</Fragment> |
||||
); |
||||
}; |
||||
|
||||
return null; |
||||
}; |
||||
|
||||
export default DronToast; |
@ -1,66 +0,0 @@
|
||||
import { object } from 'prop-types'; |
||||
import { useEffect, useState } from 'react'; |
||||
import { useDispatch, useSelector } from 'react-redux'; |
||||
import { controlGpHisAction } from '../../../../modules/control/gp'; |
||||
|
||||
export const NewDronHistory = props => { |
||||
const dispatch = useDispatch(); |
||||
|
||||
const { controlGpHistory } = useSelector(state => state.controlGpHisState); |
||||
const { controlGpList } = useSelector(state => state.controlGpState); |
||||
|
||||
// const { objectId, isClickObject } = useSelector(
|
||||
// state => state.controlMapReducer
|
||||
// );
|
||||
|
||||
// const [arrHistory, setArrHistory] = useState([]);
|
||||
|
||||
let naver = props.naver; |
||||
let polyline = []; |
||||
let polylinePath = [[]]; |
||||
|
||||
const [arrHistory, setArrHistory] = useState([]); |
||||
const [controlIdArr, setControlIdArr] = useState([]); |
||||
|
||||
useEffect(() => { |
||||
if (controlGpList) { |
||||
const listArr = controlGpList.map(gpList => { |
||||
return gpList.objectId; |
||||
}); |
||||
if (controlIdArr != listArr) { |
||||
setControlIdArr(listArr); |
||||
const diff = controlIdArr.filter(list => !listArr.includes(list)); |
||||
if (diff.length > 0) console.log(diff); |
||||
} |
||||
// console.log(controlGpList, '>>>>');
|
||||
} |
||||
}, [controlGpList]); |
||||
|
||||
useEffect(() => { |
||||
if (controlGpHistory) { |
||||
// const tt = controlGpHistory[0].objectId;
|
||||
// console.log(tt);
|
||||
historyInit(); |
||||
} |
||||
}, [controlGpHistory]); |
||||
|
||||
const historyInit = () => { |
||||
const hisList = controlGpHistory; |
||||
const line = new naver.maps.Polyline({ |
||||
clickable: false, |
||||
strokeColor: '#ff4961', |
||||
strokeStyle: 'solid', |
||||
strokeOpacity: 5, |
||||
strokeWeight: 1.5 |
||||
}); |
||||
hisList.map(item => { |
||||
if (item.lat > 0 && item.lng > 0) { |
||||
const position = new naver.maps.LatLng(item.lat, item.lng); |
||||
polylinePath.push(position); |
||||
} |
||||
}); |
||||
// line.setPath(poly)
|
||||
}; |
||||
|
||||
return null; |
||||
}; |
@ -1,131 +0,0 @@
|
||||
import { useEffect, useState } from 'react'; |
||||
import { useSelector, useDispatch } from 'react-redux'; |
||||
import { controlGpFlightPlanInitAction } from '../../../../modules/control/gp'; |
||||
|
||||
const NewDronPlan = ({ naver, map }) => { |
||||
const dispatch = useDispatch(); |
||||
|
||||
const { controlGpList } = useSelector(state => state.controlGpState); |
||||
const { controlGpFltPlanList } = useSelector( |
||||
state => state.controlGpFltPlanState |
||||
); |
||||
|
||||
const [areaArr, setAreaArr] = useState([]); |
||||
const [bufferArr, setBufferArr] = useState([]); |
||||
const [controlIdArr, setControlIdArr] = useState([]); |
||||
|
||||
useEffect(() => { |
||||
if (controlGpFltPlanList) { |
||||
planInit(); |
||||
} |
||||
}, [controlGpFltPlanList]); |
||||
|
||||
useEffect(() => { |
||||
if (controlGpList) { |
||||
const listArr = controlGpList.map(gpList => { |
||||
return gpList.objectId; |
||||
}); |
||||
if (controlIdArr != listArr) { |
||||
setControlIdArr(listArr); |
||||
const diff = controlIdArr.filter(list => !listArr.includes(list)); |
||||
if (diff) clear(diff); |
||||
} |
||||
} |
||||
}, [controlGpList]); |
||||
|
||||
const planInit = () => { |
||||
const planList = controlGpFltPlanList; |
||||
planList.forEach(plan => { |
||||
const areaList = plan.areaList; |
||||
|
||||
areaList.forEach(area => { |
||||
const coordList = area.coordList; // 기초 좌표
|
||||
const bufferList = area.bufferCoordList; // 기초 좌표의 버퍼 좌표
|
||||
const bufferZone = area.bufferZone; // 반경 값
|
||||
const areaType = area.areaType; // 도형 타입
|
||||
|
||||
const paths = []; |
||||
coordList.forEach(coord => { |
||||
const path = new naver.maps.LatLng(coord.lat, coord.lon); |
||||
|
||||
paths.push(path); |
||||
}); |
||||
|
||||
const idntfNum = plan.arcrftList[0].idntfNum; |
||||
if (areaType === 'LINE') { |
||||
polyline(paths, bufferList, idntfNum); |
||||
} |
||||
if (areaType === 'POLYGON') { |
||||
//
|
||||
} |
||||
if (areaType === 'CIRCLE') { |
||||
//
|
||||
} |
||||
}); |
||||
}); |
||||
}; |
||||
|
||||
const polyline = (paths, bufferList, idntfNum) => { |
||||
if (paths && paths.length > 1) { |
||||
const line = new naver.maps.Polyline({ |
||||
strokeLineCap: 'round', |
||||
strokeLineJoin: 'round', |
||||
strokeColor: '#283046', |
||||
strokeWeight: 1, |
||||
strokeOpacity: 0.5, |
||||
path: paths, |
||||
map: map |
||||
}); |
||||
setAreaArr(prev => [...prev, { idntfNum: idntfNum, line: line }]); |
||||
} |
||||
if (bufferList && bufferList.length > 1) { |
||||
const paths = []; |
||||
bufferList.forEach(buffer => { |
||||
const path = new naver.maps.LatLng(buffer.lat, buffer.lon); |
||||
|
||||
paths.push(path); |
||||
}); |
||||
|
||||
const lineBuffer = new naver.maps.Polygon({ |
||||
strokeColor: '#283046', |
||||
strokeOpacity: 1, |
||||
fillColor: '#8a1c05', |
||||
fillOpacity: 0.1, |
||||
paths: paths, |
||||
map: map |
||||
}); |
||||
|
||||
setBufferArr(prev => [ |
||||
...prev, |
||||
{ idntfNum: idntfNum, lineBuffer: lineBuffer } |
||||
]); |
||||
} |
||||
}; |
||||
|
||||
const clear = diffArr => { |
||||
if (areaArr) { |
||||
const clearArea = areaArr |
||||
.filter(area => diffArr.includes(area.idntfNum)) |
||||
.map(obj => obj.line); |
||||
|
||||
const clearBuffer = bufferArr |
||||
.filter(buffer => diffArr.includes(buffer.idntfNum)) |
||||
.map(obj => obj.lineBuffer); |
||||
|
||||
clearArea.map(area => area.setMap(null)); |
||||
clearBuffer.map(buffer => buffer.setMap(null)); |
||||
|
||||
const saveArea = areaArr.filter(area => !diffArr.includes(area.idntfNum)); |
||||
const saveBuffer = bufferArr.filter( |
||||
buffer => !diffArr.includes(buffer.idntfNum) |
||||
); |
||||
setAreaArr(saveArea); |
||||
setBufferArr(saveBuffer); |
||||
// dispatch(controlGpFlightPlanInitAction());
|
||||
} |
||||
}; |
||||
|
||||
return null; |
||||
}; |
||||
|
||||
export default NewDronPlan; |
@ -1,170 +0,0 @@
|
||||
import { useEffect, useState } from 'react'; |
||||
import { useSelector } from 'react-redux'; |
||||
import '../../../../assets/css/custom.css'; |
||||
|
||||
export const FeatureAirZone = props => { |
||||
const mapControl = useSelector(state => state.controlMapReducer); |
||||
let infoWindow; |
||||
|
||||
useEffect(() => { |
||||
featureAirZoneInit(); |
||||
featureAirEvent(); |
||||
}, [mapControl]); |
||||
|
||||
useEffect(() => { |
||||
props.poly?.map(air => { |
||||
air?.map(a => { |
||||
a.setMap(props.map); |
||||
}); |
||||
}); |
||||
}, [props.poly]); |
||||
|
||||
const infowindowOpen = data => { |
||||
const content = |
||||
'<div class="tooltip-box">' + |
||||
'<div class="tooltip-ti">' + |
||||
'<span>' + |
||||
data.title + |
||||
'</span>' + |
||||
'</div>' + |
||||
'<div class="tooltip-txt">' + |
||||
'<div class="tooltip-txt-list">' + |
||||
// '<span class="ti">설명</span>' +
|
||||
'<span>' + |
||||
data.description + |
||||
'</span>' + |
||||
'</div>' + |
||||
// '<div class="tooltip-txt-list">' +
|
||||
// '<span class="ti">좌표정보</span>' +
|
||||
// '<span>'+data.coord+'</span>' +
|
||||
// '</div>' +
|
||||
'</div>' + |
||||
// '<span class="arrow"></span>' +
|
||||
'</div>'; |
||||
|
||||
infoWindow = new props.naver.maps.InfoWindow({ |
||||
class: 'tooltip-test', |
||||
content: content, |
||||
maxWidth: 200, |
||||
backgroundColor: '#283046', //박스안쪽영역 컬러
|
||||
// borderColor: '#333', //테두리컬러
|
||||
// borderWidth: 3, //테두리 굵기
|
||||
anchorSize: new props.naver.maps.Size(30, -10), |
||||
anchorSkew: false, |
||||
anchorColor: '#283046', |
||||
|
||||
pixelOffset: new props.naver.maps.Point(20, -20) |
||||
}); |
||||
|
||||
infoWindow.open(props.map, data.coord); |
||||
}; |
||||
|
||||
const featureAirZoneInit = () => { |
||||
let arrGeoJson = []; |
||||
// props.map.data.removeGeoJson(props.geoJson);
|
||||
// let geoJson = originGeoJson;
|
||||
let useGeoJson = { type: 'FeatureCollection' }; |
||||
useGeoJson.features = props.features; |
||||
|
||||
props.map.data.removeGeoJson(useGeoJson); |
||||
|
||||
props.features.map(item => { |
||||
if (item.properties.type === '0001' && mapControl.area0001) { |
||||
arrGeoJson.push(item); |
||||
} else if (item.properties.type === '0002' && mapControl.area0002) { |
||||
arrGeoJson.push(item); |
||||
} else if (item.properties.type === '0003' && mapControl.area0003) { |
||||
arrGeoJson.push(item); |
||||
} else if (item.properties.type === '0004' && mapControl.area0004) { |
||||
arrGeoJson.push(item); |
||||
} else if (item.properties.type === '0005' && mapControl.area0005) { |
||||
arrGeoJson.push(item); |
||||
} else if (item.properties.type === '0006' && mapControl.area0006) { |
||||
arrGeoJson.push(item); |
||||
} |
||||
}); |
||||
|
||||
useGeoJson.features = arrGeoJson; |
||||
props.map.data.addGeoJson(useGeoJson); |
||||
|
||||
props.map.data.setStyle(feature => { |
||||
var color; |
||||
|
||||
//0001 비행금지구역 #FF3648
|
||||
//0002 비행제한구역 #FFA1AA
|
||||
//0003 관제권(공항) #FFA800
|
||||
//0004 비행장(군사) #A16B00
|
||||
//0005 이착륙장(RC비행장) #AB40FF
|
||||
//0006 초경량비행장치 #009cad
|
||||
// 공역 색상 변경
|
||||
const type = feature.getProperty('type'); |
||||
const name = feature.getProperty('name'); |
||||
|
||||
if (type === '0001') { |
||||
color = '#FF3648'; |
||||
} else if (type === '0002') { |
||||
color = '#FFA1AA'; |
||||
} else if (type === '0003') { |
||||
color = '#FFA800'; |
||||
} else if (type === '0004') { |
||||
color = '#A16B00'; |
||||
} else if (type === '0005') { |
||||
color = '#AB40FF'; |
||||
} else if (type === '0006' && name != '김포공항') { |
||||
color = '#009cad'; |
||||
} else if (name === '김포공항') { |
||||
color = '#020715'; |
||||
} |
||||
|
||||
return { |
||||
fillColor: name === '김포공항' ? '#ffffff' : color, |
||||
opercity: name === '김포공항' ? 0 : 1, |
||||
strokeColor: color, |
||||
strokeWeight: name === '김포공항' ? 1 : 0.7, |
||||
icon: null |
||||
}; |
||||
}); |
||||
|
||||
// const coordzip = [];
|
||||
// let tt = 0;
|
||||
// for (let i = 0; i <= 180; i++) {
|
||||
// const coord1 = new naver.maps.EPSG3857.getDestinationCoord(
|
||||
// new naver.maps.LatLng(33.3943517, 126.7142598),
|
||||
// tt,
|
||||
// 9300
|
||||
// );
|
||||
// coordzip.push(coord1);
|
||||
// tt += 2;
|
||||
// }
|
||||
// console.log(coordzip);
|
||||
// console.log(tt);
|
||||
}; |
||||
|
||||
const featureAirEvent = () => { |
||||
props.map.data.addListener('click', function (e) { |
||||
// e.feature.setProperty('isColorful', true);
|
||||
}); |
||||
|
||||
props.map.data.addListener('mouseover', function (e) { |
||||
const data = {}; |
||||
data.coord = e.coord; |
||||
data.title = e.feature.property_name; |
||||
data.description = e.feature.property_description; |
||||
props.map.data.overrideStyle(e.feature, { |
||||
strokeWeight: 3 |
||||
// icon: HOME_PATH +'/img/example/pin_spot.png'
|
||||
}); |
||||
|
||||
infowindowOpen(data); |
||||
}); |
||||
|
||||
props.map.data.addListener('mouseout', function (e) { |
||||
props.map.data.revertStyle(); |
||||
|
||||
if (infoWindow) { |
||||
infoWindow.close(); |
||||
} |
||||
}); |
||||
}; |
||||
return null; |
||||
}; |
@ -1,23 +0,0 @@
|
||||
import { useEffect } from 'react'; |
||||
|
||||
export const NaverMapSearch = props => { |
||||
useEffect(() => { |
||||
props.naver.maps.Service.geocode( |
||||
{ |
||||
address: '산곡동' |
||||
}, |
||||
function (status, response) { |
||||
if (status !== naver.maps.Service.Status.OK) { |
||||
return alert('Something wrong!'); |
||||
} |
||||
|
||||
var result = response.result, // 검색 결과의 컨테이너
|
||||
items = result.items; // 검색 결과의 배열
|
||||
|
||||
// do Something
|
||||
} |
||||
); |
||||
}); |
||||
|
||||
return null; |
||||
}; |
Loading…
Reference in new issue