feat: 보고서 지도캡처 + 드론/CCTV/확산예측 UI 기능 개선 #91
@ -47,6 +47,166 @@ const BASE_STYLE: StyleSpecification = {
|
||||
],
|
||||
}
|
||||
|
||||
// MarineTraffic 스타일 — 깔끔한 연한 회색 육지 + 흰색 바다 + 한글 라벨
|
||||
const LIGHT_STYLE: StyleSpecification = {
|
||||
version: 8,
|
||||
glyphs: 'https://demotiles.maplibre.org/font/{fontstack}/{range}.pbf',
|
||||
sources: {
|
||||
'ofm-chart': {
|
||||
type: 'vector',
|
||||
url: 'https://tiles.openfreemap.org/planet',
|
||||
},
|
||||
},
|
||||
layers: [
|
||||
// ── 배경 = 육지 (연한 회색) ──
|
||||
{
|
||||
id: 'land-bg',
|
||||
type: 'background',
|
||||
paint: { 'background-color': '#e8e8e8' },
|
||||
},
|
||||
// ── 바다/호수/강 = water 레이어 (파란색) ──
|
||||
{
|
||||
id: 'water',
|
||||
type: 'fill',
|
||||
source: 'ofm-chart',
|
||||
'source-layer': 'water',
|
||||
paint: { 'fill-color': '#a8cce0' },
|
||||
},
|
||||
// ── 주요 도로 (zoom 9+) ──
|
||||
{
|
||||
id: 'roads-major',
|
||||
type: 'line',
|
||||
source: 'ofm-chart',
|
||||
'source-layer': 'transportation',
|
||||
minzoom: 9,
|
||||
filter: ['in', 'class', 'motorway', 'trunk', 'primary'],
|
||||
paint: {
|
||||
'line-color': '#c0c0c0',
|
||||
'line-width': ['interpolate', ['linear'], ['zoom'], 9, 0.4, 14, 1.5],
|
||||
},
|
||||
},
|
||||
// ── 보조 도로 (zoom 12+) ──
|
||||
{
|
||||
id: 'roads-secondary',
|
||||
type: 'line',
|
||||
source: 'ofm-chart',
|
||||
'source-layer': 'transportation',
|
||||
minzoom: 12,
|
||||
filter: ['in', 'class', 'secondary', 'tertiary'],
|
||||
paint: {
|
||||
'line-color': '#cccccc',
|
||||
'line-width': ['interpolate', ['linear'], ['zoom'], 12, 0.3, 14, 1],
|
||||
},
|
||||
},
|
||||
// ── 건물 (zoom 14+) ──
|
||||
{
|
||||
id: 'buildings',
|
||||
type: 'fill',
|
||||
source: 'ofm-chart',
|
||||
'source-layer': 'building',
|
||||
minzoom: 14,
|
||||
paint: { 'fill-color': '#cbcbcb', 'fill-opacity': 0.5 },
|
||||
},
|
||||
// ── 국경선 ──
|
||||
{
|
||||
id: 'boundaries-country',
|
||||
type: 'line',
|
||||
source: 'ofm-chart',
|
||||
'source-layer': 'boundary',
|
||||
filter: ['==', 'admin_level', 2],
|
||||
paint: { 'line-color': '#999999', 'line-width': 1, 'line-dasharray': [4, 2] },
|
||||
},
|
||||
// ── 시도 경계 (zoom 5+) ──
|
||||
{
|
||||
id: 'boundaries-province',
|
||||
type: 'line',
|
||||
source: 'ofm-chart',
|
||||
'source-layer': 'boundary',
|
||||
minzoom: 5,
|
||||
filter: ['==', 'admin_level', 4],
|
||||
paint: { 'line-color': '#bbbbbb', 'line-width': 0.5, 'line-dasharray': [3, 2] },
|
||||
},
|
||||
// ── 국가/시도 라벨 (한글) ──
|
||||
{
|
||||
id: 'place-labels-major',
|
||||
type: 'symbol',
|
||||
source: 'ofm-chart',
|
||||
'source-layer': 'place',
|
||||
minzoom: 3,
|
||||
filter: ['in', 'class', 'country', 'state'],
|
||||
layout: {
|
||||
'text-field': ['coalesce', ['get', 'name:ko'], ['get', 'name']],
|
||||
'text-font': ['Open Sans Bold'],
|
||||
'text-size': ['interpolate', ['linear'], ['zoom'], 3, 11, 8, 16],
|
||||
'text-max-width': 8,
|
||||
},
|
||||
paint: {
|
||||
'text-color': '#555555',
|
||||
'text-halo-color': '#ffffff',
|
||||
'text-halo-width': 2,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'place-labels-city',
|
||||
type: 'symbol',
|
||||
source: 'ofm-chart',
|
||||
'source-layer': 'place',
|
||||
minzoom: 5,
|
||||
filter: ['in', 'class', 'city', 'town'],
|
||||
layout: {
|
||||
'text-field': ['coalesce', ['get', 'name:ko'], ['get', 'name']],
|
||||
'text-font': ['Open Sans Regular'],
|
||||
'text-size': ['interpolate', ['linear'], ['zoom'], 5, 10, 12, 14],
|
||||
'text-max-width': 7,
|
||||
},
|
||||
paint: {
|
||||
'text-color': '#666666',
|
||||
'text-halo-color': '#ffffff',
|
||||
'text-halo-width': 1.5,
|
||||
},
|
||||
},
|
||||
// ── 해양 지명 (water_name) ──
|
||||
{
|
||||
id: 'water-labels',
|
||||
type: 'symbol',
|
||||
source: 'ofm-chart',
|
||||
'source-layer': 'water_name',
|
||||
layout: {
|
||||
'text-field': ['coalesce', ['get', 'name:ko'], ['get', 'name']],
|
||||
'text-font': ['Open Sans Italic'],
|
||||
'text-size': ['interpolate', ['linear'], ['zoom'], 3, 10, 8, 14],
|
||||
'text-max-width': 10,
|
||||
'text-letter-spacing': 0.15,
|
||||
},
|
||||
paint: {
|
||||
'text-color': '#8899aa',
|
||||
'text-halo-color': 'rgba(168,204,224,0.7)',
|
||||
'text-halo-width': 1,
|
||||
},
|
||||
},
|
||||
// ── 마을/소지명 (zoom 10+) ──
|
||||
{
|
||||
id: 'place-labels-village',
|
||||
type: 'symbol',
|
||||
source: 'ofm-chart',
|
||||
'source-layer': 'place',
|
||||
minzoom: 10,
|
||||
filter: ['in', 'class', 'village', 'suburb', 'hamlet'],
|
||||
layout: {
|
||||
'text-field': ['coalesce', ['get', 'name:ko'], ['get', 'name']],
|
||||
'text-font': ['Open Sans Regular'],
|
||||
'text-size': ['interpolate', ['linear'], ['zoom'], 10, 9, 14, 12],
|
||||
'text-max-width': 6,
|
||||
},
|
||||
paint: {
|
||||
'text-color': '#777777',
|
||||
'text-halo-color': '#ffffff',
|
||||
'text-halo-width': 1,
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
// 3D 위성 스타일 (VWorld 위성 배경 + OpenFreeMap 건물 extrusion)
|
||||
// VWorld WMTS: {z}/{y}/{x} (row/col 순서)
|
||||
// OpenFreeMap: CORS 허용, 전 세계 OSM 벡터타일 (building: render_height 포함)
|
||||
@ -178,6 +338,8 @@ interface MapViewProps {
|
||||
}
|
||||
sensitiveResources?: SensitiveResource[]
|
||||
mapCaptureRef?: React.MutableRefObject<(() => string | null) | null>
|
||||
/** 밝은 톤 지도 스타일 사용 (CartoDB Positron) */
|
||||
lightMode?: boolean
|
||||
}
|
||||
|
||||
// deck.gl 오버레이 컴포넌트 (MapLibre 컨트롤로 등록, interleaved)
|
||||
@ -262,6 +424,7 @@ export function MapView({
|
||||
backtrackReplay,
|
||||
sensitiveResources = [],
|
||||
mapCaptureRef,
|
||||
lightMode = false,
|
||||
}: MapViewProps) {
|
||||
const { mapToggles } = useMapStore()
|
||||
const [currentPosition, setCurrentPosition] = useState<[number, number]>(DEFAULT_CENTER)
|
||||
@ -732,8 +895,8 @@ export function MapView({
|
||||
sensitiveResources,
|
||||
])
|
||||
|
||||
// 3D 모드에 따른 지도 스타일 전환
|
||||
const currentMapStyle = mapToggles.threeD ? SATELLITE_3D_STYLE : BASE_STYLE
|
||||
// 3D 모드 / 밝은 톤에 따른 지도 스타일 전환
|
||||
const currentMapStyle = mapToggles.threeD ? SATELLITE_3D_STYLE : lightMode ? LIGHT_STYLE : BASE_STYLE
|
||||
|
||||
return (
|
||||
<div className="w-full h-full relative">
|
||||
|
||||
@ -461,6 +461,7 @@ export function OilSpillView() {
|
||||
layerOpacity={layerOpacity}
|
||||
layerBrightness={layerBrightness}
|
||||
sensitiveResources={sensitiveResources}
|
||||
lightMode
|
||||
backtrackReplay={isReplayActive && replayShips.length > 0 ? {
|
||||
isActive: true,
|
||||
ships: replayShips,
|
||||
|
||||
불러오는 중...
Reference in New Issue
Block a user