Skip to content

Commit dc40c14

Browse files
Merge pull request #73 from pirogramming/feat-sy
feat: 카테고리별 마커 색상 다르게 함
2 parents d19c3e3 + 3181870 commit dc40c14

3 files changed

Lines changed: 104 additions & 50 deletions

File tree

backend-core/static/missions/css/mission_list.css

Lines changed: 40 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -134,23 +134,59 @@
134134
animation: pulse-pin 2s infinite;
135135
}
136136

137-
/* 미션 마커 (노란색) */
137+
/* 미션 마커 - 색상은 JS(CATEGORY_COLORS)에서 inline style로 주입됨 */
138138
.mission-marker {
139-
background: #FFC107;
140139
z-index: 50;
140+
/* background 는 map_manager.js 의 CATEGORY_COLORS 에서 결정 */
141141
}
142142

143143
.mission-marker:hover {
144144
transform: translate(-50%, -100%) rotate(-45deg) scale(1.1);
145145
z-index: 101;
146146
}
147147

148+
/* 매칭 완료된 미션 마커는 약간 흐리게 처리 */
149+
.mission-marker.status-matched,
150+
.mission-marker.status-completed {
151+
opacity: 0.5;
152+
}
153+
148154
@keyframes pulse-pin {
149155
0% { transform: scale(1); opacity: 0.8; }
150156
100% { transform: scale(2.5); opacity: 0; }
151157
}
152158

153-
/* ==================== 4. 헤더 & 필터 UI ==================== */
159+
/* ==================== 4. 지도 범례 ==================== */
160+
.map-legend {
161+
position: absolute;
162+
left: 12px;
163+
bottom: 12px;
164+
z-index: 10;
165+
background: white;
166+
border-radius: 10px;
167+
padding: 8px 12px;
168+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
169+
font-size: 11px;
170+
color: #374151;
171+
pointer-events: none; /* 지도 클릭 방해 안 하도록 */
172+
}
173+
174+
.map-legend-item {
175+
display: flex;
176+
align-items: center;
177+
gap: 6px;
178+
margin: 3px 0;
179+
line-height: 1;
180+
}
181+
182+
.map-legend-dot {
183+
width: 10px;
184+
height: 10px;
185+
border-radius: 50%;
186+
flex-shrink: 0;
187+
}
188+
189+
/* ==================== 5. 헤더 & 필터 UI ==================== */
154190
.mission-header {
155191
height: 70px;
156192
max-width: 450px;
@@ -205,10 +241,6 @@
205241
}
206242

207243

208-
209-
210-
211-
212244
/* 필터 버튼 활성화 상태 */
213245
.filter-btn {
214246
width: 40px;
@@ -240,7 +272,7 @@
240272
stroke: white;
241273
}
242274

243-
/* ==================== 5. 기타 UI 요소 (툴바, 패널 등) ==================== */
275+
/* ==================== 6. 기타 UI 요소 (툴바, 패널 등) ==================== */
244276
.mission-toolbar {
245277
display: flex;
246278
flex-direction: column;
@@ -430,9 +462,6 @@
430462
}
431463

432464

433-
434-
435-
436465
/* 전체화면 지도 컨테이너 */
437466
#fullscreen-map-container {
438467
position: fixed;

backend-core/static/missions/js/map_manager.js

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,32 @@
1414
*
1515
* 수정 사항:
1616
* - getUserLocation(): 3단계 폴백 전략
17-
* - 커스텀 마커: CSS 스타일 사용 (파란색 핀/노란색 핀)
17+
* - 커스텀 마커: CSS 스타일 사용 (파란색 핀/카테고리별 색상 핀)
18+
* - CATEGORY_COLORS: 카테고리별 색상 단일 소스 관리
1819
*/
1920

