Compare commits

...

7 Commits

Author SHA1 Message Date
junh_eee(이준희) ca450f2a18 . 2 years ago
junh_eee(이준희) 710186424f 지도 projection 변경 2 years ago
junh_eee(이준희) 7f9b30ccc2 라이브러리 추가 2 years ago
junh_eee(이준희) 365dceb484 연결화면 모달 2 years ago
junh_eee(이준희) 36c0aa7550 Reducer, Action 생성 및 수정 2 years ago
junh_eee(이준희) 039340c59c 비행구역 draw 기능 옮기기 2 years ago
junh_eee(이준희) 642fcdb857 branch test 2 years ago
  1. 15
      package-lock.json
  2. 1
      package.json
  3. 1
      src/assets/css/custom.css
  4. 206
      src/components/basis/flight/plan/FlightPlanAreaDetailForm.js
  5. 40
      src/components/basis/flight/plan/FlightPlanAreaDetailModal.js
  6. 138
      src/components/basis/flight/plan/FlightPlanAreaMap.js
  7. 32
      src/components/basis/flight/plan/FlightPlanAreaModal.js
  8. 75
      src/components/basis/flight/plan/FlightPlanForm.js
  9. 652
      src/components/map/naver/draw/FlightPlanDraw.js
  10. 719
      src/components/map/naver/draw/FlightPlanDrawTest.js
  11. 71
      src/containers/basis/flight/plan/FlightPlanAreaContainer.js
  12. 45
      src/containers/basis/flight/plan/FlightPlanAreaDetailContainer.js
  13. 16
      src/containers/basis/flight/plan/FlightPlanDetailContainer.js
  14. 33
      src/modules/basis/flight/actions/basisFlightDrawAction.ts
  15. 59
      src/modules/basis/flight/reducers/basisFlightDrawReducer.ts
  16. 7
      src/modules/control/map/reducers/controlMapReducer.ts
  17. 4
      src/redux/reducers/rootReducer.ts

15
package-lock.json generated

@ -3680,6 +3680,15 @@
"resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
"integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4="
},
"@types/jsts": {
"version": "0.17.12",
"resolved": "https://registry.npmjs.org/@types/jsts/-/jsts-0.17.12.tgz",
"integrity": "sha512-CVRlGD914G8Lce/r6PBDCNX5KSfdI5ZXCJ4cefy09/5gZBMEy3rcv5prjJuSHusfDaKMnqWc9Asz4I08q/YrAQ==",
"dev": true,
"requires": {
"@types/openlayers": "*"
}
},
"@types/lodash": {
"version": "4.14.170",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.170.tgz",
@ -3700,6 +3709,12 @@
"resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz",
"integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA=="
},
"@types/openlayers": {
"version": "4.6.18",
"resolved": "https://registry.npmjs.org/@types/openlayers/-/openlayers-4.6.18.tgz",
"integrity": "sha512-srqcI4chyzzs11ZhYpnZqT6Lh1v/O5EXh+pPENDtAwhE7CM31h+JsGomt+ioGhuNVJ96Jl4UkHR1Lllb/XrQAA==",
"dev": true
},
"@types/parse-json": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",

1
package.json

@ -126,6 +126,7 @@
"extends": "react-app"
},
"devDependencies": {
"@types/jsts": "^0.17.12",
"@types/sortablejs": "^1.10.6",
"@typescript-eslint/eslint-plugin": "^4.28.1",
"@typescript-eslint/parser": "^4.28.1",

1
src/assets/css/custom.css

@ -250,6 +250,7 @@ h1.logo span{display:block;color:#f4f4f4;font-weight:bold;letter-spacing:2px;fon
.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;}
.area-button{position:relative; z-index:100; margin-top:10px; margin-left:10px;}
.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;}

206
src/components/basis/flight/plan/FlightPlanAreaDetailForm.js

@ -0,0 +1,206 @@
import React, { useEffect, useState } from 'react';
import {
Card,
CardBody,
Col,
FormGroup,
Input,
Label,
Row,
Button
} from 'reactstrap';
import { useDispatch, useSelector } from 'react-redux';
import { FeatureAirZone } from '../../../map/naver/feature/FeatureAirZone';
import { FlightPlanDraw } from '../../../map/naver/draw/FlightPlanDraw';
import { drawTypeChangeAction, drawCheckAction } from '../../../../modules/control/map/actions/controlMapActions';
import { FlightPlanDrawTest } from '../../../map/naver/draw/FlightPlanDrawTest';
const FlightPlanAreaDetailForm = (props) => {
const dispatch = useDispatch();
const naver = window.naver;
// const airArea = props.airArea;
const mapControl = useSelector(state => state.controlMapReducer);
const [map, setMap] = useState();
const [isMapLoad, setIsMapLoad] = useState(false);
const [mode, setMode] = useState();
// useEffect(() => {
// setIsMapLoad(true);
// }, [airArea]);
// useEffect(() => {
// ModeInit();
// }, [mapControl.drawType])
// const ModeInit = () => {
// setMode(mapControl.drawType)
// }
return (
// <Card className='mb-0'>
<Row>
<Col sm='12'>
<Card>
<CardBody className='pt-2 card-body-tab-cont'>
<Row>
<Col>
<Card>
<CardBody className='pal-card-body'>
<div className='search-cont search-info pd-0'>
<div className='cont-ti mb-1 d-flex justify-content-between align-items-sm-center align-items-start flex-sm-row'>
<div>
<h4>비행 구역 상세 정보</h4>
</div>
</div>
<dl>
<dt>
<div className='search-info-ti d-flex justify-content-between'>
<h4>좌표</h4>
</div>
<div className='search-info-box'>
<Row>
<Col className='list-input' lg={4} md={6} sm={12}>
<FormGroup>
<Label for='test'><span className='necessary'>*</span>1</Label>
<Input
type='text'
id='coord'
name='coord'
bsSize='sm'
placeholdeer=''
readOnly
/>
</FormGroup>
</Col>
<Col className='list-input' lg={4} md={6} sm={12}>
<FormGroup>
<Label for='test'><span className='necessary'>*</span>2</Label>
<Input
type='text'
id='coord'
name='coord'
bsSize='sm'
placeholdeer=''
readOnly
/>
</FormGroup>
</Col>
</Row>
</div>
<div className='search-info-box'>
<Row>
<Col className='list-input' lg={4} md={6} sm={12}>
<FormGroup>
<Label for='test'><span className='necessary'>*</span>3</Label>
<Input
type='text'
id='coord'
name='coord'
bsSize='sm'
placeholdeer=''
readOnly
/>
</FormGroup>
</Col>
<Col className='list-input' lg={4} md={6} sm={12}>
<FormGroup>
<Label for='test'><span className='necessary'>*</span>4</Label>
<Input
type='text'
id='coord'
name='coord'
bsSize='sm'
placeholdeer=''
readOnly
/>
</FormGroup>
</Col>
</Row>
</div>
</dt>
<dt>
<div className='search-info-ti d-flex justify-content-between'>
<h4>기타정보</h4>
</div>
<div className='search-info-box'>
<Row>
<Col className='list-input' lg={5} md={7} sm={12}>
<FormGroup className='m_ft'>
<div className='m_ft_box'>
<Label for='test'>
<span className='necessary'>*</span> 반경 / 고도
</Label>
<Input
type='text'
id='ownerNm'
name='ownerNm'
bsSize='sm'
placeholder='반경'
readOnly
/>
</div>
<div className='m_ft_box'>
<Input
type='text'
id='ownerNm'
name='ownerNm'
bsSize='sm'
placeholder='고도'
readOnly
/>
</div>
</FormGroup>
</Col>
<Col className='list-input' lg={4} md={6} sm={12}>
<FormGroup>
<Label for='test'><span className='necessary'>*</span></Label>
<Input
type='text'
id='ownerNm'
name='ownerNm'
bsSize='sm'
placeholder=''
readOnly
/>
</FormGroup>
</Col>
</Row>
</div>
</dt>
</dl>
</div>
<div className='d-flex align-items-center mt-2'>
<Button.Ripple
type='submit'
className='mr-1'
color='primary'
>
등록
</Button.Ripple>
<Button.Ripple
className='mr-1'
color='primary'
>
닫기
</Button.Ripple>
</div>
</CardBody>
</Card>
</Col>
</Row>
</CardBody>
</Card>
</Col>
</Row>
)
}
export default FlightPlanAreaDetailForm;

