Files
Pier_v1/랜딩페이지/sample-explorer.ts
T

49 lines
7.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { sampleProjects } from './sample-projects';
import { sampleLocations } from './sample-locations';
import { renderSamplePreview } from './sample-preview';
import { createSampleMap } from './sample-map';
import './sample-explorer.css';
export type Sample=typeof sampleProjects[number];
export const sampleExplorerMarkup=`<aside class="sample-explorer" aria-label="기설계 교량" data-guide-target="sample">
<header class="sample-explorer-head"><div><span>EXPLORE PROJECTS</span><h2>교각·교대 설계 라이브러리</h2></div><b>12<span> PROJECTS</span></b></header>
<section class="sample-map-section"><div class="sample-section-title"><h3>설계 프로젝트 위치</h3><div class="sample-map-modes" role="group" aria-label="지도 종류"><button type="button" data-map-mode="street" aria-pressed="true">일반</button><button type="button" data-map-mode="satellite" aria-pressed="false">위성</button></div></div><div class="sample-map" aria-label="대한민국 기설계 교량 지도"><div class="sample-location"><div class="sample-location-heading"><strong>📍 <span class="sample-location-name"></span> 위치정보</strong></div><p class="sample-address"></p><dl><dt>좌표계</dt><dd class="sample-crs"></dd><dt>조사좌표</dt><dd class="sample-survey"></dd><dt>위도·경도</dt><dd class="sample-wgs84"></dd></dl><small class="sample-coordinate-basis"></small></div><div class="sample-map-tiles"></div><div class="sample-map-markers"></div><div class="sample-map-zoom"><button type="button" data-zoom="1" aria-label="지도 확대">+</button><button type="button" data-zoom="-1" aria-label="지도 축소">−</button><button type="button" data-zoom="0" aria-label="남한 중심 기본 지도">⌂</button></div><span class="sample-map-attribution"></span><span class="sample-map-error" hidden>배경지도 연결 대기 · 좌표 마커 표시</span></div></section>
<section class="sample-selection" aria-label="선택 교량 상세"><div class="sample-section-title"><h3>하부구조 3D 미리보기</h3><span class="sample-selection-index"></span></div>
<div class="sample-preview" role="region" aria-label="지도·지반·교각 통합 3D 미리보기"></div>
</section>
<section class="sample-list-section"><div class="sample-section-title"><h3>기존 설계 프로젝트</h3><span>총 12개 프로젝트</span></div><div class="sample-list" role="group" aria-label="교량 선택"></div><div class="sample-project-action"><div class="sample-selection-info"><h3></h3><p></p></div><p id="landing-sample-status" role="status" aria-live="polite"></p><button type="button" class="sample-load">설계 프로젝트 불러오기 ↗</button></div></section>
</aside>`;
export function createSampleExplorer(root:HTMLElement,load:(sample:Sample)=>Promise<void>):void{
const panel=root.querySelector<HTMLElement>('.sample-explorer')!,list=panel.querySelector<HTMLElement>('.sample-list')!,status=panel.querySelector<HTMLElement>('#landing-sample-status')!,button=panel.querySelector<HTMLButtonElement>('.sample-load')!;
let selected:Sample=sampleProjects[0],busy=false,previewToken=0;
let map:ReturnType<typeof createSampleMap>|undefined;
const select=(sample:Sample,focus=true)=>{
if(busy)return;selected=sample;panel.dataset.selected=String(sample.sample);button.dataset.sample=String(sample.sample);status.textContent=sample.pierCount?'':'원본 프로젝트에 교각 형상이 없습니다. 실제 지반·지도 자료를 엽니다.';
button.disabled=false;button.textContent=sample.pierCount?'설계 프로젝트 불러오기 ↗':'설계 프로젝트 불러오기 ↗';
panel.querySelectorAll<HTMLElement>('[data-sample-row]').forEach(row=>{const active=Number(row.dataset.sampleRow)===sample.sample;row.classList.toggle('is-selected',active);row.setAttribute('aria-pressed',String(active));});
panel.querySelector('.sample-selection-info h3')!.textContent=sample.bridge;
panel.querySelector('.sample-selection-info p')!.textContent=`${sampleLocations.find(p=>p.sample===sample.sample)?.types??'형식 미확인'} · 원본 교각 ${sample.pierCount}기`;
panel.querySelector('.sample-selection-index')!.textContent=`PROJECT ${String(sample.sample).padStart(2,'0')}`;
const loc=sampleLocations.find(p=>p.sample===sample.sample);
panel.querySelector('.sample-location-name')!.textContent='프로젝트';const address=panel.querySelector<HTMLElement>('.sample-address')!;address.textContent=loc?.address??'주소 확인 불가';address.title='ArcGIS 역지오코딩 · 지도 좌표 기준 시·도 / 시·군 · 상세주소 제외';
panel.querySelector('.sample-crs')!.textContent=loc?`${loc.crs}${loc.crsAssumed?' · 원본 CRS 미확정':''}`:'좌표계 미확인';
panel.querySelector('.sample-survey')!.textContent=loc?`X(N) ${loc.surveyX.toFixed(3)} / Y(E) ${loc.surveyY.toFixed(3)} m`:'좌표 확인 불가';
panel.querySelector('.sample-wgs84')!.textContent=loc?`${loc.lat.toFixed(6)}° N / ${loc.lon.toFixed(6)}° E`:'변환 불가';
panel.querySelector('.sample-coordinate-basis')!.textContent=loc?`${loc.basis} · 프로그램 x=E/y=N`:'대표 좌표 없음';
const token=++previewToken;void renderSamplePreview(panel.querySelector('.sample-preview')!,sample,()=>token===previewToken);
map?.highlight();if(focus)map?.focus(sample.sample);
};
for(const sample of sampleProjects){const row=document.createElement('button');row.type='button';row.dataset.sampleRow=String(sample.sample);row.className='sample-row';
row.innerHTML=`<span class="sample-row-number">${String(sample.sample).padStart(2,'0')}</span><span><strong>${sample.bridge}</strong><small>${sampleLocations.find(p=>p.sample===sample.sample)?.types??'미확인'} · 교각 ${sample.pierCount}기</small></span><span class="sample-row-arrow">↗</span>`;
row.addEventListener('click',()=>select(sample));for(const event of ['pointerenter','focus'])row.addEventListener(event,()=>{row.classList.add('is-hovered');map?.hover(sample.sample);});for(const event of ['pointerleave','blur'])row.addEventListener(event,()=>{row.classList.remove('is-hovered');map?.hover(null);});list.append(row);
}
map=createSampleMap(panel,id=>{const sample=sampleProjects.find(s=>s.sample===id);if(sample){select(sample);list.querySelector(`[data-sample-row="${id}"]`)?.scrollIntoView({block:'nearest'});}},()=>selected.sample,()=>busy);
button.addEventListener('click',async()=>{
if(busy)return;const target=selected;busy=true;button.disabled=true;button.textContent=`${target.bridge} 불러오는 중…`;list.querySelectorAll('button').forEach(b=>b.disabled=true);map!.refresh();status.textContent=`${target.bridge}: 실제 프로젝트 파일을 여는 중…`;
try{await load(target);status.textContent=`${target.bridge}: 교각 ${target.pierCount}기 · 실제 지반/지도 복원 완료`;}
catch(error){status.textContent=`${target.bridge}: ${(error as Error).message}`;panel.dataset.loadError=String(target.sample);}
finally{busy=false;button.disabled=false;button.textContent=target.pierCount?'설계 프로젝트 불러오기 ↗':'설계 프로젝트 불러오기 ↗';list.querySelectorAll('button').forEach(b=>b.disabled=false);map!.refresh();}
});select(selected,false);
}