Browse Source

Merge remote-tracking branch 'origin/master'

pull/2/head
지대한 2 years ago
parent
commit
405e2b6ec3
  1. 2
      package.json
  2. 11
      src/assets/css/custom.css
  3. 105
      src/components/basis/flight/plan/FlightPlanAreaForm.js
  4. 28
      src/components/basis/flight/plan/FlightPlanAreaModal.js
  5. 45
      src/components/basis/flight/plan/FlightPlanForm.js
  6. 30
      src/components/mapDraw/naver/NaverMap.js
  7. 65
      src/components/mapDraw/naver/draw/DrawMap.js
  8. 154
      src/components/mapDraw/naver/draw/DrawPath.js
  9. 496
      src/components/mapDraw/naver/draw/JQueryDraw.js
  10. 48
      src/containers/basis/flight/plan/FlightPlanAreaContainer.js
  11. 44
      src/containers/basis/flight/plan/FlightPlanDetailContainer.js
  12. 16
      src/modules/basis/flight/actions/basisFlightAction.ts
  13. 12
      src/modules/basis/flight/models/basisFlightModel.ts
  14. 8
      src/modules/basis/flight/reducers/basisFlightReducer.ts
  15. 18
      src/modules/basis/flight/sagas/basisFlightSaga.ts
  16. 63
      src/views/testDraw/main/ControlMainDraw.js

2
package.json

@ -47,7 +47,7 @@
"html-to-draftjs": "1.5.0",
"http-proxy-middleware": "^2.0.1",
"intl-messageformat": "7.8.4",
"jquery": "3.5.1",
"jquery": "^3.5.1",
"js-cookie": "^3.0.0",
"jsonwebtoken": "8.5.1",
"jwt-decode": "^3.1.2",

11
src/assets/css/custom.css

