Dandy Now!
  • [React.js] 네이버 지도 API 마커 중앙 정렬과 레이어 제어
    2025년 05월 14일 19시 55분 18초에 업로드 된 글입니다.
    작성자: DandyNow
    728x90
    반응형

    네이버 지도 API 마커 중앙 정렬과 레이어 제어

    웹 인터페이스를 개발할 때 요소들을 정확한 위치에 배치하고, 사용자와의 인터랙션에 따라 요소들의 표시 순서를 바꾸는 것은 중요한 사용자 경험 요소이다. 이번 글에서는 CSS를 사용한 절대 위치 요소의 정밀한 중앙 정렬 기법과, React 컴포넌트 상태에 따라 네이버 지도 마커의 표시 레이어(z-index)를 동적으로 변경하는 방법에 대해 이야기해보겠다.

    1. 절대 위치 요소의 정확한 중앙 정렬 기법

    CSS에서 position: absoluteleft: 50% 또는 right: 50%를 함께 사용하여 요소를 가로 중앙에 배치하려 할 때, 요소가 화면 중앙에서 미묘하게 왼쪽이나 오른쪽으로 치우치는 경험을 할 수 있다. 이는 left: 50%가 요소의 왼쪽 가장자리를 부모 컨테이너의 가로 중앙에 맞추기 때문에 발생한다. 요소 자체의 너비를 고려하여 정확한 중앙에 배치하려면 transform 속성을 추가해야 한다.

    • left: 50%transform: translateX(-50%) 활용: 요소를 절대 위치로 설정하고 left: 50%를 지정하여 왼쪽 가장자리를 부모의 중앙에 맞춘다. 그 후 transform: translateX(-50%) 속성을 추가하여 요소 너비의 절반만큼 요소를 왼쪽으로 이동시킨다. 이 과정을 통해 요소의 가로 중앙이 부모의 가로 중앙과 일치하게 된다. 만약 right: 50%를 사용한다면 transform: translateX(50%)를 사용하여 오른쪽으로 이동시켜야 한다.

    예제 코드 (CSS):

    /* 부모 요소 (기준점 설정) */
    .parent-container {
      position: relative; /* 자식 절대 위치 요소의 기준점이 된다. */
      width: 300px; /* 예시 너비 */
      height: 200px; /* 예시 높이 */
      border: 1px solid blue; /* 시각화를 위한 보더 */
    }
    
    /* 중앙에 위치시킬 절대 위치 요소 */
    .centered-element {
      position: absolute;
      top: 50px; /* 상단에서부터의 거리 (예시) */
      left: 50%; /* 부모 너비의 중앙에 왼쪽 가장자리를 맞춘다. */
      transform: translateX(-50%); /* 요소 너비의 절반만큼 왼쪽으로 이동하여 중앙 정렬 */
      width: 100px; /* 예시 너비 */
      height: 50px; /* 예시 높이 */
      background-color: yellow; /* 배경색 */
      text-align: center;
      line-height: 50px;
    }

    이 기법은 툴팁의 화살표나 모달 중앙 배치 등 다양한 상황에서 절대 위치 요소를 정밀하게 중앙 정렬하는 데 유용하게 사용된다.

    2. React와 네이버 지도 API 활용: 마커 레이어(z-index) 동적 제어

    지도 위에서 여러 마커를 표시할 때, 특정 마커에 마우스를 올리거나 선택했을 때 해당 마커가 다른 마커들보다 항상 위에 보이도록 표시 순서(레이어)를 조정해야 하는 경우가 있다. react-naver-maps 라이브러리의 <Marker> 컴포넌트가 제공하는 zIndex prop과 React의 상태 관리를 통해 이를 구현할 수 있다.

    • 상태를 이용한 마커 식별: 부모 컴포넌트에서 useState 훅을 사용하여 현재 마우스 오버되거나 선택된 마커의 고유 식별자(ID)를 상태로 관리한다.
    • Props를 통해 마커 컴포넌트로 상태 전달: 마커 목록을 렌더링할 때, 각 마커 컴포넌트에게 해당 마커가 현재 활성화된(마우스 오버된) 상태인지 여부를 boolean 타입의 props(예: isHovered)로 전달한다.
    • Marker 컴포넌트의 zIndex prop 활용: 마커 컴포넌트 내부에서는 전달받은 isHovered props 값을 확인하여, 활성화 상태일 경우 다른 마커들보다 높은 zIndex 값을 <Marker> 컴포넌트의 zIndex prop에 할당한다.

    예제 코드 (React with react-naver-maps):

    // Parent Component (MapComponent.js)
    import React, { useState } from 'react';
    import { NaverMap, Marker } from 'react-naver-maps'; // 라이브러리 임포트 (예시)
    import CustomMarker from './CustomMarker'; // 커스텀 마커 컴포넌트 임포트
    
    const initialMarkerData = [
      { id: 'marker_a', lat: 35.134, lng: 129.058 }, // 부산 지역 예시 좌표
      { id: 'marker_b', lat: 35.137, lng: 129.062 },
      { id: 'marker_c', lat: 35.139, lng: 129.055 },
    ];
    
    function MapComponent() {
      const [hoveredMarkerId, setHoveredMarkerId] = useState(null); // 마우스 오버된 마커 ID 상태 관리
    
      return (
        <NaverMap
          mapDivId={'react-naver-map'} // 지도 컨테이너 div ID
          style={{ width: '100%', height: '500px' }} // 지도 스타일
          defaultCenter={{ lat: 35.137, lng: 129.058 }} // 기본 중심 좌표
          defaultZoom={13} // 기본 확대 레벨
        >
          {initialMarkerData.map(marker => (
            <CustomMarker
              key={marker.id}
              markerData={marker}
              onMouseEnter={() => setHoveredMarkerId(marker.id)} // 마우스 진입 시 ID 저장
              onMouseLeave={() => setHoveredMarkerId(null)} // 마우스 이탈 시 ID 초기화
              isHovered={marker.id === hoveredMarkerId} // 현재 마커가 호버 상태인지 전달
            />
          ))}
        </NaverMap>
      );
    }
    
    // CustomMarker Component (CustomMarker.js)
    import React from 'react';
    import { Marker } from 'react-naver-maps'; // react-naver-maps의 Marker 임포트
    
    function CustomMarker({ markerData, onMouseEnter, onMouseLeave, isHovered }) {
      // 호버 상태에 따라 zIndex 값 결정
      const markerZIndex = isHovered ? 1000 : 100; // 호버 시 높게 (예: 1000), 기본 값 (예: 100)
    
      return (
        <Marker
          position={{ lat: markerData.lat, lng: markerData.lng }}
          onMouseover={onMouseEnter} // 네이버 맵스 이벤트 핸들러 (소문자 주의)
          onMouseout={onMouseLeave}
          zIndex={markerZIndex} // 계산된 zIndex 값을 Marker props에 적용
          // 마커의 모양과 내용을 정의하는 icon prop 등은 여기에 추가한다.
           icon={{ // 예시 아이콘 설정
              content: `<div style="padding: 5px; background: ${isHovered ? '#fff' : '#eee'}; border: 1px solid gray; border-radius: 5px; font-size: small;">${markerData.id}</div>`,
              size: { width: markerData.id.length * 8 + 20, height: 30 }, // 텍스트 길이에 따른 크기 조절
              anchor: { x: (markerData.id.length * 8 + 20) / 2, y: 30 } // 중앙 하단 앵커
           }}
        />
      );
    }
    
    export default MapComponent;

    위 예제 코드는 <NaverMap> 컴포넌트 내에서 initialMarkerData 배열을 순회하며 <CustomMarker> 컴포넌트를 렌더링한다. MapComponenthoveredMarkerId 상태를 통해 어떤 마커가 현재 마우스 오버되었는지 추적하고, 이 정보를 isHovered props를 통해 각 CustomMarker에게 전달한다. CustomMarker 내부에서는 isHovered 값에 따라 <Marker> 컴포넌트의 zIndex prop을 다르게 설정하여 마커의 표시 레이어를 제어하게 된다. zIndex 값은 다른 요소들의 레이어 순서를 고려하여 적절히 설정해야 한다.

    결론

    CSS의 left/right, transform: translateX() 조합은 절대 위치 요소의 정확한 가로 중앙 정렬을 가능하게 하며, 이는 레이아웃의 정밀도를 높이는 데 기여한다. 더불어 React의 상태 관리와 props 전달을 활용하여 react-naver-maps와 같은 라이브러리 컴포넌트의 속성(예: zIndex)을 동적으로 제어하는 기법은 지도 애플리케이션 등에서 사용자 인터랙션에 반응하여 요소들의 표시 순서를 유연하게 변경하는 데 매우 유용하다. 이러한 웹 개발의 기본적인 기법들을 숙지하면 더욱 풍부하고 동적인 사용자 경험을 제공하는 애플리케이션을 구현할 수 있을 것이다.

    728x90
    반응형
    댓글