From eb4f8ba55a2cdbd8922e876bf12003c82bc498a7 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Sat, 17 Oct 2026 11:48:16 +0900 Subject: [PATCH] =?UTF-8?q?=EF=BB=BFfeat(B05):=20367-1=20=EC=9C=A0?= =?UTF-8?q?=ED=86=A0=EA=B3=A1=EC=84=A0=20=EB=8A=98=20=EC=A0=84=EC=B2=B4=20?= =?UTF-8?q?=EB=A7=9E=EC=B6=A4=20=C2=B7=20=EC=B8=A1=EC=A0=90=20=EC=97=B0?= =?UTF-8?q?=EA=B3=84=20=EB=B3=B4=EA=B8=B0=20=EC=A7=80=EC=9B=80=20=C2=B7=20?= =?UTF-8?q?=EA=B8=B0=EB=B3=B8=20=3D=20=ED=9A=A1=EB=8B=A8=20=EA=B8=B0?= =?UTF-8?q?=EC=A4=80=20+=20=ED=86=A0=EB=9F=89=20=EB=B6=84=EB=B0=B0=20?= =?UTF-8?q?=C2=B7=20[=EB=8F=84=ED=98=95=20=EC=9C=84=EC=B9=98=20=EC=B4=88?= =?UTF-8?q?=EA=B8=B0=ED=99=94]=20=ED=9A=A1=EB=8B=A8=20=EA=B8=B0=EC=A4=80?= =?UTF-8?q?=20=EC=99=BC=EC=AA=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 유토곡선 = 늘 노선 전체 한 화면(측점선 · 스크롤 동기 · 휠 · 스크롤마다 다시 그림 지움) - 범례 기본값에 토량 분배 더함 · masshaul-visible 판 v6 - [토량 분배] = 분배 그림 보임/숨김 · [도형 위치 초기화] 범례 맨 앞 - 시험 354_1 · 354_2 · 354_3 · 224_1b 고쳐 씀 Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01QfHKQs7J3hQELKMWQMUJEy --- A00_Common/b_page_state.ts | 2 +- A00_Common/design/design_profile_overlays.ts | 2 - .../B05_Profile_UI_Profile_MassHaul.ts | 155 ++++-------------- B05_Profile/B05_Profile_UI_Profile_Render.ts | 14 -- B05_Profile/B05_Profile_UI_Style_MassHaul.css | 6 +- common_util/common_util_mass_haul_view.ts | 3 +- .../helper_354_2_masshaul_cross_only.cjs | 2 +- .../tester/test_224_1b_masshaul_docked.py | 7 +- .../tester/test_354_1_masshaul_own_panel.py | 4 +- .../tester/test_354_2_masshaul_cross_only.py | 2 +- resources/tester/test_354_3_scroll_echo.py | 40 ++--- 11 files changed, 66 insertions(+), 171 deletions(-) diff --git a/A00_Common/b_page_state.ts b/A00_Common/b_page_state.ts index 3b0edc52f..f2359879c 100644 --- a/A00_Common/b_page_state.ts +++ b/A00_Common/b_page_state.ts @@ -89,7 +89,7 @@ export const STATE_REGISTRY = { "masshaul-visible": { bucket: "pref", scope: "global", - version: 5, + version: 6, legacy: () => "b06:masshaul-visible-v4", }, "table-open": { bucket: "pref", scope: "global", legacy: () => "b05:profile:table:open" }, diff --git a/A00_Common/design/design_profile_overlays.ts b/A00_Common/design/design_profile_overlays.ts index 5926afe74..f5735dcb2 100644 --- a/A00_Common/design/design_profile_overlays.ts +++ b/A00_Common/design/design_profile_overlays.ts @@ -59,8 +59,6 @@ export function createProfileOverlays(deps: ProfileOverlaysDeps) { const column = document.createElement("div"); column.className = "b05-route-profile__column"; column.append(bodyWrap, massHaul.overlay); - // 판의 가로 스크롤을 종단 스크롤러와 양방향 동기화 — 측점 세로선 정렬 유지. - massHaul.attachScrollSync(body); // 테이블은 종단 칸 바닥 겹침 판(2026-08-05 사용자 지시). const tableOverlay = createProfileTableOverlay(onChange); bodyWrap.append(tableOverlay.overlay, tableOverlay.handle); diff --git a/B05_Profile/B05_Profile_UI_Profile_MassHaul.ts b/B05_Profile/B05_Profile_UI_Profile_MassHaul.ts index 201cfa586..c544caf0d 100644 --- a/B05_Profile/B05_Profile_UI_Profile_MassHaul.ts +++ b/B05_Profile/B05_Profile_UI_Profile_MassHaul.ts @@ -17,8 +17,8 @@ * ── 배치 (354-1 · 요구 235-7 「유토곡선도 분리」) ───────────────────── * 종단 열(그래프 · 표) 아래 칸에 따로 선다 — 종단도 · 표 위를 덮지 않고 높이 나눔 · 표 쌓기에도 * 안 낀다. 높이는 판 위 경계 리사이저(`createPanelResizer`)로 조절하고 세션 동안 유지한다. - * 머리줄([창 분할] · 접기 손잡이)은 접어도 남는다. 곡선 SVG는 판 안 자체 가로 스크롤러에 - * 들어가며, 종단 스크롤러와 scrollLeft를 양방향 동기화해 측점 세로선이 어긋나지 않게 한다. + * 접으면 손잡이만 남는다(367-2). 곡선은 늘 노선 전체를 한 화면에 맞춰 그린다 — 종단 측점과 + * 맞물리는 보기 · 스크롤 동기는 없앰(367-1). * ========================================================================== */ import { readStateRaw, stateKey, writeStateRaw } from "../A00_Common/b_page_state"; @@ -46,16 +46,13 @@ import { resetBalloonOffsets } from "@util/common_util_mass_haul_balance_view"; import { createMassHaulChart, createMassHaulLegend, - createMassHaulWindowState, MASS_HAUL_MIN_HEIGHT, - scheduleMassHaulSettle, } from "@util/common_util_mass_haul_view"; import { Y_WINDOW_BAKED_ATTR } from "../B06_Section/B06_Section_UI_Longitudinal"; import { createWorkflowPanelHandle } from "@ui/ui_template_overlay"; import { createPanelResizer } from "@ui/ui_template_resizer"; import "@util/common_util_mass_haul.css"; import "./B05_Profile_UI_Style_MassHaul.css"; -import { attachWheelHorizontalScroll, linkScrollLeft } from "./B05_Profile_UI_Profile_Wheel"; import { frameOf } from "../common_util/common_util_view_window"; /** 2차 패널 펼침 여부 — 세션 동안만 유지(패널 높이·접힘과 같은 수명). */ @@ -76,10 +73,8 @@ const HEIGHT_VAR = "--b05-masshaul-height"; * 표시 상태가 갈리면 "같은 곡선인데 왜 다르게 보이나"가 된다(2026-08-03 사용자 확정). * 정의처는 B06 `_UI_Section_View`와 이 파일 두 곳뿐이며 값이 반드시 같아야 한다. */ -/** 처음 열 때는 **곡선만** 보인다 — 토량 분배(평형선·운반 블록)는 범례에서 켠다 - * (2026-09-06 사용자 지시). 판을 v4 → v5 로 올려 이미 켜 둔 브라우저도 새 기본값으로 - * 시작하게 한다. */ -const DEFAULT_VISIBLE: string[] = [...MASS_HAUL_DEFAULT_VISIBLE]; +/** 기본 = 횡단 기준 + 토량 분배 켬(367-1) — 판 v6. [토량 분배] 는 분배 그림 보임/숨김. */ +const DEFAULT_VISIBLE: string[] = [...MASS_HAUL_DEFAULT_VISIBLE, MASS_HAUL_BALANCE_KEY]; /** 유토곡선 계산에 필요한 프로젝트 설정 — B05 Page가 `fetchSectionContext()`에서 받아 넘긴다. */ export interface RouteMassHaulContext { @@ -150,12 +145,8 @@ export interface RouteMassHaulPanel { overlay: HTMLElement; isOpen(): boolean; setContext(next: RouteMassHaulContext | null): void; - /** 종단 가로 스크롤러와 scrollLeft를 양방향 동기화한다(설치 1회). */ - attachScrollSync(main: HTMLElement): void; /** 판 내용을 다시 그린다. 접혀 있으면 머리줄만 남기고 끝낸다. */ draw(params: RouteMassHaulDrawParams): void; - /** 가로 스크롤로 보이는 구간만 바뀜 — 창을 따를 때만 · 한 틀 한 번 · 다시 셈 없음(354-3). */ - drawWindow(params: RouteMassHaulDrawParams): void; } function readVisible(): Set { @@ -248,10 +239,6 @@ export function createRouteMassHaulPanel( pendingChip.hidden = true; overlay.append(resizer.root, head, bar, scroll, legendLayer, pendingChip); - // 종단 그래프 영역과 같은 문법 — 세로 휠을 가로 이동으로 돌린다(2026-08-04 사용자 지시). - // scrollLeft 동기화 덕에 위 종단 그래프도 함께 움직인다. Shift+휠은 브라우저 기본 그대로. - attachWheelHorizontalScroll(scroll); - /** 곡선을 그리는가 — 펼침이거나 새 창으로 뗌(뗀 창엔 접기가 없음 · 354-1). */ const shown = (): boolean => open || overlay.classList.contains("is-popout"); @@ -279,29 +266,14 @@ export function createRouteMassHaulPanel( onChanged(); } - // 종단 스크롤러와의 양방향 동기화 — 메아리는 공용 도우미가 걸러 냄(354-3). - // 토량 분배(전체 맞춤) 중에는 끊는다 — 유토곡선이 0 으로 붙으며 낸 scroll 이 종단 그래프 · - // 표까지 0 으로 되돌렸다(PLAN 79-1). 유토곡선만 스크롤이 없는 상태. - let fitted = false; - let syncedMain: HTMLElement | null = null; - let putScroll: ((to: HTMLElement, left: number) => void) | null = null; - /** 종단과 맞물려 그린 곡선이 놓인 문서 — 처음 · 분배 맞춤 뒤 · 창 옮김 뒤면 종단 자리로 맞춘다. */ - let syncedIn: Document | null = null; - function attachScrollSync(main: HTMLElement): void { - if (syncedMain === main) return; - syncedMain = main; - putScroll = linkScrollLeft(main, scroll, () => fitted); - } - /** 곡선을 한 번이라도 그렸는지 — 재계산 대기 중 화면을 비우지 않기 위한 표시. */ let drawnOnce = false; - /** 마지막으로 낸 계열 — 가로 스크롤(보이는 구간만 바뀜)은 다시 셈 없이 이걸로 그린다(354-3). */ + /** 마지막으로 낸 계열 — 같은 계열이면 총괄값을 다시 내지 않는다. */ let lastSeries: MassHaulSeries[] | null = null; function note(message: string): void { drawnOnce = false; lastSeries = null; - syncedIn = null; pendingChip.hidden = true; bar.replaceChildren(); scroll.replaceChildren(); @@ -312,11 +284,6 @@ export function createRouteMassHaulPanel( bar.append(empty); } - // 세로창 버티기·부드러운 이동 상태 — 이 패널이 사는 동안 하나만 둔다(2026-09-04). - const windowState = createMassHaulWindowState(); - /** 마지막으로 그린 입력 — 이동이 아직 안 끝났으면 다음 프레임에 이걸로 한 번 더 그린다. */ - let lastParams: RouteMassHaulDrawParams | null = null; - /** 이미 낸 계열에서 총괄값만 꺼낸다 — 계산은 하지 않는다. */ function emitSummary(series: MassHaulSeries[]): void { if (!onSummary) return; @@ -348,33 +315,16 @@ export function createRouteMassHaulPanel( ); } - /** 그리기 몫 기록(349-0s) — 묶음 마지막 차례 `work.유토곡선`. `reuse` = 마지막 계열로(다시 셈 없음). */ - function draw(params: RouteMassHaulDrawParams, reuse = false): void { - pipelineWork("유토곡선", () => drawNow(params, reuse)); + /** 그리기 몫 기록(349-0s) — 묶음 마지막 차례 `work.유토곡선`. */ + function draw(params: RouteMassHaulDrawParams): void { + pipelineWork("유토곡선", () => drawNow(params)); } - /** 가로 스크롤로 보이는 구간만 바뀜(354-3) — 곡선이 창을 따를 때만(열림 · 분배 맞춤 아님 · 붙음) · - * 한 틀 한 번 · 다시 셈 없이 세로 창만 다시 그림. 접힘 · 분배 · 새 창은 스크롤마다 할 일 없음. */ - let windowDirty = false; - function drawWindow(params: RouteMassHaulDrawParams): void { - if (!open || fitted || overlay.classList.contains("is-popout") || !lastSeries) return; - lastParams = params; - // 미끄러짐 틀이 이미 잡혀 있으면 그 틀이 이 값으로 그림 - if (windowDirty || windowState.frame) return; - windowDirty = true; - frameOf(overlay, () => { - if (windowDirty && lastParams) draw(lastParams, true); - }); - } - - function drawNow(params: RouteMassHaulDrawParams, reuse: boolean): void { - lastParams = params; - windowDirty = false; + function drawNow(params: RouteMassHaulDrawParams): void { overlay.classList.toggle("is-collapsed", !open); // 접혀 있어도 상단줄에는 값이 서야 한다 — 이때는 **횡단 기준만** 적분한다. // 펼친 경우에는 아래에서 낸 계열로 총괄값을 낸다(계산 한 번). if (!shown()) { - syncedIn = null; reportSummary(params); return; } @@ -407,17 +357,13 @@ export function createRouteMassHaulPanel( // (354-2 · 계산 코드는 공용에 남김). // 결과를 아껴 두지 **않는다** — 횡단 설계가 제자리에서 갈리므로 객체 동일성으로는 // 바뀐 것을 못 잰다(2026-09-04 캐시를 넣었다가 곡선이 안 따라와 되돌림). - // 스크롤로 창만 바뀐 그리기(`reuse`)는 직전 계열 그대로 — 같은 입력의 두 번째 적분이었다(354-3). - const series: MassHaulSeries[] = - reuse && lastSeries - ? lastSeries - : computeMassHaulSeries( - params.longitudinal, - params.crossSections, - context.conversion, - context.naturalSpoilMinSlope, - ["cross"], - ); + const series: MassHaulSeries[] = computeMassHaulSeries( + params.longitudinal, + params.crossSections, + context.conversion, + context.naturalSpoilMinSlope, + ["cross"], + ); // 총괄값은 방금 낸 계열에서 꺼낸다 — 접힘 경로처럼 따로 적분하지 않는다. if (series !== lastSeries) emitSummary(series); lastSeries = series; @@ -446,29 +392,16 @@ export function createRouteMassHaulPanel( (overlay.clientHeight || OVERLAY_DEFAULT_HEIGHT) - bar.offsetHeight - 12; const chartHeight = Math.max(scrollHeight, MASS_HAUL_MIN_HEIGHT); - // 토량 분배를 켜면 **곡선 전체가 한 화면에** 들어와야 한다(2026-09-06 사용자 지시). - // 평형선·운반 블록은 노선 전체를 놓고 읽는 그림이라, 종단 그래프와의 X 맞춤(가로 - // 스크롤)과 보이는 구간만 보는 Y 창을 둘 다 버리고 스크롤러 안쪽 폭·전 구간 Y로 그린다. - // 종단과 맞물릴 필요가 없으므로 반 칸 들여쓰기(originOffset)도 쓰지 않는다 — 그만큼 - // 좌우가 비어 곡선이 가운데로 쪼그라들었다(2026-09-06 사용자 보고: 「우측 여유 과다」). - const fitAll = haulPlan !== null; - fitted = fitAll; - const widthPx = fitAll ? scroll.clientWidth || params.widthPx : params.widthPx; - const chartAxis = fitAll - ? { - ...params.axis, - padLeft: params.axis.axisX ?? params.axis.padLeft, - padRight: MASS_FIT_PAD_RIGHT, - viewRange: undefined, - window: undefined, - hideStations: true, - } - : { - ...params.axis, - // 새 창으로 뗀 판은 넓어 메인 보이는 구간 세로면 잘림 — 노선 전체 세로(325-2). - viewRange: overlay.classList.contains("is-popout") ? undefined : params.axis.viewRange, - window: windowState, - }; + // 늘 **곡선 전체가 한 화면에**(367-1 · 측점 연계 보기 없앰) — 스크롤러 안쪽 폭 · 전 구간 Y · + // 측점선 없음. 반 칸 들여쓰기(originOffset)도 안 씀(2026-09-06 「우측 여유 과다」). + const widthPx = scroll.clientWidth || params.widthPx; + const chartAxis = { + ...params.axis, + padLeft: params.axis.axisX ?? params.axis.padLeft, + padRight: MASS_FIT_PAD_RIGHT, + viewRange: undefined, + hideStations: true, + }; let massAxis: { padLeft: number; ticks: Array<{ y: number; label: string }> } | null = null; const chart = createMassHaulChart( @@ -495,33 +428,17 @@ export function createRouteMassHaulPanel( wrap.append(chart); // 앵커는 첫 자식 — SVG 뒤면 흐름 위치가 밀려 스크롤 시 축이 안 보인다(B06과 같은 규칙). if (massAxis) wrap.prepend(buildStickyYAxis(massAxis, chartHeight)); - // 이미 종단과 맞물려 그린 곡선이면 제 자리 그대로 — 종단 값으로 되쓰면 그 사이 유토 쪽 휠이 - // 더 간 만큼 뒤로 튐(354-3). 처음 · 분배 맞춤 뒤 · 창 옮김 뒤만 종단 자리에서 시작한다. - const keepLeft = !fitAll && syncedIn === scroll.ownerDocument ? scroll.scrollLeft : null; scroll.replaceChildren(wrap); - // 전체 맞춤일 때는 스크롤할 것이 없으므로 왼쪽 끝에 둔다. - if (fitAll) scroll.scrollLeft = 0; - else if (keepLeft !== null) scroll.scrollLeft = keepLeft; - else if (syncedMain) putScroll?.(scroll, syncedMain.scrollLeft); - syncedIn = fitAll ? null : scroll.ownerDocument; + // 스크롤할 것이 없으므로 왼쪽 끝에 둔다. + scroll.scrollLeft = 0; - // 범례는 계열 · 켬이 바뀔 때만 — 스크롤 그리기는 그대로 둔다. - if (!reuse || !legendLayer.firstChild) - legendLayer.replaceChildren( - createMassHaulLegend(series, visible, toggleSeries, () => { - resetBalloonOffsets(); - onChanged(); - }), - ); - drawnOnce = true; - // 세로창이 아직 목표까지 안 갔으면 다음 프레임에 한 걸음 더 — 확 튀지 않고 미끄러진다. - scheduleMassHaulSettle( - windowState, - () => { - if (lastParams) draw(lastParams, true); - }, - overlay, + legendLayer.replaceChildren( + createMassHaulLegend(series, visible, toggleSeries, () => { + resetBalloonOffsets(); + onChanged(); + }), ); + drawnOnce = true; } return { @@ -531,8 +448,6 @@ export function createRouteMassHaulPanel( setContext(next) { context = next; }, - attachScrollSync, - draw: (params) => draw(params), - drawWindow, + draw, }; } diff --git a/B05_Profile/B05_Profile_UI_Profile_Render.ts b/B05_Profile/B05_Profile_UI_Profile_Render.ts index d0a4fad59..23d26fc01 100644 --- a/B05_Profile/B05_Profile_UI_Profile_Render.ts +++ b/B05_Profile/B05_Profile_UI_Profile_Render.ts @@ -66,7 +66,6 @@ export interface ProfileRenderContext { callbacks: RouteProfilePanelCallbacks | undefined; massHaul: { draw: (params: RouteMassHaulDrawParams) => void; - drawWindow: (params: RouteMassHaulDrawParams) => void; }; tableOverlay: { isOpen: () => boolean; @@ -337,8 +336,6 @@ export function renderProfile(ctx: ProfileRenderContext): void { }); // 세로 창 갱신기 — 가로로 스크롤할 때마다 패널이 이것을 부른다. 도형은 그대로 두고 // 겹 하나의 변환만 갈아 끼우므로 매 프레임 불러도 된다(2026-09-04 사용자 확정). - // 유토곡선 갱신기 — 아래에서 유토곡선을 그린 뒤 채워진다(그리기 순서상 여기서는 아직 없다). - let massHaulUpdater: ((fromM: number, toM: number) => void) | null = null; ctx.setElevationWindowUpdater(() => { const from = Math.max(0, toChainage(body.scrollLeft)); const to = Math.min(maxChainageM, toChainage(body.scrollLeft + body.clientWidth)); @@ -349,7 +346,6 @@ export function renderProfile(ctx: ProfileRenderContext): void { to, ) ?? null, ); - massHaulUpdater?.(from, to); return applyElevationWindow(chartWrap, next); }); @@ -452,15 +448,5 @@ export function renderProfile(ctx: ProfileRenderContext): void { onSelectStation: ctx.selectStation, }; massHaul.draw(massHaulParams); - // 유토곡선도 **같은 창**을 본다(2026-09-04 사용자 확정) — 스크롤할 때마다 곡선만 다시 - // 그린다. 종단처럼 변환으로 옮기지 않는 이유: 곡선 위에 앉는 말풍선·EP 표·측점 점이 - // 세로로 늘어나면 안 되는 것들이라, 그것만 따로 옮기는 값이 곡선 자체를 다시 그리는 - // 값보다 크다(요소 수가 종단의 1/3). 열림 · 분배 맞춤 아닐 때만 · 한 틀 한 번 · 다시 셈 없음(354-3). - massHaulUpdater = (fromM, toM) => { - massHaul.drawWindow({ - ...massHaulParams, - axis: { ...massHaulParams.axis, viewRange: { fromM, toM } }, - }); - }; } } diff --git a/B05_Profile/B05_Profile_UI_Style_MassHaul.css b/B05_Profile/B05_Profile_UI_Style_MassHaul.css index 59cc32b50..2af4459c8 100644 --- a/B05_Profile/B05_Profile_UI_Style_MassHaul.css +++ b/B05_Profile/B05_Profile_UI_Style_MassHaul.css @@ -129,14 +129,12 @@ background: var(--color-surface); } -/* 곡선 가로 스크롤러 — 종단 스크롤러와 scrollLeft를 동기화한다(JS). 세로는 잘라낸다. - 스크롤바는 항상 표시(scroll) — auto면 생겼다 없어질 때 곡선 높이가 널뛰고, - clientHeight 기반 높이 계산도 함께 흔들린다. */ +/* 곡선 칸 — 늘 전체 맞춤이라 스크롤 없음(367-1). */ .b05-profile__masshaul-scroll { position: relative; flex: 1 1 auto; min-height: 0; - overflow-x: scroll; + overflow-x: hidden; overflow-y: hidden; } diff --git a/common_util/common_util_mass_haul_view.ts b/common_util/common_util_mass_haul_view.ts index 95d618d03..41bc3a659 100644 --- a/common_util/common_util_mass_haul_view.ts +++ b/common_util/common_util_mass_haul_view.ts @@ -786,7 +786,8 @@ export function createMassHaulLegend( reset.textContent = L("B06_MassHaul_Balloon_Reset"); reset.title = L("B06_MassHaul_Balloon_Reset_Tip"); reset.addEventListener("click", onResetBalloons); - legend.append(reset); + // [횡단 기준] 왼쪽(367-1) + legend.prepend(reset); } return legend; } diff --git a/resources/tester/helper_354_2_masshaul_cross_only.cjs b/resources/tester/helper_354_2_masshaul_cross_only.cjs index 8a688c9a6..088ea97e2 100644 --- a/resources/tester/helper_354_2_masshaul_cross_only.cjs +++ b/resources/tester/helper_354_2_masshaul_cross_only.cjs @@ -23,7 +23,7 @@ const mass = read("B05_Profile", "B05_Profile_UI_Profile_MassHaul.ts"); let stored = null; const src = [ 'const SERIES_BASES = ["cross", "longitudinal"];', - 'const DEFAULT_VISIBLE = ["cross"];', + 'const DEFAULT_VISIBLE = ["cross", "balance"];', // 367-1 기본 = 횡단 + 분배 block(util, "export function normalizeVisibleBasis("), block(mass, "function readVisible(): Set {"), block(util, "export function computeMassHaulSeries("), diff --git a/resources/tester/test_224_1b_masshaul_docked.py b/resources/tester/test_224_1b_masshaul_docked.py index 942ae8347..b1be9a1c7 100644 --- a/resources/tester/test_224_1b_masshaul_docked.py +++ b/resources/tester/test_224_1b_masshaul_docked.py @@ -11,7 +11,6 @@ import json import os -import re import subprocess from pathlib import Path @@ -65,7 +64,5 @@ def test_끌기도_유토_판_안_셈(): def test_뗀_유토는_노선_전체_세로(): mass = (B05 / "B05_Profile_UI_Profile_MassHaul.ts").read_text(encoding="utf-8") - assert re.search( - r'viewRange: overlay\.classList\.contains\("is-popout"\) \? undefined : params\.axis\.viewRange', - mass, - ) + # 367-1 붙음 · 뗌 모두 노선 전체 세로 + assert "viewRange: undefined," in mass diff --git a/resources/tester/test_354_1_masshaul_own_panel.py b/resources/tester/test_354_1_masshaul_own_panel.py index b92159eb4..ae4531f89 100644 --- a/resources/tester/test_354_1_masshaul_own_panel.py +++ b/resources/tester/test_354_1_masshaul_own_panel.py @@ -4,7 +4,7 @@ - 종단 열(`b05-route-profile__column`) = [종단 칸(bodyWrap), 유토 판] · content 안이라 종단 [창 분할] (`.is-popout > :not(content)` 숨김)에도 같이 감 · B05 · B06 이 같은 `design_profile` 하나. - 유토 판은 흐름 칸(겹침 아님) · 자기 리사이저 높이 · 접으면 머리줄만(손잡이 · [창 분할] 닿음). -- 높이 나눔 · 표 쌓기에서 빠짐(표 bottomOffset 없음) · X 동기화는 그대로. +- 높이 나눔 · 표 쌓기에서 빠짐(표 bottomOffset 없음) · X 동기화 없음(367-1 늘 전체 맞춤). """ import os @@ -30,7 +30,7 @@ def test_종단_열_아래_자기_칸(): assert 'column.className = "b05-route-profile__column";' in overlays assert "column.append(bodyWrap, massHaul.overlay);" in overlays assert "bodyWrap.append(massHaul.overlay" not in overlays - assert "massHaul.attachScrollSync(body);" in overlays + assert "massHaul.attachScrollSync" not in overlays # 367-1 측점 연계 없앰 profile = read("A00_Common/design/design_profile.ts") assert "content.append(column);" in profile assert sum(1 for _ in profile.splitlines()) <= 700 diff --git a/resources/tester/test_354_2_masshaul_cross_only.py b/resources/tester/test_354_2_masshaul_cross_only.py index fe84be732..b6ad7f172 100644 --- a/resources/tester/test_354_2_masshaul_cross_only.py +++ b/resources/tester/test_354_2_masshaul_cross_only.py @@ -37,7 +37,7 @@ def test_저장된_종단_범례는_횡단으로(r): assert r["longitudinal"] == ["cross"] assert r["longitudinalBalance"] == ["balance", "cross"] assert r["cross"] == ["cross"] - assert r["empty"] == ["cross"] and r["broken"] == ["cross"] + assert r["empty"] == ["balance", "cross"] and r["broken"] == ["balance", "cross"] def test_기준_횡단만_계산(r): diff --git a/resources/tester/test_354_3_scroll_echo.py b/resources/tester/test_354_3_scroll_echo.py index 869f9df34..9e5452d8f 100644 --- a/resources/tester/test_354_3_scroll_echo.py +++ b/resources/tester/test_354_3_scroll_echo.py @@ -4,14 +4,13 @@ - 메아리: scroll 은 다음 틀에 옴 → 동기 플래그로 못 막아 한 틀 전 값을 되씀 → 뒤로 튐 → 휠 이동이 접힘. 공용 `linkScrollLeft`(Wheel.ts)가 써 넣은 값으로 온 scroll 을 무시. 가짜 창(다음 틀 scroll) 재현 — 옛 잇기는 뒤로 튐 · 멈춤, 새 잇기는 4 경우 × 휠 쪽 둘 모두 튐 0. -- 유토 스크롤 그리기 = 열림 · 분배 맞춤 아님 · 붙음일 때만 · 한 틀 한 번 · 다시 셈 없음. +- 유토곡선 = 늘 전체 맞춤 · 종단과 안 이음(367-1) — 휠 · 잇기 경우는 공용 도우미 시험으로 남김. `helper_354_3_scroll_echo.cjs` 가 진짜 휠 · 잇기 TS 를 가짜 창 위에서 돌림. """ import json import os -import re import subprocess from pathlib import Path @@ -64,24 +63,25 @@ def test_새_잇기는_뒤로_튐_0_끝까지(r, case): assert got["mass"] == (0 if balance else 1200) -def test_유토_표_같은_도우미(): - for name in ("MassHaul", "TableOverlay"): - src = (B05 / f"B05_Profile_UI_Profile_{name}.ts").read_text(encoding="utf-8") - assert "linkScrollLeft(main, scroll" in src - assert "syncing" not in src - - -def test_유토_스크롤_그리기는_창_따를_때만_한_틀_한_번(): +def test_표만_잇기_유토는_안_이음(): + # 367-1 유토곡선 = 늘 전체 맞춤 · 종단 스크롤과 안 이음 + table = (B05 / "B05_Profile_UI_Profile_TableOverlay.ts").read_text(encoding="utf-8") + assert "linkScrollLeft(main, scroll" in table + assert "syncing" not in table mass = (B05 / "B05_Profile_UI_Profile_MassHaul.ts").read_text(encoding="utf-8") - body = mass[mass.index("function drawWindow(") :] - body = body[: body.index("\n }\n")] - assert '!open || fitted || overlay.classList.contains("is-popout") || !lastSeries' in body - assert "windowState.frame" in body and "frameOf(overlay" in body - assert "draw(lastParams, true)" in body - # 다시 셈 없음 · 총괄값 · 범례는 계열이 바뀔 때만 - assert re.search(r"reuse && lastSeries\s*\? lastSeries", mass) + for gone in ("linkScrollLeft", "attachWheelHorizontalScroll", "attachScrollSync", "drawWindow"): + assert gone not in mass, gone + + +def test_유토는_늘_전체_맞춤_스크롤마다_안_그림(): + mass = (B05 / "B05_Profile_UI_Profile_MassHaul.ts").read_text(encoding="utf-8") + assert "hideStations: true," in mass + assert "viewRange: undefined," in mass + assert "scroll.scrollLeft = 0;" in mass + assert "createMassHaulWindowState" not in mass and "scheduleMassHaulSettle" not in mass assert "if (series !== lastSeries) emitSummary(series);" in mass - # 다시 그려도 제 자리 — 종단 값으로 되쓰는 것은 처음 · 맞춤 뒤 · 창 옮김 뒤만 - assert "scroll.scrollLeft = syncedMain.scrollLeft" not in mass render = (B05 / "B05_Profile_UI_Profile_Render.ts").read_text(encoding="utf-8") - assert "massHaul.drawWindow({" in render + assert "drawWindow" not in render and "massHaulUpdater" not in render + css = (B05 / "B05_Profile_UI_Style_MassHaul.css").read_text(encoding="utf-8") + block = css[css.index(".b05-profile__masshaul-scroll {") :] + assert "overflow-x: hidden;" in block[: block.index("}")]