From 0fc59bb20124a13095c5394aa0fecf462a8d6db5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?junh=5Feee=28=EC=9D=B4=EC=A4=80=ED=9D=AC=29?= Date: Mon, 12 Jun 2023 21:09:44 +0900 Subject: [PATCH 1/3] =?UTF-8?q?=EA=B4=80=EC=A0=9C=20=EA=B3=B5=EC=97=AD=20?= =?UTF-8?q?=EA=B7=B8=EB=A6=AC=EA=B8=B0=20=EC=A7=84=ED=96=89=20=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/map/naver/NaverMap.js | 12 +- src/components/map/naver/draw/ControlDraw.js | 151 ++++++++++++++++++ .../control/map/actions/controlMapActions.ts | 11 +- .../control/map/reducers/controlMapReducer.ts | 18 ++- src/views/control/main/ControlMain.js | 28 +++- 5 files changed, 206 insertions(+), 14 deletions(-) create mode 100644 src/components/map/naver/draw/ControlDraw.js diff --git a/src/components/map/naver/NaverMap.js b/src/components/map/naver/NaverMap.js index b791fa9..4fb47ae 100644 --- a/src/components/map/naver/NaverMap.js +++ b/src/components/map/naver/NaverMap.js @@ -11,6 +11,7 @@ import NewDronPlan from './dron/NewDronPlan'; import { NewDronHistory } from './dron/NewDronHistroy'; import DronToast from './dron/DronToast'; import SensorZone from './sensor/SensorZone'; +import ControlDraw from './draw/ControlDraw'; export const NaverCustomMap = () => { const dispatch = useDispatch(); @@ -126,7 +127,8 @@ export const NaverCustomMap = () => { useEffect(() => { NaverMapInit(); - airPort?.map(air => polyArea(air)); + // airPort?.map(air => polyArea(air)); + airPort?.map((air, idx) => polyArea(air, idx)); }, []); useEffect(() => { @@ -198,11 +200,11 @@ export const NaverCustomMap = () => { setArrPolyline([...arrPolyline, line]); }; - const polyArea = air => { + const polyArea = (air, idx) => { //격자 공역 const polyArr = []; const radius = air.buffer; - const position = air.center; + const position = air.center; //공역 센터 const color = '#000'; const opacity = 0.7; @@ -215,6 +217,8 @@ export const NaverCustomMap = () => { // buffer += 2000; buffer += 1000; + //EPSG3857.getDestinationCoord + //지정한 좌표에서 북쪽을 기준으로 각도와 거리만큼 떨어진 위치의 좌표 반환 const coord = new naver.maps.EPSG3857.getDestinationCoord( position, angle, @@ -308,6 +312,8 @@ export const NaverCustomMap = () => { + + {/* state.controlMapReducer); + + const naver = props.naver; + const map = props.map; + let mode; + + const [mapClickEvent, setMapClickEvent] = useState(); + const [circleArr, setCircleArr] = useState([]); + + const [up, setUp] = useState(false); + + useEffect(() => { + if (up) { + const delay = 100; + const timer = setTimeout(() => { + createMapClick(); + setUp(false); + }, delay); + + return () => { + clearTimeout(timer); + }; + } + }, [up]); + + useEffect(() => { + drawInit(); + }, [mapControl.ctrlDrawType]); + + const drawInit = () => { + removeMapClick(); + if (mapControl.ctrlDrawType === 'CIRCLE') { + onClickButton('CIRCLE'); + } else if (mapControl.ctrlDrawType === 'RESET') { + onClickReset(); + } + }; + + const onClickButton = newMode => { + removeMapClick(); + if (mode === newMode) { + mode = null; + return; + } + + // startMode(newMode); + if (!newMode) return; + + createMapClick(); + }; + + const onClickReset = () => { + console.log('초기화 진행'); + circleArr.map(circle => circle.setMap(null)); + setCircleArr([]); + + removeMapClick(); + }; + + const removeMapClick = () => { + $(document).off('mousemove.measure'); + $(document).off('mouseup.measure'); + + // naver.maps.Event.clearInstanceListeners(map); + naver.maps.Event.removeListener(mapClickEvent); + setMapClickEvent(); + }; + + const createMapClick = () => { + setMapClickEvent( + naver.maps.Event.addListener(map, 'click', function (e) { + onClickCircle(e); + }) + ); + }; + + const onClickCircle = e => { + const coord = e.coord; + + const circle = new naver.maps.Circle({ + strokeColor: '#283046', + strokeOpacity: 1, + fillColor: '#7367F0', + fillOpacity: 0.1, + center: coord, + radius: 100, + map: map, + clickable: true + }); + setCircleArr(prev => [...prev, circle]); + + naver.maps.Event.addListener(circle, 'mousedown', function () { + onMouseDown(circle); + }); + setUp(false); + }; + + const onMouseDown = circle => { + map.setOptions({ + draggable: false, + pinchZoom: false, + scrollWheel: false, + keyboardShortcuts: false, + disableDoubleTapZoom: true, + disableDoubleClickZoom: true, + disableTwoFingerTapZoom: true + }); + + $(document).on('mousemove.measure', function (e) { + onMouseMove(e, circle); + }); + + $(document).on('mouseup.measure', function (e) { + onMouseUp(); + }); + }; + + const onMouseMove = (e, circle) => { + const proj = map.getProjection(); + const coord = proj.fromPageXYToCoord( + new naver.maps.Point(e.pageX, e.pageY) + ); + + const center = circle.getCenter(); + const r = proj.getDistance(coord, center); + + circle.setRadius(r); + }; + + const onMouseUp = () => { + map.setOptions({ + draggable: true, + pinchZoom: true, + scrollWheel: true, + keyboardShortcuts: true, + disableDoubleTapZoom: false, + disableDoubleClickZoom: false, + disableTwoFingerTapZoom: false + }); + + removeMapClick(); + setUp(true); + }; + + return null; +} diff --git a/src/modules/control/map/actions/controlMapActions.ts b/src/modules/control/map/actions/controlMapActions.ts index 6b8e0a3..be85343 100644 --- a/src/modules/control/map/actions/controlMapActions.ts +++ b/src/modules/control/map/actions/controlMapActions.ts @@ -2,12 +2,12 @@ export const mapTypeChangeAction = (value: any) => dispatch => dispatch({ type: 'MAP_TYPE_CHANGE', value }); - // draw 옵션 변경 Action +// draw 옵션 변경 Action export const drawTypeChangeAction = (value: any) => dispatch => -dispatch({type: 'DRAW_TYPE_CHANGE', value}); + dispatch({ type: 'DRAW_TYPE_CHANGE', value }); export const drawCheckAction = (value: any) => dispatch => -dispatch({type: 'DRAW_CHECK', value}); + dispatch({ type: 'DRAW_CHECK', value }); // 드론체 클릭 시 Action export const objectClickAction = (value: any) => dispatch => @@ -20,4 +20,7 @@ export const areaClickAction = (value: any) => dispatch => dispatch({ type: 'AREA_CLICK', value }); export const sensorClickAction = (value: any) => dispatch => - dispatch({type: 'SENSOR_CLICK', value}) + dispatch({ type: 'SENSOR_CLICK', value }); + +export const ctrlDrawTypeChangeAction = (value: any) => dispatch => + dispatch({ type: 'CTRL_DRAW_TYPE_CHANGE', value }); diff --git a/src/modules/control/map/reducers/controlMapReducer.ts b/src/modules/control/map/reducers/controlMapReducer.ts index 116007a..57d6457 100644 --- a/src/modules/control/map/reducers/controlMapReducer.ts +++ b/src/modules/control/map/reducers/controlMapReducer.ts @@ -13,19 +13,21 @@ const initialState = { drawType: null, + ctrlDrawType: null, + drawCheck: '' }; const controlReducerReducer = (state = initialState, action) => { switch (action.type) { case 'MAP_TYPE_CHANGE': - return {...state, mapType: action.value}; + return { ...state, mapType: action.value }; - case 'OBJECT_CLICK': - return {...state, objectId: action.value, isClickObject: true}; + case 'OBJECT_CLICK': + return { ...state, objectId: action.value, isClickObject: true }; case 'OBEJCT_UN_CLICK': - return {...state, isClickObject: false}; + return { ...state, isClickObject: false }; case 'AREA_CLICK': if (action.value === '0001') { @@ -67,7 +69,7 @@ const controlReducerReducer = (state = initialState, action) => { return { ...state, sensor: action.value - } + }; break; default: return state; @@ -78,6 +80,12 @@ const controlReducerReducer = (state = initialState, action) => { drawType: action.value }; + case 'CTRL_DRAW_TYPE_CHANGE': + return { + ...state, + ctrlDrawType: action.value + }; + case 'DRAW_CHECK': return { ...state, diff --git a/src/views/control/main/ControlMain.js b/src/views/control/main/ControlMain.js index 9cbdfe7..5b37c8e 100644 --- a/src/views/control/main/ControlMain.js +++ b/src/views/control/main/ControlMain.js @@ -19,7 +19,7 @@ import { import { AiOutlinePoweroff, AiOutlineExclamation } from 'react-icons/ai'; import { IoAlertOutline } from 'react-icons/io5'; import { ReactComponent as DroneMenuIcon } from '../../../assets/images/drone_menu_icon.svg'; -import { Card } from 'reactstrap'; +import { Card, Button } from 'reactstrap'; import ControlAlarmNotice from '../alarm/ControlAlarmNotice'; import ControlReportList from '../report/ControlReportList'; import ControlReportDetail from '../report/ControlReportDetail'; @@ -30,7 +30,10 @@ import WebsocketClient from '../../../components/websocket/WebsocketClient'; import { useDispatch, useSelector } from 'react-redux'; import { controlweatherAction } from '../../../modules/control/gp/actions/controlGpAction'; import * as Actions from '../../../modules/account/login/actions/authAction'; -import { objectUnClickAction } from '../../../modules/control/map/actions/controlMapActions'; +import { + ctrlDrawTypeChangeAction, + objectUnClickAction +} from '../../../modules/control/map/actions/controlMapActions'; const ControlMain = () => { const dispatch = useDispatch(); @@ -149,6 +152,11 @@ const ControlMain = () => { } else return ; } } + + const handlerDrawType = val => { + dispatch(ctrlDrawTypeChangeAction(val)); + }; + return ( <> @@ -295,6 +303,22 @@ const ControlMain = () => { +
+ handlerDrawType('CIRCLE')} + > + Circle + + handlerDrawType('RESET')} + > + 초기화 + +
{oepnReportList ? ( Date: Tue, 13 Jun 2023 14:54:09 +0900 Subject: [PATCH 2/3] =?UTF-8?q?=EA=B4=80=EC=A0=9C=20circle=20=EA=B3=B5?= =?UTF-8?q?=EC=97=AD=20=EA=B7=B8=EB=A6=AC=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/map/naver/draw/ControlDraw.js | 136 +++++++++++++------ 1 file changed, 93 insertions(+), 43 deletions(-) diff --git a/src/components/map/naver/draw/ControlDraw.js b/src/components/map/naver/draw/ControlDraw.js index 04b1a61..864e016 100644 --- a/src/components/map/naver/draw/ControlDraw.js +++ b/src/components/map/naver/draw/ControlDraw.js @@ -1,82 +1,98 @@ import $ from 'jquery'; import { useState, useEffect } from 'react'; -import { useDispatch, useSelector } from 'react-redux'; +import { useSelector } from 'react-redux'; export default function ControlDraw(props) { const mapControl = useSelector(state => state.controlMapReducer); const naver = props.naver; const map = props.map; - let mode; - const [mapClickEvent, setMapClickEvent] = useState(); const [circleArr, setCircleArr] = useState([]); + const [markerArr, setMarkerArr] = useState([]); - const [up, setUp] = useState(false); + const [upCircle, setUpCircle] = useState(false); useEffect(() => { - if (up) { + if (upCircle) { const delay = 100; const timer = setTimeout(() => { - createMapClick(); - setUp(false); + resumeMapClick(); + setUpCircle(false); + + const index = circleArr.findIndex( + prev => prev.center === upCircle.getCenter() + ); + + markerArr.map((prev, idx) => { + if (idx === index) { + const text = fromMetersToText(upCircle.getRadius()); + const content = + '
' + + text + + '
'; + prev.setIcon({ + ...prev.getIcon(), + content: content + }); + } + }); }, delay); return () => { clearTimeout(timer); }; } - }, [up]); + }, [upCircle]); + + useEffect(() => { + naver.maps.Event.addListener(map, 'click', onClickCircle); + stopMapClick(); + }, []); useEffect(() => { drawInit(); }, [mapControl.ctrlDrawType]); const drawInit = () => { - removeMapClick(); if (mapControl.ctrlDrawType === 'CIRCLE') { onClickButton('CIRCLE'); } else if (mapControl.ctrlDrawType === 'RESET') { - onClickReset(); + clearMode(); } }; const onClickButton = newMode => { - removeMapClick(); - if (mode === newMode) { - mode = null; - return; - } + clearMode(); + startMode(newMode); + }; + + const clearMode = () => { + if (circleArr.length != 0) { + circleArr.map(obj => obj.circle.setMap(null)); + setCircleArr([]); - // startMode(newMode); - if (!newMode) return; + markerArr.map(marker => marker.setMap(null)); + setMarkerArr([]); - createMapClick(); + stopMapClick(); + } }; - const onClickReset = () => { - console.log('초기화 진행'); - circleArr.map(circle => circle.setMap(null)); - setCircleArr([]); + const startMode = mode => { + if (!mode) return; - removeMapClick(); + if (mode === 'CIRCLE') { + resumeMapClick(); + } }; - const removeMapClick = () => { - $(document).off('mousemove.measure'); - $(document).off('mouseup.measure'); - - // naver.maps.Event.clearInstanceListeners(map); - naver.maps.Event.removeListener(mapClickEvent); - setMapClickEvent(); + const stopMapClick = () => { + naver.maps.Event.stopDispatch(map, 'click'); }; - const createMapClick = () => { - setMapClickEvent( - naver.maps.Event.addListener(map, 'click', function (e) { - onClickCircle(e); - }) - ); + const resumeMapClick = () => { + naver.maps.Event.resumeDispatch(map, 'click'); }; const onClickCircle = e => { @@ -92,12 +108,16 @@ export default function ControlDraw(props) { map: map, clickable: true }); - setCircleArr(prev => [...prev, circle]); + setCircleArr(prev => [ + ...prev, + { center: coord, circle: circle, radius: 100 } + ]); naver.maps.Event.addListener(circle, 'mousedown', function () { onMouseDown(circle); }); - setUp(false); + + addMileStone(coord, fromMetersToText(100)); }; const onMouseDown = circle => { @@ -115,8 +135,8 @@ export default function ControlDraw(props) { onMouseMove(e, circle); }); - $(document).on('mouseup.measure', function (e) { - onMouseUp(); + $(document).on('mouseup.measure', function () { + onMouseUp(circle); }); }; @@ -132,7 +152,7 @@ export default function ControlDraw(props) { circle.setRadius(r); }; - const onMouseUp = () => { + const onMouseUp = circle => { map.setOptions({ draggable: true, pinchZoom: true, @@ -143,8 +163,38 @@ export default function ControlDraw(props) { disableTwoFingerTapZoom: false }); - removeMapClick(); - setUp(true); + $(document).off('mousemove.measure'); + $(document).off('mouseup.measure'); + + stopMapClick(); + setUpCircle(circle); + }; + + const addMileStone = (coord, text) => { + const content = + '
' + + text + + '
'; + + const midPoint = coord; + + const anchor = new naver.maps.Point(20, 35); + + const marker = new naver.maps.Marker({ + position: midPoint, + icon: { + content: content, + anchor: anchor + } + }); + marker.setMap(map); + setMarkerArr(prev => [...prev, marker]); + }; + + const fromMetersToText = meters => { + meters = meters || 0; + const text = parseFloat(meters.toFixed(1)) + 'm'; + return text; }; return null; -- 2.30.3 From 8e725dffe53a007a04ee1955eb692212817f3387 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?junh=5Feee=28=EC=9D=B4=EC=A4=80=ED=9D=AC=29?= Date: Tue, 13 Jun 2023 15:15:29 +0900 Subject: [PATCH 3/3] =?UTF-8?q?=EB=B2=84=ED=8A=BC=20=EC=88=98=EC=A0=95,=20?= =?UTF-8?q?circle=20=EC=83=89=EC=83=81=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/map/naver/draw/ControlDraw.js | 6 ++-- src/views/control/main/ControlMain.js | 31 ++++++++++---------- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/src/components/map/naver/draw/ControlDraw.js b/src/components/map/naver/draw/ControlDraw.js index 864e016..489044d 100644 --- a/src/components/map/naver/draw/ControlDraw.js +++ b/src/components/map/naver/draw/ControlDraw.js @@ -99,10 +99,10 @@ export default function ControlDraw(props) { const coord = e.coord; const circle = new naver.maps.Circle({ - strokeColor: '#283046', + strokeColor: '#ff0000', strokeOpacity: 1, - fillColor: '#7367F0', - fillOpacity: 0.1, + fillColor: '#ff0000', + fillOpacity: 0.3, center: coord, radius: 100, map: map, diff --git a/src/views/control/main/ControlMain.js b/src/views/control/main/ControlMain.js index 5b37c8e..e4dc7b2 100644 --- a/src/views/control/main/ControlMain.js +++ b/src/views/control/main/ControlMain.js @@ -303,21 +303,22 @@ const ControlMain = () => { -
- handlerDrawType('CIRCLE')} - > - Circle - - handlerDrawType('RESET')} - > - 초기화 - +
+ +
+ 화재경보 +
+
+
+ handlerDrawType('CIRCLE')}> + 화재구역설정 + +
+
+ handlerDrawType('RESET')}>초기화 +
+
+
{oepnReportList ? ( -- 2.30.3