article thumbnail

React와 OpenLayers를 사용한 기능 포스팅을 몇 개 올렸지만 가장 기본적인 지도를 화면에 출력하는 방법에 대한 포스팅을 이제 올리게 되었다.

여기서 React의 provider와 context 개념이 필요한데, 이에 대해서는 후에 다른 포스팅으로 자세히 설명하려고 한다.

 

프로젝트 생성 및 라이브러리 설치

프로젝트 생성

npx create-react-app react-context-openlayer
cd react-context-openlayer

 

OpenLayers 라이브러리 설치

npm install ol

yarn과 npm이 있는데 npm을 사용하여 OpeLayers 라이브러리인 ol을 설치하였다.

 

화면에 Map 출력하기

MapContext 생성

./Map/MapContext.js

import React from "react";
const MapContext = new React.createContext({});
export default MapContext;

MapContext는 map 객체를 저장할 저장소로 보면 된다.

 

Map Provider 생성

MapContext에서 지도(sampleMap)을 쉽게 핸들링할 수 있도록 하는 Provider를 작성한다.

OpenLayers 객체를 통해 초기에 셋팅해야 할 사항들을 설정해주고 지도를 Provider에 저장한다.

 

./Map/SampleMap.jsx

import { useEffect, useState } from "react"
import { Map as OlMap, View } from 'ol';
import { defaults as defaultControls } from 'ol/control';
import { fromLonLat, get as getProjection } from 'ol/proj';
import { Tile as TileLayer } from 'ol/layer';
import { OSM } from 'ol/source';
import MapContext from "./MapContext";
import 'ol/ol.css';

const SampleMap = ({children}) => {
    const [mapObj, setMapObj] = useState({});

    useEffect(() => {
        // Map 객체 생성 및 OSM 배경지도 추가
        const sampleMap = new OlMap({
            controls: defaultControls({zoom: false, rotate: false}).extend([]),
            layers: [
                new TileLayer({
                    source: new OSM(),
                })
                // 지도를 그리는 layer
            ],
            target: 'sampleMap', // 하위 요소 중 id가 sampleMap인 element가 있어야 함
            // 처음 지도가 로딩될 때 기준이 될 중심 좌표와 좌표계
            view: new View({
                projection: getProjection('EPSG:4326'),
                center: fromLonLat([126.9706440, 37.5545380], getProjection('EPSG:4326')),
                zoom: 19,
            }),
        });

        setMapObj({sampleMap});
        return () => sampleMap.setTarget(undefined);
    }, []);


    // MapContext.Provider에 객체 저장
    return <MapContext.Provider value={mapObj}>{children}</MapContext.Provider>
};

export default SampleMap;

OSM은 OpenStreetMap에서 제공되는 지도 source이다.
TileLayer 외에 다른 Layer와 지도 source를 사용하여 지도 레이어를 만들 수 있다.(VWorld, Google 지도 등)
그 밖에 layers[] 배열 내부에 다른 원하는 레이어들을 추가하여 지도가 처음 로드될 때 레이어들을 초기화할 수 있다.

 

Map 가져오기

./Map/index.js

export {default as SampleMap} from "./SampleMap";

Provider를 import 할 때 경로만을 가져올 수 있도록 한다.

 

./index.js

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { SampleMap } from './Map';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <SampleMap>
      <App />
    </SampleMap>
  </React.StrictMode>
);

reportWebVitals();

프로젝트가 처음 생성될 때 만들어지는 index 파일에 앞에서 만든 Context.Provider로 자식요소를 감싼다.

Provider에서 저장한 객체를 사용하기 위해서는 위와 같이 자식요소를 Provider로 감싸야 한다.

 

./App.js

import { useContext } from "react";
import MapContext from "./Map/MapContext";


function App() {

  // context에 저장되어 있는 객체를 가져옴
  const { sampleMap } = useContext(MapContext);

  // zoom-in
  const handleZoomInClick = () => {
    sampleMap.getView().setZoom(sampleMap.getView().getZoom() + 1);
  };

  // zoom-out
  const handleZoomOutClick = () => {
    sampleMap.getView().setZoom(sampleMap.getView().getZoom() - 1);
  };

  return (
    <>
      <button onClick={handleZoomInClick}>zoomIn</button>
      <button onClick={handleZoomOutClick}>zoomOut</button>
      <div id="sampleMap" style={{width:'100%', height:600}} />
    </>
  );
}

export default App;

zoomIn과 zoomOut 버튼까지 생성하여 지도를 출력할 수 있다.

지도의 height 설정을 부여하지 않으면 지도가 보이지 않기 때문에 높이를 지정해주어야 한다.

 

 

번외

지도에서 내가 보고 있는 위치가 어디인지 지도로 바로 확인하고 싶을 땐 provider를 만들 때 해당 요소를 함께 초기화하여 저장하면 된다.

아래 작성된 코드의 기능은 지도 위에 마우스 커서를 올렸을 때 커서가 지도에서 어느 좌표인지를 알려주는 기능이다.

import { defaults as defaultControls, MousePosition } from 'ol/control';

// ...
        const mousePositionControl = new MousePosition({
            coordinateFormat: (coordinate) => {
                const formattedCoordinate = coordinate.map((coord) => coord.toFixed(8));
                return formattedCoordinate.toString();
            },
            projection: 'EPSG:4326',
            className: 'custom-mouse-position',
            target: document.getElementById('mouse-position'),
        });
        
        const sampleMap = new OlMap({
            controls: defaultControls({zoom: false, rotate: false}).extend([mousePositionControl]),
// ...

 

useEffect 내부의 지도를 생성하는 변수를 초기화 하기 전 mousePosition API(mousePositionControl)를 추가한다.

이 API를 지도에 추가하면 지도 왼쪽 상단에 마우스 커서가 위치한 좌표가 무엇인지 출력된다.

 

 


[ 참고 ]

https://songjang.tistory.com/25

https://openlayers.org/en/latest/examples/mouse-position.html