40
src/components/basis/flight/plan/FlightPlanAreaDetailModal.js

@ -0,0 +1,40 @@
import { useEffect, useState } from 'react';
import { Modal, ModalHeader, ModalBody } from 'reactstrap';
import FlightPlanAreaDetailContainer from '../../../../containers/basis/flight/plan/FlightPlanAreaDetailContainer';
export const FlightPlanAreaDetailModal = props => {
const [onSubmit, setOnSubmit] = useState(false);
useEffect(() => {
console.log('비행구역 상세정보 모달')
}, [])
return (
<div className='vertically-centered-modal'>
<Modal
isOpen={props.modal.isOpen}
// toggle={() =>
// props.setModal({ ...props.modal, isOpen: !props.modal.isOpen })
// }
className='modal-dialog-centered modal-xl'
>
<ModalHeader
toggle={() =>
props.setModal({ ...props.modal, isOpen: !props.modal.isOpen })
}
>
{props.modal.title}
</ModalHeader>
<ModalBody>
<FlightPlanAreaDetailContainer
modal={props.modal}
setModal={props.setModal}
onSubmit={onSubmit}
setOnSubmit={setOnSubmit}
/>
</ModalBody>
</Modal>
</div>
);
};

138
src/components/basis/flight/plan/FlightPlanAreaMap.js

