feat(map): NaverMapView 채널별 마커 색상
- GoogleMapView와 동일 팔레트 (8 색) - 식당 첫 채널 기준 색상, activeChannel 있으면 우선 - getChannelColorMap 재사용 패턴 동일 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -6,6 +6,10 @@
|
||||
|
||||
## 2026-06-16
|
||||
|
||||
### 🎨 NaverMapView 채널별 마커 색상 (v0.1.60)
|
||||
- GoogleMapView와 동일 팔레트 (amber/blue/green/pink/purple/red/teal/yellow)
|
||||
- 식당의 첫 채널 기준 색상, activeChannel 있으면 그 채널 우선
|
||||
|
||||
### ⚡ NaverMapView SDK 네이티브 마커 + InfoWindow (v0.1.59)
|
||||
- 마커를 React `absolute div` overlay → `naver.maps.Marker` 네이티브로 교체
|
||||
- 줌/팬 시 SDK가 GPU 최적화, 매 frame React 리렌더링 없음 → 랙 해소
|
||||
|
||||
@@ -44,6 +44,30 @@ type NaverInfoWindow = {
|
||||
|
||||
const NAVER_CLIENT_ID = process.env.NEXT_PUBLIC_NAVER_MAP_CLIENT_ID || "";
|
||||
|
||||
// Channel color palette — GoogleMapView와 동일
|
||||
const CHANNEL_COLORS = [
|
||||
{ border: "#f59e0b" }, // amber (default)
|
||||
{ border: "#3b82f6" }, // blue
|
||||
{ border: "#22c55e" }, // green
|
||||
{ border: "#ec4899" }, // pink
|
||||
{ border: "#a855f7" }, // purple
|
||||
{ border: "#ef4444" }, // red
|
||||
{ border: "#14b8a6" }, // teal
|
||||
{ border: "#eab308" }, // yellow
|
||||
];
|
||||
|
||||
function getChannelColorMap(restaurants: Restaurant[]) {
|
||||
const channels = new Set<string>();
|
||||
restaurants.forEach((r) => r.channels?.forEach((ch) => channels.add(ch)));
|
||||
const map: Record<string, typeof CHANNEL_COLORS[0]> = {};
|
||||
let i = 0;
|
||||
for (const ch of channels) {
|
||||
map[ch] = CHANNEL_COLORS[i % CHANNEL_COLORS.length];
|
||||
i++;
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
function useNaverMaps(): { ready: boolean; error: string | null } {
|
||||
const [ready, setReady] = useState(typeof window !== "undefined" && !!window.naver?.maps);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
@@ -101,9 +125,9 @@ function getClusterSize(count: number): number {
|
||||
return 54;
|
||||
}
|
||||
|
||||
// SVG data URL — 단일 마커(주황 핀)
|
||||
function markerIconHtml(): string {
|
||||
return `<div style="width:28px;height:28px;border-radius:9999px;background:#f59e0b;border:2px solid #fff;box-shadow:0 2px 6px rgba(0,0,0,.25);"></div>`;
|
||||
// 단일 마커 — 채널 색상별
|
||||
function markerIconHtml(color: string): string {
|
||||
return `<div style="width:28px;height:28px;border-radius:9999px;background:${color};border:2px solid #fff;box-shadow:0 2px 6px rgba(0,0,0,.25);"></div>`;
|
||||
}
|
||||
// SVG data URL — 클러스터(숫자)
|
||||
function clusterIconHtml(count: number, size: number): string {
|
||||
@@ -117,7 +141,9 @@ export default function NaverMapView({
|
||||
onBoundsChanged,
|
||||
flyTo,
|
||||
onMyLocation,
|
||||
activeChannel,
|
||||
}: MapViewProps) {
|
||||
const channelColors = useMemo(() => getChannelColorMap(restaurants), [restaurants]);
|
||||
const { ready, error } = useNaverMaps();
|
||||
const divRef = useRef<HTMLDivElement | null>(null);
|
||||
const mapRef = useRef<NaverMapInstance | null>(null);
|
||||
@@ -230,12 +256,14 @@ export default function NaverMapView({
|
||||
markersRef.current.push(marker);
|
||||
} else {
|
||||
const r = (feature.properties as RestaurantProps).restaurant;
|
||||
const chKey = activeChannel && r.channels?.includes(activeChannel) ? activeChannel : r.channels?.[0];
|
||||
const chColor = chKey ? channelColors[chKey] : CHANNEL_COLORS[0];
|
||||
const marker = new naver.Marker({
|
||||
position: new naver.LatLng(lat, lng),
|
||||
map: m,
|
||||
title: r.name,
|
||||
icon: {
|
||||
content: markerIconHtml(),
|
||||
content: markerIconHtml(chColor?.border ?? "#f59e0b"),
|
||||
anchor: new naver.Point(14, 14),
|
||||
},
|
||||
});
|
||||
@@ -252,7 +280,7 @@ export default function NaverMapView({
|
||||
markersRef.current.push(marker);
|
||||
}
|
||||
}
|
||||
}, [clusters, getExpansionZoom, onSelectRestaurant]);
|
||||
}, [clusters, getExpansionZoom, onSelectRestaurant, channelColors, activeChannel]);
|
||||
|
||||
// 컴포넌트 unmount 시 마커 정리
|
||||
useEffect(() => {
|
||||
|
||||
Reference in New Issue
Block a user