이번 포스팅에서는 지도 마커 아이콘을 반응형 커스텀하는 방법에 대해서 알아보겠습니다.
MarkerOptions 객체에서 icon 속성을 직접 지정하지 않으면 기본 아이콘이 적용됩니다. 마커 아이콘을 이미지로도 지정할 수 있습니다.
하지만 각 위치 이름을 마커에 렌더링하기 위해 HTML 콘텐츠를 사용해보겠습니다.
화면 너비를 기준으로 마커 아이콘을 동적으로 조정할 것입니다. 이를 위해
viewportWidth state에 화면 너비값을 저장합니다.
초기 값은 window.innerWidth를 사용하여 브라우저의 현재 너비로 지정합니다.
viewport가 resize될 때 상태를 변경해주기 위해 useEffect를 통해 resize 이벤트 핸들러를 등록합니다.
const [viewportWidth, setViewportWidth] = useState(window.innerWidth);
useEffect(() => {
const handleResize = () => {
setViewportWidth(window.innerWidth);
};
window.addEventListener('resize', handleResize);
return () => {
window.removeEventListener('resize', handleResize);
};
}, []);
마커 생성 전후 과정에 대한 내용은 2편을 참고해주시길 바랍니다.
- content <string | HTMLElement>
마커의 아이콘으로 사용할 HTML 마크업 또는 HTML 요소- size: <naver.maps.Size | SizeLiteral>
마커의 크기- anchor: <naver.maps.Point | PointLiteral | naver.maps.Position>
지도 위에 놓이는 마커의 위치와 일치시킬 아이콘의 기준 위치. 기본값은 (0, 0)
content 속성은 필수이며 이 부분에 HTML Element를 넣어줄 것입니다.
let newMarker = new naver.maps.Marker({
position: new naver.maps.LatLng(lng, lat),
map,
title: name,
clickable: true,
icon: {
//html element를 반환하는 CustomMapMarker 컴포넌트 할당
content: CustomMapMarker({ title: name, windowWidth: viewportWidth }),
//마커의 크기 지정
size: new naver.maps.Size(38, 58),
//마커의 기준위치 지정
anchor: new naver.maps.Point(19, 58),
},
});
CustomMapMarker 컴포넌트는 제목과 화면너비를 props로 받아 HTMLElement를 반환합니다.
const CustomMapMarker = ({ title, windowWidth }: {
title: string;
windowWidth: number;
}) => {
const mobileContentArray = [
'<div style="margin: 0; display: table; padding: 0.5rem; table-layout: auto; border-radius: 2.3rem; border: 0.2rem solid var(--color--darkgreen); background: white; cursor: pointer; position: relative; z-index: 2">',
'<div style="display: table-cell; display: inline-block; width: 2.5rem; height: 2.5rem; background-image: url(Images/markerIcon.svg); background-size: cover; background-position: center; background-repeat: no-repeat;"></div>',
'<span style="position: absolute; border-style: solid; border-width: 1rem 1rem 0 1rem; border-color: #ffffff transparent; display: block; width: 0; z-index: 1; top: 3.1rem; left: 0.75rem;"></span>',
'<span style="position: absolute; border-style: solid; border-width: 1rem 1rem 0 1rem; border-color: var(--color--darkgreen) transparent; display: block; width: 0; z-index: 0; top: 3.35rem; left: 0.75rem;"></span>',
'</div>',
];
const PCContentArray = [
'<div style="margin: 0; display: table; padding: 0.5rem; table-layout: auto; border-radius: 2.3rem; border: 0.2rem solid var(--color--darkgreen); background: white; cursor: pointer; position: relative; z-index: 2">',
'<div style="display: table-cell; display: inline-block; width: 4rem; height: 4rem; background-image: url(Images/markerIcon.svg); background-size: cover; background-position: center; background-repeat: no-repeat;"></div>',
'<div style="max-width: 23rem; height: 4rem; padding: 0 0.8rem 0 0.8rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; display: table-cell; vertical-align: middle; cursor: pointer; font-size: 1.5rem; letter-spacing: -0.04rem; font-weight: 600; line-height: 4rem;">',
title,
'</div>',
'<span style="position: absolute; border-style: solid; border-width: 1.2rem 1rem 0 1rem; border-color: #ffffff transparent; display: block; width: 0; z-index: 1; top: 4.8rem; left: 1.4rem;"></span>',
'<span style="position: absolute; border-style: solid; border-width: 1.2rem 1rem 0 1rem; border-color: var(--color--darkgreen) transparent; display: block; width: 0; z-index: 0; top: 5.05rem; left: 1.4rem;"></span>',
'</div>',
];
if (windowWidth < 768) return mobileContentArray.join('');
return PCContentArray.join('');
};
export default CustomMapMarker;
const mobileContentArray = [ ... ];
const PCContentArray = [ ... ];
if (windowWidth < 768) return mobileContentArray.join('');
return PCContentArray.join('');
⬇️ 싸커퀵 ⬇️
https://soccerquick.kr/