diff --git a/src/components/map/naver/NaverMap.js b/src/components/map/naver/NaverMap.js index b791fa91..4fb47ae2 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; + + const [circleArr, setCircleArr] = useState([]); + const [markerArr, setMarkerArr] = useState([]); + + const [upCircle, setUpCircle] = useState(false); + + useEffect(() => { + if (upCircle) { + const delay = 100; + const timer = setTimeout(() => { + 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); + }; + } + }, [upCircle]); + + useEffect(() => { + naver.maps.Event.addListener(map, 'click', onClickCircle); + stopMapClick(); + }, []); + + useEffect(() => { + drawInit(); + }, [mapControl.ctrlDrawType]); + + const drawInit = () => { + if (mapControl.ctrlDrawType === 'CIRCLE') { + onClickButton('CIRCLE'); + } else if (mapControl.ctrlDrawType === 'RESET') { + clearMode(); + } + }; + + const onClickButton = newMode => { + clearMode(); + startMode(newMode); + }; + + const clearMode = () => { + if (circleArr.length != 0) { + circleArr.map(obj => obj.circle.setMap(null)); + setCircleArr([]); + + markerArr.map(marker => marker.setMap(null)); + setMarkerArr([]); + + stopMapClick(); + } + }; + + const startMode = mode => { + if (!mode) return; + + if (mode === 'CIRCLE') { + resumeMapClick(); + } + }; + + const stopMapClick = () => { + naver.maps.Event.stopDispatch(map, 'click'); + }; + + const resumeMapClick = () => { + naver.maps.Event.resumeDispatch(map, 'click'); + }; + + const onClickCircle = e => { + const coord = e.coord; + + const circle = new naver.maps.Circle({ + strokeColor: '#ff0000', + strokeOpacity: 1, + fillColor: '#ff0000', + fillOpacity: 0.3, + center: coord, + radius: 100, + map: map, + clickable: true + }); + setCircleArr(prev => [ + ...prev, + { center: coord, circle: circle, radius: 100 } + ]); + + naver.maps.Event.addListener(circle, 'mousedown', function () { + onMouseDown(circle); + }); + + addMileStone(coord, fromMetersToText(100)); + }; + + 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 () { + onMouseUp(circle); + }); + }; + + 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 = circle => { + map.setOptions({ + draggable: true, + pinchZoom: true, + scrollWheel: true, + keyboardShortcuts: true, + disableDoubleTapZoom: false, + disableDoubleClickZoom: false, + disableTwoFingerTapZoom: false + }); + + $(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; +} diff --git a/src/modules/control/map/actions/controlMapActions.ts b/src/modules/control/map/actions/controlMapActions.ts index 6b8e0a30..be85343c 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 116007a2..57d64570 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 9cbdfe7a..e4dc7b2b 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,23 @@ const ControlMain = () => { +
+ +
+ 화재경보 +
+
+
+ handlerDrawType('CIRCLE')}> + 화재구역설정 + +
+
+ handlerDrawType('RESET')}>초기화 +
+
+
+
{oepnReportList ? (