21+
// ==================== 카테고리 색상 단일 소스 ====================
22+
23+
const CATEGORY_COLORS = {
24+
ERRAND: '#3679E3', // 심부름 - 파랑
25+
STUDY: '#27C27B', // 학업 - 초록
26+
RENTAL: '#FFB800', // 대여 - 노랑
27+
RECRUIT: '#8B5CF6', // 구인 - 보라
28+
LIFE: '#FF6B9A', // 생활 - 핑크
29+
OTHER: '#94A3B8', // 기타 - 회색
30+
};
31+
32+
const CATEGORY_LABELS = {
33+
ERRAND: '심부름',
34+
STUDY: '학업',
35+
RENTAL: '대여',
36+
RECRUIT: '구인',
37+
LIFE: '생활',
38+
OTHER: '기타',
39+
};
40+
41+
const CATEGORY_COLOR_DEFAULT = '#94A3B8'; // fallback
42+
2043
class KakaoMapManager {
2144
constructor(containerId, options = {}) {
2245
this.containerId = containerId;
@@ -177,10 +200,10 @@ class KakaoMapManager {
177200
}
178201

179202
/**
180-
* 커스텀 마커 추가 (CSS 스타일 사용 - 노란색 핀)
203+
* 커스텀 마커 추가 (카테고리별 색상 적용)
181204
* @param {number} lat
182205
* @param {number} lng
183-
* @param {object} options { status: 'WAITING'|'MATCHED'|'COMPLETED', onClick: fn }
206+
* @param {object} options { category: 'ERRAND'|'STUDY'|..., status: 'WAITING'|..., onClick: fn }
184207
* @returns {kakao.maps.CustomOverlay}
185208
*/
186209
addCustomMarker(lat, lng, options = {}) {
@@ -191,13 +214,17 @@ class KakaoMapManager {
191214

192215
const position = new kakao.maps.LatLng(lat, lng);
193216

194-
// CSS 마커 DOM 생성
217+
// 카테고리 색상 결정 (단일 소스: CATEGORY_COLORS)
218+
const color = CATEGORY_COLORS[options.category] ?? CATEGORY_COLOR_DEFAULT;
219+
220+
// CSS 마커 DOM 생성 (색상은 inline style로 주입)
195221
const markerEl = document.createElement('div');
196222
markerEl.className = 'mission-marker';
197-
198-
// 상태별 클래스 추가
223+
markerEl.style.background = color;
224+
225+
// 상태별 클래스 추가 (흐리게 처리 등 상태 UI에 활용)
199226
if (options.status) {
200-
markerEl.classList.add(options.status.toLowerCase());
227+
markerEl.classList.add(`status-${options.status.toLowerCase()}`);
201228
}
202229

203230
// CustomOverlay 생성
@@ -404,6 +431,8 @@ function waitForKakaoMaps() {
404431
// ==================== 전역 노출 ====================
405432

406433
window.KakaoMapManager = KakaoMapManager;
434+
window.CATEGORY_COLORS = CATEGORY_COLORS;
435+
window.CATEGORY_LABELS = CATEGORY_LABELS;
407436
window.MapUtils = {
408437
displayUserLocation,
409438
waitForKakaoMaps

backend-core/static/missions/js/mission_list.js

Lines changed: 28 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -232,16 +232,11 @@
232232
const lng = parseFloat(mission.location_lng);
233233

234234
if (isNaN(lat) || isNaN(lng)) return;
235-
fullscreenMapManager.addCustomMarker(lat, lng, {
236-
status: mission.status,
237-
onClick: () => {
238-
window.location.href = `/api/missions/${mission.id}/`;
239-
}
240-
});
241235

242-
// ✨ 마커 생성 + 클릭 시 상세페이지 이동
243-
const marker = fullscreenMapManager.addCustomMarker(lat, lng, {
244-
status: mission.status, // WAITING/MATCHED/COMPLETED
236+
// ✨ category 전달 → 카테고리별 색상 자동 적용
237+
fullscreenMapManager.addCustomMarker(lat, lng, {
238+
category: mission.category,
239+
status: mission.status,
245240
onClick: () => {
246241
window.location.href = `/api/missions/${mission.id}/`;
247242
}
@@ -292,7 +287,7 @@
292287

293288
/**
294289
* 지도 마커 업데이트
295-
* - map_manager: 마커 생성/표시 (CSS 스타일 적용)
290+
* - map_manager: 마커 생성/표시 (카테고리별 색상 적용)
296291
* - mission_list: 클릭 시 상세페이지 이동
297292
*/
298293
function updateMapMarkers(missions) {
@@ -311,9 +306,10 @@
311306
return;
312307
}
313308

314-
// ✨ 마커 생성 + 클릭 시 상세페이지 이동
315-
const marker = mapManager.addCustomMarker(lat, lng, {
316-
status: mission.status, // WAITING/MATCHED/COMPLETED
309+
// ✨ category 전달 → 카테고리별 색상 자동 적용
310+
mapManager.addCustomMarker(lat, lng, {
311+
category: mission.category,
312+
status: mission.status,
317313
onClick: () => {
318314
window.location.href = `/api/missions/${mission.id}/`;
319315
}
@@ -432,28 +428,28 @@
432428
}
433429

434430
window.moveToCurrentLocation = async function(isFullscreen = false) {
435-
const targetManager = isFullscreen ? fullscreenMapManager : mapManager;
436-
437-
if (!targetManager) return;
438-
439-
console.log(isFullscreen ? "전체화면 현위치 탐색..." : "일반 지도 현위치 탐색...");
440-
441-
try {
442-
// KakaoMapManager 내부의 getUserLocation 활용
443-
const loc = await targetManager.getUserLocation();
431+
const targetManager = isFullscreen ? fullscreenMapManager : mapManager;
444432

445-
// 해당 지도의 중심 이동
446-
targetManager.setCenter(loc.lat, loc.lng);
447-
targetManager.setLevel(3);
433+
if (!targetManager) return;
448434

449-
// 내 위치 마커 표시 (MapUtils 활용)
450-
await MapUtils.displayUserLocation(targetManager);
435+
console.log(isFullscreen ? "전체화면 현위치 탐색..." : "일반 지도 현위치 탐색...");
451436

452-
} catch (err) {
453-
console.error("현위치 이동 실패:", err);
454-
alert("위치 정보를 가져올 수 없습니다.");
455-
}
456-
};
437+
try {
438+
// KakaoMapManager 내부의 getUserLocation 활용
439+
const loc = await targetManager.getUserLocation();
440+
441+
// 해당 지도의 중심 이동
442+
targetManager.setCenter(loc.lat, loc.lng);
443+
targetManager.setLevel(3);
444+
445+
// 내 위치 마커 표시 (MapUtils 활용)
446+
await MapUtils.displayUserLocation(targetManager);
447+
448+
} catch (err) {
449+
console.error("현위치 이동 실패:", err);
450+
alert("위치 정보를 가져올 수 없습니다.");
451+
}
452+
};
457453

458454
// ==================== 전역 함수 노출 ====================
459455

0 commit comments

Comments
 (0)