diff --git a/package.json b/package.json
index f15f57f..bc99e88 100644
--- a/package.json
+++ b/package.json
@@ -13,6 +13,7 @@
"@fullcalendar/timegrid": "5.7.2",
"@fullcalendar/timeline": "5.7.2",
"@hookform/resolvers": "1.3.4",
+ "@mapbox/mapbox-gl-draw": "^1.4.2",
"@mapbox/mapbox-gl-language": "1.0.1",
"@stomp/stompjs": "^6.1.0",
"@turf/buffer": "^6.5.0",
@@ -62,7 +63,7 @@
"nouislider-react": "3.3.8",
"postcss-rtl": "1.5.0",
"prismjs": "1.19.0",
- "proj4": "^2.8.0",
+ "proj4": "^2.9.0",
"prop-types": "15.7.2",
"react": "17.0.1",
"react-apexcharts": "1.3.6",
diff --git a/src/components/basis/flight/plan/FlightPlanAreaMapBox.js b/src/components/basis/flight/plan/FlightPlanAreaMapBox.js
new file mode 100644
index 0000000..88f33c8
--- /dev/null
+++ b/src/components/basis/flight/plan/FlightPlanAreaMapBox.js
@@ -0,0 +1,395 @@
+import { useEffect, useRef, useState } from 'react';
+import 'mapbox-gl/dist/mapbox-gl.css';
+import mapboxgl from 'mapbox-gl';
+import MapboxLanguage from '@mapbox/mapbox-gl-language';
+import { MAPBOX_TOKEN } from '../../../../configs/constants';
+import * as turf from '@turf/turf';
+import proj4 from 'proj4/dist/proj4';
+import {
+ Card,
+ CardBody,
+ Button,
+ Input,
+ InputGroup,
+ InputGroupAddon,
+ InputGroupText,
+ Modal,
+ ModalHeader,
+ ModalBody,
+ ModalFooter
+} from 'reactstrap';
+import { useDispatch, useSelector } from 'react-redux';
+import { initFlightBas } from '../../../../modules/basis/flight/models/basisFlightModel';
+import { AREA_DETAIL_INIT } from '../../../../modules/basis/flight/actions/basisFlightAction';
+import { flightPlanAPI } from '../../../../modules/basis/flight/apis/basisFlightApi';
+import { Search } from 'react-feather';
+import { FeatureAirZone } from '../../../map/mapbox/feature/FeatureAirZone';
+import { drawTypeChangeAction } from '../../../../modules/control/map/actions/controlMapActions';
+import { MapBoxDraw } from '../../../map/mapbox/draw/MapBoxDraw';
+
+export const FlightPlanAreaMapBox = props => {
+ const dispatch = useDispatch();
+ const mapControl = useSelector(state => state.controlMapReducer);
+ const { areaCoordList } = useSelector(state => state.flightState);
+
+ const mapContainer = useRef(null);
+ const [mapObject, setMapObject] = useState();
+ const [isMapLoad, setIsMapLoad] = useState(false);
+ const [mode, setMode] = useState();
+ const [mapAreaCoordList, setMapAreaCoordList] = useState(
+ initFlightBas.initDetail.areaList
+ );
+
+ const [query, setQuery] = useState('');
+ const [searchRes, setSearchRes] = useState([]);
+ const [isSearch, setIsSearch] = useState(false);
+
+ const [dragSize, setDragSize] = useState(70);
+ const [pastDragCircle, setDragCircle] = useState([]);
+
+ const [number, setNumber] = useState(0);
+
+ const [formModal, setFormModal] = useState(false);
+
+ useEffect(() => {
+ mapBoxMapInit();
+
+ return () => {
+ dispatch(AREA_DETAIL_INIT());
+ };
+ }, []);
+
+ const mapBoxMapInit = () => {
+ const bufferZoom = {};
+ if (areaCoordList) {
+ if (
+ areaCoordList[0].bufferZone >= 0 &&
+ areaCoordList[0].bufferZone < 2000
+ ) {
+ bufferZoom.bufferzoom = 13;
+ } else if (
+ areaCoordList[0].bufferZone >= 2000 &&
+ areaCoordList[0].bufferZone < 5000
+ ) {
+ bufferZoom.bufferzoom = 12;
+ } else if (
+ areaCoordList[0].bufferZone >= 5000 &&
+ areaCoordList[0].bufferZone <= 9000
+ ) {
+ bufferZoom.bufferzoom = 11;
+ } else {
+ bufferZoom.bufferzoom = 10;
+ }
+ }
+
+ mapboxgl.accessToken = MAPBOX_TOKEN;
+
+ const map = new mapboxgl.Map({
+ container: 'map', // container ID
+ style: 'mapbox://styles/mapbox/streets-v12', // style URL
+ center: [126.612647, 37.519893], // starting position [lng, lat]
+ zoom: !areaCoordList ? 11 : bufferZoom.bufferzoom, // starting zoom
+ antialias: true
+ });
+
+ const language = new MapboxLanguage();
+ map.addControl(language);
+
+ map.on('load', () => {
+ const layers = map.getStyle().layers;
+
+ const labelLayerId = layers.find(
+ layer => layer.type === 'symbol' && layer.layout['text-field']
+ ).id;
+
+ // 지형 3d start
+ map.addSource('mapbox-dem', {
+ type: 'raster-dem',
+ url: 'mapbox://mapbox.mapbox-terrain-dem-v1',
+ tileSize: 512,
+ maxZoom: 16
+ });
+ map.setTerrain({ source: 'mapbox-dem', exaggeration: 1.5 });
+ map.addLayer({
+ id: 'contour-labels',
+ type: 'symbol',
+ source: {
+ type: 'vector',
+ url: 'mapbox://mapbox.mapbox-terrain-v2'
+ },
+ 'source-layer': 'contour',
+ layout: {
+ visibility: 'visible',
+ 'symbol-placement': 'line',
+ 'text-field': ['concat', ['to-string', ['get', 'ele']], 'm']
+ },
+ paint: {
+ 'icon-color': '#877b59',
+ 'icon-halo-width': 1,
+ 'text-color': '#877b59',
+ 'text-halo-width': 1
+ }
+ });
+ map.addLayer({
+ id: 'sky',
+ type: 'sky',
+ paint: {
+ 'sky-type': 'atmosphere',
+ 'sky-atmosphere-sun': [0.0, 90.0],
+ 'sky-atmosphere-sun-intensity': 15
+ }
+ });
+ // 지형 3d end
+ // 등고선 start
+ map.addLayer({
+ id: 'contours',
+ type: 'line',
+ source: {
+ type: 'vector',
+ url: 'mapbox://mapbox.mapbox-terrain-v2'
+ },
+ 'source-layer': 'contour',
+ layout: {
+ visibility: 'visible',
+ 'line-join': 'round',
+ 'line-cap': 'round'
+ },
+ paint: {
+ 'line-color': '#877b59',
+ 'line-width': 1
+ }
+ });
+ // 등고선 end
+ // 3d building
+ map.addLayer(
+ {
+ id: 'add-3d-buildings',
+ source: 'composite',
+ 'source-layer': 'building',
+ filter: ['==', 'extrude', 'true'],
+ type: 'fill-extrusion',
+ minzoom: 15,
+ paint: {
+ 'fill-extrusion-color': '#aaa',
+
+ // Use an 'interpolate' expression to
+ // add a smooth transition effect to
+ // the buildings as the user zooms in.
+ 'fill-extrusion-height': [
+ 'interpolate',
+ ['linear'],
+ ['zoom'],
+ 15,
+ 0,
+ 15.05,
+ ['get', 'height']
+ ],
+ 'fill-extrusion-base': [
+ 'interpolate',
+ ['linear'],
+ ['zoom'],
+ 15,
+ 0,
+ 15.05,
+ ['get', 'min_height']
+ ],
+ 'fill-extrusion-opacity': 0.6
+ }
+ },
+ labelLayerId
+ );
+ // 3d building
+ setMapObject(map);
+ setIsMapLoad(true);
+ });
+ };
+
+ const handlerSearch = async () => {
+ const res = await flightPlanAPI.searchArea({ query: query });
+ setIsSearch(true);
+ setSearchRes(res.data.items);
+ };
+
+ const handlerChange = e => {
+ const { name, value } = e.target;
+
+ if (name == 'searchInput') {
+ setQuery(value);
+ }
+ };
+
+ const handlerEnter = e => {
+ if (e.key == 'Enter') {
+ handlerSearch();
+ }
+ };
+
+ const handlerCoord = (mapx, mapy) => {
+ const numberString = [mapx, mapy];
+ const latlng = [];
+
+ numberString.map(coord => {
+ let digits = coord.split('');
+
+ if (digits[0] !== '1') {
+ digits.splice(2, 0, '.');
+ } else {
+ digits.splice(3, 0, '.');
+ }
+
+ latlng.push(Number(digits.join('')));
+ });
+
+ setIsSearch(false);
+ mapObject.setCenter(latlng);
+ mapObject.setZoom(15);
+ };
+
+ const handler = () => {
+ setFormModal(!formModal);
+ };
+
+ const handlerDrawType = val => {
+ dispatch(drawTypeChangeAction(val));
+ };
+
+ return (
+ 지도 영역
+
+ {searchRes?.length !== 0 && isSearch ? (
+ searchRes?.map(search => {
+ const title = search.title
+ .replaceAll('', '')
+ .replaceAll('', '');
+
+ return (
+
+