노승철
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