@ -4,38 +4,97 @@ import {
CardBody,
Button
} from 'reactstrap';
import { useDispatch, useSelector } from 'react-redux';
import { FeatureAirZone } from '../../../map/naver/feature/FeatureAirZone';
import { drawTypeChangeAction, drawCheckAction } from '../../../../modules/control/map/actions/controlMapActions';
import { FlightPlanDrawTest } from '../../../map/naver/draw/FlightPlanDrawTest';
const FlightPlanAreaMap = (props) => {
const dispatch = useDispatch();
const naver = window.naver;
const airArea = props.airArea;
const openModal = props.openModal;
const mapControl = useSelector(state => state.controlMapReducer);
const [map, setMap] = useState();
const [isMapLoad, setIsMapLoad] = useState(false);
const [mode, setMode] = useState();
useEffect(() => {
NaverMapInit();
NaverMapInit();
}, []);
useEffect(() => {
setIsMapLoad(true);
setIsMapLoad(true);
}, [airArea]);
useEffect(() => {
ModeInit();
}, [mapControl.drawType])
const ModeInit = () => {
setMode(mapControl.drawType)
}
const NaverMapInit = () => {
const mapOptions = {
center: new naver.maps.LatLng(36.56793936069445, 127.85101412107547),
zoom: 10,
// center: new naver.maps.LatLng(36.56793936069445, 127.85101412107547),
center: new naver.maps.LatLng(37.520357, 126.610166),
// zoom: 10,
zoom:15,
zoomControl: true,
mapTypeId: naver.maps.MapTypeId.HYBRID,
mapTypeId: naver.maps.MapTypeId.NORMAL,
zoomControlOptions: {
position: naver.maps.Position.TOP_LEFT,
position: naver.maps.Position.LEFT_CENTER,
style: naver.maps.ZoomControlStyle.SMALL
}
};
setMap(new naver.maps.Map('map', mapOptions));
setMap(new naver.maps.Map('map', mapOptions));
// const mapOptions = {
// center: new naver.maps.LatLng(37.520357, 126.610166),
// zoom: 15,
// zoomControl: true,
// zoomControlOptions: {
// position: naver.maps.Position.LEFT_CENTER,
// style: naver.maps.ZoomControlStyle.SMALL
// },
// mapTypeControl: true,
// mapTypeControlOptions: {
// style: naver.maps.MapTypeControlStyle.DROPDOWN
// }
// }
// const openStreetMapType = new naver.maps.ImageMapType({
// name: 'OSM',
// minZoom: 0,
// maxZoom: 19,
// tileSize: new naver.maps.Size(256, 256),
// projection: naver.maps.EPSG3857,
// repeatX: true,
// tileSet: "https://c.tile.openstreetmap.org/{z}/{x}/{y}.png",
// provider: [{
// title: " /OpenStreetMap", // 출처 표기는 이미지 제공처의 정책을 따라야 합니다.
// link: "http://www.openstreetmap.org/copyright"
// }]
// })
// const map = new naver.maps.Map('map', mapOptions);
// map.mapTypes.set('osm', openStreetMapType);
// map.setMapTypeId('osm');
// setMap(map);
};
const handlerDrawType = val => {
dispatch(drawTypeChangeAction(val));
};
const handlerDrawCheck = val => {
dispatch(drawCheckAction(val));
};
return (
<Card className='mb-0'>
@ -48,27 +107,64 @@ const FlightPlanAreaMap = (props) => {
</div>
</div>
<div id="map" style={{ width: '100%', height: '50vh'}}></div>
<div style={{position:'relative'}}>
<div id="map" style={{ width: '100%', height: '60vh', position: 'absoulte'}}>
<FlightPlanDrawTest
map = {map}
naver = {naver}
mode = {mode}
openModal={openModal}
/>
<Button.Ripple
color='primary'
className='area-button'
onClick = {props.openModal}
>
확인
</Button.Ripple>
<Button.Ripple
color='primary'
className='area-button'
onClick={e => handlerDrawType('RESET')}
>
초기화
</Button.Ripple>
<Button.Ripple
color='primary'
className='area-button'
>
적용
</Button.Ripple>
</div>
</div>
{isMapLoad ? (
<FeatureAirZone map={map} naver={naver} features={airArea.features} />
) : null}
<div className='d-flex align-items-center mt-2'>
<Button.Ripple
className='mr-1'
color='primary'
>
Line
</Button.Ripple>
<Button.Ripple
color='primary'
>
Circle
</Button.Ripple>
<Button.Ripple
className='mr-1'
color='primary'
onClick={e => handlerDrawType('LINE')}
>
WayPoint
</Button.Ripple>
<Button.Ripple
className='mr-1'
color='primary'
onClick={e => handlerDrawType('CIRCLE')}
>
Circle
</Button.Ripple>
<Button.Ripple
color='primary'
onClick={e => handlerDrawType('POLYGON')}
>
Polygon
</Button.Ripple>
</div>
</CardBody>
</Card>

32
src/components/basis/flight/plan/FlightPlanAreaModal.js

@ -1,4 +1,4 @@
import { useState } from 'react';
import { useEffect, useState } from 'react';
import { Button, Modal, ModalHeader, ModalBody, ModalFooter } from 'reactstrap';
import FlightPlanAreaContainer from '../../../../containers/basis/flight/plan/FlightPlanAreaContainer';
@ -6,13 +6,18 @@ export const FlightPlanAreaModal = props => {
const [onSubmit, setOnSubmit] = useState(false);
useEffect(() => {
console.log('비행구역설정 모달')
}, [])
return (
<div className='vertically-centered-modal'>
<Modal
isOpen={props.modal.isOpen}
toggle={() =>
props.setModal({ ...props.modal, isOpen: !props.modal.isOpen })
}
//없어도 문제되는거 없는더 왜 있지
// toggle={() =>
// props.setModal({ ...props.modal, isOpen: !props.modal.isOpen })
// }
className='modal-dialog-centered modal-xl'
>
<ModalHeader
@ -26,23 +31,10 @@ export const FlightPlanAreaModal = props => {
<FlightPlanAreaContainer
modal={props.modal}
setModal={props.setModal}
onSubmit={onSubmit}
setOnSubmit={setOnSubmit}
/>
// onSubmit={onSubmit}
// setOnSubmit={setOnSubmit}
/>
</ModalBody>
{/* <ModalFooter>
<Button
type="submit"
color='primary'
// onClick={() =>
// // props.setModal({ ...props.modal, isOpen: !props.modal.isOpen })
// setOnSubmit(true)
// }
outline
>
저장
</Button>
</ModalFooter> */}
</Modal>
</div>
);

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

@ -49,7 +49,8 @@ const FlightPlanForm = (props) => {
type='text'
id='applicantNm'
name='applicantNm'
size='sm'
// size='sm'
bsSize='sm'
// innerRef={props.data}
placeholder=''
/>
@ -62,7 +63,8 @@ const FlightPlanForm = (props) => {
type='text'
id='applicantBirthDt'
name='applicantBirthDt'
size='sm'
// size='sm'
bsSize='sm'
// innerRef={props.data}
placeholder=''
/>
@ -79,7 +81,8 @@ const FlightPlanForm = (props) => {
type='text'
id='applicantPhone'
name='applicantPhone'
size='sm'
// size='sm'
bsSize='sm'
// innerRef={props.data}
placeholder=''
/>
@ -92,7 +95,8 @@ const FlightPlanForm = (props) => {
type='text'
id='applicantPhone'
name='applicantPhone'
size='sm'
// size='sm'
bsSize='sm'
// innerRef={props.data}
placeholder=''
/>
@ -145,7 +149,8 @@ const FlightPlanForm = (props) => {
<Label for='test'>
<span className='necessary'>*</span>
</Label>
<Flatpickr size='sm' className='form-control calendar-flat' />
{/* <Flatpickr size='sm' className='form-control calendar-flat' /> */}
<Flatpickr bsSize='sm' className='form-control calendar-flat' />
</FormGroup>
</Col>
<Col className='list-input' lg={4} md={6} sm={12}>
@ -153,7 +158,8 @@ const FlightPlanForm = (props) => {
<Label for='test'>
<span className='necessary'>*</span>
</Label>
<Flatpickr size='sm' className='form-control calendar-flat' />
{/* <Flatpickr size='sm' className='form-control calendar-flat' /> */}
<Flatpickr bsSize='sm' className='form-control calendar-flat' />
</FormGroup>
</Col>
<Col className='list-input' lg={4} md={6} sm={12}>
@ -165,7 +171,8 @@ const FlightPlanForm = (props) => {
type='select'
name='arcrftTypeCd'
id='arcrftTypeCd'
size='sm'
// size='sm'
bsSize='sm'
// innerRef={props.data}
// className={classnames({
// 'is-invalid': props.errors.arcrftTypeCd
@ -276,7 +283,8 @@ const FlightPlanForm = (props) => {
type='text'
id='ownerNm'
name='ownerNm'
size='sm'
// size='sm'
bsSize='sm'
placeholder=''
readOnly
/>
@ -292,7 +300,8 @@ const FlightPlanForm = (props) => {
type='text'
id='ownerNm'
name='ownerNm'
size='sm'
// size='sm'
bsSize='sm'
placeholder='반경'
readOnly
/>
@ -302,7 +311,8 @@ const FlightPlanForm = (props) => {
type='text'
id='ownerNm'
name='ownerNm'
size='sm'
// size='sm'
bsSize='sm'
placeholder='고도'
readOnly
/>
@ -322,7 +332,8 @@ const FlightPlanForm = (props) => {
type='text'
id='ownerNm'
name='ownerNm'
size='sm'
// size='sm'
bsSize='sm'
placeholder=''
readOnly
/>
@ -337,7 +348,8 @@ const FlightPlanForm = (props) => {
type='text'
id='ownerNm'
name='ownerNm'
size='sm'
// size='sm'
bsSize='sm'
placeholder=''
readOnly
/>
@ -352,7 +364,8 @@ const FlightPlanForm = (props) => {
type='text'
id='ownerNm'
name='ownerNm'
size='sm'
// size='sm'
bsSize='sm'
placeholder=''
readOnly
/>
@ -383,7 +396,8 @@ const FlightPlanForm = (props) => {
type='text'
id='ownerNm'
name='ownerNm'
size='sm'
// size='sm'
bsSize='sm'
placeholder=''
readOnly
/>
@ -398,7 +412,8 @@ const FlightPlanForm = (props) => {
type='text'
id='ownerNm'
name='ownerNm'
size='sm'
// size='sm'
bsSize='sm'
placeholder=''
readOnly
/>
@ -418,7 +433,8 @@ const FlightPlanForm = (props) => {
type='text'
id='ownerNm'
name='ownerNm'
size='sm'
// size='sm'
bsSize='sm'
placeholder='+82'
readOnly
/>
@ -428,7 +444,8 @@ const FlightPlanForm = (props) => {
type='text'
id='ownerNm'
name='ownerNm'
size='sm'
// size='sm'
bsSize='sm'
placeholder='010-0000-0000'
readOnly
@ -445,7 +462,8 @@ const FlightPlanForm = (props) => {
type='text'
id='ownerNm'
name='ownerNm'
size='sm'
// size='sm'
bsSize='sm'
placeholder=''
readOnly
/>
@ -475,7 +493,8 @@ const FlightPlanForm = (props) => {
type='text'
id='ownerNm'
name='ownerNm'
size='sm'
// size='sm'
bsSize='sm'
placeholder=''
readOnly
/>
@ -490,7 +509,8 @@ const FlightPlanForm = (props) => {
type='text'
id='ownerNm'
name='ownerNm'
size='sm'
// size='sm'
bsSize='sm'
placeholder=''
readOnly
/>
@ -509,7 +529,8 @@ const FlightPlanForm = (props) => {
type='text'
id='ownerNm'
name='ownerNm'
size='sm'
// size='sm'
bsSize='sm'
placeholder=''
readOnly
/>
@ -525,7 +546,8 @@ const FlightPlanForm = (props) => {
type='text'
id='ownerNm'
name='ownerNm'
size='sm'
// size='sm'
bsSize='sm'
placeholder='m'
readOnly
/>
@ -535,7 +557,8 @@ const FlightPlanForm = (props) => {
type='text'
id='ownerNm'
name='ownerNm'
size='sm'
// size='sm'
bsSize='sm'
placeholder='ft'
readOnly
/>
@ -551,7 +574,8 @@ const FlightPlanForm = (props) => {
<Button.Ripple
className='mr-1'
color='primary'
size='sm'
// size='sm'
bsSize='sm'
// onClick={
// pageType === 'create'
// ? handleSubmit(handlerCreate)
@ -562,7 +586,8 @@ const FlightPlanForm = (props) => {
</Button.Ripple>
<Button.Ripple
color='danger'
size='sm'
// size='sm'
bsSize='sm'
// onClick={handlerDelete}
>
삭제

652
src/components/map/naver/draw/FlightPlanDraw.js

@ -0,0 +1,652 @@
import $ from 'jquery';
import '../../../../assets/css/custom.css';
import { CustomInput } from 'reactstrap';
import buffer from '@turf/buffer'
export const FlightPlanDraw = props => {
const {naver} = props;
const {map} = props;
var Measure = function(buttons) {
this.$btnLine = buttons.line;
this.$btnPolygon = buttons.polygon;
this.$btnCircle = buttons.circle;
this.$btnRectangle = buttons.rectangle;
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();
} if (mode === 'rectangle') {
this._startRectangle();
}
},
_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))
];
},
_startRectangle: function() {
console.log('startRectangle')
var map = this.map;
this._rectangleListeners = [
naver.maps.Event.addListener(map, 'click', this._onClickRectangle.bind(this)),
naver.maps.Event.addListener(map, 'rightclick', this._finishRectangle.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()._array, 'path')
let polypaths = this._polyline.getPath()._array;
//파싱
let polypathJSON = new Array();
for(let i = 0; i< polypaths.length; i++) {
//파싱
let obj = new Object();
obj.x = '' + polypaths[i]._lng + '';
obj.y = '' + polypaths[i]._lat + '';
obj = JSON.stringify(obj);
polypathJSON.push(JSON.parse(obj));
}
console.log(polypathJSON, 'json polyline path')
//버퍼 생성에 필요한 coordinates 배열 변환
let lineStringPaths = [];
for(let i = 0; i < this._polyline.getPath().length; i++) {
lineStringPaths.push([this._polyline.getPath()._array[i].x, this._polyline.getPath()._array[i].y]);
}
console.log(lineStringPaths, 'polyline path')
//버퍼 생성을 위한 line 객체
const originalGeojson = {
type: "FeatureCollection",
features: [
{
type: "Feature",
properties: {},
geometry: {
type: "LineString",
coordinates: lineStringPaths
}
}
]
};
console.log(originalGeojson)
//버퍼 객체
const bufferObj = buffer(originalGeojson, 50, {units:'meters'});
//버퍼 라인 생성
let bufferPath = bufferObj.features[0].geometry.coordinates[0];
console.log(bufferPath, 'buffer path')
this.bufferPolyline = new naver.maps.Polyline({
strokeColor: '#ff0000',
strokeWeight: 2,
strokeStyle: [4, 4],
strokeOpacity: 0.6,
path : bufferPath,
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;
},
_finishRectangle: function() {
console.log('finishRectangle')
naver.maps.Event.removeListener(this._rectangleListeners);
delete this._rectangleListeners;
$(document).off('mousemove.measure');
if(this._rectangle) {
this._guiderectangle.setMap(null);
delete this._guiderectangle;
}
this.$btnRectangle.removeClass('control-on').blur();
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();
} if (mode === 'rectangle') {
this._finishRectangle();
}
},
_fromMetersToText: function(meters) {
meters = meters || 0;
var km = 1000,
text = meters;
if(meters >= km) {
text = parseFloat((meters / km).toFixed(1)) + 'km';
} else {
text = parseFloat(meters.toFixed(1)) + 'm';
}
return text;
},
_addMileStone: function(coord, text, css) {
if(!this._ms) this._ms = [];
let content;
if(text == 'Start') {
content = '<div style="display:inline-block;padding:5px;text-align:center;background-color:#fff;border:1px solid #000;font-size:14px;color:#ff0000;"><span>'+ text +'</span></div>'
} else {
content = '<div style="display:inline-block;padding:5px;text-align:center;background-color:#fff;border:1px solid #000;color:#737373;"><span>'+ text +'</span></div>'
}
var ms = new naver.maps.Marker({
position: coord,
icon: {
content: content,
anchor: new naver.maps.Point(-5, -5)
},
map: this.map
});
var msElement = $(ms.getElement());
if(css) {
msElement.css(css);
} else {
msElement.css('font-size', '13px');
}
this._ms.push(ms);
},
_onClickDistance: function(e) {
console.log('onClickDistance')
var map = this.map,
coord = e.coord;
if (!this._polyline) {
// 임시로 보여줄 점선 폴리라인을 생성합니다.
this._guideline = new naver.maps.Polyline({
strokeColor: '#0000ff',
strokeWeight: 3,
strokeStyle: [4, 4],
strokeOpacity: 0.2,
path: [coord],
map: map
});
// this._lastDistance = this._guideline.getDistance();
$(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: '#0000ff',
strokeWeight: 3,
strokeOpacity: 0.6,
path: [coord],
map: map
});
this._lastDistance = this._polyline.getDistance();
this._addMileStone(coord, 'Start');
} else {
this._guideline.setPath([e.coord]);
this._polyline.getPath().push(coord);
var distance = this._polyline.getDistance();
this._addMileStone(coord, this._fromMetersToText(distance - this._lastDistance));
this._lastDistance = distance;
}
},
_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();
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({
strokeOpacity: 0.8,
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({
strokeStyle: [4, 4],
strokeOpacity: 0.6,
path: [coord],
map: map
});
this._lastDistance = this._radius.getDistance();
// 임시로 보여줄 원형
this._guidecircle = new naver.maps.Circle({
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({
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);
},
_onClickRectangle: function(e) {
console.log('onClickRectangle')
var map = this.map,
coord = e.coord;
this.max_x = 0;
this.max_y = 0;
if(!this._rectangle) {
//min = 고정값
this.fixed = coord;
this.min = [this.fixed.x, this.fixed.y];
this.max = [this.max_x, this.max_y];
this.boundscoord = [this.min[0], this.min[1], this.min[0], this.min[1]];
// 임시로 보여줄 사각형
this._guiderectangle = new naver.maps.Rectangle({
strokeStyle: [4, 4],
strokeOpacity: 0.6,
bounds: this.boundscoord,
map: map
});
$(document).on('mousemove.measure', this._onMouseMoveRectangle.bind(this));
this._rectangleListeners.push(naver.maps.Event.addListener(map, 'rightclick', this._finishRectangle.bind(this)));
//실제 사용되는 사각형
this._rectangle = new naver.maps.Rectangle({
strokeOpacity: 0.8,
fillColor: '#0000ff',
fillOpacity: 0.1,
bounds: this.boundscoord,
map: map
});
} else {
this.max = [coord.x, coord.y];
this.boundscoord = [this.min[0], this.min[1], this.max[0], this.max[1]];
this._rectangle.setBounds(this.boundscoord);
}
},
_onMouseMoveRectangle: function(e) {
console.log('onMouseMoveRectangle')
if(!this._rectangle) return;
var map = this.map,
proj = this.map.getProjection(),
coord = proj.fromPageXYToCoord(new naver.maps.Point(e.pageX, e.pageY)),
bounds = this._guiderectangle.getBounds(),
max = [coord.x, coord.y];
this.boundscoord = [this.min[0], this.min[1],max[0], max[1]];
this._guiderectangle.setBounds(this.boundscoord);
},
_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'));
this.$btnRectangle.on('click.measure', this._onClickButton.bind(this, 'rectangle'));
},
_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 === 'rectangle') {
if(this._rectangle) {
this._rectangle.setMap(null);
delete this._rectangle;
}
}
}
});
// id랑 매치시켜서 옵션 지정함
var measures = new Measure({
line: $('#line'),
polygon: $('#polygon'),
circle: $('#circle'),
rectangle: $('#rectangle')
});
measures.setMap(map);
return(
<>
<div style={{ position: 'relative' }}>
<ul className="measure-control">
<li>
<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'
/>
<CustomInput
id='rectangle'
type='image'
className='control-btn'
src='http://static.naver.net/maps/mantle/drawing/1x/rectangle.png'
/>
</li>
</ul>
</div>
</>
)
}

719
src/components/map/naver/draw/FlightPlanDrawTest.js

@ -0,0 +1,719 @@
import $ from 'jquery';
import buffer from '@turf/buffer'
import { useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { drawTypeChangeAction } from '../../../../modules/control/map/actions/controlMapActions';
import GeoJSONReader from 'jsts/org/locationtech/jts/io/GeoJSONReader';
import GeometryFactory from 'jsts/org/locationtech/jts/geom/GeometryFactory';
import {BufferOp} from 'jsts/org/locationtech/jts/operation/buffer';
import {DistanceOp} from 'jsts/org/locationtech/jts/operation/distance/DistanceOp';
import JSTSWKTReader from 'jsts/org/locationtech/jts/io/WKTReader';
import GeoJSONWriter from 'jsts/org/locationtech/jts/io/GeoJSONWriter';
import JSTSBufferOp from 'jsts/org/locationtech/jts/operation/buffer/BufferOp'
import JSTSBufferParameter from 'jsts/org/locationtech/jts/operation/buffer/BufferParameters';
export const FlightPlanDrawTest = props => {
const dispatch = useDispatch();
const mapControl = useSelector(state => state.controlMapReducer);
const draw = useSelector(state => state.basisFlightDrawReducer);
const [pastPolyline, setPolyline] = useState();
const [pastBuffer, setBuffer] = useState();
const [pastPolygon, setPolygon] = useState();
const [pastCircle, setCircle] = useState();
const [pastEve, setEve] = useState();
const [pastDragCircle, setDragCircle] = useState([]);
const naver = props.naver;
const map = props.map;
const openModal = props.openModal;
let mode = props.mode;
let areaInfo;
let lastDistance;
let polyline;
let guideline;
let bufferPolyline;
let polygon;
let circle;
let radiusline;
let Eve = {
clickEve: '',
mousedownEve: '',
rightclickEve: ''
}
let dragCircle = [];
let dragCircleEve = [];
let check;
useEffect(() => {
drawInit();
}, [mapControl.drawType])
const handlerDrawType = val => {
dispatch(drawTypeChangeAction(val));
};
// useEffect(() => {
// onClickCheck();
// }, [mapControl.drawCheck])
const zoomChange = () => {
let change;
if(change) {
naver.maps.Event.removeListener(change);
} else {
change = naver.maps.Event.addListener(map, 'zoom_changed', function() {
if(dragCircle) {
// dragCircle.forEach(prev => prev.setRadius(map._mapOptions.zoom + 5));
// dragCircle.forEach(prev => prev.setRadius(prev.getRadius() * 1.25));
}
})
}
}
const drawInit = () => {
if(mapControl.drawType==='LINE') {
onClickButton('LINE');
} else if(mapControl.drawType==='CIRCLE') {
onClickButton('CIRCLE');
} else if(mapControl.drawType==='POLYGON') {
onClickButton('POLYGON');
} else if(mapControl.drawType==='RESET') {
onClickButton('RESET')
}
}
const onClickButton = (newMode) => {
console.log('onClickButton');
zoomChange();
clearMode(mode);
if(mode === newMode) {
mode = null;
return;
}
mode = newMode;
startMode(newMode);
}
const clearMode = (mode) => {
console.log('clearMode')
if(!mode) return;
if (mode === 'LINE') {
if(pastPolyline) {
pastPolyline.setMap(null);
setPolyline();
pastBuffer.setMap(null);
setBuffer();
pastDragCircle.forEach(prev => prev.setMap(null));
setDragCircle([]);
}
} else if(mode === 'POLYGON') {
if(pastPolygon) {
pastPolygon.setMap(null);
setPolygon();
pastDragCircle.forEach(prev => prev.setMap(null));
setDragCircle([]);
}
} else if(mode === 'CIRCLE') {
if(pastCircle) {
pastCircle.setMap(null);
setCircle();
naver.maps.Event.removeListener(pastEve);
}
}
finishDraw();
}
const startMode = (mode) => {
console.log('startMode')
console.log(polyline, 'polyline', pastPolyline, 'pastPolyline');
console.log(polygon, 'polygon', pastPolygon, 'pastPolygon');
console.log(circle, 'circle', pastCircle, 'pastCircle');
if (!mode) return;
if (mode === 'LINE') {
Eve.clickEve = naver.maps.Event.addListener(map, 'click', function(e) { onClickPolyline(e) });
} else if (mode === 'POLYGON') {
Eve.clickEve = naver.maps.Event.addListener(map, 'click', function(e) { onClickPolygon(e) });
} else if (mode === 'CIRCLE') {
setEve(naver.maps.Event.addListener(map, 'click', function(e) { onClickCircle(e) }))
}
}
const removeListener = () => {
console.log('removeListener')
naver.maps.Event.removeListener(Eve.clickEve);
naver.maps.Event.removeListener(Eve.mousedownEve);
naver.maps.Event.removeListener(Eve.rightclickEve);
if(!circle) $(document).off('mousemove.measure');
// if(pastCircle) naver.maps.Event.removeListener(pastEve);
naver.maps.Event.removeListener(pastEve);
}
const finishDraw = () => {
console.log('finishDraw')
removeListener();
if(polyline) {
let polypaths = polyline.getPath()._array;
if(guideline) {
guideline.setMap(null);
guideline = '';
}
if(polypaths.length >= 2) {
//꼭짓점 circle 생성
for(let index = 0; index < polypaths.length; index++) {
dragCircle.push(
new naver.maps.Circle({
strokeOpacity: 1,
strokeColor: '#000000',
fillColor: '#ffffff',
fillOpacity: 1,
center: polypaths[index],
radius: 10,
map: map,
clickable: true
})
)
dragCircleEve.push(naver.maps.Event.addListener(dragCircle[index], 'mousedown', function() { onMouseDownDrag(index) }))
}
setDragCircle(dragCircle);
//파싱
let polypathJSON = new Array();
for(let i = 0; i< polypaths.length; i++) {
let obj = new Object();
obj.x = '' + polypaths[i]._lng + '';
obj.y = '' + polypaths[i]._lat + '';
obj = JSON.stringify(obj);
polypathJSON.push(JSON.parse(obj));
}
// console.log(polypathJSON, 'json polyline path');
// bufferMove();
bufferTest();
} else {
polyline.setMap(null);
polyline = '';
}
} else if(polygon) {
let path = polygon.getPath();
path.pop();
let polygonpaths = polygon.getPath()._array;
//꼭짓점 circle 생성
for(let index = 0; index < polygonpaths.length; index++) {
dragCircle.push(
new naver.maps.Circle({
strokeOpacity: 1,
strokeColor: '#000000',
fillColor: '#ffffff',
fillOpacity: 1,
center: polygonpaths[index],
radius: 10,
map: map,
clickable: true
})
)
dragCircleEve.push(naver.maps.Event.addListener(dragCircle[index], 'mousedown', function() { onMouseDownDrag(index) }))
}
setDragCircle(dragCircle);
setPolygon(polygon);
setAreaInfo(polygonpaths, '');
}
}
const onClickPolyline = (e) => {
console.log('onClickPolyline')
var coord = e.coord;
if(!check) {
if(!polyline) {
//가이드라인
guideline = new naver.maps.Polyline({
strokeColor: '#283046',
strokeWeight: 2,
strokeOpacity: 0.3,
path: [coord],
map: map
});
// lastDistance = guideline.getDistance();
//실제 사용되는 라인
polyline = new naver.maps.Polyline({
strokeLineCap: 'round',
strokeLineJoin: 'round',
strokeColor: '#283046',
strokeWeight: 3,
strokeOpacity: 1,
path: [coord],
map: map
});
Eve.rightclickEve = naver.maps.Event.addListener(map, 'rightclick', function() { finishDraw() })
$(document).on('mousemove.measure', function(e) { onMouseMovePolyline(e); });
lastDistance = polyline.getDistance();
// this._addMileStone(coord, 'Start');
} else {
guideline.setPath([e.coord]);
polyline.getPath().push(coord);
var distance = polyline.getDistance();
// addMileStone(coord, this._fromMetersToText(distance - this._lastDistance));
lastDistance = distance;
}
}
}
const onMouseMovePolyline = (e) => {
console.log('onMouseMovePolyline')
var proj = map.getProjection(),
coord = proj.fromPageXYToCoord(new naver.maps.Point(e.pageX, e.pageY)),
path = guideline.getPath();
if(path.getLength() === 2) {
path.pop();
}
path.push(coord);
}
const onClickPolygon = (e) => {
console.log('onClickPolygon')
var coord = e.coord;
if(!polygon) {
polygon = new naver.maps.Polygon({
strokeColor: '#283046',
strokeOpacity: 1,
fillColor: '#7367F0',
fillOpacity: 0.1,
paths: [coord],
map: map
});
Eve.rightclickEve = naver.maps.Event.addListener(map, 'rightclick', function() { finishDraw() })
$(document).on('mousemove.measure', function(e) { onMouseMovePolygon(e) });
} else {
polygon.getPath().push(coord);
}
}
const onMouseMovePolygon = (e) => {
console.log('onMouseMovePolygon')
if(!polygon) return;
var proj = map.getProjection(),
coord = proj.fromPageXYToCoord(new naver.maps.Point(e.pageX, e.pageY)),
path = polygon.getPath();
if(path.getLength() >= 2) {
path.pop();
}
path.push(coord);
}
const onClickCircle = (e) => {
console.log('onClickCircle')
var coord = e.coord;
if(!check) {
if(!circle) {
//가이드라인
radiusline = new naver.maps.Polyline({
// strokeStyle: [4, 4],
// strokeOpacity: 0.6,
path: [coord],
// map: map
});
lastDistance = radiusline.getDistance();
//실제 사용되는 원형
circle = new naver.maps.Circle({
strokeColor: '#283046',
strokeOpacity: 1,
fillColor: '#7367F0',
fillOpacity: 0.1,
center: coord,
radius: 100,
map: map,
clickable: true
});
Eve.mousedownEve = naver.maps.Event.addListener(circle, 'mousedown', function() { onMouseDownDrag(0); })
} else {
circle.setRadius(100);
circle.setCenter(coord);
radiusline.setPath([coord])
}
setCircle(circle);
setAreaInfo('', '');
}
}
const onMouseDownDrag = (index) => {
console.log('onMouseDownDrag')
if(circle) {
naver.maps.Event.removeListener(Eve.clickEve);
}
map.setOptions({
draggable: false,
pinchZoom: false,
scrollWheel: false,
keyboardShortcuts: false,
disableDoubleTapZoom: true,
disableDoubleClickZoom: true,
disableTwoFingerTapZoom: true
})
$(document).on('mousemove.measure', function(e) { onMouseMoveDrag(e, index) });
$(document).on('mouseup.measure', function() { onMouseUpDrag() });
}
const onMouseMoveDrag = (e, index) => {
console.log('onMouseMoveDrag')
check = true;
var proj = map.getProjection(),
coord = proj.fromPageXYToCoord(new naver.maps.Point(e.pageX, e.pageY));
if(polyline) {
var polypaths = polyline.getPath()._array;
let movepath = [];
for(let i = 0; i < polypaths.length; i++) {
let path;
if(i === index) {
path = coord;
} else {
path = polypaths[i]
}
movepath.push(path);
}
polyline.setPath(movepath);
} else if(polygon) {
var polygonpaths = polygon.getPath()._array;
let movepath = [];
for(let i = 0; i < polygonpaths.length; i++) {
let path;
if(i === index) {
path = coord;
} else {
path = polygonpaths[i]
}
movepath.push(path);
}
polygon.setPaths(movepath)
} else if(circle) {
var circlepath = radiusline.getPath(),
center = circle.getCenter(),
r = proj.getDistance(coord, center);
if(circlepath.getLength() === 2) {
circlepath.pop();
}
circlepath.push(coord);
circle.setRadius(r);
}
if(!circle) {
dragCircle[index].setCenter(coord);
}
}
const onMouseUpDrag = () => {
console.log('onMouseUpDrag')
map.setOptions({
draggable: true,
pinchZoom: true,
scrollWheel: true,
keyboardShortcuts: true,
disableDoubleTapZoom: false,
disableDoubleClickZoom: false,
disableTwoFingerTapZoom: false
})
if(polyline) {
bufferPolyline.setMap(null);
// bufferMove();
}
if(polygon) {
var path = polygon.getPath()._array;
setPolygon(polygon);
setAreaInfo(path, '');
}
$(document).off('mousemove.measure');
$(document).off('mouseup.measure');
if(circle) {
// Eve.clickEve = naver.maps.Event.addListener(map, 'click', function(e) { onClickCircle(e); })
setEve(naver.maps.Event.addListener(map, 'click', function(e) { onClickCircle(e) }))
setCircle(circle);
setAreaInfo('', '');
}
check = false;
}
const setAreaInfo = (path, bufferpath) => {
areaInfo = '';
let prePath = [];
path.forEach(prev=> prePath.push([prev.x, prev.y]))
if(polyline) {
areaInfo = {
linepath: prePath,
linebuffer: 50,
bufferpath: bufferpath
}
} else if(polygon) {
areaInfo = {
polygonpath: prePath
}
} else if(circle) {
areaInfo = {
center: circle.getCenter(),
radius: circle.getRadius()
}
}
console.log(areaInfo, 'areaInfo')
}
const bufferTest = () => {
let pol = polyline.getPath()._array; //latlng point 다 준건가?
console.log(pol)
let lineStringPaths = [];
for(let i = 0; i< pol.length; i++) {
// lineStringPaths.push(naver.maps.TransCoord.fromLatLngToEPSG3857(pol[i]))
// lineStringPaths.push(naver.maps.TransCoord.fromLatLngToNaver(pol[i]))
// lineStringPaths.push(naver.maps.TransCoord.fromLatLngToTM128(pol[i]))
// lineStringPaths.push(naver.maps.TransCoord.fromLatLngToUTMK(pol[i]))
// lineStringPaths.push(naver.maps.TransCoord.fromEPSG3857ToLatLng(naver.maps.Point(pol[i].x, pol[i].y)))
// lineStringPaths.push(naver.maps.TransCoord.fromEPSG3857ToNaver(naver.maps.Point(pol[i].x, pol[i].y)))
// lineStringPaths.push(naver.maps.TransCoord.fromEPSG3857ToTM128(naver.maps.Point(pol[i].x, pol[i].y)))
// lineStringPaths.push(naver.maps.TransCoord.fromEPSG3857ToUTMK(naver.maps.Point(pol[i].x, pol[i].y)))
lineStringPaths.push([pol[i].x, pol[i].y]);
}
// console.log(map.getProjection().getProjectionName());
// console.log(map.getProjection())
// console.log(map.getPrimitiveProjection())
console.log(lineStringPaths)
//옆에 화면에 라이브러리 활용해서 제발 성공하자..
let bufferRadius = 100;
const wkt = 'LINESTRING (126.6061581 37.5218642, 126.6061581 37.518052)'
let coords = {
"type": "LineString",
"coordinates" : lineStringPaths
};
const bufferCenter = new JSTSWKTReader().read(wkt)
const bufferResult = JSTSBufferOp.bufferOp(
bufferCenter,
bufferRadius
)
const bufferResultGeoJSON = new GeoJSONWriter().write(bufferResult)
console.log(bufferResultGeoJSON)
// bufferPolyline = new naver.maps.Polyline({
// strokeColor: '#ff0000',
// strokeColor: '#283046',
// strokeWeight: 2,
// strokeStyle: [4, 4],
// strokeOpacity: 1,
// path : bufferPaths,
// // path: [
// // ],
// map: map
// });
}
const bufferMove = () => {
console.log('bufferMove')
//버퍼 생성에 필요한 coordinates 배열 변환
let pol = polyline.getPath()._array;
let lineStringPaths = [];
for(let i = 0; i< polyline.getPath().length; i++) {
lineStringPaths.push([pol[i].x, pol[i].y]);
}
console.log(lineStringPaths, 'polyline path')
// //버퍼 생성을 위한 line 객체
// const originalGeojson = {
// type: "FeatureCollection",
// features: [
// {
// type: "Feature",
// properties: {},
// geometry: {
// type: "LineString",
// coordinates: lineStringPaths
// }
// }
// ]
// };
// // console.log(originalGeojson, 'Feature type Object')
// //버퍼 객체
// const bufferObj = buffer(originalGeojson, 50, {units:'meters'});
// //버퍼 라인 생성
// let bufferPath = bufferObj.features[0].geometry.coordinates[0];
// // console.log(bufferPath, 'buffer path')
// bufferPolyline = new naver.maps.Polyline({
// // strokeColor: '#ff0000',
// strokeColor: '#283046',
// strokeWeight: 2,
// strokeStyle: [4, 4],
// strokeOpacity: 1,
// path : bufferPath,
// map: map
// });
//------------------------
let coords = {
"type": "LineString",
"coordinates" : lineStringPaths
};
const reader = new GeoJSONReader();
const writer = new GeoJSONWriter();
const distance = (100 * 0.001) / 111.12; //100미터
const line = reader.read(coords);
// const buffer = BufferOp.bufferOp(line, distance);
const buffer = BufferOp.bufferOp(line, distance, 0, 3);
let bufferpath = buffer._shell._points._coordinates;
let bufferPaths = [];
for(let i = 0; i< bufferpath.length; i++) {
bufferPaths.push([bufferpath[i].x, bufferpath[i].y]);
}
console.log(bufferPaths, 'bufferPaths')
bufferPolyline = new naver.maps.Polyline({
strokeColor: '#ff0000',
strokeColor: '#283046',
strokeWeight: 2,
strokeStyle: [4, 4],
strokeOpacity: 1,
path : bufferPaths,
// path: [
// ],
map: map
});
// setAreaInfo(polyline.getPath()._array, bufferPath);
setAreaInfo(polyline.getPath()._array, bufferPaths);
setPolyline(polyline);
setBuffer(bufferPolyline)
}
const onClickCheck = () => {
console.log('onClickReset')
// if(!mapControl.drawType) return;
if(mapControl.drawCheck === 'RESET') {
clearMode(mode);
mode = newMode;
startMode(newMode);
// removeListener();
// if(polyline) {
// polyline.setMap(null);
// polyline = '';
// guideline.setMap(null);
// guideline = '';
// bufferPolyline.setMap(null);
// bufferPolyline = '';
// }
// if(polygon) {
// console.log(polygon)
// polygon.setMap(null);
// polygon = '';
// }
// if(circle) {
// circle.setMap(null);
// circle = '';
// radiusline.setMap(null);
// radiusline = '';
// }
}
}
return (
<>
{/* <Button.Ripple
color='primary'
className='area-button'
onClick = {props.openModal}
>
확인
</Button.Ripple>
<Button.Ripple
color='primary'
className='area-button'
// onClick = {e => handlerDrawCheck('RESET')}
onClick={e => handlerDrawType('RESET')}
>
초기화
</Button.Ripple> */}
</>
);
};

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

@ -2,12 +2,13 @@ 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 {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';
import FlightPlanAreaMap from '../../../../components/basis/flight/plan/FlightPlanAreaMap';
import FlightPlanAreaDetailContainer from './FlightPlanAreaDetailContainer';
import { FlightPlanAreaDetailModal } from '../../../../components/basis/flight/plan/FlightPlanAreaDetailModal';
const FlightPlanAreaContainer = (props) => {
const dispatch = useDispatch();
@ -15,6 +16,11 @@ const FlightPlanAreaContainer = (props) => {
const { areaList } = useSelector(state => state.flightState);
const [airArea, setAirArea] = useState(null);
const [modal, setModal] = useState({
isOpen: false,
title: '',
body: <FlightPlanAreaDetailContainer />
});
const validSchema = yup.object().shape({
});
@ -29,17 +35,29 @@ const FlightPlanAreaContainer = (props) => {
resolver: yupResolver(validSchema)
});
const saveFlightPlanAreaDetail = () => {
console.log("비행 구역 상세정보 저장")
}
const openModal = () => {
setModal({
isOpen: true,
title: '비행 구역 상세 정보'
});
}
//이거 실행하면 Network탭에 area생김
const getAirAreaList = () => {
dispatch(Actions.AREA_LIST.request());
}
const createAirArea = async data => {
dispatch(Actions.FLIGHT_PLAN_AREA.request(data));
// const createAirArea = async data => {
// dispatch(Actions.FLIGHT_PLAN_AREA.request(data));
props.setModal({ ...props.modal, isOpen: !props.modal.isOpen });
props.setOnSubmit(false);
}
// props.setModal({ ...props.modal, isOpen: !props.modal.isOpen });
// props.setOnSubmit(false);
// }
useEffect(() => {
getAirAreaList();
@ -49,26 +67,25 @@ const FlightPlanAreaContainer = (props) => {
setAirArea(areaList);
}, [areaList])
return (
<Row>
<Col md={6} lg={6}>
{airArea != null ? (
<FlightPlanAreaMap
airArea={airArea}
/>
) : null}
</Col>
<Col md={6} lg={6}>
<FlightPlanAreaForm
modal={props.modal}
setModal={props.setModal}
data={register}
errors={errors}
submit={handleSubmit(createAirArea)}
/>
</Col>
</Row>
return (
<Row>
<Col>
{airArea != null ? (
<FlightPlanAreaMap
airArea={airArea}
openModal={openModal}
/>
) : null}
{modal.isOpen ? (
<FlightPlanAreaDetailModal
modal={modal}
save={saveFlightPlanAreaDetail}
setModal={setModal}
/>
) : null
}
</Col>
</Row>
)
}

45
src/containers/basis/flight/plan/FlightPlanAreaDetailContainer.js

@ -0,0 +1,45 @@
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 {Col, Row, Form } from 'reactstrap';
import * as Actions from '../../../../modules/basis/flight/actions/basisFlightAction';
import * as yup from 'yup';
import { yupResolver } from '@hookform/resolvers/yup';
import FlightPlanAreaDetailForm from '../../../../components/basis/flight/plan/FlightPlanAreaDetailForm';
const FlightPlanAreaDetailContainer = (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)
});
return (
<Row>
<Col>
<FlightPlanAreaDetailForm
// openModal={openModal}
/>
</Col>
</Row>
)
}
export default FlightPlanAreaDetailContainer;

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

@ -18,7 +18,8 @@ const FlightPlanDetailContainer = () => {
const [areaInfo, setAreaInfo] = useState();
const [modal, setModal] = useState({
isOpen: false,
title: '',
title: '',
body: <FlightPlanAreaContainer />
});
/* Form Validation Checking */
@ -55,11 +56,14 @@ const FlightPlanDetailContainer = () => {
openModal={openModal}
areaInfo={areaInfo}
/>
<FlightPlanAreaModal
modal={modal}
save={saveFlightPlanArea}
setModal={setModal}
/>
{modal.isOpen ? (
<FlightPlanAreaModal
modal={modal}
save={saveFlightPlanArea}
setModal={setModal}
/>
) : null
}
</CustomDetailLayout>
)

33
src/modules/basis/flight/actions/basisFlightDrawAction.ts

@ -0,0 +1,33 @@
// draw 옵션 변경 Action
export const polylineChangeAction = (value: any) => dispatch =>
dispatch({type: 'POLYLINE_CHANGE', value});
export const guidelineChangeAction = (value: any) => dispatch =>
dispatch({type: 'GUIDELINE_CHANGE', value});
export const bufferpolylineChangeAction = (value: any) => dispatch =>
dispatch({type: 'BUFFERPOLYLINE_CHANGE', value});
export const polygonChangeAction = (value: any) => dispatch =>
dispatch({type: 'POLYGON_CHANGE', value});
export const circleChangeAction = (value: any) => dispatch =>
dispatch({type: 'CIRCLE_CHANGE', value});
export const radiuslineChangeAction = (value: any) => dispatch =>
dispatch({type: 'RADIUSLINE_CHANGE', value});
export const clickEveChangeAction = (value: any) => dispatch =>
dispatch({type: 'CLICKEVE_CHANGE', value});
export const mousedownEveChangeAction = (value: any) => dispatch =>
dispatch({type: 'MOUSEDOWNEVE_CHANGE', value});
export const rightclickEveChangeAction = (value: any) => dispatch =>
dispatch({type: 'RIGHTCLICKEVE_CHANGE', value});
export const dragCircleChangeAction = (value: any) => dispatch =>
dispatch({type: 'DRAGCIRCLE_CHANGE', value});
export const checkChangeAction = (value: any) => dispatch =>
dispatch({type: 'CHECK_CHANGE', value});

59
src/modules/basis/flight/reducers/basisFlightDrawReducer.ts

@ -0,0 +1,59 @@
// ** Initial State
const initial = {
polyline: '',
guideline: '',
bufferPolyline: '',
polygon: '',
circle: '',
radiusline: '',
clickEve: '',
mousedownEve: '',
rightclickEve: '',
dragCircle: [],
check: ''
};
const drawReducerReducer = (state = initial, action) => {
switch (action.type) {
case 'POLYLINE_CHANGE':
return {...state, polyline: action.value};
case 'GUIDELINE_CHANGE':
return { ...state, guideline: action.value};
case 'BUFFERPOLYLINE_CHANGE':
return {...state, bufferPolyline: action.value};
case 'POLYGON_CHANGE':
return {...state, polygon: action.value};
case 'CIRCLE_CHANGE':
return {...state, circle: action.value};
case 'RADIUSLINE_CHANGE':
return {...state, radiusline: action.value};
case 'CLICKEVE_CHANGE':
return {...state, clickEve: action.value};
case 'MOUSEDOWNEVE_CHANGE':
return {...state, mousedownEve: action.value};
case 'RIGHTCLICKEVE_CHANGE':
return {...state, rightclickEve: action.value};
case 'DRAGCIRCLE_CHANGE':
return {...state, dragCircle: action.value};
case 'CHECK_CHANGE':
return {...state, check: action.value};
default:
return state;
}
};
export default drawReducerReducer;

7
src/modules/control/map/reducers/controlMapReducer.ts

@ -1,6 +1,6 @@
// ** Initial State
const initialState = {
mapType: 'HYBRID',
mapType: 'NORMAL',
objectId: null,
isClickObject: false,
area0001: true, // 비행금지 구역
@ -11,9 +11,10 @@ const initialState = {
area0006: true, // 초경량비행장치
sensor: 'dust',
drawType: '',
drawType: null,
drawCheck: false
// drawCheck: false
drawCheck: ''
};
const controlReducerReducer = (state = initialState, action) => {

4
src/redux/reducers/rootReducer.ts

@ -22,6 +22,9 @@ import {
ControlGpState
} from '../../modules/control/gp';
import controlMapReducer from '../../modules/control/map/reducers/controlMapReducer';
import basisFlightDrawReducer from '../../modules/basis/flight/reducers/basisFlightDrawReducer';
import { mainDahReducer } from '../../modules/main/dash/reducers/mainDashReducer';
import { mainDashSaga } from '../../modules/main/dash/sagas/mainDashSaga';
import { menuReducer } from '../../modules/menu/reducers/menuReducer';
@ -53,6 +56,7 @@ const rootReducer = combineReducers({
navbar,
layout,
controlMapReducer,
basisFlightDrawReducer,
mainDashState: mainDahReducer,
messageState: messageReducer,
groupState: groupReducer,

Loading…
Cancel
Save