Merge remote-tracking branch 'origin/sub_laptop_1' into main_desktop_1
This commit is contained in:
@@ -47,6 +47,7 @@ import { STRUCTURE_LANE_HEIGHT_PX } from "../B05_Profile/B05_Profile_UI_Structur
|
||||
import type { SectionStructureEdit } from "./B06_Section_UI_Section_View_Menu";
|
||||
import {
|
||||
attachWindowScroll,
|
||||
createElevationHold,
|
||||
drawLongitudinalPanel,
|
||||
type LongitudinalPanelInput,
|
||||
} from "./B06_Section_UI_Section_View_Draw";
|
||||
@@ -119,10 +120,9 @@ export interface SectionViewController {
|
||||
structures: ReadonlyArray<StructureInstance>,
|
||||
types: ReadonlyArray<StructureType>,
|
||||
) => void;
|
||||
/** 종단 그래프 우클릭으로 구조물을 넣고 빼는 길 — 없으면 메뉴가 안 뜬다
|
||||
* (2026-09-12 B05·B06 일원화). */
|
||||
/** 종단 그래프 우클릭으로 구조물을 넣고 빼는 길(2026-09-12 B05·B06 일원화). */
|
||||
setStructureEdit: (edit: SectionStructureEdit | null) => void;
|
||||
/** 계획선 편집 ▲/▼ — 그릴 때마다 불러 지금 선형·편집 함수를 받는다(null = 버튼 없음). */
|
||||
/** 계획선 편집 ▲/▼ — 그릴 때마다 불러 선형·편집 함수를 받는다(null = 버튼 없음). */
|
||||
setGradeEdit: (provider: (() => LongitudinalPanelInput["grade"]) | null) => void;
|
||||
dispose: () => void;
|
||||
}
|
||||
@@ -157,7 +157,7 @@ export function createSectionView(
|
||||
let markStructures: ReadonlyArray<StructureInstance> = [];
|
||||
let markTypes: ReadonlyArray<StructureType> = [];
|
||||
let structureEdit: SectionStructureEdit | null = null;
|
||||
let gradeEditProvider: (() => LongitudinalPanelInput["grade"]) | null = null;
|
||||
let gradeEdit: (() => LongitudinalPanelInput["grade"]) | null = null;
|
||||
let renderWidth = 0;
|
||||
let resizeTimer = 0;
|
||||
let panelResizeTimer = 0;
|
||||
@@ -515,7 +515,8 @@ export function createSectionView(
|
||||
naturalSpoilSlope: currentNaturalSpoilSlope,
|
||||
selectStation: (stationId) => selectStation(stationId, true),
|
||||
setMassBadge: (values) => massBadge.set(values),
|
||||
grade: gradeEditProvider?.() ?? null,
|
||||
grade: gradeEdit?.() ?? null,
|
||||
holdRange,
|
||||
});
|
||||
// 상단 패널이 sticky라 선택 카드가 그 아래로 숨는다 — 패널 높이만큼 스크롤 여백을 잡아 준다.
|
||||
syncScrollMargin();
|
||||
@@ -534,6 +535,7 @@ export function createSectionView(
|
||||
}
|
||||
|
||||
attachWindowScroll(chartWrap, () => updateChartWindow, drawPanel);
|
||||
const holdRange = createElevationHold(chartWrap, drawPanel);
|
||||
|
||||
const draw = (): void => {
|
||||
if (!currentDetail || !Number.isFinite(renderWidth) || renderWidth <= 0) return;
|
||||
@@ -668,7 +670,7 @@ export function createSectionView(
|
||||
drawPanel();
|
||||
},
|
||||
setGradeEdit(provider) {
|
||||
gradeEditProvider = provider;
|
||||
gradeEdit = provider;
|
||||
drawPanel();
|
||||
},
|
||||
setStructureMarks(structures, types) {
|
||||
|
||||
@@ -34,6 +34,11 @@ export interface LongitudinalChartInput {
|
||||
onDragStation?: (stationId: string, toChainageM: number) => void;
|
||||
/** X축·측점 라벨을 바닥에서 이만큼(px) 올린다 — 계획고 편집 ▼ 버튼과 겹치지 않게. */
|
||||
bottomInsetPx?: number;
|
||||
/** 세로 창을 가로채는 자리 — 계획고를 ▲▼ 로 만지는 동안 창을 **고정**하는 데 쓴다.
|
||||
* 안 넘기면 늘 보이는 구간에 맞춘다(종전 동작). */
|
||||
holdRange?: (
|
||||
next: { min: number; max: number } | null,
|
||||
) => { min: number; max: number } | undefined;
|
||||
}
|
||||
|
||||
export interface LongitudinalChartResult {
|
||||
@@ -118,7 +123,9 @@ export function buildLongitudinalChart(input: LongitudinalChartInput): Longitudi
|
||||
input.onDragStation,
|
||||
input.bottomInsetPx ?? 0,
|
||||
0,
|
||||
visibleElevationRange(detail, fromM, toM) ?? undefined,
|
||||
input.holdRange
|
||||
? input.holdRange(visibleElevationRange(detail, fromM, toM))
|
||||
: (visibleElevationRange(detail, fromM, toM) ?? undefined),
|
||||
),
|
||||
);
|
||||
return { node, axis, toChainage, toX, maxChainageM, viewFromM: fromM, viewToM: toM };
|
||||
|
||||
@@ -55,6 +55,10 @@ export interface LongitudinalPanelInput {
|
||||
conversion?: EarthworkConversion;
|
||||
naturalSpoilSlope?: number;
|
||||
selectStation: (stationId: string) => void;
|
||||
/** 세로 창 가로채기 — 계획고를 만지는 동안 창을 고정한다(B05 와 같은 장치). */
|
||||
holdRange?: (
|
||||
next: { min: number; max: number } | null,
|
||||
) => { min: number; max: number } | undefined;
|
||||
/** 계획선 편집 — 넘기면 종단 그래프 위에 ▲/▼ 버튼층이 선다(B05 와 같은 부품).
|
||||
* 안 넘기면 버튼이 없고 그래프만 보인다(옛 저장분처럼 선형이 없는 노선). */
|
||||
grade?: {
|
||||
@@ -104,6 +108,7 @@ export function drawLongitudinalPanel(
|
||||
// 계획고 편집 ▼ 버튼이 바닥에 붙으므로 X축·측점 라벨을 그만큼 밀어 올린다
|
||||
// (B05 와 같은 값 15px). 버튼이 없으면 0 — 종전 여백 그대로다.
|
||||
bottomInsetPx: input.grade ? 15 : 0,
|
||||
holdRange: input.holdRange,
|
||||
// 측점선을 끌면 그 구조물이 옮겨 간다 — 관은 예약 이동, 구조물은 정본 이동.
|
||||
onDragStation: edit ? moveMark : undefined,
|
||||
});
|
||||
@@ -208,7 +213,11 @@ export function drawLongitudinalPanel(
|
||||
chartWrap.scrollLeft,
|
||||
chartWrap.clientWidth || chartWidth,
|
||||
);
|
||||
return applyElevationWindow(chartWrap, visibleElevationRange(detail, fromM, toM) ?? undefined);
|
||||
const next = visibleElevationRange(detail, fromM, toM);
|
||||
return applyElevationWindow(
|
||||
chartWrap,
|
||||
input.holdRange ? input.holdRange(next) : (next ?? undefined),
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -239,3 +248,35 @@ export function attachWindowScroll(
|
||||
}, SCROLL_SETTLE_MS);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 계획고 ▲▼ 를 **누르고 있는 동안 세로 창을 고정**한다(B05 와 같은 장치).
|
||||
*
|
||||
* 안 그러면 창이 새 계획선에 맞춰 다시 잡혀, 값은 바뀌는데 선은 제자리에 있는 것처럼
|
||||
* 보인다(2026-09-12 사용자 보고: 「버튼을 눌러도 계획 종단선이 안 바뀐다」). 손을 뗀 뒤
|
||||
* 한 번만 다시 맞춘다.
|
||||
*/
|
||||
export function createElevationHold(
|
||||
chartWrap: HTMLElement,
|
||||
redraw: () => void,
|
||||
): (next: { min: number; max: number } | null) => { min: number; max: number } | undefined {
|
||||
let editing = false;
|
||||
let held: { min: number; max: number } | undefined;
|
||||
chartWrap.addEventListener("pointerdown", (event) => {
|
||||
if (!(event.target as HTMLElement).closest(".b05-profile-edit__btn")) return;
|
||||
editing = true;
|
||||
const release = (): void => {
|
||||
editing = false;
|
||||
window.removeEventListener("pointerup", release);
|
||||
window.removeEventListener("pointercancel", release);
|
||||
redraw();
|
||||
};
|
||||
window.addEventListener("pointerup", release);
|
||||
window.addEventListener("pointercancel", release);
|
||||
});
|
||||
return (next) => {
|
||||
if (editing) return held;
|
||||
held = next ?? undefined;
|
||||
return held;
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user