노승철
2 years ago
31 changed files with 8601 additions and 1 deletions
@ -0,0 +1,10 @@ |
|||||||
|
import React from 'react'; |
||||||
|
import { GoogleCustomMap } from './google/GoogleMap'; |
||||||
|
import { NaverCustomMap } from './naver/NaverMap'; |
||||||
|
|
||||||
|
export const MapControlDraw = props => { |
||||||
|
// console.log('```````````````````````');
|
||||||
|
return ( |
||||||
|
<>{props.mapType === 'google' ? <GoogleCustomMap /> : <NaverCustomMap />}</> |
||||||
|
); |
||||||
|
}; |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,24 @@ |
|||||||
|
import React from 'react'; |
||||||
|
import { useEffect, useRef, useState } from 'react'; |
||||||
|
import InfoBox from 'react-google-maps/lib/components/addons/InfoBox'; |
||||||
|
import Marker from 'react-google-maps/lib/components/Marker'; |
||||||
|
import OverlayView from 'react-google-maps/lib/components/OverlayView'; |
||||||
|
import dronicon from '../../../assets/control/icon/drone.png'; |
||||||
|
import { useDispatch, useSelector } from 'react-redux'; |
||||||
|
import { ControlGpData } from '../../../modules/control/gp'; |
||||||
|
import { StoreState } from '../../../modules'; |
||||||
|
|
||||||
|
export const DronMarker = props => { |
||||||
|
return ( |
||||||
|
<Marker |
||||||
|
key={props.dronInfo.objectId} |
||||||
|
icon={{ |
||||||
|
url: dronicon, |
||||||
|
scaledSize: new window.google.maps.Size(25, 25) |
||||||
|
}} |
||||||
|
title={props.dronInfo.objectId} |
||||||
|
onClick={() => alert(11111)} |
||||||
|
position={{ lat: props.dronInfo.lat, lng: props.dronInfo.lng }} |
||||||
|
></Marker> |
||||||
|
); |
||||||
|
}; |
@ -0,0 +1,64 @@ |
|||||||
|
import React, { useEffect, useState } from 'react'; |
||||||
|
import { |
||||||
|
GoogleMap, |
||||||
|
GroundOverlay, |
||||||
|
Marker, |
||||||
|
Polyline, |
||||||
|
withGoogleMap, |
||||||
|
withScriptjs |
||||||
|
} from 'react-google-maps'; |
||||||
|
import { DronMarker } from './DronMarker'; |
||||||
|
// import { StoreState } from '../../../modules';
|
||||||
|
import { useSelector } from 'react-redux'; |
||||||
|
import SearchBox from 'react-google-maps/lib/components/places/SearchBox'; |
||||||
|
import InfoWindow from 'react-google-maps/lib/components/InfoWindow'; |
||||||
|
|
||||||
|
const MapInit = () => { |
||||||
|
const { controlGpList } = useSelector(state => state.controlGpState); |
||||||
|
const [bounds, setBounds] = useState(null); |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
console.log('GoogleMap >>>>>', controlGpList); |
||||||
|
}, [controlGpList]); |
||||||
|
const onSearchBoxMounted = () => {}; |
||||||
|
|
||||||
|
const onPlacesChanged = () => {}; |
||||||
|
|
||||||
|
return ( |
||||||
|
<> |
||||||
|
<GoogleMap |
||||||
|
defaultZoom={10} |
||||||
|
defaultCenter={{ lat: 37.5, lng: 127 }} |
||||||
|
defaultOptions={{}} |
||||||
|
> |
||||||
|
<div style={{ height: 100 }}>test</div> |
||||||
|
|
||||||
|
{controlGpList?.map(item => ( |
||||||
|
// <DronMarker controlGpList={controlGpList} />
|
||||||
|
<DronMarker dronInfo={item} key={item.objectId} /> |
||||||
|
))} |
||||||
|
</GoogleMap> |
||||||
|
</> |
||||||
|
); |
||||||
|
}; |
||||||
|
|
||||||
|
const GoogleMapWrapped = withScriptjs(withGoogleMap(MapInit)); |
||||||
|
|
||||||
|
export const GoogleCustomMap = () => { |
||||||
|
const mapProps = { |
||||||
|
key: 'AIzaSyDKCsI8cbzgi4es3xCUIhElUm6NRM73QuI', |
||||||
|
url: 'https://maps.googleapis.com/maps/api/js?v=3.exp&libraries=drawing,geometryplaces' |
||||||
|
}; |
||||||
|
|
||||||
|
console.log(`${mapProps.url}&key=${mapProps.key}`); |
||||||
|
return ( |
||||||
|
<div style={{ width: '100vw', height: '100vh' }}> |
||||||
|
<GoogleMapWrapped |
||||||
|
googleMapURL={`${mapProps.url}&key=${mapProps.key}`} |
||||||
|
loadingElement={<div style={{ height: `100%` }} />} |
||||||
|
containerElement={<div style={{ height: `100%` }} />} |
||||||
|
mapElement={<div style={{ height: `100%` }} />} |
||||||
|
/> |
||||||
|
</div> |
||||||
|
); |
||||||
|
}; |
@ -0,0 +1,107 @@ |
|||||||
|
import React, { useEffect, useState } from 'react'; |
||||||
|
import { useSelector } from 'react-redux'; |
||||||
|
import dronicon from '../../../assets/control/icon/drone.png'; |
||||||
|
import { DronMarker } from './dron/DronMarker'; |
||||||
|
import { DronHistory } from './dron/DronHistory'; |
||||||
|
|
||||||
|
import NaverMapControl from './NaverMapControl'; |
||||||
|
import { NaverMapSearch } from './search/NaverMapSearch'; |
||||||
|
import { FeatureAirZone } from './feature/FeatureAirZone'; |
||||||
|
import { DrawPath } from './draw/DrawPath'; |
||||||
|
import { DrawTest0 } from './draw/DrawTest0'; |
||||||
|
import { DrawTest1 } from './draw/DrawTest1'; |
||||||
|
import { DrawTest2 } from './draw/DrawTest2'; |
||||||
|
|
||||||
|
import geoJson from '../geojson/airArea.json'; |
||||||
|
import SensorZone from "./sensor/SensorZone"; |
||||||
|
|
||||||
|
export const NaverCustomMap = () => { |
||||||
|
const naver = window.naver; |
||||||
|
let map; |
||||||
|
|
||||||
|
const [isMapLoad, setIsMapLoad] = useState(false); |
||||||
|
const [mapObject, setMapObject] = useState(null); |
||||||
|
|
||||||
|
let arrMarkers = []; // 마커 배열
|
||||||
|
let arrPolyline = []; // 폴리라인 배열
|
||||||
|
let features = geoJson.features; |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
NaverMapInit(); |
||||||
|
// console.log(map);
|
||||||
|
|
||||||
|
// console.log(features);
|
||||||
|
|
||||||
|
// setIsMapLoad(true);
|
||||||
|
}, []); |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
// console.log('==============11111==================', mapObject);
|
||||||
|
}, [mapObject]); |
||||||
|
|
||||||
|
const removeArrMarkers = arrData => { |
||||||
|
arrMarkers = arrData; |
||||||
|
}; |
||||||
|
|
||||||
|
const NaverMapInit = () => { |
||||||
|
const mapOptions = { |
||||||
|
// center: new naver.maps.LatLng(36.56793936069445, 127.85101412107547),
|
||||||
|
center: new naver.maps.LatLng(37.445949, 126.673868), |
||||||
|
zoom: 13, |
||||||
|
zoomControl: true, |
||||||
|
mapTypeId: naver.maps.MapTypeId.HYBRID, |
||||||
|
zoomControlOptions: { |
||||||
|
position: naver.maps.Position.TOP_LEFT, |
||||||
|
|
||||||
|
style: naver.maps.ZoomControlStyle.SMALL |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
// map = ;
|
||||||
|
setMapObject(new naver.maps.Map('map', mapOptions)); |
||||||
|
// naver.maps.Event.addListener(map, 'click', function (e) {
|
||||||
|
// console.log(e);
|
||||||
|
// });
|
||||||
|
|
||||||
|
// naver.maps.Event.addListener(map, 'idle', function (e) {
|
||||||
|
// console.log(e);
|
||||||
|
// });
|
||||||
|
}; |
||||||
|
|
||||||
|
return ( |
||||||
|
<> |
||||||
|
<div id='map' style={{ width: '100%', height: '100vh' }}></div> |
||||||
|
{mapObject != null ? ( |
||||||
|
<> |
||||||
|
{/* <DronMarker |
||||||
|
map={mapObject} |
||||||
|
naver={naver} |
||||||
|
arrMarkers={arrMarkers} |
||||||
|
removeArrMarkers={removeArrMarkers} |
||||||
|
test={test} |
||||||
|
/> */} |
||||||
|
|
||||||
|
<NaverMapControl map={mapObject} /> |
||||||
|
|
||||||
|
{/* <DronHistory |
||||||
|
map={mapObject} |
||||||
|
naver={naver} |
||||||
|
arrPolyline={arrPolyline} |
||||||
|
/> */} |
||||||
|
|
||||||
|
<FeatureAirZone map={mapObject} naver={naver} features={features} /> |
||||||
|
{/* <NaverMapSearch map={mapObject} naver={naver} /> */} |
||||||
|
{/* <SensorZone map={mapObject} naver={naver} /> */} |
||||||
|
|
||||||
|
{/* <DrawLine map={mapObject} naver={naver} /> */} |
||||||
|
{/* <DrawTest2 map={mapObject} naver={naver} /> */} |
||||||
|
{/* <DrawTest map={mapObject} naver={naver} /> */} |
||||||
|
<DrawPath map={mapObject} naver={naver} /> |
||||||
|
|
||||||
|
</> |
||||||
|
) : null} |
||||||
|
|
||||||
|
{/* */} |
||||||
|
</> |
||||||
|
); |
||||||
|
}; |
@ -0,0 +1,31 @@ |
|||||||
|
import { useEffect } from 'react'; |
||||||
|
import { useSelector } from 'react-redux'; |
||||||
|
|
||||||
|
const NaverMapControl = props => { |
||||||
|
const mapControl = useSelector(state => state.controlMapReducer); |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
}, [mapControl]); |
||||||
|
|
||||||
|
//맵타입 변경
|
||||||
|
if (mapControl.mapType === 'NORMAL') { |
||||||
|
props.map.setMapTypeId(naver.maps.MapTypeId.NORMAL); |
||||||
|
} else if (mapControl.mapType === 'TERRAIN') { |
||||||
|
props.map.setMapTypeId(naver.maps.MapTypeId.TERRAIN); |
||||||
|
} else if (mapControl.mapType === 'HYBRID') { |
||||||
|
props.map.setMapTypeId(naver.maps.MapTypeId.HYBRID); |
||||||
|
} |
||||||
|
|
||||||
|
//그리기타입 변경
|
||||||
|
// if(mapControl.drawType === 'CIRCLE') {
|
||||||
|
// console.log("circle")
|
||||||
|
// } else if(mapControl.drawType === 'LINE') {
|
||||||
|
// console.log("line")
|
||||||
|
// } else if(mapControl.drawType === 'POLYGON') {
|
||||||
|
// console.log("polygon")
|
||||||
|
// }
|
||||||
|
|
||||||
|
return null; |
||||||
|
}; |
||||||
|
|
||||||
|
export default NaverMapControl; |
@ -0,0 +1,129 @@ |
|||||||
|
import { useEffect, useState } from "react"; |
||||||
|
import { BiCaretLeftCircle } from "react-icons/bi"; |
||||||
|
import { useSelector } from "react-redux"; |
||||||
|
|
||||||
|
export const DrawPath = props => { |
||||||
|
const {naver} = props; |
||||||
|
const {map} = props; |
||||||
|
const {drawType} = useSelector(state => state.controlMapReducer); |
||||||
|
|
||||||
|
let linePath = ([]); |
||||||
|
let circleCenter = ''; |
||||||
|
// let events = ([]);
|
||||||
|
const [eventGroup, setEventGroup] = useState([]); |
||||||
|
|
||||||
|
const [polylines, setPolylines] = useState([]); |
||||||
|
const [circleLayers, setCircleLayers] = useState([]); |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
init(); |
||||||
|
}, [drawType]); |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
}, [eventGroup]); |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
moveCircle(); |
||||||
|
}, [circleLayers]); |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const init = () => { |
||||||
|
removeEvent(); |
||||||
|
removeLayers(); |
||||||
|
} |
||||||
|
|
||||||
|
const removeEvent = () => { |
||||||
|
eventGroup.forEach(prev => naver.maps.Event.removeListener(prev)); |
||||||
|
setEventGroup([]); |
||||||
|
addEvent(); |
||||||
|
} |
||||||
|
|
||||||
|
const removeLayers = () => { |
||||||
|
if(polylines) { |
||||||
|
polylines.forEach(prev => prev.setMap(null)); |
||||||
|
setPolylines([]); |
||||||
|
}; |
||||||
|
if(circleLayers) { |
||||||
|
circleLayers.forEach(prev => prev.setMap(null)); |
||||||
|
setCircleLayers([]); |
||||||
|
}; |
||||||
|
linePath = []; |
||||||
|
// circleCenter = '';
|
||||||
|
} |
||||||
|
|
||||||
|
const addEvent = () => { |
||||||
|
let addClick = naver.maps.Event.addListener(map, 'click', function(e) { |
||||||
|
if(drawType) { |
||||||
|
linePath.push(e.coord); |
||||||
|
circleCenter = e.coord; |
||||||
|
startDraw(); |
||||||
|
} else { |
||||||
|
// console.log('1');
|
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
let escDown = naver.maps.Event.addListener(map, 'keydown', function(e) { |
||||||
|
const keyboardEvent = e.keyboardEvent, |
||||||
|
keyCode = keyboardEvent.keyCode || keyboardEvent.which; |
||||||
|
|
||||||
|
const ESC = 27; |
||||||
|
if(keyCode === ESC) { |
||||||
|
keyboardEvent.preventDefault(); |
||||||
|
// removeLayers();
|
||||||
|
} |
||||||
|
}); |
||||||
|
setEventGroup(prev => ([...prev, addClick, escDown])); |
||||||
|
} |
||||||
|
|
||||||
|
const startDraw = () => { |
||||||
|
if(drawType === 'LINE') { |
||||||
|
createPolyline(); |
||||||
|
} else if(drawType === 'CIRCLE') { |
||||||
|
createCircle(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const createPolyline = () => { |
||||||
|
if(linePath.length >= 2) { |
||||||
|
const polyline = new naver.maps.Polyline({ |
||||||
|
path: linePath, |
||||||
|
strokeColor: '#ff0000', |
||||||
|
strokeWeight: 2, |
||||||
|
strokeOpacity: 0.5, |
||||||
|
map: map |
||||||
|
}); |
||||||
|
linePath.shift(); |
||||||
|
setPolylines(prev => ([...prev, polyline])); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const createCircle = () => { |
||||||
|
const circle = new naver.maps.Circle({ |
||||||
|
center: circleCenter, |
||||||
|
strokeColor: '#ff0000', |
||||||
|
strokeWeight: 2, |
||||||
|
strokeOpacity: 1, |
||||||
|
fillColor: '#0000ff', |
||||||
|
fillOpacity: 0.35, |
||||||
|
radius: 1000, |
||||||
|
clickable: false, |
||||||
|
map: map |
||||||
|
}); |
||||||
|
// circleCenter = '';
|
||||||
|
setCircleLayers(prev => ([...prev, circle])); |
||||||
|
} |
||||||
|
|
||||||
|
const moveCircle = () => { |
||||||
|
if(circleLayers.length >= 2) { |
||||||
|
circleLayers[0].setMap(null); |
||||||
|
setCircleLayers(prev => ([prev[circleLayers.length-1]])); |
||||||
|
}
|
||||||
|
// else {
|
||||||
|
// console.log(circleLayers);
|
||||||
|
// }
|
||||||
|
} |
||||||
|
|
||||||
|
return null; |
||||||
|
}; |
||||||
|
|
@ -0,0 +1,71 @@ |
|||||||
|
import { useEffect, useState } from "react"; |
||||||
|
import { useSelector } from "react-redux"; |
||||||
|
|
||||||
|
|
||||||
|
export const DrawTest0 = props => { |
||||||
|
const {naver} = props; |
||||||
|
const {map} = props; |
||||||
|
|
||||||
|
const mapControl = useSelector(state => state.controlMapReducer); |
||||||
|
|
||||||
|
// const [linePositions, setLinePositions] = useState([]);
|
||||||
|
const positions = ([]); |
||||||
|
const [lineZips, setLineZips] = useState([]); |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
}, [mapControl.drawType]); |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if(mapControl.drawType === 'LINE') { |
||||||
|
naver.maps.Event.addListener(map, 'click', function(e) { |
||||||
|
// const position = e.coord;
|
||||||
|
positions.push(e.coord); |
||||||
|
createPolyline(positions); |
||||||
|
}) |
||||||
|
|
||||||
|
// naver.maps.Event.addListener(map, 'dbclick', function(e) {
|
||||||
|
// console.log("dbclick")
|
||||||
|
// })
|
||||||
|
|
||||||
|
naver.maps.Event.addListener(map, 'keydown', function(e) { |
||||||
|
const keyboardEvent = e.keyboardEvent, |
||||||
|
keyCode = keyboardEvent.keyCode || keyboardEvent.which; |
||||||
|
|
||||||
|
const ESC = 27; |
||||||
|
|
||||||
|
if(keyCode === ESC) { |
||||||
|
keyboardEvent.preventDefault(); |
||||||
|
|
||||||
|
// for(var i=0, ii=lineZips.length; i<ii; i++) {
|
||||||
|
// lineZips[i].setMap(null);
|
||||||
|
// // console.log(lineZips[i]);
|
||||||
|
// }
|
||||||
|
lineZips.forEach(line => line.setMap(null)); |
||||||
|
setLineZips([]); |
||||||
|
console.log(lineZips); |
||||||
|
|
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
const createPolyline = (positions) => { |
||||||
|
if(positions.length >= 2) { |
||||||
|
const polyline = new naver.maps.Polyline({ |
||||||
|
path: [positions[(positions.length)-1], positions[(positions.length)-2]], |
||||||
|
strokeWeight: 2, |
||||||
|
strokeOpacity: 1, |
||||||
|
strokeColor: '#ff0000', |
||||||
|
map: map |
||||||
|
}) |
||||||
|
// polyline.setMap(map);
|
||||||
|
setLineZips([...lineZips, positions]); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const removeLine = () => { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
return null; |
||||||
|
} |
@ -0,0 +1,157 @@ |
|||||||
|
import { useEffect, useState } from "react"; |
||||||
|
import { BiCaretLeftCircle } from "react-icons/bi"; |
||||||
|
import { useSelector } from "react-redux"; |
||||||
|
|
||||||
|
export const DrawTest1 = props => { |
||||||
|
const {naver} = props; |
||||||
|
const {map} = props; |
||||||
|
const {drawType} = useSelector(state => state.controlMapReducer); |
||||||
|
|
||||||
|
let linePath = ([]); |
||||||
|
let circleCenter = ''; |
||||||
|
// let positions = ([]);
|
||||||
|
// let po = '';
|
||||||
|
|
||||||
|
const r = 1000; |
||||||
|
// const [polylines, setPolylines] = useState([]);
|
||||||
|
// const [circleLayers, setCircleLayers] = useState();
|
||||||
|
let polylines = ([]); |
||||||
|
// let circleLayers = ('');
|
||||||
|
let circleLayers = ([]); |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
init(); |
||||||
|
}, []); |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
remove(); |
||||||
|
console.log(drawType) |
||||||
|
// init();
|
||||||
|
}, [drawType]); |
||||||
|
|
||||||
|
const event = () => { |
||||||
|
let addClick = naver.maps.Event.addListener(map, 'click', function(e) { |
||||||
|
if(drawType) { |
||||||
|
linePath.push(e.coord); |
||||||
|
circleCenter = e.coord |
||||||
|
clickDraw(); |
||||||
|
} else { |
||||||
|
|
||||||
|
} |
||||||
|
}) |
||||||
|
|
||||||
|
let escDown = naver.maps.Event.addListener(map, 'keydown', function(e) { |
||||||
|
const keyboardEvent = e.keyboardEvent, |
||||||
|
keyCode = keyboardEvent.keyCode || keyboardEvent.which; |
||||||
|
|
||||||
|
const ESC = 27; |
||||||
|
|
||||||
|
if(keyCode === ESC) { |
||||||
|
keyboardEvent.preventDefault(); |
||||||
|
remove(); |
||||||
|
} |
||||||
|
}) |
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
const init = () => { |
||||||
|
remove(); |
||||||
|
event(); |
||||||
|
} |
||||||
|
|
||||||
|
const clickDraw = () => { |
||||||
|
// if(!drawType) {
|
||||||
|
// alert("path option을 선택해주세요.")
|
||||||
|
// } else {
|
||||||
|
// if(drawType === 'LINE') {
|
||||||
|
// console.log("LINE")
|
||||||
|
// createPolyline();
|
||||||
|
// } else if(drawType === 'CIRCLE') {
|
||||||
|
// console.log("CIRCLE")
|
||||||
|
// createCircle();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
if(drawType === 'LINE') { |
||||||
|
console.log('1') |
||||||
|
createPolyline(); |
||||||
|
} else if(drawType === 'CIRCLE') { |
||||||
|
createCircle(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const createPolyline = () => { |
||||||
|
if(linePath.length >= 2) { |
||||||
|
const polyline = new naver.maps.Polyline({ |
||||||
|
// path: [positions[positions.length-1], po],
|
||||||
|
path: linePath, |
||||||
|
strokeColor: '#ff0000', |
||||||
|
strokeWeight: 2, |
||||||
|
strokeOpacity: 0.5, |
||||||
|
map: map |
||||||
|
}); |
||||||
|
linePath.shift(); |
||||||
|
// setPolylines(prev => ([...prev, polyline]));
|
||||||
|
polylines.push(polyline); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// const createCircle = (positions) => {
|
||||||
|
const createCircle = () => { |
||||||
|
if(circleLayers) remove(); |
||||||
|
// const circleCenter = positions[0];
|
||||||
|
// console.log(circleCenter)
|
||||||
|
// console.log(po)
|
||||||
|
// const te = positions[0];
|
||||||
|
const circle = new naver.maps.Circle({ |
||||||
|
center: circleCenter, |
||||||
|
// center: positions[0],
|
||||||
|
strokeColor: '#ff0000', |
||||||
|
strokeWeight: 2, |
||||||
|
strokeOpacity: 1, |
||||||
|
fillColor: '#0000ff', |
||||||
|
fillOpacity: 0.35, |
||||||
|
radius: r, |
||||||
|
clickable: false, |
||||||
|
map: map |
||||||
|
}) |
||||||
|
// circleCenter.shift();
|
||||||
|
// setCircleLayers(circle);
|
||||||
|
// circleLayers = circle;
|
||||||
|
circleLayers.push(circle); |
||||||
|
} |
||||||
|
|
||||||
|
// const reCircle = () => {
|
||||||
|
// // circle.setMap(null);
|
||||||
|
// // positions = ([]);
|
||||||
|
// // circleLayers.forEach(cir => cir.setMap(null));
|
||||||
|
// circleLayers.setMap(null);
|
||||||
|
// // setCircleLayers();
|
||||||
|
// circleLayers = '';
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
const remove = () => { |
||||||
|
// debugger;
|
||||||
|
if(polylines) { |
||||||
|
polylines.forEach(poly => poly.setMap(null)); |
||||||
|
polylines = ([]); |
||||||
|
// console.log("poly remove")
|
||||||
|
} |
||||||
|
if(circleLayers) { |
||||||
|
circleLayers.forEach(cir => cir.setMap(null)); |
||||||
|
circleLayers = ([]); |
||||||
|
// console.log("circle remove")
|
||||||
|
} |
||||||
|
// circleLayers.forEach(cir => cir.setMap(null));
|
||||||
|
// circleLayers = ([]);
|
||||||
|
circleCenter = ''; |
||||||
|
linePath = ([]); |
||||||
|
// console.log("remove!!")
|
||||||
|
// setClickable(0);
|
||||||
|
} |
||||||
|
|
||||||
|
return null; |
||||||
|
}; |
||||||
|
|
@ -0,0 +1,180 @@ |
|||||||
|
import { useEffect, useState } from "react"; |
||||||
|
import { useSelector } from "react-redux"; |
||||||
|
|
||||||
|
|
||||||
|
export const DrawTest2 = props => { |
||||||
|
const {naver} = props; |
||||||
|
const {map} = props; |
||||||
|
let draw = ''; |
||||||
|
const {drawType} = useSelector(state => state.controlMapReducer); |
||||||
|
|
||||||
|
const r = 1000; |
||||||
|
let positions = ([]); |
||||||
|
const [polyGroup, setPolyGroup] = useState([]); |
||||||
|
const [eventGroup, setEventGrouop] = useState([]); |
||||||
|
const [circleGroup, setCircleGroup] = useState([]); |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
remove2(); |
||||||
|
clickEvent(); |
||||||
|
}, [drawType]); |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
remove(); |
||||||
|
}, [polyGroup, eventGroup]); |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
// moveCircle();
|
||||||
|
remove(); |
||||||
|
}, [circleGroup]); |
||||||
|
|
||||||
|
|
||||||
|
const moveCircle = () => { |
||||||
|
if(circleGroup) { |
||||||
|
circleGroup.forEach(prev => prev.setMap(null)); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
const movePoly = () => { |
||||||
|
if(polyGroup) { |
||||||
|
polyGroup.forEach(prev => prev.setMap(null)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const clickEvent = () => { |
||||||
|
console.log("d") |
||||||
|
// remove2();
|
||||||
|
// drawType =
|
||||||
|
if(drawType === 'CIRCLE') { |
||||||
|
console.log("circle") |
||||||
|
} else if(drawType === 'LINE') { |
||||||
|
console.log("LINE") |
||||||
|
}else if(drawType === 'POLYGON') { |
||||||
|
console.log("POLYGON") |
||||||
|
} |
||||||
|
|
||||||
|
addPositions(); |
||||||
|
} |
||||||
|
|
||||||
|
const remove2 = () => { |
||||||
|
polyGroup.forEach(poly => poly.setMap(null)); |
||||||
|
setPolyGroup([]); |
||||||
|
circleGroup.forEach(cir => cir.setMap(null)); |
||||||
|
setCircleGroup([]); |
||||||
|
eventGroup.forEach(eve => naver.maps.Event.removeListener(eve)); |
||||||
|
setEventGrouop([]); |
||||||
|
positions = []; |
||||||
|
} |
||||||
|
|
||||||
|
const addPositions = () => { |
||||||
|
if(event) naver.maps.Event.removeListener(event); |
||||||
|
var event = naver.maps.Event.addListener(map, 'click', function(e) { |
||||||
|
debugger; |
||||||
|
if(drawType === 'LINE') { |
||||||
|
positions.push(e.coord); |
||||||
|
createPolyline(positions); |
||||||
|
} else if(drawType === 'CIRCLE') { |
||||||
|
positions = e.coord; |
||||||
|
createCircle(positions); |
||||||
|
} |
||||||
|
}) |
||||||
|
// setEventGrouop(prev => ([...prev, event]));
|
||||||
|
} |
||||||
|
|
||||||
|
const createCircle = (positions) => { |
||||||
|
moveCircle(); |
||||||
|
const circle = new naver.maps.Circle({ |
||||||
|
center: positions, |
||||||
|
strokeColor: '#ff0000', |
||||||
|
strokeWeight: 2, |
||||||
|
strokeOpacity: 1, |
||||||
|
fillColor: '#0000ff', |
||||||
|
fillOpacity: 0.35, |
||||||
|
radius: r, |
||||||
|
clickable: false, |
||||||
|
map: map |
||||||
|
}) |
||||||
|
draw = drawType; |
||||||
|
setCircleGroup(prev => ([...prev, circle])); |
||||||
|
} |
||||||
|
|
||||||
|
const createPolyline = (positions) => { |
||||||
|
if(positions.length >= 2) { |
||||||
|
movePoly(); |
||||||
|
const polyline = new naver.maps.Polyline({ |
||||||
|
// path: [positions[(positions.length)-1], positions[(positions.length)-2]],
|
||||||
|
path: positions, |
||||||
|
strokeColor: '#ff0000', |
||||||
|
strokeWeight: 2, |
||||||
|
strokeOpacity: 1, |
||||||
|
map: map |
||||||
|
}) |
||||||
|
positions.shift(); |
||||||
|
console.log(positions) |
||||||
|
draw = drawType; |
||||||
|
setPolyGroup(prev => ([...prev, polyline])); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
const remove = () => { |
||||||
|
if(drawType!=draw) { |
||||||
|
naver.maps.Event.addListener(map, 'keydown', function(e) { |
||||||
|
const keyboardEvent = e.keyboardEvent, |
||||||
|
keyCode = keyboardEvent.keyCode || keyboardEvent.which; |
||||||
|
|
||||||
|
const ESC = 27; |
||||||
|
|
||||||
|
if(keyCode === ESC) { |
||||||
|
keyboardEvent.preventDefault(); |
||||||
|
polyGroup.forEach(poly => poly.setMap(null)); |
||||||
|
setPolyGroup([]); |
||||||
|
circleGroup.forEach(cir => cir.setMap(null)); |
||||||
|
setCircleGroup([]); |
||||||
|
// eventGroup.forEach(eve => naver.maps.Event.removeListener(eve));
|
||||||
|
// setEventGrouop([]);
|
||||||
|
positions = []; |
||||||
|
// debugger;
|
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// const drawTypeChange = () => {
|
||||||
|
// remove();
|
||||||
|
// draw = drawType;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// const init = () => {
|
||||||
|
// // draw = drawType;
|
||||||
|
// if(draw) {
|
||||||
|
// var event = naver.maps.Event.addListener(map, 'click', function(e) {
|
||||||
|
// draw = drawType;
|
||||||
|
// console.log(drawType, "drawType")
|
||||||
|
// // remove(draw, event);
|
||||||
|
// drawTypeChange();
|
||||||
|
// // naver.maps.Event.removeListener(event);
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
// // remove(event);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// const remove = (draw, event) => {
|
||||||
|
// if(draw == drawType) {
|
||||||
|
// console.log("안지워")
|
||||||
|
// } else {
|
||||||
|
// console.log("지워")
|
||||||
|
// naver.maps.Event.removeListener(event);
|
||||||
|
// }
|
||||||
|
// if(positions) naver.maps.Event.removeListener(map, 'click', function(e) {
|
||||||
|
// console.log(e);
|
||||||
|
// });
|
||||||
|
// naver.maps.removeListener(event);
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return null; |
||||||
|
} |
@ -0,0 +1,63 @@ |
|||||||
|
import { useEffect } 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 { objectId, isClickObject } = useSelector( |
||||||
|
state => state.controlMapReducer |
||||||
|
); |
||||||
|
|
||||||
|
let naver = props.naver; |
||||||
|
let polyline; |
||||||
|
let polylinePath = []; |
||||||
|
|
||||||
|
const dispatch = useDispatch(); |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
// console.log('>>>', controlGpHistory);
|
||||||
|
polylineRemove(); |
||||||
|
polylineInit(); |
||||||
|
}, [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 = () => { |
||||||
|
if (controlGpHistory) { |
||||||
|
polyline = new naver.maps.Polyline({ |
||||||
|
clickable: false, |
||||||
|
strokeColor: '#ff4961', |
||||||
|
strokeStyle: 'solid', |
||||||
|
strokeOpacity: 5, |
||||||
|
strokeWeight: 1.5 |
||||||
|
}); |
||||||
|
|
||||||
|
controlGpHistory.map(item => { |
||||||
|
if (item.lat > 0 && item.lng > 0) { |
||||||
|
const position = new naver.maps.LatLng(item.lat, item.lng); |
||||||
|
polylinePath.push(position); |
||||||
|
} |
||||||
|
// console.log('>>>>>>>>>>>', item);
|
||||||
|
}); |
||||||
|
|
||||||
|
polyline.setPath(polylinePath); |
||||||
|
polyline.setMap(props.map); |
||||||
|
props.arrPolyline.push(polyline); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
return null; |
||||||
|
}; |
@ -0,0 +1,158 @@ |
|||||||
|
import { useEffect } from 'react'; |
||||||
|
import { useDispatch, useSelector } from 'react-redux'; |
||||||
|
import '../../../../assets/css/custom.css'; |
||||||
|
import DronIconPulple from '../../../../assets/images/drone-marker-icon-pulple.png'; |
||||||
|
import DronIcon from '../../../../assets/images/drone-marker-icon.png'; |
||||||
|
import { controlGpDtlAction } from '../../../../modules/control/gp'; |
||||||
|
import { objectClickAction } from '../../../../modules/control/map/actions/controlMapActions'; |
||||||
|
|
||||||
|
export const DronMarker = props => { |
||||||
|
const { controlGpList } = useSelector(state => state.controlGpState); |
||||||
|
const { objectId, isClickObject } = useSelector( |
||||||
|
state => state.controlMapReducer |
||||||
|
); |
||||||
|
const dispatch = useDispatch(); |
||||||
|
|
||||||
|
let naver = props.naver; |
||||||
|
|
||||||
|
var contentString = ['<div class="iw_inner"> dddd', '</div>'].join(''); |
||||||
|
|
||||||
|
var infowindow = new naver.maps.InfoWindow({ |
||||||
|
content: contentString |
||||||
|
}); |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
markerInit(); |
||||||
|
}, [controlGpList]); |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
console.log('>>>>>>>>>>>>>>>>', objectId, isClickObject); |
||||||
|
|
||||||
|
props.arrMarkers.map(clickMarker => { |
||||||
|
if (objectId === clickMarker.id && isClickObject) { |
||||||
|
clickMarker.setIcon(DronIconPulple); |
||||||
|
} else { |
||||||
|
clickMarker.setIcon(DronIcon); |
||||||
|
} |
||||||
|
}); |
||||||
|
// }else{
|
||||||
|
|
||||||
|
// }
|
||||||
|
}, [objectId, isClickObject]); |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
props.arrMarkers.map(clickMarker => { |
||||||
|
if (objectId === clickMarker.id) { |
||||||
|
console.log(clickMarker); |
||||||
|
props.map.setCenter(clickMarker.getPosition()); |
||||||
|
// $('#btn_modal').click();
|
||||||
|
props.map.setZoom(13, true); |
||||||
|
} |
||||||
|
}); |
||||||
|
}, [objectId]); |
||||||
|
|
||||||
|
//마커를 그린다.
|
||||||
|
const addMarkers = (position, id, controlId) => { |
||||||
|
var marker = new naver.maps.Marker({ |
||||||
|
position: position, |
||||||
|
title: id, |
||||||
|
id: id, |
||||||
|
controlId: controlId, |
||||||
|
icon: { |
||||||
|
// content: [
|
||||||
|
// '<div>dddd</div>',
|
||||||
|
|
||||||
|
// ].join(''),
|
||||||
|
url: DronIcon, |
||||||
|
// scaledSize: new naver.maps.scaledSize(50, 50)
|
||||||
|
// size: new naver.maps.Size(1000, 1000),
|
||||||
|
// origin: new naver.maps.Point(0, 0)
|
||||||
|
// anchor: new naver.maps.Point(25, 25)
|
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
marker.setMap(props.map); |
||||||
|
|
||||||
|
naver.maps.Event.addListener(marker, 'click', function (e) { |
||||||
|
handlerDronClick(marker); |
||||||
|
}); |
||||||
|
|
||||||
|
props.arrMarkers.push(marker); |
||||||
|
}; |
||||||
|
|
||||||
|
const handlerDronClick = marker => { |
||||||
|
if (marker.getAnimation() != null) { |
||||||
|
// marker.setAnimation(null);
|
||||||
|
// infowindow.close();
|
||||||
|
// dispatch(Actions.controlGpHisAction.request(controlGpList));
|
||||||
|
} else { |
||||||
|
// infowindow.open(props.map, marker);
|
||||||
|
// marker.setAnimation(naver.maps.Animation.BOUNCE);
|
||||||
|
} |
||||||
|
|
||||||
|
// marker.setIcon(DronIconPulple);
|
||||||
|
// console.log(marker.id);
|
||||||
|
const markerId = marker.id; |
||||||
|
const contorlId = marker.controlId; |
||||||
|
console.log('contorlId ::::::::::< ', marker.controlId); |
||||||
|
//히스토리 불러오기
|
||||||
|
|
||||||
|
dispatch(objectClickAction(markerId)); |
||||||
|
dispatch(controlGpDtlAction.request(contorlId)); |
||||||
|
}; |
||||||
|
|
||||||
|
//마커를 삭제 한다.
|
||||||
|
const removeMarkers = marker => { |
||||||
|
marker.setMap(null); |
||||||
|
}; |
||||||
|
|
||||||
|
//마커에 위치를 이동한다.
|
||||||
|
const moveMarkers = (marker, position) => { |
||||||
|
// console.log(marker);
|
||||||
|
marker.setPosition(position); |
||||||
|
}; |
||||||
|
|
||||||
|
//데이터가 없는 마커를 모두 삭제 한다.
|
||||||
|
const allRemoveMarkers = () => { |
||||||
|
if (props.arrMarkers && controlGpList) { |
||||||
|
props.arrMarkers.map(marker => { |
||||||
|
const isExists = controlGpList.find( |
||||||
|
item => item.objectId === marker.id |
||||||
|
); |
||||||
|
if (!isExists) { |
||||||
|
removeMarkers(marker); |
||||||
|
const arrData = props.arrMarkers.filter( |
||||||
|
item => item.objectId != marker.id |
||||||
|
); |
||||||
|
props.removeArrMarkers(arrData); |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
// }
|
||||||
|
}; |
||||||
|
|
||||||
|
//마커를 셋팅 한다.
|
||||||
|
const markerInit = () => { |
||||||
|
if (controlGpList) { |
||||||
|
allRemoveMarkers(); |
||||||
|
controlGpList.map(item => { |
||||||
|
const position = new naver.maps.LatLng(item.lat, item.lng); |
||||||
|
if (props.arrMarkers) { |
||||||
|
const isExists = props.arrMarkers.find( |
||||||
|
ele => ele.id === item.objectId |
||||||
|
); |
||||||
|
if (isExists) { |
||||||
|
moveMarkers(isExists, position); |
||||||
|
} else { |
||||||
|
// console.log(' ADD >>>', props.arrMarkers);
|
||||||
|
addMarkers(position, item.objectId, item.controlId); |
||||||
|
} |
||||||
|
} else { |
||||||
|
addMarkers(position, item.objectId, item.controlId); |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
return null; |
||||||
|
}; |
@ -0,0 +1,150 @@ |
|||||||
|
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(() => { |
||||||
|
// console.log('>>>>>', mapControl);
|
||||||
|
featureAirZoneInit(); |
||||||
|
featureAirEvent(); |
||||||
|
}, [mapControl]); |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
// console.log(">>>>>>>>" , props.features)
|
||||||
|
}, []); |
||||||
|
|
||||||
|
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'); |
||||||
|
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') { |
||||||
|
color = '#009cad'; |
||||||
|
} |
||||||
|
|
||||||
|
return { |
||||||
|
fillColor: color, |
||||||
|
strokeColor: color, |
||||||
|
strokeWeight: 0.7, |
||||||
|
icon: null |
||||||
|
}; |
||||||
|
}); |
||||||
|
}; |
||||||
|
|
||||||
|
const featureAirEvent = () => { |
||||||
|
props.map.data.addListener('click', function (e) { |
||||||
|
// e.feature.setProperty('isColorful', true);
|
||||||
|
console.log(e.feature.property_name); |
||||||
|
}); |
||||||
|
|
||||||
|
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; |
||||||
|
}; |
@ -0,0 +1,25 @@ |
|||||||
|
import { useEffect } from 'react'; |
||||||
|
|
||||||
|
export const NaverMapSearch = props => { |
||||||
|
useEffect(() => { |
||||||
|
console.log('>>>>', props.naver.maps.Service); |
||||||
|
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; // 검색 결과의 배열
|
||||||
|
console.log(result); |
||||||
|
|
||||||
|
// do Something
|
||||||
|
} |
||||||
|
); |
||||||
|
}); |
||||||
|
|
||||||
|
return null; |
||||||
|
}; |
@ -0,0 +1,488 @@ |
|||||||
|
import React, {useEffect, useState} from 'react'; |
||||||
|
import {useSelector} from "react-redux"; |
||||||
|
|
||||||
|
const SENSOR_RADIUS = '100'; |
||||||
|
const SENSOR_RADIUS_DIVISION = '3'; |
||||||
|
let lenderCnt = 0; |
||||||
|
const SensorZone = (props) => { |
||||||
|
const {naver} = props; |
||||||
|
// 드론 실시간 정보
|
||||||
|
const {controlGpList} = useSelector(state => state.controlGpState); |
||||||
|
// 환경지표 타입(dust, co, o3, no2, so2)
|
||||||
|
const {sensor} = useSelector(state => state.controlMapReducer); |
||||||
|
// 센서레이어(환경지표) 관리
|
||||||
|
const [circleLayers, setCircleLayers] = useState([]); |
||||||
|
const [polilineGroupLayers, setPolilineGroupLayers] = useState({}); |
||||||
|
|
||||||
|
// console.log('########## SensorZone ###########', lenderCnt, {controlGpList, circleLayer: circleLayers, polilineLayer: polilineGroupLayers});
|
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
lenderCnt++ |
||||||
|
if (!sensor) { |
||||||
|
removeSensorLayers(); |
||||||
|
} else { |
||||||
|
initSensorLayer(); |
||||||
|
} |
||||||
|
}, [controlGpList, sensor]); |
||||||
|
|
||||||
|
let infoWindow; |
||||||
|
// 센서 레이어 Info
|
||||||
|
const infowindowOpen = data => { |
||||||
|
// console.log('data', data)
|
||||||
|
const content = ` |
||||||
|
<div class="tooltip-box" style="max-width: 300px;"> |
||||||
|
<div class="tooltip-ti"> |
||||||
|
<span>${data.title}</span> |
||||||
|
</div> |
||||||
|
<div class="tooltip-txt"> |
||||||
|
<div class="tooltip-txt-list"> |
||||||
|
<div style="color: ${data.sensor.sensorDust.color};"> |
||||||
|
<span style="width: 120px; display: inline-block;">${data.sensor.sensorDust.title}(${data.sensor.sensorDust.text})</span> |
||||||
|
<span>${data.sensor.sensorDust.value}</span> |
||||||
|
</div> |
||||||
|
<div style="color: ${data.sensor.sensorO3.color};"> |
||||||
|
<span style="width: 120px; display: inline-block;">${data.sensor.sensorO3.title}(${data.sensor.sensorO3.text})</span> |
||||||
|
<span>${data.sensor.sensorO3.value}</span> |
||||||
|
</div> |
||||||
|
<div style="color: ${data.sensor.sensorNo2.color};"> |
||||||
|
<span style="width: 120px; display: inline-block;">${data.sensor.sensorNo2.title}(${data.sensor.sensorNo2.text})</span> |
||||||
|
<span>${data.sensor.sensorNo2.value}</span> |
||||||
|
</div> |
||||||
|
<div style="color: ${data.sensor.sensorCo.color};"> |
||||||
|
<span style="width: 120px; display: inline-block;">${data.sensor.sensorCo.title}(${data.sensor.sensorCo.text})</span> |
||||||
|
<span>${data.sensor.sensorCo.value}</span> |
||||||
|
</div> |
||||||
|
<div style="color: ${data.sensor.sensorSo2.color};"> |
||||||
|
<span style="width: 120px; display: inline-block;">${data.sensor.sensorSo2.title}(${data.sensor.sensorSo2.text})</span> |
||||||
|
<span>${data.sensor.sensorSo2.value}</span> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
`;
|
||||||
|
|
||||||
|
infoWindow = new naver.maps.InfoWindow({ |
||||||
|
class: 'tooltip-sensor', |
||||||
|
content: content, |
||||||
|
maxWidth: 300, |
||||||
|
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); |
||||||
|
}; |
||||||
|
// 센서레이어 초기화
|
||||||
|
const initSensorLayer = () => { |
||||||
|
emtpyLayerRemove(); |
||||||
|
if (controlGpList) { |
||||||
|
controlGpList.forEach(controlGp => { |
||||||
|
const {controlId, lat, lng, objectId} = controlGp; |
||||||
|
let color = undefined; |
||||||
|
const sensorData = convtSensorData(controlGp); |
||||||
|
if (sensorData) { |
||||||
|
if (sensor === 'dust') color = sensorData.sensorDust.color; |
||||||
|
else if (sensor === 'co') color = sensorData.sensorCo.color; |
||||||
|
else if (sensor === 'so2') color = sensorData.sensorSo2.color; |
||||||
|
else if (sensor === 'no2') color = sensorData.sensorNo2.color; |
||||||
|
else if (sensor === 'o3') color = sensorData.sensorO3.color; |
||||||
|
} |
||||||
|
|
||||||
|
const position = new naver.maps.LatLng(controlGp.lat, controlGp.lng); |
||||||
|
|
||||||
|
const polilineLayers = polilineGroupLayers[controlId]; |
||||||
|
if (polilineLayers) { |
||||||
|
// const prevPosition = polilineLayers[0].position;
|
||||||
|
// if(!prevPosition.equals(position)){
|
||||||
|
movePolilineLayers(polilineLayers, position, color); |
||||||
|
// }
|
||||||
|
} else { |
||||||
|
addPolilineLayers(controlId, objectId, position, color); |
||||||
|
} |
||||||
|
|
||||||
|
const circleLayer = circleLayers.find(layer => layer.controlId === controlId); |
||||||
|
if (circleLayer) moveCircleLayer(circleLayer, position, color, sensorData); |
||||||
|
else addCircleLayer(controlId, objectId, position, color, sensorData); |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// 센서레이어 생성
|
||||||
|
const addSensorLayer = (position, id, controlId, color, sensorData) => { |
||||||
|
addPolilineLayers(controlId, id, position, color); |
||||||
|
addCircleLayer(controlId, id, position, color, sensorData); |
||||||
|
} |
||||||
|
// Circle 레이어 생성
|
||||||
|
const addCircleLayer = (controlId, id, position, color, sensorData) => { |
||||||
|
// console.log({controlId, id, position, color, sensorData})
|
||||||
|
const circleLayer = new naver.maps.Circle({ |
||||||
|
title: id, |
||||||
|
id: id, |
||||||
|
controlId: controlId, |
||||||
|
clickable: true, |
||||||
|
center: position, |
||||||
|
radius: SENSOR_RADIUS, |
||||||
|
// map: props.map,
|
||||||
|
strokeColor: color, |
||||||
|
strokeOpacity: 1, |
||||||
|
strokeWeight: 2, |
||||||
|
fillColor: color, |
||||||
|
fillOpacity: 0.2, |
||||||
|
sensorData: sensorData |
||||||
|
}) |
||||||
|
// Circle 이벤트 주입
|
||||||
|
naver.maps.Event.addListener(circleLayer, 'mouseover', function (e) { |
||||||
|
const data = {}; |
||||||
|
data.coord = e.coord; |
||||||
|
data.title = '환경지표'; |
||||||
|
data.controlId = e.overlay.controlId; |
||||||
|
data.sensor = e.overlay.sensorData; |
||||||
|
e.overlay.setOptions({ |
||||||
|
strokeWeight: 5, |
||||||
|
fillOpacity: 0.5 |
||||||
|
}) |
||||||
|
infowindowOpen(data); |
||||||
|
}); |
||||||
|
naver.maps.Event.addListener(circleLayer, 'mouseout', function (e) { |
||||||
|
e.overlay.setOptions({ |
||||||
|
strokeWeight: 2, |
||||||
|
fillOpacity: 0.2 |
||||||
|
}) |
||||||
|
// props.map.Event.revertStyle();
|
||||||
|
if (infoWindow) { |
||||||
|
infoWindow.close(); |
||||||
|
} |
||||||
|
}); |
||||||
|
circleLayer.setMap(props.map) |
||||||
|
setCircleLayers(prev => ([...prev, circleLayer])); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
const addPolilineLayers = (controlId, id, position, color) => { |
||||||
|
// 지도에 적용 및 레이어 관리 추가
|
||||||
|
// console.log('addPolilineLayers', controlId)
|
||||||
|
const polilineLayers = createCircleInGrid(position, id, controlId, color); |
||||||
|
polilineLayers.forEach(layer => layer.setMap(props.map)); |
||||||
|
setPolilineGroupLayers(prev => ({ |
||||||
|
...prev, |
||||||
|
[controlId]: polilineLayers |
||||||
|
})); |
||||||
|
} |
||||||
|
|
||||||
|
// 센서레이어 이동
|
||||||
|
const moveSensorLayer = (controlId, position, color) => { |
||||||
|
const circleLayer = circleLayers.find(layer => layer.controlId === controlId); |
||||||
|
moveCircleLayer(circleLayer, position, color); |
||||||
|
|
||||||
|
const polilineLayers = polilineGroupLayers[controlId]; |
||||||
|
movePolilineLayers(polilineLayers, position, color); |
||||||
|
} |
||||||
|
const moveCircleLayer = (circleLayer, position, color, sensorData) => { |
||||||
|
// const circleLayer = circleLayers.find(layer => layer.controlId === controlId);
|
||||||
|
if (circleLayer) { |
||||||
|
circleLayer.sensorData = sensorData; |
||||||
|
circleLayer.setOptions({center: position, strokeColor: color, fillColor: color}) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const movePolilineLayers = (polilineLayers, position, color) => { |
||||||
|
const {controlId, id, position: prevPosition} = polilineLayers[0]; |
||||||
|
if (prevPosition.equals(position)) { |
||||||
|
if (polilineLayers) { |
||||||
|
polilineLayers.forEach(layer => layer.setOptions({strokeColor: color})); |
||||||
|
} |
||||||
|
} else { |
||||||
|
if (polilineLayers) { |
||||||
|
polilineLayers.forEach(layer => layer.setMap(null)); |
||||||
|
} |
||||||
|
const newPolilineLayers = createCircleInGrid(position, id, controlId, color); |
||||||
|
newPolilineLayers.forEach(layer => layer.setMap(props.map)); |
||||||
|
setPolilineGroupLayers(prev => ({ |
||||||
|
...prev, |
||||||
|
[controlId]: newPolilineLayers |
||||||
|
})); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// 센서레이어 제거
|
||||||
|
const removeSensorLayer = (controlId) => { |
||||||
|
removeCircleLayer(controlId); |
||||||
|
removePolilineLayer(controlId); |
||||||
|
} |
||||||
|
const removeCircleLayer = (controlId) => { |
||||||
|
const idx = circleLayers.findIndex(layer => layer.controlId === controlId); |
||||||
|
circleLayers[idx].setMap(null); |
||||||
|
setCircleLayers(prev => { |
||||||
|
prev.splice(idx, 1); |
||||||
|
return prev; |
||||||
|
}) |
||||||
|
} |
||||||
|
const removePolilineLayer = (controlId) => { |
||||||
|
const polilineLayers = polilineGroupLayers[controlId]; |
||||||
|
if (polilineLayers) polilineLayers.forEach(layer => layer.setMap(null)); |
||||||
|
setPolilineGroupLayers(prev => { |
||||||
|
delete prev[controlId]; |
||||||
|
return prev; |
||||||
|
}) |
||||||
|
} |
||||||
|
// 센서레이어 모두 제거
|
||||||
|
const removeSensorLayers = () => { |
||||||
|
circleLayers.forEach(layer => layer.setMap(null)); |
||||||
|
setCircleLayers([]); |
||||||
|
const keys = Object.keys(polilineGroupLayers); |
||||||
|
keys.forEach((key) => { |
||||||
|
polilineGroupLayers[key].forEach(layer => layer.setMap(null)); |
||||||
|
}) |
||||||
|
setPolilineGroupLayers({}); |
||||||
|
} |
||||||
|
|
||||||
|
// 레이어관리시 새로운 데이터에 없는 좌표 제거
|
||||||
|
const emtpyLayerRemove = () => { |
||||||
|
setCircleLayers(prev => { |
||||||
|
const remainCircleLayers = prev.filter((circleLayer, i) => { |
||||||
|
const controlId = circleLayer.controlId; |
||||||
|
const findObj = controlGpList.find(controlGp => controlGp.controlId === controlId); |
||||||
|
if (findObj) { |
||||||
|
return circleLayer; |
||||||
|
} else { |
||||||
|
circleLayer.setMap(null); |
||||||
|
} |
||||||
|
}) |
||||||
|
return remainCircleLayers; |
||||||
|
}) |
||||||
|
setPolilineGroupLayers(prev => { |
||||||
|
const keys = Object.keys(prev); |
||||||
|
const remainPolilineGroupLayer = {}; |
||||||
|
keys.forEach((controlId, i) => { |
||||||
|
const findObj = controlGpList.find(controlGp => controlGp.controlId === controlId); |
||||||
|
if (findObj) { |
||||||
|
remainPolilineGroupLayer[controlId] = prev[controlId]; |
||||||
|
} else { |
||||||
|
const polilineLayers = prev[controlId]; |
||||||
|
polilineLayers.forEach(layer => { |
||||||
|
layer.setMap(null); |
||||||
|
}) |
||||||
|
} |
||||||
|
}) |
||||||
|
return remainPolilineGroupLayer; |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
// Circle안에 격자 무늬 생성
|
||||||
|
const createCircleInGrid = (position, id, controlId, color) => { |
||||||
|
// Circle 레이어 안의 격자무늬
|
||||||
|
const polilineLayers = []; |
||||||
|
for (let i = 0; i <= SENSOR_RADIUS_DIVISION; i++) { |
||||||
|
// 각 사분면 각도
|
||||||
|
const diff = 90 / SENSOR_RADIUS_DIVISION; |
||||||
|
const angleQuadrant1 = diff * i; |
||||||
|
const angleQuadrant2 = 180 - (diff * i); |
||||||
|
const angleQuadrant3 = 180 + (diff * i); |
||||||
|
const angleQuadrant4 = diff * -i; |
||||||
|
// 각 사분면 좌표
|
||||||
|
const coord1 = new naver.maps.EPSG3857.getDestinationCoord(position, angleQuadrant1, SENSOR_RADIUS); |
||||||
|
const coord2 = new naver.maps.EPSG3857.getDestinationCoord(position, angleQuadrant2, SENSOR_RADIUS); |
||||||
|
const coord3 = new naver.maps.EPSG3857.getDestinationCoord(position, angleQuadrant3, SENSOR_RADIUS); |
||||||
|
const coord4 = new naver.maps.EPSG3857.getDestinationCoord(position, angleQuadrant4, SENSOR_RADIUS); |
||||||
|
const polyline12 = new naver.maps.Polyline({ |
||||||
|
id, |
||||||
|
position, |
||||||
|
controlId, |
||||||
|
path: [coord1, coord2], |
||||||
|
strokeWeight: 0.8, |
||||||
|
// strokeWeight: 2,
|
||||||
|
strokeOpacity: 1, |
||||||
|
strokeColor: color, |
||||||
|
strokeStyle: 'shortdash' |
||||||
|
}) |
||||||
|
polilineLayers.push(polyline12); |
||||||
|
const polyline23 = new naver.maps.Polyline({ |
||||||
|
id, |
||||||
|
position, |
||||||
|
controlId, |
||||||
|
path: [coord2, coord3], |
||||||
|
strokeWeight: 0.8, |
||||||
|
// strokeWeight: 2,
|
||||||
|
strokeOpacity: 1, |
||||||
|
strokeColor: color, |
||||||
|
strokeStyle: 'shortdash' |
||||||
|
}) |
||||||
|
polilineLayers.push(polyline23); |
||||||
|
const polyline34 = new naver.maps.Polyline({ |
||||||
|
id, |
||||||
|
position, |
||||||
|
controlId, |
||||||
|
path: [coord3, coord4], |
||||||
|
strokeWeight: 0.8, |
||||||
|
// strokeWeight: 2,
|
||||||
|
strokeOpacity: 1, |
||||||
|
strokeColor: color, |
||||||
|
strokeStyle: 'shortdash' |
||||||
|
}) |
||||||
|
polilineLayers.push(polyline34); |
||||||
|
const polyline41 = new naver.maps.Polyline({ |
||||||
|
id, |
||||||
|
position, |
||||||
|
controlId, |
||||||
|
path: [coord4, coord1], |
||||||
|
strokeWeight: 0.8, |
||||||
|
// strokeWeight: 2,
|
||||||
|
strokeOpacity: 1, |
||||||
|
strokeColor: color, |
||||||
|
strokeStyle: 'shortdash' |
||||||
|
}) |
||||||
|
polilineLayers.push(polyline41); |
||||||
|
} |
||||||
|
return polilineLayers; |
||||||
|
} |
||||||
|
|
||||||
|
// 환경지표 필요한 데이터로 변환
|
||||||
|
const convtSensorData = (sensorData) => { |
||||||
|
const r = { |
||||||
|
sensorDust: { |
||||||
|
title: '미세먼지', |
||||||
|
value: '-', |
||||||
|
text: '-', |
||||||
|
color: undefined |
||||||
|
}, |
||||||
|
sensorCo: { |
||||||
|
title: '일산화탄소', |
||||||
|
value: '-', |
||||||
|
text: '-', |
||||||
|
color: undefined |
||||||
|
}, |
||||||
|
sensorSo2: { |
||||||
|
title: '아황산가스', |
||||||
|
value: '-', |
||||||
|
text: '-', |
||||||
|
color: undefined |
||||||
|
}, |
||||||
|
sensorNo2: { |
||||||
|
title: '이산화질소', |
||||||
|
value: '-', |
||||||
|
text: '-', |
||||||
|
color: undefined |
||||||
|
}, |
||||||
|
sensorO3: { |
||||||
|
title: '오존', |
||||||
|
value: '-', |
||||||
|
text: '-', |
||||||
|
color: undefined |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// 정수: 미세먼지 || 소수점 1자리 : 일산화탄소 || 소수점 3자리 : 오존, 이산화질소, 아황산가스
|
||||||
|
// 좋음 : 파랑, 보통 : 노랑, 나쁨 : 주황, 매우나쁨 : 빨강
|
||||||
|
// 미세먼지 : 좋음(0~30) 보통(31~80) 나쁨(81~150) 매우나쁨(151~)
|
||||||
|
if (sensorData.sensorDust != undefined && sensorData.sensorDust != null) { |
||||||
|
const val = r.sensorDust.value = Math.round(sensorData.sensorDust); |
||||||
|
if (val <= 30) { |
||||||
|
r.sensorDust.text = '좋음'; |
||||||
|
r.sensorDust.color = '#37c9ff'; |
||||||
|
} else if (val <= 80) { |
||||||
|
r.sensorDust.text = '보통'; |
||||||
|
r.sensorDust.color = '#ffff44'; |
||||||
|
} else if (val <= 150) { |
||||||
|
r.sensorDust.text = '나쁨'; |
||||||
|
r.sensorDust.color = '#ffa044'; |
||||||
|
} else if (val > 150) { |
||||||
|
r.sensorDust.text = '매우나쁨'; |
||||||
|
r.sensorDust.color = '#ff5959'; |
||||||
|
} else { |
||||||
|
r.sensorDust.text = '-'; |
||||||
|
r.sensorDust.color = '#a1a1a1'; |
||||||
|
} |
||||||
|
} |
||||||
|
// 일산화탄소 : 좋음(0~2) 보통(2.1~9) 나쁨(9.1~15) 매우나쁨(15.1~)
|
||||||
|
if (sensorData.sensorCo != undefined && sensorData.sensorCo != null) { |
||||||
|
const val = r.sensorCo.value = Math.round(sensorData.sensorCo * 10) / 10; |
||||||
|
if (val <= 0.2) { |
||||||
|
r.sensorCo.text = '좋음'; |
||||||
|
r.sensorCo.color = '#37c9ff'; |
||||||
|
} else if (val <= 9) { |
||||||
|
r.sensorCo.text = '보통'; |
||||||
|
r.sensorCo.color = '#ffff44'; |
||||||
|
} else if (val <= 15) { |
||||||
|
r.sensorCo.text = '나쁨'; |
||||||
|
r.sensorCo.color = '#ffa044'; |
||||||
|
} else if (val > 15) { |
||||||
|
r.sensorCo.text = '매우나쁨'; |
||||||
|
r.sensorCo.color = '#ff5959'; |
||||||
|
} else { |
||||||
|
r.sensorCo.text = '-'; |
||||||
|
r.sensorCo.color = '#a1a1a1'; |
||||||
|
} |
||||||
|
} |
||||||
|
// 아황산가스 : 좋음(0~0.02) 보통(0.021~0.05) 나쁨(0.051~0.15) 매우나쁨 (0.151 ~)
|
||||||
|
if (sensorData.sensorSo2 != undefined && sensorData.sensorSo2 != null) { |
||||||
|
const val = r.sensorSo2.value = Math.round(sensorData.sensorSo2 * 1000) / 1000; |
||||||
|
if (val <= 0.02) { |
||||||
|
r.sensorSo2.text = '좋음'; |
||||||
|
r.sensorSo2.color = '#37c9ff'; |
||||||
|
} else if (val <= 0.05) { |
||||||
|
r.sensorSo2.text = '보통'; |
||||||
|
r.sensorSo2.color = '#ffff44'; |
||||||
|
} else if (val <= 0.15) { |
||||||
|
r.sensorSo2.text = '나쁨'; |
||||||
|
r.sensorSo2.color = '#ffa044'; |
||||||
|
} else if (val > 0.15) { |
||||||
|
r.sensorSo2.text = '매우나쁨'; |
||||||
|
r.sensorSo2.color = '#ff5959'; |
||||||
|
} else { |
||||||
|
r.sensorSo2.text = '-'; |
||||||
|
r.sensorSo2.color = '#a1a1a1'; |
||||||
|
} |
||||||
|
} |
||||||
|
// 이산화질소 : 좋음(0~0.03) 보통(0.031~0.06) 나쁨(0.061~0.2) 매우나쁨(0.201~)
|
||||||
|
if (sensorData.sensorNo2 != undefined && sensorData.sensorNo2 != null) { |
||||||
|
const val = r.sensorNo2.value = Math.round(sensorData.sensorNo2 * 1000) / 1000; |
||||||
|
if (val <= 0.03) { |
||||||
|
r.sensorNo2.text = '좋음'; |
||||||
|
r.sensorNo2.color = '#37c9ff'; |
||||||
|
} else if (val <= 0.06) { |
||||||
|
r.sensorNo2.text = '보통'; |
||||||
|
r.sensorNo2.color = '#ffff44'; |
||||||
|
} else if (val <= 0.2) { |
||||||
|
r.sensorNo2.text = '나쁨'; |
||||||
|
r.sensorNo2.color = '#ffa044'; |
||||||
|
} else if (val > 0.2) { |
||||||
|
r.sensorNo2.text = '매우나쁨'; |
||||||
|
r.sensorNo2.color = '#ff5959'; |
||||||
|
} else { |
||||||
|
r.sensorNo2.text = '-'; |
||||||
|
r.sensorNo2.color = '#a1a1a1'; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
// 오존 : 좋음(0~0.03) 보통(0.031~0.09) 나쁨(0.091~0.15) 매우나쁨(0.151~)
|
||||||
|
if (sensorData.sensorO3 != undefined && sensorData.sensorO3 != null) { |
||||||
|
const val = r.sensorO3.value = Math.round(sensorData.sensorO3 * 1000) / 1000; |
||||||
|
if (val <= 0.03) { |
||||||
|
r.sensorO3.text = '좋음'; |
||||||
|
r.sensorO3.color = '#37c9ff'; |
||||||
|
} else if (val <= 0.09) { |
||||||
|
r.sensorO3.text = '보통'; |
||||||
|
r.sensorO3.color = '#ffff44'; |
||||||
|
} else if (val <= 0.15) { |
||||||
|
r.sensorO3.text = '나쁨'; |
||||||
|
r.sensorO3.color = '#ffa044'; |
||||||
|
} else if (val > 0.15) { |
||||||
|
r.sensorO3.text = '매우나쁨'; |
||||||
|
r.sensorO3.color = '#ff5959'; |
||||||
|
} else { |
||||||
|
r.sensorO3.text = '-'; |
||||||
|
r.sensorO3.color = '#a1a1a1'; |
||||||
|
} |
||||||
|
} |
||||||
|
return r; |
||||||
|
} |
||||||
|
|
||||||
|
return null; |
||||||
|
}; |
||||||
|
|
||||||
|
export default SensorZone; |
@ -0,0 +1,42 @@ |
|||||||
|
import { useEffect, useState } from 'react'; |
||||||
|
|
||||||
|
export const NMap = props => { |
||||||
|
const naver = window.naver; |
||||||
|
|
||||||
|
const [mapObject, setMapObject] = useState(null); |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
mapInit(); |
||||||
|
// console.log(map);
|
||||||
|
|
||||||
|
// console.log(features);
|
||||||
|
|
||||||
|
// setIsMapLoad(true);
|
||||||
|
}, []); |
||||||
|
|
||||||
|
const mapInit = () => { |
||||||
|
// const mapOptions = {
|
||||||
|
// center: new naver.maps.LatLng(36.56793936069445, 127.85101412107547),
|
||||||
|
// // ceneter: new naver.maps.LatLng(37.445949, 126.673868),
|
||||||
|
// zoom: 15,
|
||||||
|
// zoomControl: true,
|
||||||
|
// mapTypeId: naver.maps.MapTypeId.HYBRID,
|
||||||
|
// zoomControlOptions: {
|
||||||
|
// position: naver.maps.Position.TOP_LEFT,
|
||||||
|
|
||||||
|
// style: naver.maps.ZoomControlStyle.SMALL
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
|
||||||
|
// map = ;
|
||||||
|
props.setMapObject(new naver.maps.Map('map', mapOptions)); |
||||||
|
// naver.maps.Event.addListener(map, 'click', function (e) {
|
||||||
|
// console.log(e);
|
||||||
|
// });
|
||||||
|
|
||||||
|
// naver.maps.Event.addListener(map, 'idle', function (e) {
|
||||||
|
// console.log(e);
|
||||||
|
// });
|
||||||
|
}; |
||||||
|
return <div id='map' style={{ width: '100%', height: '100vh' }}></div>; |
||||||
|
}; |
@ -0,0 +1,62 @@ |
|||||||
|
import { useEffect } from 'react'; |
||||||
|
import DronIcon from '../../../assets/images//drone-marker-icon.png'; |
||||||
|
export const NMapMarker = props => { |
||||||
|
const naver = window.naver; |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
if (props.selMarker && props.selMarker.setMap) { |
||||||
|
props.selMarker.setMap(null); |
||||||
|
} |
||||||
|
|
||||||
|
if (props.data) { |
||||||
|
for (let i = 0; i < props.data?.length; i++) { |
||||||
|
if (props.data[i].lat > 0 && props.data[i].lon > 0) { |
||||||
|
const position = new naver.maps.LatLng( |
||||||
|
props.data[i]?.lat, |
||||||
|
props.data[i]?.lon |
||||||
|
); |
||||||
|
addMarkers(position, props.data[i]?.cntrlId); |
||||||
|
|
||||||
|
return; |
||||||
|
} |
||||||
|
} |
||||||
|
props.data?.map((item, index) => {}); |
||||||
|
} |
||||||
|
}, [props.data]); |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
// console.log('info>>>:' + props.info.lat);
|
||||||
|
// console.log(props.selMarker);
|
||||||
|
|
||||||
|
if (props.selMarker && props.selMarker) { |
||||||
|
const position = new naver.maps.LatLng(props.info?.lat, props.info?.lon); |
||||||
|
props.selMarker?.setPosition(position); |
||||||
|
|
||||||
|
// moveMarkers(props.selMarker, position);
|
||||||
|
} |
||||||
|
}, [props.info]); |
||||||
|
|
||||||
|
const addMarkers = (position, id) => { |
||||||
|
//이미 지정된 마커 제거
|
||||||
|
|
||||||
|
var marker = new naver.maps.Marker({ |
||||||
|
position: position, |
||||||
|
title: id, |
||||||
|
id: id, |
||||||
|
icon: { |
||||||
|
url: DronIcon |
||||||
|
} |
||||||
|
}); |
||||||
|
props.map.setCenter(position); |
||||||
|
props.map.setZoom(14); |
||||||
|
marker.setMap(props.map); |
||||||
|
props.setSelMarker(marker); |
||||||
|
}; |
||||||
|
|
||||||
|
const moveMarkers = (marker, position) => { |
||||||
|
// console.log('dddddddddddddddddddd', marker, position);
|
||||||
|
// marker.setPositon(position);
|
||||||
|
}; |
||||||
|
|
||||||
|
return null; |
||||||
|
}; |
@ -0,0 +1,47 @@ |
|||||||
|
import { useEffect } from 'react'; |
||||||
|
|
||||||
|
export const NMapPolyline = props => { |
||||||
|
const naver = window.naver; |
||||||
|
|
||||||
|
// console.log(props);
|
||||||
|
|
||||||
|
let polyline; |
||||||
|
let polylinePath = []; |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
//기존 폴리라인 삭제 처리
|
||||||
|
if (props.selPolyline && props.selPolyline.setMap) { |
||||||
|
props.selPolyline.setMap(null); |
||||||
|
} |
||||||
|
|
||||||
|
addPolyline(); |
||||||
|
}, [props.data]); |
||||||
|
|
||||||
|
const addPolyline = () => { |
||||||
|
if (props.data) { |
||||||
|
polyline = new naver.maps.Polyline({ |
||||||
|
clickable: false, |
||||||
|
strokeColor: '#ff4961', |
||||||
|
strokeStyle: 'solid', |
||||||
|
strokeOpacity: 5, |
||||||
|
strokeWeight: 1.5 |
||||||
|
}); |
||||||
|
|
||||||
|
props.data.map(item => { |
||||||
|
if (item.lat > 0 && item.lon > 0) { |
||||||
|
const position = new naver.maps.LatLng(item.lat, item.lon); |
||||||
|
polylinePath.push(position); |
||||||
|
} |
||||||
|
// console.log('>>>>>>>>>>>', item);
|
||||||
|
}); |
||||||
|
|
||||||
|
polyline.setPath(polylinePath); |
||||||
|
|
||||||
|
polyline.setMap(props.map); |
||||||
|
props.setSelPolyline(polyline); |
||||||
|
// props.arrPolyline.push(polyline);
|
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
return null; |
||||||
|
}; |
@ -0,0 +1,66 @@ |
|||||||
|
import { X } from 'react-feather'; |
||||||
|
|
||||||
|
const ControlAlarmList = props => { |
||||||
|
return ( |
||||||
|
<div className='left-layer'> |
||||||
|
<div className='layer-content'> |
||||||
|
<div className='layer-ti'> |
||||||
|
<h4>알림 리스트</h4> |
||||||
|
<button |
||||||
|
className='btn-icon' |
||||||
|
outline |
||||||
|
color='primary' |
||||||
|
onClick={() => props.setOpenAlarmList(false)} |
||||||
|
> |
||||||
|
<X size={20} /> |
||||||
|
</button> |
||||||
|
</div> |
||||||
|
<div className='layer-content-list'> |
||||||
|
<dl className='notice-list'> |
||||||
|
<dt> |
||||||
|
<div className='list-ti'> |
||||||
|
<div className='list-left-txt'>전체 2000건</div> |
||||||
|
<div className='list-right-txt'>오늘 120건</div> |
||||||
|
</div> |
||||||
|
</dt> |
||||||
|
</dl> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div className='layer-content'> |
||||||
|
<div className='layer-ti'> |
||||||
|
<h4>알림 목록</h4> |
||||||
|
</div> |
||||||
|
<div className='layer-content-list'> |
||||||
|
<dl className='notice-list'> |
||||||
|
<dt> |
||||||
|
<div className='list-ti'> |
||||||
|
<div className='list-left-txt'>통신 장애 알림</div> |
||||||
|
<div className='list-right-txt'>6월 17일</div> |
||||||
|
</div> |
||||||
|
<div className='list-txt'> |
||||||
|
통신장애 통신장애 통신장애 통신장애 통신장애 통신장애 통신장애 |
||||||
|
통신장애 통신장애{' '} |
||||||
|
</div> |
||||||
|
</dt> |
||||||
|
</dl> |
||||||
|
</div> |
||||||
|
<div className='layer-content-list'> |
||||||
|
<dl className='notice-list'> |
||||||
|
<dt> |
||||||
|
<div className='list-ti'> |
||||||
|
<div className='list-left-txt'>비행 경로 이탈</div> |
||||||
|
<div className='list-right-txt'>6월 17일</div> |
||||||
|
</div> |
||||||
|
<div className='list-txt'> |
||||||
|
비행경로이탈 비행경로이탈 비행경로이탈 비행경로이탈 비행경로이탈 |
||||||
|
비행경로이탈 비행경로이탈 비행경로이탈 비행경로이탈 비행경로이탈 |
||||||
|
</div> |
||||||
|
</dt> |
||||||
|
</dl> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
); |
||||||
|
}; |
||||||
|
|
||||||
|
export default ControlAlarmList; |
@ -0,0 +1,45 @@ |
|||||||
|
import { Bell, ChevronDown, ChevronUp } from "react-feather"; |
||||||
|
import { ReactComponent as DroneMenuIcon } from '../../../assets/images/drone_menu_icon.svg'; |
||||||
|
|
||||||
|
const ControlAlarmNotice = () => { |
||||||
|
{/* 알림 위아래 롤링은 구현해주셔야되는데 따른 컴포넌트있으면 그거사용해도됩니다...제가 만들어논거는 45px씩 움직여주면되거든요..저도자세히는모르겠습니다...제이쿼리로만써봐서... */} |
||||||
|
return( |
||||||
|
|
||||||
|
<div> |
||||||
|
{/* <div className='notice'> |
||||||
|
<div className='notice-icon'> |
||||||
|
<Bell size={20} /> |
||||||
|
</div> |
||||||
|
<div className='notice-txt'> |
||||||
|
<dl> |
||||||
|
<dt> |
||||||
|
<span className='time'>2021-06-17 12:00:00</span>AVSF123 장애물 |
||||||
|
지역에 접근하였습니다111. |
||||||
|
</dt> |
||||||
|
<dt> |
||||||
|
<span className='time'>2021-06-30 13:00:00</span>AVSF123 |
||||||
|
비행금지구역에 접근하였습니다. |
||||||
|
</dt> |
||||||
|
<dt> |
||||||
|
<span className='time'>2021-08-20 14:00:00</span>AVSF123 |
||||||
|
국립공원구역에 접근하였습니다. |
||||||
|
</dt> |
||||||
|
</dl> |
||||||
|
</div> |
||||||
|
<div className='notice-btn'> |
||||||
|
<button> |
||||||
|
<ChevronUp size={15} /> |
||||||
|
</button> |
||||||
|
<button> |
||||||
|
<ChevronDown size={15} /> |
||||||
|
</button> |
||||||
|
</div> |
||||||
|
</div> */} |
||||||
|
|
||||||
|
</div> |
||||||
|
|
||||||
|
|
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
export default ControlAlarmNotice; |
@ -0,0 +1,18 @@ |
|||||||
|
import React, { useEffect, useState } from 'react'; |
||||||
|
import { MapControlDraw } from '../../components/mapDraw/MapControlDraw'; |
||||||
|
// import { WebsocketClient } from '../../components/websocket/WebsocketClient';
|
||||||
|
import ControlMainDraw from './main/ControlMainDraw'; |
||||||
|
|
||||||
|
const ControlViewDraw = () => { |
||||||
|
return ( |
||||||
|
<div className='pal-container'> |
||||||
|
<div className='map'> |
||||||
|
<MapControlDraw /> |
||||||
|
</div> |
||||||
|
|
||||||
|
<ControlMainDraw /> |
||||||
|
</div> |
||||||
|
); |
||||||
|
}; |
||||||
|
|
||||||
|
export default ControlViewDraw; |
@ -0,0 +1,183 @@ |
|||||||
|
import React, { useEffect, useState } from 'react'; |
||||||
|
|
||||||
|
import '../../../assets/css/custom.css'; |
||||||
|
import logo from '../../../assets/images/pal_logo.png'; |
||||||
|
|
||||||
|
import { Sun, Map, Bell } from 'react-feather'; |
||||||
|
|
||||||
|
import { AiOutlinePoweroff } from 'react-icons/ai'; |
||||||
|
|
||||||
|
import { ReactComponent as DroneMenuIcon } from '../../../assets/images/drone_menu_icon.svg'; |
||||||
|
|
||||||
|
import ControlAlarmNotice from '../alarm/ControlAlarmNotice'; |
||||||
|
import ControlReportList from '../report/ControlReportList'; |
||||||
|
import ControlReportDetail from '../report/ControlReportDetail'; |
||||||
|
import WeatherList from '../weather/WeatherList'; |
||||||
|
import ControlAlarmList from '../alarm/ControlAlarmList'; |
||||||
|
import ControlSetting from '../setting/ControlSetting'; |
||||||
|
import WebsocketClient from '../../../components/websocket/WebsocketClient'; |
||||||
|
import { useDispatch, useSelector } from 'react-redux'; |
||||||
|
|
||||||
|
import * as Actions from '../../../modules/account/login/actions/authAction'; |
||||||
|
|
||||||
|
import { |
||||||
|
ButtonGroup, |
||||||
|
Button, |
||||||
|
Badge, |
||||||
|
CustomInput |
||||||
|
} from 'reactstrap' |
||||||
|
|
||||||
|
import { |
||||||
|
drawTypeChangeAction |
||||||
|
} from '../../../modules/control/map/actions/controlMapActions'; |
||||||
|
|
||||||
|
const ControlMainDraw = () => { |
||||||
|
const dispatch = useDispatch(); |
||||||
|
|
||||||
|
const { isClickObject } = useSelector(state => state.controlMapReducer); |
||||||
|
|
||||||
|
const [oepnReportList, setOpenReportList] = useState(false); |
||||||
|
const [openReportDetail, setOpenReportDetail] = useState(false); |
||||||
|
const [openWeatherList, setOpenWeatherList] = useState(false); |
||||||
|
|
||||||
|
const [openAlarmList, setOpenAlarmList] = useState(false); |
||||||
|
|
||||||
|
const [openSetting, setOpenSetting] = useState(false); |
||||||
|
|
||||||
|
const mapControl = useSelector(state => state.controlMapReducer); |
||||||
|
|
||||||
|
const openMenu = val => { |
||||||
|
if (val === 'reportList') { |
||||||
|
setOpenReportList(true); |
||||||
|
setOpenReportDetail(false); |
||||||
|
setOpenWeatherList(false); |
||||||
|
setOpenAlarmList(false); |
||||||
|
} else if (val === 'weatherList') { |
||||||
|
setOpenReportList(false); |
||||||
|
setOpenReportDetail(false); |
||||||
|
setOpenWeatherList(true); |
||||||
|
setOpenAlarmList(false); |
||||||
|
} else if (val === 'alarmList') { |
||||||
|
setOpenReportList(false); |
||||||
|
setOpenReportDetail(false); |
||||||
|
setOpenWeatherList(false); |
||||||
|
setOpenAlarmList(true); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
const openReportDetailParam = val => { |
||||||
|
console.log(val); |
||||||
|
setOpenReportDetail(true); |
||||||
|
}; |
||||||
|
|
||||||
|
const handlerLogout = () => { |
||||||
|
dispatch(Actions.logout.request()); |
||||||
|
}; |
||||||
|
|
||||||
|
const handlerDrawType = val => { |
||||||
|
dispatch(drawTypeChangeAction(val)); |
||||||
|
}; |
||||||
|
|
||||||
|
return ( |
||||||
|
<> |
||||||
|
<ControlAlarmNotice /> |
||||||
|
|
||||||
|
<div className='left-menu'> |
||||||
|
<h1 className='logo'> |
||||||
|
<img src={logo} width='80' /> |
||||||
|
<span>PAL</span> |
||||||
|
</h1> |
||||||
|
<ul className='left-menu-nav'> |
||||||
|
<li> |
||||||
|
<button onClick={() => openMenu('reportList')}> |
||||||
|
<DroneMenuIcon width='30' height='30' /> |
||||||
|
</button> |
||||||
|
</li> |
||||||
|
</ul> |
||||||
|
|
||||||
|
{/* pathDraw Test */} |
||||||
|
<ul className='left-menu-nav'> |
||||||
|
<li> |
||||||
|
<CustomInput |
||||||
|
type='button' |
||||||
|
onClick={e => handlerDrawType('CIRCLE')} |
||||||
|
value='CIRCLE' |
||||||
|
/> |
||||||
|
<CustomInput |
||||||
|
type='button' |
||||||
|
onClick={e => handlerDrawType('LINE')} |
||||||
|
value='LINE' |
||||||
|
/><br/> |
||||||
|
<CustomInput |
||||||
|
type='button' |
||||||
|
onClick={e => handlerDrawType('')} |
||||||
|
value='X' |
||||||
|
/> |
||||||
|
</li> |
||||||
|
</ul> |
||||||
|
|
||||||
|
<ul className='left-menu-footer'> |
||||||
|
<li> |
||||||
|
<AiOutlinePoweroff |
||||||
|
size={25} |
||||||
|
className='logout-btn' |
||||||
|
onClick={handlerLogout} |
||||||
|
/> |
||||||
|
</li> |
||||||
|
<WebsocketClient /> |
||||||
|
</ul> |
||||||
|
</div> |
||||||
|
|
||||||
|
{oepnReportList ? ( |
||||||
|
<ControlReportList |
||||||
|
openReportDetailParam={openReportDetailParam} |
||||||
|
setOpenReportList={setOpenReportList} |
||||||
|
/> |
||||||
|
) : ( |
||||||
|
<div /> |
||||||
|
)} |
||||||
|
{isClickObject ? ( |
||||||
|
<ControlReportDetail setOpenReportDetail={setOpenReportDetail} /> |
||||||
|
) : ( |
||||||
|
<div /> |
||||||
|
)} |
||||||
|
{openWeatherList ? ( |
||||||
|
<WeatherList setOpenWeatherList={setOpenWeatherList} /> |
||||||
|
) : ( |
||||||
|
<div /> |
||||||
|
)} |
||||||
|
|
||||||
|
{openAlarmList ? ( |
||||||
|
<ControlAlarmList setOpenAlarmList={setOpenAlarmList} /> |
||||||
|
) : ( |
||||||
|
<div /> |
||||||
|
)} |
||||||
|
|
||||||
|
{openSetting ? ( |
||||||
|
<div className='right-menu active'> |
||||||
|
<button |
||||||
|
className='right-layer-btn' |
||||||
|
onClick={() => setOpenSetting(false)} |
||||||
|
> |
||||||
|
<Map size={18} /> |
||||||
|
</button> |
||||||
|
<div className='right-layer active'> |
||||||
|
<ControlSetting /> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
) : ( |
||||||
|
<div className='right-menu'> |
||||||
|
<button |
||||||
|
className='right-layer-btn' |
||||||
|
onClick={() => setOpenSetting(true)} |
||||||
|
> |
||||||
|
<Map size={18} /> |
||||||
|
</button> |
||||||
|
<div className='right-layer'></div> |
||||||
|
</div> |
||||||
|
)} |
||||||
|
</> |
||||||
|
); |
||||||
|
}; |
||||||
|
|
||||||
|
export default ControlMainDraw; |
@ -0,0 +1,10 @@ |
|||||||
|
|
||||||
|
import React, { useEffect, useState } from 'react'; |
||||||
|
|
||||||
|
const ControlMenuLeft = () => { |
||||||
|
return( |
||||||
|
<></> |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
export default ControlMenuLeft(); |
@ -0,0 +1,219 @@ |
|||||||
|
import moment from 'moment'; |
||||||
|
import React from 'react'; |
||||||
|
import { X } from 'react-feather'; |
||||||
|
import { useDispatch, useSelector } from 'react-redux'; |
||||||
|
import drone_img from '../../../assets/images/drone.jpg'; |
||||||
|
import drone_yellow from '../../../assets/images/drone_yellow.png'; |
||||||
|
import { IMG_PATH } from '../../../configs/constants'; |
||||||
|
import { objectUnClickAction } from '../../../modules/control/map/actions/controlMapActions'; |
||||||
|
import { |
||||||
|
GET_ARCTFT_TYPE_CD, |
||||||
|
GET_WGHT_TYPE_CD |
||||||
|
} from '../../../utility/CondeUtil'; |
||||||
|
|
||||||
|
const ControlReportDetail = props => { |
||||||
|
const dispatch = useDispatch(); |
||||||
|
|
||||||
|
const { controlGpDetail, controlDetail } = useSelector( |
||||||
|
state => state.controlGpDtlState |
||||||
|
); |
||||||
|
|
||||||
|
// useEffect(() => {
|
||||||
|
// // console.log(controlGpDetail);
|
||||||
|
// }, [controlGpDetail]);
|
||||||
|
|
||||||
|
const handlerClose = () => { |
||||||
|
// console.log('================');
|
||||||
|
dispatch(objectUnClickAction()); |
||||||
|
}; |
||||||
|
|
||||||
|
const nullMessage = val => { |
||||||
|
if (val) { |
||||||
|
return val; |
||||||
|
} else { |
||||||
|
return '-'; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
return ( |
||||||
|
<div className='left-layer'> |
||||||
|
<div className='layer-content'> |
||||||
|
<div className='layer-ti'> |
||||||
|
<h4>드론 상세정보</h4> |
||||||
|
<button |
||||||
|
className='btn-icon' |
||||||
|
color='primary' |
||||||
|
// onClick={() => props.setOpenReportDetail(false)}
|
||||||
|
onClick={() => handlerClose()} |
||||||
|
> |
||||||
|
<X size={20} /> |
||||||
|
</button> |
||||||
|
</div> |
||||||
|
<div className='layer-content-box'> |
||||||
|
<div className='drone-ti'> |
||||||
|
<img src={drone_yellow} width='40' /> |
||||||
|
{controlDetail?.arcrftModelNm |
||||||
|
? controlDetail?.arcrftModelNm |
||||||
|
: controlGpDetail?.objectId} |
||||||
|
</div> |
||||||
|
<div className='drone-img'> |
||||||
|
{controlDetail?.imageUrl ? ( |
||||||
|
<img src={IMG_PATH + controlDetail?.imageUrl} /> |
||||||
|
) : ( |
||||||
|
<img src={drone_img} /> |
||||||
|
)} |
||||||
|
</div> |
||||||
|
<div className='layer-content-info'> |
||||||
|
<dl> |
||||||
|
<dt> |
||||||
|
<div className='list-left-txt'>제작번호</div> |
||||||
|
<div className='list-right-txt'> |
||||||
|
{nullMessage(controlDetail?.prdctNum)} |
||||||
|
</div> |
||||||
|
</dt> |
||||||
|
<dt> |
||||||
|
<div className='list-left-txt'>식별번호</div> |
||||||
|
<div className='list-right-txt'> |
||||||
|
{controlGpDetail?.objectId} |
||||||
|
</div> |
||||||
|
</dt> |
||||||
|
<dt> |
||||||
|
<div className='list-left-txt'>중량</div> |
||||||
|
<div className='list-right-txt'> |
||||||
|
{GET_WGHT_TYPE_CD(controlDetail?.wghtTypeCd)} |
||||||
|
</div> |
||||||
|
</dt> |
||||||
|
<dt> |
||||||
|
<div className='list-left-txt'>종류</div> |
||||||
|
<div className='list-right-txt'> |
||||||
|
{GET_ARCTFT_TYPE_CD(controlDetail?.arcrftTypeCd)} |
||||||
|
</div> |
||||||
|
</dt> |
||||||
|
<dt> |
||||||
|
<div className='list-left-txt'>배터리 잔량</div> |
||||||
|
<div className='list-right-txt'> |
||||||
|
{controlGpDetail?.betteryLevel} % |
||||||
|
</div> |
||||||
|
</dt> |
||||||
|
<dt> |
||||||
|
<div className='list-left-txt'>배터리 전압</div> |
||||||
|
<div className='list-right-txt'> |
||||||
|
{controlGpDetail?.betteryVoltage} volt |
||||||
|
</div> |
||||||
|
</dt> |
||||||
|
</dl> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div className='layer-content'> |
||||||
|
<div className='layer-ti'> |
||||||
|
<h4>비행정보</h4> |
||||||
|
</div> |
||||||
|
<div className='layer-content-box'> |
||||||
|
<div className='layer-content-info'> |
||||||
|
<dl> |
||||||
|
<dt> |
||||||
|
<div className='list-left-txt'>시작위치</div> |
||||||
|
<div className='list-right-txt'> |
||||||
|
{nullMessage(controlDetail?.stAreaNm)} |
||||||
|
</div> |
||||||
|
</dt> |
||||||
|
<dt> |
||||||
|
<div className='list-left-txt'>시작시간</div> |
||||||
|
<div className='list-right-txt'> |
||||||
|
{moment( |
||||||
|
controlGpDetail?.controlStartDt, |
||||||
|
'YYYYMMDDHHmmss' |
||||||
|
).format('MM-DD HH:mm:ss')} |
||||||
|
</div> |
||||||
|
</dt> |
||||||
|
{/* <dt> |
||||||
|
<div className='list-left-txt'>현재위치</div> |
||||||
|
<div className='list-right-txt'> |
||||||
|
인천광역시 부평구 안남로 272 |
||||||
|
</div> |
||||||
|
</dt> */} |
||||||
|
<dt> |
||||||
|
<div className='list-left-txt'>속도</div> |
||||||
|
<div className='list-right-txt'> |
||||||
|
{controlGpDetail?.speed} {controlGpDetail?.speedType} |
||||||
|
</div> |
||||||
|
</dt> |
||||||
|
<dt> |
||||||
|
<div className='list-left-txt'>고도</div> |
||||||
|
<div className='list-right-txt'> |
||||||
|
{controlGpDetail?.elev} {controlGpDetail?.elevType} |
||||||
|
</div> |
||||||
|
</dt> |
||||||
|
<dt> |
||||||
|
<div className='list-left-txt'>좌표</div> |
||||||
|
<div className='list-right-txt'> |
||||||
|
{controlGpDetail?.lat} , {controlGpDetail?.lng} |
||||||
|
</div> |
||||||
|
</dt> |
||||||
|
<dt> |
||||||
|
<div className='list-left-txt'>비행거리</div> |
||||||
|
<div className='list-right-txt'> |
||||||
|
{nullMessage(controlGpDetail?.moveDistance)}{' '} |
||||||
|
{controlGpDetail?.moveDistanceType} |
||||||
|
</div> |
||||||
|
</dt> |
||||||
|
<dt> |
||||||
|
<div className='list-left-txt'>헤딩 방위각</div> |
||||||
|
<div className='list-right-txt'> |
||||||
|
{controlGpDetail?.heading} ° |
||||||
|
</div> |
||||||
|
</dt> |
||||||
|
<dt> |
||||||
|
<div className='list-left-txt'>상태</div> |
||||||
|
<div className='list-right-txt'> |
||||||
|
{nullMessage(controlGpDetail?.dronStatus)} |
||||||
|
</div> |
||||||
|
</dt> |
||||||
|
<dt> |
||||||
|
<div className='list-left-txt'>위치정보 수신 시간</div> |
||||||
|
<div className='list-right-txt'> |
||||||
|
{' '} |
||||||
|
{moment( |
||||||
|
controlGpDetail?.serverRcvDt, |
||||||
|
'YYYYMMDDHHmmss' |
||||||
|
).format('MM-DD HH:mm:ss')} |
||||||
|
</div> |
||||||
|
</dt> |
||||||
|
</dl> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div className='layer-content'> |
||||||
|
<div className='layer-ti'> |
||||||
|
<h4>운영자 정보</h4> |
||||||
|
</div> |
||||||
|
<div className='layer-content-box'> |
||||||
|
<div className='layer-content-info'> |
||||||
|
<dl> |
||||||
|
{/* <dt> |
||||||
|
<div className='list-left-txt'>소속기관</div> |
||||||
|
<div className='list-right-txt'>팔네트웍스</div> |
||||||
|
</dt> */} |
||||||
|
<dt> |
||||||
|
<div className='list-left-txt'>담당자 이름</div> |
||||||
|
<div className='list-right-txt'> |
||||||
|
{' '} |
||||||
|
{nullMessage(controlDetail?.ownerNm)} |
||||||
|
</div> |
||||||
|
</dt> |
||||||
|
<dt> |
||||||
|
<div className='list-left-txt'>담당자 연락처</div> |
||||||
|
<div className='list-right-txt'> |
||||||
|
{nullMessage(controlDetail?.hpno)} |
||||||
|
</div> |
||||||
|
</dt> |
||||||
|
</dl> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
); |
||||||
|
}; |
||||||
|
|
||||||
|
export default ControlReportDetail; |
@ -0,0 +1,115 @@ |
|||||||
|
import moment from 'moment'; |
||||||
|
import React, { useEffect, useState } from 'react'; |
||||||
|
import { Search, X } from 'react-feather'; |
||||||
|
import { useDispatch, useSelector } from 'react-redux'; |
||||||
|
import { Badge, Button, Input, InputGroup } from 'reactstrap'; |
||||||
|
import { controlGpDtlAction } from '../../../modules/control/gp'; |
||||||
|
import { objectClickAction } from '../../../modules/control/map/actions/controlMapActions'; |
||||||
|
|
||||||
|
const ControlReportList = props => { |
||||||
|
const { controlGpList } = useSelector(state => state.controlGpState); |
||||||
|
const [filterId, setFilterId] = useState(''); |
||||||
|
|
||||||
|
const dispatch = useDispatch(); |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
// console.log('>>>>', filterId);
|
||||||
|
controlGpList; |
||||||
|
}, [controlGpList]); |
||||||
|
|
||||||
|
const handlerDetail = (objectId, cntrlId) => { |
||||||
|
dispatch(objectClickAction(objectId)); |
||||||
|
dispatch(controlGpDtlAction.request(cntrlId)); |
||||||
|
}; |
||||||
|
|
||||||
|
// useEffect(() => {}, [filterId]);
|
||||||
|
|
||||||
|
return ( |
||||||
|
<div className='left-layer'> |
||||||
|
<div className='layer-content'> |
||||||
|
<div className='layer-ti'> |
||||||
|
<h4>드론 비행 현황 정보{filterId}</h4> |
||||||
|
<button |
||||||
|
className='btn-icon' |
||||||
|
color='primary' |
||||||
|
onClick={() => props.setOpenReportList(false)} |
||||||
|
> |
||||||
|
<X size={20} /> |
||||||
|
</button> |
||||||
|
</div> |
||||||
|
<div className='layer-search'> |
||||||
|
<InputGroup> |
||||||
|
<Input |
||||||
|
type='text' |
||||||
|
placeholder='식별번호를 입력하세요' |
||||||
|
value={filterId} |
||||||
|
onChange={e => setFilterId(`${e.target.value}`)} |
||||||
|
/> |
||||||
|
<Button color='primary' outline> |
||||||
|
<Search size={18} /> |
||||||
|
</Button> |
||||||
|
</InputGroup> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div className='layer-content drone-list'> |
||||||
|
<div className='layer-ti'> |
||||||
|
<h4>드론 현황</h4> |
||||||
|
<Badge color='light-primary'> |
||||||
|
{controlGpList ? controlGpList.length : 0} 대 비행중 |
||||||
|
</Badge> |
||||||
|
</div> |
||||||
|
|
||||||
|
{controlGpList?.map(item => { |
||||||
|
// console.log(item);
|
||||||
|
|
||||||
|
if (item.objectId && item.objectId.indexOf(filterId) != -1) { |
||||||
|
console.log(item); |
||||||
|
return ( |
||||||
|
<div |
||||||
|
className='layer-content-list' |
||||||
|
onClick={() => handlerDetail(item.objectId, item.controlId)} |
||||||
|
key={item.objectId} |
||||||
|
> |
||||||
|
<dl> |
||||||
|
<dt> |
||||||
|
<div className='list-left-txt'>식별번호</div> |
||||||
|
<div className='list-right-txt'>{item.objectId}</div> |
||||||
|
</dt> |
||||||
|
<dt> |
||||||
|
<div className='list-left-txt'>이륙 위치</div> |
||||||
|
<div className='list-right-txt'>-</div> |
||||||
|
</dt> |
||||||
|
<dt> |
||||||
|
<div className='list-left-txt'>이륙 시간</div> |
||||||
|
<div className='list-right-txt'> |
||||||
|
{moment(item.controlStartDt, 'YYYYMMDDHHmmss').format( |
||||||
|
'MM-DD HH:mm:ss' |
||||||
|
)} |
||||||
|
</div> |
||||||
|
</dt> |
||||||
|
<dt> |
||||||
|
<div className='list-left-txt'>속도(고도)</div> |
||||||
|
<div className='list-right-txt'> |
||||||
|
{item.speed ? item.speed : '-'}{' '} |
||||||
|
{item.speed ? item.speedType : ''} ( |
||||||
|
{item.elev ? item.elev : '-'}{' '} |
||||||
|
{item.elev ? item.elevType : ''}) |
||||||
|
</div> |
||||||
|
</dt> |
||||||
|
<dt> |
||||||
|
<div className='list-left-txt'>상태</div> |
||||||
|
<div className='list-right-txt'> |
||||||
|
{item.dronStatus ? item.dronStatus : '-'} |
||||||
|
</div> |
||||||
|
</dt> |
||||||
|
</dl> |
||||||
|
</div> |
||||||
|
); |
||||||
|
} |
||||||
|
})} |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
); |
||||||
|
}; |
||||||
|
|
||||||
|
export default ControlReportList; |
@ -0,0 +1,244 @@ |
|||||||
|
import React, { useEffect, useState } from 'react'; |
||||||
|
import { Search } from 'react-feather'; |
||||||
|
import { BiBuildings, BiGridAlt } from 'react-icons/bi'; |
||||||
|
import { CgTrees } from 'react-icons/cg'; |
||||||
|
import { VscRadioTower } from 'react-icons/vsc'; |
||||||
|
import { useDispatch, useSelector } from 'react-redux'; |
||||||
|
import { |
||||||
|
Button, |
||||||
|
InputGroup, |
||||||
|
ButtonGroup, |
||||||
|
InputGroupAddon, |
||||||
|
Input, |
||||||
|
CustomInput |
||||||
|
} from 'reactstrap'; |
||||||
|
import { |
||||||
|
areaClickAction, environmentClickAction, |
||||||
|
mapTypeChangeAction, sensorClickAction, drawTypeChangeAction |
||||||
|
} from '../../../modules/control/map/actions/controlMapActions'; |
||||||
|
|
||||||
|
const ControlSetting = props => { |
||||||
|
const dispatch = useDispatch(); |
||||||
|
|
||||||
|
const mapControl = useSelector(state => state.controlMapReducer); |
||||||
|
|
||||||
|
// console.log('111111111111111');
|
||||||
|
// useEffect(() => {
|
||||||
|
// console.log('111111111111111');
|
||||||
|
// }, []);
|
||||||
|
useEffect(() => { |
||||||
|
console.log('>>>>', mapControl); |
||||||
|
}, [mapControl]); |
||||||
|
|
||||||
|
const handlerMapType = val => { |
||||||
|
dispatch(mapTypeChangeAction(val)); |
||||||
|
}; |
||||||
|
|
||||||
|
const handlerAreaClick = val => { |
||||||
|
dispatch(areaClickAction(val)); |
||||||
|
}; |
||||||
|
|
||||||
|
// const handlerDrawType = val => {
|
||||||
|
// dispatch(drawTypeChangeAction(val));
|
||||||
|
// };
|
||||||
|
|
||||||
|
const handlerSensorClick = (val, isChecked) => { |
||||||
|
if(isChecked){ |
||||||
|
dispatch(sensorClickAction(val)); |
||||||
|
} else { |
||||||
|
dispatch(sensorClickAction('')); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return ( |
||||||
|
<div className=''> |
||||||
|
{/* <div className='layer-content'> |
||||||
|
<div className='layer-ti'> |
||||||
|
<h4>flight path option</h4> |
||||||
|
</div> |
||||||
|
<div className='map-btn'> |
||||||
|
<ButtonGroup> |
||||||
|
<Button |
||||||
|
color={mapControl.drawType === 'CIRCLE' ? 'primary' : ''} |
||||||
|
onClick={e => handlerDrawType('CIRCLE')} |
||||||
|
> |
||||||
|
circle |
||||||
|
</Button> |
||||||
|
<Button |
||||||
|
color={mapControl.drawType === 'LINE' ? 'primary' : ''} |
||||||
|
onClick={e => handlerDrawType('LINE')} |
||||||
|
> |
||||||
|
line |
||||||
|
</Button> |
||||||
|
<Button |
||||||
|
color={mapControl.drawType === 'POLYGON' ? 'primary' : ''} |
||||||
|
onClick={e => handlerDrawType('POLYGON')} |
||||||
|
> |
||||||
|
polygon |
||||||
|
</Button> |
||||||
|
</ButtonGroup> |
||||||
|
</div> |
||||||
|
</div> */} |
||||||
|
|
||||||
|
<div className='layer-content'> |
||||||
|
<div className='layer-ti'> |
||||||
|
<h4>지도유형</h4> |
||||||
|
{/* <button className='btn-icon' outline color='primary'><X size={20} /></button> */} |
||||||
|
</div> |
||||||
|
<div className='map-btn'> |
||||||
|
<ButtonGroup> |
||||||
|
<Button |
||||||
|
color={mapControl.mapType === 'HYBRID' ? 'primary' : ''} |
||||||
|
onClick={e => handlerMapType('HYBRID')} |
||||||
|
> |
||||||
|
위성지도 |
||||||
|
</Button> |
||||||
|
<Button |
||||||
|
color={mapControl.mapType === 'NORMAL' ? 'primary' : ''} |
||||||
|
onClick={e => handlerMapType('NORMAL')} |
||||||
|
> |
||||||
|
일반지도 |
||||||
|
</Button> |
||||||
|
<Button |
||||||
|
color={mapControl.mapType === 'TERRAIN' ? 'primary' : ''} |
||||||
|
onClick={e => handlerMapType('TERRAIN')} |
||||||
|
> |
||||||
|
지형지도 |
||||||
|
</Button> |
||||||
|
</ButtonGroup> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div className='layer-content'> |
||||||
|
<div className='layer-ti'> |
||||||
|
<h4>공역 표출 정보</h4> |
||||||
|
</div> |
||||||
|
<div className='layer-content-box'> |
||||||
|
<div className='layer-content-info layer-switch-list'> |
||||||
|
<dl> |
||||||
|
<dt> |
||||||
|
<div className='list-left-txt'> |
||||||
|
<span className='dot-icon color-red'></span>비행금지구역 |
||||||
|
</div> |
||||||
|
<div className='list-right-txt'> |
||||||
|
<CustomInput |
||||||
|
onClick={e => handlerAreaClick('0001')} |
||||||
|
className='custom-control-primary' |
||||||
|
type='switch' |
||||||
|
id='test01' |
||||||
|
name='test01' |
||||||
|
inline |
||||||
|
defaultChecked={mapControl.area0001} |
||||||
|
/> |
||||||
|
</div> |
||||||
|
</dt> |
||||||
|
<dt> |
||||||
|
<div className='list-left-txt'> |
||||||
|
<span className='dot-icon color-pink'></span>비행제한구역 |
||||||
|
</div> |
||||||
|
<div className='list-right-txt'> |
||||||
|
<CustomInput |
||||||
|
onClick={e => handlerAreaClick('0002')} |
||||||
|
className='custom-control-primary' |
||||||
|
type='switch' |
||||||
|
id='test02' |
||||||
|
name='test02' |
||||||
|
inline |
||||||
|
defaultChecked={mapControl.area0002} |
||||||
|
/> |
||||||
|
</div> |
||||||
|
</dt> |
||||||
|
<dt> |
||||||
|
<div className='list-left-txt'> |
||||||
|
<span className='dot-icon color-orange'></span>관제권(공항) |
||||||
|
</div> |
||||||
|
<div className='list-right-txt'> |
||||||
|
<CustomInput |
||||||
|
onClick={e => handlerAreaClick('0003')} |
||||||
|
className='custom-control-primary' |
||||||
|
type='switch' |
||||||
|
id='test03' |
||||||
|
name='test03' |
||||||
|
inline |
||||||
|
defaultChecked={mapControl.area0003} |
||||||
|
/> |
||||||
|
</div> |
||||||
|
</dt> |
||||||
|
<dt> |
||||||
|
<div className='list-left-txt'> |
||||||
|
<span className='dot-icon color-brown'></span>비행장(군사) |
||||||
|
</div> |
||||||
|
<div className='list-right-txt'> |
||||||
|
<CustomInput |
||||||
|
onClick={e => handlerAreaClick('0004')} |
||||||
|
className='custom-control-primary' |
||||||
|
type='switch' |
||||||
|
id='test04' |
||||||
|
name='test04' |
||||||
|
inline |
||||||
|
defaultChecked={mapControl.area0004} |
||||||
|
/> |
||||||
|
</div> |
||||||
|
</dt> |
||||||
|
<dt> |
||||||
|
<div className='list-left-txt'> |
||||||
|
<span className='dot-icon color-purple'></span>이착륙장 |
||||||
|
</div> |
||||||
|
<div className='list-right-txt'> |
||||||
|
<CustomInput |
||||||
|
onClick={e => handlerAreaClick('0005')} |
||||||
|
className='custom-control-primary' |
||||||
|
type='switch' |
||||||
|
id='test05' |
||||||
|
name='test05' |
||||||
|
inline |
||||||
|
defaultChecked={mapControl.area0005} |
||||||
|
/> |
||||||
|
</div> |
||||||
|
</dt> |
||||||
|
<dt> |
||||||
|
<div className='list-left-txt'> |
||||||
|
<span className='dot-icon color-skyblue'></span> |
||||||
|
초경량비행장치공역 |
||||||
|
</div> |
||||||
|
<div className='list-right-txt'> |
||||||
|
<CustomInput |
||||||
|
onClick={e => handlerAreaClick('0006')} |
||||||
|
className='custom-control-primary' |
||||||
|
type='switch' |
||||||
|
id='test06' |
||||||
|
name='test06' |
||||||
|
inline |
||||||
|
defaultChecked={mapControl.area0006} |
||||||
|
/> |
||||||
|
</div> |
||||||
|
</dt> |
||||||
|
</dl> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
{/* <dt> |
||||||
|
<div className='list-left-txt'> |
||||||
|
<span className='dot-icon color-red'></span>미세먼지(DUST) |
||||||
|
</div> |
||||||
|
<div className='list-right-txt'> |
||||||
|
<CustomInput |
||||||
|
onChange={e => handlerSensorClick('dust', e.target.checked)} |
||||||
|
className='custom-control-primary' |
||||||
|
type='switch' |
||||||
|
id='sensorDust' |
||||||
|
name='sensorDust' |
||||||
|
inline |
||||||
|
checked={mapControl.sensor === 'dust'} |
||||||
|
// defaultChecked={mapControl.sensor === 'dust'}
|
||||||
|
/> |
||||||
|
</div> |
||||||
|
</dt> */} |
||||||
|
|
||||||
|
</div> |
||||||
|
); |
||||||
|
}; |
||||||
|
export default ControlSetting; |
@ -0,0 +1,233 @@ |
|||||||
|
import React, { useEffect, useState } from 'react'; |
||||||
|
import { |
||||||
|
CloudDrizzle, |
||||||
|
CloudLightning, |
||||||
|
Navigation2, |
||||||
|
X, |
||||||
|
Search, |
||||||
|
Compass, |
||||||
|
Sun, |
||||||
|
Cloud, |
||||||
|
CloudRain, |
||||||
|
CloudSnow |
||||||
|
} from 'react-feather'; |
||||||
|
import { Button, InputGroup, InputGroupAddon, Input, Table } from 'reactstrap'; |
||||||
|
|
||||||
|
const WeatherList = props => { |
||||||
|
const [clickTab, setClickTab] = useState(true); |
||||||
|
|
||||||
|
return ( |
||||||
|
<div className='left-layer'> |
||||||
|
<div className='layer-content'> |
||||||
|
<div className='layer-ti'> |
||||||
|
<h4>날씨 상세정보</h4> |
||||||
|
<button |
||||||
|
className='btn-icon' |
||||||
|
outline |
||||||
|
color='primary' |
||||||
|
onClick={() => props.setOpenWeatherList(false)} |
||||||
|
> |
||||||
|
<X size={20} /> |
||||||
|
</button> |
||||||
|
</div> |
||||||
|
<div className='layer-search'> |
||||||
|
<InputGroup> |
||||||
|
<Input type='text' placeholder='검색어를 입력하세요' /> |
||||||
|
<Button color='primary' outline> |
||||||
|
<Search size={18} /> |
||||||
|
</Button> |
||||||
|
</InputGroup> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div className='layer-content'> |
||||||
|
<div className='layer-weather-box'> |
||||||
|
<div className='layer-weather-info'> |
||||||
|
<div className='layer-weather-table'> |
||||||
|
<div className='layer-weather-address'> |
||||||
|
검색하신 지역의 날씨 정보입니다. |
||||||
|
<span> |
||||||
|
<Compass size={20} /> 인천광역시 부평구 안남로 272 |
||||||
|
</span> |
||||||
|
</div> |
||||||
|
{/* 탭메뉴or탭내용 활성화 active */} |
||||||
|
<div className='tab-menu'> |
||||||
|
<ul> |
||||||
|
{clickTab ? ( |
||||||
|
<> |
||||||
|
<li className='active'>오늘</li> |
||||||
|
|
||||||
|
<li className='' onClick={e => setClickTab(false)}> |
||||||
|
주간 |
||||||
|
</li> |
||||||
|
</> |
||||||
|
) : ( |
||||||
|
<> |
||||||
|
<li className='' onClick={e => setClickTab(true)}> |
||||||
|
오늘 |
||||||
|
</li> |
||||||
|
<li className='active'>주간</li> |
||||||
|
</> |
||||||
|
)} |
||||||
|
</ul> |
||||||
|
</div> |
||||||
|
{clickTab ? ( |
||||||
|
<div className='tab-content active'> |
||||||
|
<Table responsive> |
||||||
|
<thead> |
||||||
|
<tr> |
||||||
|
<th>시각</th> |
||||||
|
<th>날씨</th> |
||||||
|
<th>기온</th> |
||||||
|
<th>풍향</th> |
||||||
|
<th>풍속</th> |
||||||
|
</tr> |
||||||
|
</thead> |
||||||
|
<tbody> |
||||||
|
<tr> |
||||||
|
<td>10시</td> |
||||||
|
<td> |
||||||
|
<Sun /> |
||||||
|
</td> |
||||||
|
<td>27℃</td> |
||||||
|
<td> |
||||||
|
<Navigation2 className='rotate-45' /> |
||||||
|
</td> |
||||||
|
<td>2m/s</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td>12시</td> |
||||||
|
<td> |
||||||
|
<CloudLightning /> |
||||||
|
</td> |
||||||
|
<td>30℃</td> |
||||||
|
<td> |
||||||
|
<Navigation2 className='rotate-75' /> |
||||||
|
</td> |
||||||
|
<td>3m/s</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td>14시</td> |
||||||
|
<td> |
||||||
|
<Cloud /> |
||||||
|
</td> |
||||||
|
<td>28℃</td> |
||||||
|
<td> |
||||||
|
<Navigation2 className='rotate-90' /> |
||||||
|
</td> |
||||||
|
<td>4m/s</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td>16시</td> |
||||||
|
<td> |
||||||
|
<CloudRain /> |
||||||
|
</td> |
||||||
|
<td>27℃</td> |
||||||
|
<td> |
||||||
|
<Navigation2 className='rotate-135' /> |
||||||
|
</td> |
||||||
|
<td>7m/s</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td>18시</td> |
||||||
|
<td> |
||||||
|
<CloudSnow /> |
||||||
|
</td> |
||||||
|
<td>25℃</td> |
||||||
|
<td> |
||||||
|
<Navigation2 className='rotate-180' /> |
||||||
|
</td> |
||||||
|
<td>2m/s</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td>20시</td> |
||||||
|
<td> |
||||||
|
<CloudDrizzle /> |
||||||
|
</td> |
||||||
|
<td>26℃</td> |
||||||
|
<td> |
||||||
|
<Navigation2 className='rotate-225' /> |
||||||
|
</td> |
||||||
|
<td>2m/s</td> |
||||||
|
</tr> |
||||||
|
</tbody> |
||||||
|
</Table> |
||||||
|
</div> |
||||||
|
) : ( |
||||||
|
<div className='tab-content active'> |
||||||
|
<Table responsive> |
||||||
|
<thead> |
||||||
|
<tr> |
||||||
|
<th>날짜</th> |
||||||
|
<th>날씨</th> |
||||||
|
<th>기온</th> |
||||||
|
</tr> |
||||||
|
</thead> |
||||||
|
<tbody> |
||||||
|
<tr> |
||||||
|
<td>06.19.(토) 오전</td> |
||||||
|
<td> |
||||||
|
<Sun /> |
||||||
|
</td> |
||||||
|
<td>최저 27℃</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td>06.19.(토) 오후</td> |
||||||
|
<td> |
||||||
|
<CloudLightning /> |
||||||
|
</td> |
||||||
|
<td>30℃</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td>06.20.(일) 오전</td> |
||||||
|
<td> |
||||||
|
<CloudLightning /> |
||||||
|
</td> |
||||||
|
<td>30℃</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td>06.20.(일) 오후</td> |
||||||
|
<td> |
||||||
|
<CloudLightning /> |
||||||
|
</td> |
||||||
|
<td>30℃</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td>06.21.(월) 오전</td> |
||||||
|
<td> |
||||||
|
<CloudLightning /> |
||||||
|
</td> |
||||||
|
<td>30℃</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td>06.21.(월) 오후</td> |
||||||
|
<td> |
||||||
|
<CloudLightning /> |
||||||
|
</td> |
||||||
|
<td>30℃</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td>06.22.(화) 오전</td> |
||||||
|
<td> |
||||||
|
<CloudLightning /> |
||||||
|
</td> |
||||||
|
<td>30℃</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<td>06.2.(화) 오후</td> |
||||||
|
<td> |
||||||
|
<CloudLightning /> |
||||||
|
</td> |
||||||
|
<td>30℃</td> |
||||||
|
</tr> |
||||||
|
</tbody> |
||||||
|
</Table> |
||||||
|
</div> |
||||||
|
)} |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
); |
||||||
|
}; |
||||||
|
export default WeatherList; |
Loading…
Reference in new issue