@ -245,6 +245,17 @@ h1.logo span{display:block;color:#f4f4f4;font-weight:bold;letter-spacing:2px;fon
/* fligth path draw */
.left-menu-nav li .check{background-color: #283046; font-size:0.9rem; color: white; width:70px; border: 0px;}
.left-menu-nav.test{position: relative; z-index: 1; cursor: pointer; float: left; display: block; margin: 0px; padding: 0px; width: 28px; height: 28px; list-style: none; box-sizing: content-box !important; background: rgb(255, 255, 255);}
.left-menu-nav .test .btn-stop{margin-left:25px; width: 28px; height: 28px; display: block; border: 0px solid transparent; box-sizing: content-box !important;}
.left-menu-nav .test .btn-use{margin-left:20px; width: 35px; height: 35px; display: block; border: 0px solid transparent; box-sizing: content-box !important; background-color: #009cad;}
.measure-control{position:absolute; z-index:100;}
.control-btn{margin-left: 7px; border-bottom: solid 1px #283046; margin-bottom:5px;}
.buffer-input{text-align: center; border-radius: 100px; border: 1px solid #283046; width: 70px; margin-left: 5px;}
.buffer-btn{text-align: center; border-radius: 100px; border: 1px solid #283046; width: 30px; margin-left: 5px;}
/*메인-알림*/
.notice{width:650px;height:45px;overflow:hidden;position:absolute;left:50%;top:20px;transform: translate(-50%,0px);background:#283046;display:flex;font-size:0.9375rem;color:#f4f4f4;padding:0px 20px;border-radius:30px;}

105
src/components/basis/flight/plan/FlightPlanAreaForm.js

@ -1,20 +1,24 @@
import React from 'react';
import React, { useState, useEffect } from 'react';
import classnames from 'classnames';
import {
Card,
CardBody,
Col,
FormGroup,
FormFeedback,
Input,
Label,
Row,
Button
Button,
Form
} from 'reactstrap';
const FlightPlanAreaForm = () => {
const FlightPlanAreaForm = (props) => {
return (
<Card>
<CardBody>
<CardBody>
<div className='search-cont search-info pd-0'>
<div className='cont-ti mb-1 d-flex justify-content-between align-items-sm-center align-items-start flex-sm-row'>
<div>
@ -28,57 +32,22 @@ const FlightPlanAreaForm = () => {
</div>
<dl>
<dt>
<dt>
<div className='search-info-box'>
<Row>
<Col className='list-input' lg={6} md={6} sm={12}>
<FormGroup>
<Label for='test'>
<span className='necessary'>*</span>
<span className='necessary'></span>(m)
</Label>
<Input
type='text'
id='ownerNm'
name='ownerNm'
id='radius'
name='radius'
size='sm'
placeholder=''
/>
</FormGroup>
</Col>
</Row>
</div>
<div className='search-info-box'>
<Row>
<Col className='list-input' lg={6} md={6} sm={12}>
<FormGroup>
<Label for='test'>
<span className='necessary'>*</span>
</Label>
<Input
type='text'
id='ownerNm'
name='ownerNm'
size='sm'
placeholder=''
/>
</FormGroup>
</Col>
</Row>
</div>
<div className='search-info-box'>
<Row>
<Col className='list-input' lg={6} md={6} sm={12}>
<FormGroup>
<Label for='test'>
<span className='necessary'>*</span>(m)
</Label>
<Input
type='text'
id='ownerNm'
name='ownerNm'
size='sm'
placeholder=''
/>
placeholder=''
innerRef={props.data}
/>
</FormGroup>
</Col>
</Row>
@ -89,33 +58,55 @@ const FlightPlanAreaForm = () => {
<FormGroup className='m_ft'>
<div className='m_ft_box'>
<Label for='test'>
<span className='necessary'>*</span>(m/ft)
<span className='necessary'></span>(m/ft)
</Label>
<Input
type='text'
id='ownerNm'
name='ownerNm'
id='altitude_m'
name='altitude_m'
size='sm'
placeholder='m'
placeholder='m'
innerRef={props.data}
/>
</div>
<div className='m_ft_box'>
<Input
type='text'
id='ownerNm'
name='ownerNm'
id='altitude'
name='altitude'
size='sm'
placeholder='ft'
placeholder='ft'
innerRef={props.data}
/>
</div>
</div>
</FormGroup>
</Col>
</Col>
</Row>
</div>
<Button.Ripple
className='mr-1'
color='primary'
size='sm'
onClick={
props.submit
}
>
확인
</Button.Ripple>
<Button.Ripple
className='mr-1'
color='danger'
size='sm'
onClick={() =>
props.setModal({ ...props.modal, isOpen: !props.modal.isOpen })
}
>
취소
</Button.Ripple>
</dt>
</dl>
</div>
</div>
</CardBody>
</Card>
)

28
src/components/modal/FormModal.js → src/components/basis/flight/plan/FlightPlanAreaModal.js

@ -1,6 +1,11 @@
import { useState } from 'react';
import { Button, Modal, ModalHeader, ModalBody, ModalFooter } from 'reactstrap';
import FlightPlanAreaContainer from '../../../../containers/basis/flight/plan/FlightPlanAreaContainer';
export const FlightPlanAreaModal = props => {
const [onSubmit, setOnSubmit] = useState(false);
export const FormModal = props => {
return (
<div className='vertically-centered-modal'>
<Modal
@ -18,19 +23,26 @@ export const FormModal = props => {
{props.modal.title}
</ModalHeader>
<ModalBody>
{props.modal.contents}
<FlightPlanAreaContainer
modal={props.modal}
setModal={props.setModal}
onSubmit={onSubmit}
setOnSubmit={setOnSubmit}
/>
</ModalBody>
<ModalFooter>
{/* <ModalFooter>
<Button
type="submit"
color='primary'
onClick={() =>
props.setModal({ ...props.modal, isOpen: !props.modal.isOpen })
}
// onClick={() =>
// // props.setModal({ ...props.modal, isOpen: !props.modal.isOpen })
// setOnSubmit(true)
// }
outline
>
확인
저장
</Button>
</ModalFooter>
</ModalFooter> */}
</Modal>
</div>
);

45
src/components/basis/flight/plan/FlightPlanForm.js

@ -44,7 +44,7 @@ const FlightPlanForm = (props) => {
<Row>
<Col className='list-input' lg={4} md={6} sm={12}>
<FormGroup>
<Label for='test'>성명</Label>
<Label for='test'><span className='necessary'>*</span></Label>
<Input
type='text'
id='applicantNm'
@ -57,7 +57,7 @@ const FlightPlanForm = (props) => {
</Col>
<Col className='list-input' lg={4} md={6} sm={12}>
<FormGroup>
<Label for='test'>생년월일</Label>
<Label for='test'><span className='necessary'>*</span></Label>
<Input
type='text'
id='applicantBirthDt'
@ -67,10 +67,14 @@ const FlightPlanForm = (props) => {
placeholder=''
/>
</FormGroup>
</Col>
</Col>
</Row>
</div>
<div className='search-info-box'>
<Row>
<Col className='list-input' lg={4} md={6} sm={12}>
<FormGroup>
<Label for='test'>전화번호</Label>
<Label for='test'><span className='necessary'>*</span> </Label>
<Input
type='text'
id='applicantPhone'
@ -81,10 +85,9 @@ const FlightPlanForm = (props) => {
/>
</FormGroup>
</Col>
<Col className='list-input' lg={4} md={6} sm={12}>
<FormGroup>
<Label for='test'>팩스번호</Label>
<Label for='test'><span className='necessary'></span> </Label>
<Input
type='text'
id='applicantPhone'
@ -94,15 +97,16 @@ const FlightPlanForm = (props) => {
placeholder=''
/>
</FormGroup>
</Col>
</Row>
</div>
</Col>
</Row>
</div>
<div className='search-info-box'>
{/* <div className='search-info-box'>
<Row>
<Col className='list-input' lg={4} md={6} sm={12}>
<FormGroup>
<Label for='test'>주소</Label>
<Label for='test'><span className='necessary'>*</span></Label>
<Input
type='text'
id='applicantAddress'
@ -115,7 +119,7 @@ const FlightPlanForm = (props) => {
</Col>
<Col className='list-input' lg={4} md={6} sm={12}>
<FormGroup>
<Label for='test'>상세주소</Label>
<Label for='test'><span className='necessary'>*</span> </Label>
<Input
type='text'
id='applicantAddress'
@ -127,7 +131,7 @@ const FlightPlanForm = (props) => {
</FormGroup>
</Col>
</Row>
</div>
</div> */}
</dt>
<dt>
@ -273,7 +277,8 @@ const FlightPlanForm = (props) => {
id='ownerNm'
name='ownerNm'
size='sm'
placeholder=''
placeholder=''
readOnly
/>
</FormGroup>
</Col>
@ -287,7 +292,8 @@ const FlightPlanForm = (props) => {
id='ownerNm'
name='ownerNm'
size='sm'
placeholder=''
placeholder=''
readOnly
/>
</FormGroup>
</Col>
@ -305,7 +311,8 @@ const FlightPlanForm = (props) => {
id='ownerNm'
name='ownerNm'
size='sm'
placeholder=''
placeholder=''
readOnly
/>
</FormGroup>
</Col>
@ -320,7 +327,8 @@ const FlightPlanForm = (props) => {
id='ownerNm'
name='ownerNm'
size='sm'
placeholder='m'
placeholder='m'
readOnly
/>
</div>
<div className='m_ft_box'>
@ -329,7 +337,8 @@ const FlightPlanForm = (props) => {
id='ownerNm'
name='ownerNm'
size='sm'
placeholder='ft'
placeholder='ft'
readOnly
/>
</div>
</FormGroup>

30
src/components/mapDraw/naver/NaverMap.js

@ -1,18 +1,15 @@
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 { DrawMap } from './draw/DrawMap';
import { JQueryDraw } from './draw/JQueryDraw';
import geoJson from '../geojson/airArea.json';
import SensorZone from "./sensor/SensorZone";
import $ from 'jquery';
export const NaverCustomMap = () => {
const naver = window.naver;
// let map;
@ -26,14 +23,8 @@ export const NaverCustomMap = () => {
useEffect(() => {
NaverMapInit();
// console.log(map);
// console.log(features);
// setIsMapLoad(true);
}, []);
// useEffect(() => {
// console.log('==============11111==================', mapObject);
// }, [mapObject]);
const removeArrMarkers = arrData => {
arrMarkers = arrData;
@ -46,7 +37,7 @@ export const NaverCustomMap = () => {
zoomControl: true,
// mapTypeId: naver.maps.MapTypeId.HYBRID,
zoomControlOptions: {
position: naver.maps.Position.TOP_LEFT,
position: naver.maps.Position.LEFT_CENTER,
style: naver.maps.ZoomControlStyle.SMALL
}
@ -56,19 +47,24 @@ export const NaverCustomMap = () => {
};
return (
<>
<div id='map' style={{ width: '100%', height: '100vh' }}></div>
<div style={{position: 'relative'}}>
<div id='map' style={{ width: '100%', height: '100vh', position: 'absolute' }}>
{/* 제이쿼리로 그리기 */}
<JQueryDraw map={mapObject} naver={naver} />
</div>
{mapObject != null ? (
<>
<NaverMapControl map={mapObject} />
<FeatureAirZone map={mapObject} naver={naver} features={features} />
<DrawPath map={mapObject} naver={naver} />
{/* 그리기 도구 모음 불러오는 거 */}
<DrawMap map={mapObject} naver={naver} />
</>
) : null}
{/* */}
</>
</div>
);
};

65
src/components/mapDraw/naver/draw/DrawMap.js

@ -1,38 +1,57 @@
import { useEffect, useState } from "react";
import { render } from "react-dom";
import { BiCaretLeftCircle } from "react-icons/bi";
import { useSelector } from "react-redux";
export const DrawMap = props => {
const {naver} = props;
const {map} = props;
const [check, setCheck] = useState([]);
const [drawing, setDrawing] = useState();
const [overlay, setOverlay] = useState([]);
const {drawCheck} = useSelector(state => state.controlMapReducer);
useEffect(() => {
removeOverlay();
}, [overlay]);
useEffect(() => {
init();
}, [drawCheck]);
const removeOverlay = () => {
if(overlay.length >= 2) {
drawing.removeDrawing(overlay[0]);
setOverlay(prev => ([prev[overlay.length-1]]));
}
}
const init = () => {
removeDraw();
initRemove();
removeDrawManager();
}
const removeDraw = () => {
check.forEach(prev => prev.setMap(null));
drawSetting();
const initRemove = () => {
if(overlay) {
overlay.forEach(prev => drawing.removeDrawing(prev));
setOverlay([]);
}
}
const removeDrawManager = () => {
if(drawing) {
drawing.setMap(null);
}
drawSetting();
}
const drawSetting = () => {
if(drawCheck) {
// debugger;
let drawingManager = new naver.maps.drawing.DrawingManager({
drawingControl: [
naver.maps.drawing.DrawingMode.POLYLINE,
naver.maps.drawing.DrawingMode.POLYGON,
naver.maps.drawing.DrawingMode.ELLIPSE,
naver.maps.drawing.DrawingMode.RECTANGLE
naver.maps.drawing.DrawingMode.ELLIPSE
],
drawingControlOptions: {
position: naver.maps.Position.LEFT_CENTER,
@ -52,21 +71,15 @@ export const DrawMap = props => {
strokeWeight: 2,
}
},
rectangleOptions: {
fillColor: '#ff0000',
fillOpacity: 0.3,
strokeWeight: 2,
strokeColor: '#ff0000'
},
ellipseOptions: {
fillColor: '#ff25dc',
fillOpacity: 0.3,
strokeWeight: 2,
strokeColor: '#ff25dc'
},
polylineOptions: { // 화살표 아이콘 계열 옵션은 무시됩니다.
polylineOptions: {
strokeColor: '#222',
strokeWeight: 2
strokeWeight: 10
},
polygonOptions: {
fillColor: '#ffc300',
@ -75,12 +88,28 @@ export const DrawMap = props => {
strokeColor:'#ffc300'
}
});
// console.log(drawingManager.)
addEvent(drawingManager);
drawingManager.setMap(map);
setCheck(prev => ([...prev, drawingManager]));
setDrawing(drawingManager);
}
}
const addEvent = (drawingManager) => {
drawingManager.addListener('drawing_added', function(overlay) {
console.log(overlay)
if(overlay.OVERLAY_TYPE === 'Polygon') {
console.log(overlay.paths._array[0]._array)
} else if(overlay.OVERLAY_TYPE === 'Ellipse') {
console.log(overlay.bounds)
}
setOverlay(prev=> ([...prev, overlay]));
});
}
return null;
};

154
src/components/mapDraw/naver/draw/DrawPath.js

@ -1,154 +0,0 @@
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 = '';
const [eventGroup, setEventGroup] = useState([]);
const [polylines, setPolylines] = useState([]);
const [circleLayers, setCircleLayers] = useState([]);
useEffect(() => {
// drawSetting();
}, []);
useEffect(() => {
init();
}, [drawType]);
useEffect(() => {
}, [eventGroup]);
useEffect(() => {
moveCircle();
}, [circleLayers]);
const init = () => {
removeEvent();
removeLayers();
}
const drawSetting = () => {
const drawingManager = new naver.maps.drawing.DrawingManager({
drawingControl: [
naver.maps.drawing.DrawingMode.POLYLINE,
naver.maps.drawing.DrawingMode.POLYGON,
naver.maps.drawing.DrawingMode.ELLIPSE,
naver.maps.drawing.DrawingMode.RECTANGLE
],
drawingControlOptions: {
position: naver.maps.Position.LEFT_CENTER,
style: naver.maps.drawing.DrawingStyle.VERTICAL
}
});
drawingManager.setMap(map);
}
const removeEvent = () => {
eventGroup.forEach(prev => naver.maps.Event.removeListener(prev));
// eventGroup.forEach(prev => console.log(prev));
// const test = eventGroup.find(prev=> prev='drawingManager');
// if(test) {
// test.setMap(null);
// }
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) {
// debugger;
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]));
}
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: '#283046',
strokeWeight: 1,
strokeOpacity: 0.8,
fillColor: '#0000ff',
fillOpacity: 0.2,
radius: 150,
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;
};

496
src/components/mapDraw/naver/draw/JQueryDraw.js

@ -0,0 +1,496 @@
import $ from 'jquery';
import { useEffect } from 'react';
import { useSelector } from 'react-redux';
import '../../../../assets/css/custom.css';
import { CustomInput } from 'reactstrap';
export const JQueryDraw = props => {
const {naver} = props;
const {map} = props;
const { drawType } = useSelector(state => state.controlMapReducer);
var Measure = function(buttons) {
this.$btnLine = buttons.line;
this.$btnPolygon = buttons.polygon;
this.$btnCircle = buttons.circle;
this._mode = null;
this._bindDOMEvents();
};
$.extend(
Measure.prototype,{
constructor: Measure,
setMap: function(map) {
console.log('setMap')
if (this.map) {
this._unbindMap(this.map);
}
this.map = map;
if (map) {
this._bindMap(map);
}
},
startMode: function(mode) {
console.log('startMode')
if (!mode) return;
if (mode === 'line') {
this._startDistance();
} if (mode === 'polygon') {
this._startArea();
} if (mode === 'circle') {
this._startCircle();
}
},
_startDistance: function() {
console.log('startDistance')
var map = this.map;
this._distanceListeners = [
naver.maps.Event.addListener(map, 'click', this._onClickDistance.bind(this))
];
},
_startArea: function() {
console.log('startArea')
var map = this.map;
this._areaListeners = [
naver.maps.Event.addListener(map, 'click', this._onClickArea.bind(this)),
naver.maps.Event.addListener(map, 'rightclick', this._finishArea.bind(this))
];
$(document).on('mousemove.measure', this._onMouseMoveArea.bind(this));
},
_startCircle: function() {
console.log('startCircle')
var map = this.map;
this._circleListeners = [
naver.maps.Event.addListener(map, 'click', this._onClickCircle.bind(this)),
naver.maps.Event.addListener(map, 'rightclick', this._finishCircle.bind(this))
];
},
_finishDistance: function() {
console.log('finishDistance')
naver.maps.Event.removeListener(this._distanceListeners);
delete this._distanceListeners;
$(document).off('mousemove.measure');
if (this._guideline) {
this._guideline.setMap(null);
delete this._guideline;
}
if (this._polyline) {
console.log(this._polyline.getPath())
this._bufferPolygon = new naver.maps.Polygon({
})
// this._polygon = new naver.maps.Polygon({
// strokeColor: '#00f',
// strokeOpacity: 0.6,
// strokeWeight: 2,
// fillColor: '#00f',
// fillOpacity: 0.3,
// paths: [coord],
// map: map
// });
// 이거 하면 그동안 한거 싹 사라짐 -> 얘를 통해서 drawType이 바뀌면 다 날라가는 걸로 해보면 될듯
// this._polyline.setMap(null)
delete this._polyline;
}
//onfocus()의 반대기능 = blur()
this.$btnLine.removeClass('control-on').blur();
this._mode = null;
},
_finishArea: function() {
console.log('finishArea')
naver.maps.Event.removeListener(this._areaListeners);
delete this._areaListeners;
$(document).off('mousemove.measure');
if (this._polygon) {
var path = this._polygon.getPath();
path.pop();
delete this._polygon;
}
this.$btnPolygon.removeClass('control-on').blur();
this._mode = null;
},
_finishCircle: function() {
console.log('finishCircle')
naver.maps.Event.removeListener(this._circleListeners);
delete this._circleListeners;
$(document).off('mousemove.measure');
if(this._guidecircle) {
this._guidecircle.setMap(null);
this._radius.setMap(null);
delete this._raidus;
delete this._guidecircle;
}
if (this._circle) {
// this._circle.setMap(null);
delete this._circle;
}
this.$btnCircle.removeClass('control-on').blur();
// delete this._lastDistance;
this._mode = null;
},
finishMode: function(mode) {
console.log('finishMode')
if (!mode) return;
if (mode === 'line') {
this._finishDistance();
} if (mode === 'polygon') {
this._finishArea();
} if (mode === 'circle') {
this._finishCircle();
}
},
_onClickDistance: function(e) {
console.log('onClickDistance')
var map = this.map,
coord = e.coord;
console.log(coord, '클릭좌표1');
if (!this._polyline) {
// 임시로 보여줄 점선 폴리라인을 생성합니다.
this._guideline = new naver.maps.Polyline({
strokeColor: '#db4040',
strokeWeight: 5,
strokeStyle: [4, 4],
strokeOpacity: 0.4,
path: [coord],
map: map
});
$(document).on('mousemove.measure', this._onMouseMoveDistance.bind(this));
this._distanceListeners.push(naver.maps.Event.addListener(map, 'rightclick', this._finishDistance.bind(this)));
// 실제 거리재기에 사용되는 폴리라인을 생성합니다.
this._polyline = new naver.maps.Polyline({
strokeLineCap: 'round',
strokeLineJoin: 'round',
strokeColor: '#db4040',
strokeWeight: 5,
strokeOpacity: 1,
path: [coord],
map: map
});
this._test = new naver.maps.Polyline({
// path: [[126.6047916, 37.5237865], [126.6047719, 37.5237832]],
path: [[126.6048449, 37.5237486], [126.6047340, 37.5237299]],
map: map,
strokeweight: 5,
strokeOpacity: 1,
strokeColor: '#db4040'
})
console.log(this._test.getDistance());
} else {
this._guideline.setPath([e.coord]);
this._polyline.getPath().push(coord);
}
},
_onMouseMoveDistance: function(e) {
console.log('onMouseMoveDistance')
var map = this.map,
proj = this.map.getProjection(),
coord = proj.fromPageXYToCoord(new naver.maps.Point(e.pageX, e.pageY)),
path = this._guideline.getPath();
// console.log(coord, '실시간 좌표')
if (path.getLength() === 2) {
//맨 뒷 값 삭제 = 기존클릭좌표만 남겨둬라 = 실시간으로 좌표들어가야 하니까
path.pop();
}
// [기존 클릭 좌표, 실시간 좌표]
path.push(coord);
},
_onClickArea: function(e) {
console.log('onClickArea')
var map = this.map,
coord = e.coord;
if (!this._polygon) {
this._polygon = new naver.maps.Polygon({
strokeColor: '#00f',
strokeOpacity: 0.6,
strokeWeight: 2,
fillColor: '#0000ff',
fillOpacity: 0.1,
paths: [coord],
map: map
});
} else {
this._polygon.getPath().push(coord);
}
},
_onMouseMoveArea: function(e) {
console.log('onMouseMoveArea')
if (!this._polygon) return;
var map = this.map,
proj = this.map.getProjection(),
coord = proj.fromPageXYToCoord(new naver.maps.Point(e.pageX, e.pageY)),
path = this._polygon.getPath();
if (path.getLength() >= 2) {
path.pop();
}
path.push(coord);
},
_onClickCircle: function(e) {
console.log('onClickCircle')
var map = this.map,
coord = e.coord;
if(!this._circle) {
//가이드 라인
this._radius = new naver.maps.Polyline({
// strokeColor: '#db4040',
// strokeWeight: 2,
strokeStyle: [4, 4],
strokeOpacity: 0.6,
path: [coord],
map: map
});
this._lastDistance = this._radius.getDistance();
// 임시로 보여줄 원형
this._guidecircle = new naver.maps.Circle({
// strokeColor: '#283046',
// strokeWeight: 2,
strokeOpacity: 0.8,
strokeStyle: [4, 4],
fillColor: '#0000ff',
fillOpacity: 0.1,
center: coord,
radius: this._lastDistance,
map: map
});
$(document).on('mousemove.measure', this._onMouseMoveCircle.bind(this));
this._circleListeners.push(naver.maps.Event.addListener(map, 'rightclick', this._finishCircle.bind(this)));
// 실제 사용되는 원형
this._circle = new naver.maps.Circle({
// strokeColor: '#283046',
// strokeWeight: 2,
strokeOpacity: 0.8,
fillColor: '#0000ff',
fillOpacity: 0.1,
center: coord,
radius: this._lastDistance,
map: map
});
} else {
// this._guidecircle.setCenter(e.coord);
// this._circle.setCenter(coord);
// if(this._radius.getPath().length() === 2) {
// this._radius.getPath().pop();
// }
// this._radius.getPath().push(coord);
var distance = this._radius.getDistance();
this._lastDistance = distance;
this._circle.setRadius(this._lastDistance);
}
},
_onMouseMoveCircle: function(e) {
console.log('onMouseMoveCircle')
if(!this._circle) return;
var map = this.map,
proj = this.map.getProjection(),
coord = proj.fromPageXYToCoord(new naver.maps.Point(e.pageX, e.pageY)),
path = this._radius.getPath(),
center = this._guidecircle.getCenter(), //LatLng으로 나옴
r = proj.getDistance(coord, center);
if(path.getLength() === 2) {
path.pop();
}
path.push(coord);
this._guidecircle.setRadius(r);
},
_bindMap: function(map) {
console.log('bindMap')
},
_unbindMap: function() {
console.log('unbindMap')
this.unbindAll();
},
_bindDOMEvents: function() {
console.log('bindDOMEvents')
this.$btnLine.on('click.measure', this._onClickButton.bind(this, 'line'));
this.$btnPolygon.on('click.measure', this._onClickButton.bind(this, 'polygon'));
this.$btnCircle.on('click.measure', this._onClickButton.bind(this, 'circle'));
},
_onClickButton: function(newMode, e) {
//newMode는 방금 클릭한 값(line, polygon, circle...)
console.log('onClickButton')
e.preventDefault();
var btn = $(e.target),
map = this.map,
mode = this._mode;
//this._mode는 클릭하기 전 값(첫 클릭이면 null)
if (btn.hasClass('control-on')) {
console.log('remove')
btn.removeClass('control-on');
} else {
console.log('add')
btn.addClass('control-on');
}
this._clearMode(mode);
if (mode === newMode) {
this._mode = null;
return;
}
this._mode = newMode;
this.startMode(newMode);
},
_clearMode: function(mode) {
console.log('clearMode')
if (!mode) return;
if (mode === 'line') {
if (this._polyline) {
this._polyline.setMap(null);
delete this._polyline;
}
this._finishDistance();
} else if (mode === 'polygon') {
if (this._polygon) {
this._polygon.setMap(null);
delete this._polygon;
}
this._finishArea();
} else if (mode === 'circle') {
if (this._circle) {
this._circle.setMap(null);
delete this._circle;
}
this._finishCircle();
} else if(mode === 'CIRCLE') {
if(this._circle) {
this._circle.setMap(null);
delete this._circle;
}
}
}
});
// id랑 매치시켜서 옵션 지정함
var measures = new Measure({
line: $('#line'),
polygon: $('#polygon'),
circle: $('#circle')
});
measures.setMap(map);
return(
<>
<div style={{ position: 'relative' }}>
<ul className="measure-control">
<li>
{/* <input type='button' value='선' id='line' className='control-btn'></input> */}
{/* <input type='button' value='다각형' id='polygon' className='control-btn'></input> */}
{/* <input type='button' value='원' id='circle' className='control-btn'></input> */}
<CustomInput
id='line'
type='image'
className='control-btn'
src='http://static.naver.net/maps/mantle/drawing/1x/polyline.png'
/>
<CustomInput
id='polygon'
type='image'
className='control-btn'
src='http://static.naver.net/maps/mantle/drawing/1x/polygon.png'
/>
<CustomInput
id='circle'
type='image'
className='control-btn'
src='http://static.naver.net/maps/mantle/drawing/1x/ellipse.png'
/>
<br/>
<CustomInput
id='input'
type='input'
className='buffer-input'
/>
{/* <CustomInput
id='input-btn'
type='button'
className='buffer-btn'
/> */}
</li>
</ul>
</div>
</>
)
};

48
src/containers/basis/flight/plan/FlightPlanAreaContainer.js

@ -1,29 +1,53 @@
import React, { useEffect, useState } from 'react';
import { useForm } from 'react-hook-form';
import {useHistory} from 'react-router-dom';
import { useDispatch, useSelector } from 'react-redux';
import FlightPlanAreaForm from '../../../../components/basis/flight/plan/FlightPlanAreaForm';
import { Button, Col, Row } from 'reactstrap';
import {Col, Row, Form } from 'reactstrap';
import * as Actions from '../../../../modules/basis/flight/actions/basisFlightAction';
import FlightPlanAreaMap from '../../../../components/basis/flight/plan/FlightPlanAreaMap';
import * as yup from 'yup';
import { yupResolver } from '@hookform/resolvers/yup';
const FlightPlanAreaContainer = () => {
const FlightPlanAreaContainer = (props) => {
const dispatch = useDispatch();
const history = useHistory();
const { areaList } = useSelector(state => state.flightState);
const [airArea, setAirArea] = useState(null);
const validSchema = yup.object().shape({
});
const { register, getValues, setValue, errors, handleSubmit } = useForm({
defaultValues: {
coodinates: [],
radius: '',
altitude_m: '',
altitude_ft: '',
},
resolver: yupResolver(validSchema)
});
const getAriAreaList = () => {
const getAirAreaList = () => {
dispatch(Actions.AREA_LIST.request());
}
const createAirArea = async data => {
dispatch(Actions.FLIGHT_PLAN_AREA.request(data));
props.setModal({ ...props.modal, isOpen: !props.modal.isOpen });
props.setOnSubmit(false);
}
useEffect(() => {
getAriAreaList();
getAirAreaList();
}, []);
useEffect(() => {
setAirArea(areaList);
}, [areaList])
}, [areaList])
return (
<Row>
@ -34,8 +58,14 @@ const FlightPlanAreaContainer = () => {
/>
) : null}
</Col>
<Col md={6} lg={6}>
<FlightPlanAreaForm />
<Col md={6} lg={6}>
<FlightPlanAreaForm
modal={props.modal}
setModal={props.setModal}
data={register}
errors={errors}
submit={handleSubmit(createAirArea)}
/>
</Col>
</Row>

44
src/containers/basis/flight/plan/FlightPlanDetailContainer.js

@ -1,18 +1,38 @@
import React, {useState} from 'react';
import React, {useEffect, useState} from 'react';
import FlightPlanForm from '../../../../components/basis/flight/plan/FlightPlanForm';
import { CustomDetailLayout } from '../../../../components/layout/CustomDetailLayout';
import { FormModal } from '../../../../components/modal/FormModal';
import { FlightPlanAreaModal } from '../../../../components/basis/flight/plan/FlightPlanAreaModal';
import FlightPlanAreaContainer from './FlightPlanAreaContainer';
import {useHistory} from 'react-router-dom';
import { useDispatch, useSelector } from 'react-redux';
import * as yup from 'yup';
import { yupResolver } from '@hookform/resolvers/yup';
import * as Actions from '../../../../modules/basis/flight/actions/basisFlightAction';
import { useForm } from 'react-hook-form';
const FlightPlanDetailContainer = () => {
const dispatch = useDispatch();
const history = useHistory();
const { flightPlanArea } = useSelector(state => state.flightState);
const [areaInfo, setAreaInfo] = useState();
const [modal, setModal] = useState({
isOpen: false,
title: '',
contents: '',
title: '',
});
/* Form Validation Checking */
const validSchema = yup.object().shape({
});
const {} = useForm({
defaultValues: {
coodinates: [],
radius: '',
altitude_m: '',
altitude_ft: '',
},
resolver: yupResolver(validSchema)
})
const saveFlightPlanArea = () => {
console.log('비행 구역 설정 저장');
@ -21,20 +41,24 @@ const FlightPlanDetailContainer = () => {
const openModal = () => {
setModal({
isOpen: true,
title: '비행 구역 설정',
contents: <FlightPlanAreaContainer />
title: '비행 구역 설정',
});
}
useEffect(() => {
setAreaInfo(flightPlanArea);
}, [flightPlanArea]);
return (
<CustomDetailLayout title={"비행 계획 신청서"}>
<FlightPlanForm
openModal={openModal}
areaInfo={areaInfo}
/>
<FormModal
<FlightPlanAreaModal
modal={modal}
save={saveFlightPlanArea}
setModal={setModal}
setModal={setModal}
/>
</CustomDetailLayout>
)

16
src/modules/basis/flight/actions/basisFlightAction.ts

@ -1,6 +1,6 @@
import { AxiosError } from 'axios';
import { createAsyncAction, ActionType} from 'typesafe-actions';
import { FlightAreaData } from '../models/basisFlightModel';
import { FlightAreaData, FlightPlanArea } from '../models/basisFlightModel';
// 공역 조회
@ -8,14 +8,26 @@ const AREA_LIST_REQUEST = 'basis/flight/area/LIST_REQUEST';
const AREA_LIST_SUCCESS = 'basis/flight/area/LIST_SUCCESS';
const AREA_LIST_FAILURE = 'basis/flight/area/LIST_FAILURE';
// 비행 구역 설정
const FLIGHT_PLAN_AREA_REQUEST = 'basis/flight/plan/area/LIST_REQUEST';
const FLIGHT_PLAN_AREA_SUCCESS = 'basis/flight/plan/area/LIST_SUCCESS';
const FLIGHT_PLAN_AREA_FAILURE = 'basis/flight/plan/area/LIST_FAILURE';
export const AREA_LIST = createAsyncAction(
AREA_LIST_REQUEST,
AREA_LIST_SUCCESS,
AREA_LIST_FAILURE
)<FlightAreaData, { data: FlightAreaData }, AxiosError>();
export const FLIGHT_PLAN_AREA = createAsyncAction(
FLIGHT_PLAN_AREA_REQUEST,
FLIGHT_PLAN_AREA_SUCCESS,
FLIGHT_PLAN_AREA_FAILURE
)<FlightPlanArea, { data: FlightPlanArea }, AxiosError>();
const actions = {
AREA_LIST
AREA_LIST,
FLIGHT_PLAN_AREA
};
export type FlightAction = ActionType<typeof actions>;

12
src/modules/basis/flight/models/basisFlightModel.ts

@ -1,11 +1,21 @@
export interface FlightState {
areaList: FlightAreaData | undefined
flightPlanArea: FlightPlanArea | undefined
}
export interface FlightAreaData {
areaList: []
}
export interface FlightPlanArea {
address : '',
coordinates : '',
redius : '',
altitude_m : '',
altitude_ft : '',
}
export const initFlight = {
areaList: undefined
areaList: undefined,
flightPlanArea: undefined
};

8
src/modules/basis/flight/reducers/basisFlightReducer.ts

@ -12,4 +12,10 @@ export const flightReducer = createReducer<FlightState, Actions.FlightAction> (
const {data} = action.payload;
draft.areaList = data;
})
) ;
)
.handleAction(Actions.FLIGHT_PLAN_AREA.request, (state, action) =>
produce(state, draft => {
const data = action.payload;
draft.flightPlanArea = data;
})
)

18
src/modules/basis/flight/sagas/basisFlightSaga.ts

@ -38,6 +38,24 @@ function* listAreaSaga(action: ActionType<typeof Actions.AREA_LIST.request>) {
}
}
function* createFlightPlanArea(action: ActionType<typeof Actions.FLIGHT_PLAN_AREA.request>) {
try {
const data = action.payload;
yield put(
Actions.FLIGHT_PLAN_AREA.success({
data: data
})
)
} catch (error: any) {
yield put(
Actions.FLIGHT_PLAN_AREA.failure(error)
)
}
}
export function* flightSaga() {
yield takeEvery(Actions.AREA_LIST.request, listAreaSaga);
yield takeEvery(Actions.FLIGHT_PLAN_AREA.request, createFlightPlanArea);
}

63
src/views/testDraw/main/ControlMainDraw.js

@ -1,12 +1,8 @@
import React, { useEffect, useState } from 'react';
import '../../../assets/css/custom.css';
import logo from '../../../assets/images/pal_logo.png';
import { Sun, Map, Bell, Check } 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';
@ -99,45 +95,54 @@ const ControlMainDraw = () => {
</button>
</li>
</ul>
{/* pathDraw Test */}
{/* 네이버 그리기 도구모음 */}
<ul className='left-menu-nav'>
<li>
<CustomInput
id='circle'
id='check'
type='button'
className='check'
onClick={e => handlerDrawType('CIRCLE')}
value={mapControl.drawType === 'CIRCLE' ? 'check' : 'CIRCLE'}
onClick={e => handlerDrawCheck(!mapControl.drawCheck)}
value={mapControl.drawCheck === true ? 'IN USE' : 'STOP'}
/>
</li>
</ul>
{/* 제이쿼리로 그리기(기능 연결 중) */}
{/* <ul className='left-menu-nav'>
<li className='test'>
<CustomInput
id='line'
type='button'
className='check'
id='test'
type='image'
className={mapControl.drawType === 'LINE' ? 'btn-use' : 'btn-stop'}
src='http://static.naver.net/maps/mantle/drawing/1x/polyline.png'
onClick={e => handlerDrawType('LINE')}
value={mapControl.drawType === 'LINE' ? 'check' : 'LINE'}
/><br/>
/>
<CustomInput
id='test'
type='image'
className={mapControl.drawType === 'POLYGON' ? 'btn-use' : 'btn-stop'}
src='http://static.naver.net/maps/mantle/drawing/1x/polygon.png'
onClick={e => handlerDrawType('POLYGON')}
/>
<CustomInput
id='test'
type='image'
className={mapControl.drawType === 'CIRCLE' ? 'btn-use' : 'btn-stop'}
src='http://static.naver.net/maps/mantle/drawing/1x/ellipse.png'
onClick={e => handlerDrawType('CIRCLE')}
/>
<CustomInput
id='none'
type='button'
className='check'
onClick={e => handlerDrawType('')}
value={mapControl.drawType === '' ? 'check' : 'X'}
/>
</li>
</ul>
<ul className='left-menu-nav'>
<li>
<CustomInput
id='check'
type='button'
className='check'
onClick={e => handlerDrawCheck(!mapControl.drawCheck)}
value={mapControl.drawCheck === true ? 'IN USE' : 'STOP'}
/>
value={mapControl.drawType === '' ? 'STOP' : 'IN USE'}
/>
</li>
</ul>
</ul> */}
<ul className='left-menu-footer'>
<li>

Loading…
Cancel
Save