[React] OpenLayers 적용하기 - VWorld API(배경지도), 내 위치조회

EunCheol·2025년 3월 11일
0

React

목록 보기
1/1

React에서 OpenLayers 적용하기 - VWorld 배경지도 활용

1. 프로젝트 설정

먼저 React 프로젝트를 생성하고 필요한 패키지를 설치함.

npx create-react-app my-map-app --template typescript
cd my-map-app
npm install ol

2. MapManager.ts 파일 생성

OpenLayers를 사용하여 지도를 관리하는 MapManager 클래스를 생성함.

import Map from 'ol/Map';
import View from 'ol/View';
import { fromLonLat } from 'ol/proj';
import TileLayer from 'ol/layer/Tile';
import { Tile, Vector as VectorLayer } from 'ol/layer';
import { Vector as VectorSource, XYZ } from 'ol/source';
import { defaults as defaultControls } from 'ol/control';
import Feature from 'ol/Feature';
import Point from 'ol/geom/Point';
import { Style, Circle as CircleStyle, Fill, Stroke } from 'ol/style';

export interface LocationResult {
  success: boolean;
  error?: string;
}

export type LocationCallback = (result: LocationResult) => void;

class MapManager {
  private map: Map | null = null;
  private locationLayer: VectorLayer<VectorSource> | null = null;

  initialize(target: string): Map {
    const baseMap = new XYZ({
        url: "http://api.vworld.kr/req/wmts/1.0.0/{apiKey}/Base/{z}/{y}/{x}.png",
        crossOrigin: 'anonymous',
        transition: 0,
    });
    
    this.map = new Map({
      target,
      layers: [
        new Tile({
            source: baseMap,
            preload: 20,
        }),
      ],
      view: new View({
        center: fromLonLat([127.550, 35.871]),
        zoom: 7.5,
      }),
      controls: defaultControls({ zoom: false }),
    });

    return this.map;
  }

  findMyLocation(callback: LocationCallback): void {
    if (!this.map) {
      callback({ success: false, error: '지도가 초기화되지 않음' });
      return;
    }

    if (!navigator.geolocation) {
      callback({ success: false, error: '브라우저가 위치 정보를 지원하지 않음' });
      return;
    }

    navigator.geolocation.getCurrentPosition(
      (position) => {
        const { longitude, latitude } = position.coords;
        const location = fromLonLat([longitude, latitude]);

        const locationFeature = new Feature({
          geometry: new Point(location),
        });

        const vectorSource = new VectorSource({
          features: [locationFeature],
        });

        const vectorLayer = new VectorLayer({
          source: vectorSource,
          style: new Style({
            image: new CircleStyle({
              radius: 8,
              fill: new Fill({ color: '#3182f6' }),
              stroke: new Stroke({ color: '#ffffff', width: 2 }),
            }),
          }),
        });

        this.map.addLayer(vectorLayer);

        this.map.getView().animate({
          center: location,
          zoom: 15,
          duration: 1000,
        });

        callback({ success: true });
      },
      (error) => {
        let errorMessage = '알 수 없는 오류 발생';
        switch (error.code) {
          case error.PERMISSION_DENIED:
            errorMessage = '위치 정보 접근 권한이 거부됨';
            break;
          case error.POSITION_UNAVAILABLE:
            errorMessage = '위치 정보를 사용할 수 없음';
            break;
          case error.TIMEOUT:
            errorMessage = '위치 정보 요청 시간이 초과됨';
            break;
        }
        callback({ success: false, error: errorMessage });
      },
      { enableHighAccuracy: true, timeout: 5000, maximumAge: 0 }
    );
  }
}

export default new MapManager();

3. MapComponent.tsx 파일 생성

React 컴포넌트에서 MapManager를 사용하여 지도 렌더링 및 내 위치 찾기 기능을 추가함.

import React, { useEffect, useState } from 'react';
import MapManager from '../utils/MapManager';
import '../assets/map.css';

const MapComponent = () => {
  const [locationError, setLocationError] = useState<string | null>(null);

  useEffect(() => {
    MapManager.initialize('map');
    return () => MapManager.cleanup();
  }, []);

  const findMyLocation = () => {
    MapManager.findMyLocation((result) => {
      if (!result.success && result.error) {
        setLocationError(result.error);
      } else {
        setLocationError(null);
      }
    });
  };

  return (
    <div className="map-container">
      <div id="map" className="map" />
      <button className="location-button" onClick={findMyLocation}>
        내 위치 찾기
      </button>
      {locationError && <div className="location-error">{locationError}</div>}
    </div>
  );
};

export default MapComponent;

4. 스타일링 (map.css)

.map-container {
  position: relative;
  width: 100%;
  height: 500px;
}

.map {
  width: 100%;
  height: 100%;
}

.location-button {
  position: absolute;
  top: 10px;
  right: 10px;
  padding: 10px;
  background: blue;
  color: white;
  border: none;
  cursor: pointer;
}

.location-error {
  color: red;
  margin-top: 10px;
}

5. 결과 화면

1개의 댓글

comment-user-thumbnail
2025년 4월 8일

그래서 님 위치는 어디심?

답글 달기