- 노면공 포장층 강조 = 포장층을 직접 누른 턴만(paveShapeId) · 알약 · 목록 · 측점선 고름은 범위 테두리만 - 물넘이 콘크리트(pipe-…)는 측점 길 강조(highlightShapes)에서 뺌 — 형상 누름 「관」 고름만 켬 · 맹암거 그대로 - 벽 고름 「관」에 콘크리트 표식(형상 누름 ownerM · 관 없는 카드) · 카드 「관」 setter 를 관 그림 / 콘크리트로 가름(splitPipePick) - 연동 관 카드 콘크리트 누름 = 관 형상 안 켬 · 콘크리트 ↔ 관 바꿔 누르면 풀지 않고 옮김 · 좌측 하위 컨테이너 켬 그대로 - 측점 없는 구조물 = 카드 고름 · 스크롤 없음(revealStation 스크롤 걷음 · 넘김 focusPicked) - 시험: test_307_pick_highlight 새로 · 118 · 177_4 · 287 · 294_6 · 294_7 기대값 307 규칙으로 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014utrjfoW831Vc5wJUd13kL
135 lines
5.0 KiB
JavaScript
135 lines
5.0 KiB
JavaScript
/* 307 B06 고름 강조 헬퍼 — 진짜 TS 를 Node 로 돌려 표준출력 JSON 한 벌로.
|
|
* ① 「관」 setter 가름(splitPipePick) ② 측점 길 형상 강조(highlightShapes) ③ 벽 고름 콘크리트 표식(Station_Controls).
|
|
*/
|
|
const fs = require("fs");
|
|
const path = require("path");
|
|
const ts = require(path.join(__dirname, "..", "..", "config", "node_modules", "typescript"));
|
|
|
|
const ROOT = path.join(__dirname, "..", "..");
|
|
const cache = new Map();
|
|
const load = (file) => {
|
|
if (cache.has(file)) return cache.get(file);
|
|
const js = ts.transpileModule(fs.readFileSync(file, "utf8"), {
|
|
compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020 },
|
|
}).outputText;
|
|
const box = { exports: {} };
|
|
cache.set(file, box.exports);
|
|
const near = (m) => {
|
|
if (m.startsWith("@config/")) return load(path.join(ROOT, "config", `${m.slice(8)}.ts`));
|
|
if (m.endsWith(".json")) return require(path.join(path.dirname(file), m));
|
|
if (m.startsWith(".")) return load(path.join(path.dirname(file), `${m}.ts`));
|
|
return new Proxy({}, { get: () => () => {} });
|
|
};
|
|
new Function("exports", "module", "require", js)(box.exports, box, near);
|
|
return box.exports;
|
|
};
|
|
const memory = new Map();
|
|
globalThis.sessionStorage = {
|
|
getItem: (k) => (memory.has(k) ? memory.get(k) : null),
|
|
setItem: (k, v) => memory.set(k, String(v)),
|
|
removeItem: (k) => memory.delete(k),
|
|
};
|
|
globalThis.window = { setTimeout, clearTimeout, sessionStorage: globalThis.sessionStorage };
|
|
|
|
const B = (f) => path.join(ROOT, "B06_Section", f);
|
|
const shapePick = load(B("B06_Section_UI_Cross_Shape_Pick.ts"));
|
|
|
|
// ① 「관」 setter — 콘크리트 고름 = 콘크리트만 · 관 고름 = 관만 · 다른 벽 = 그대로
|
|
const split = (concrete, key) => {
|
|
const calls = { base: [], shape: [] };
|
|
const setter = shapePick.splitPipePick(
|
|
(k) => calls.base.push(k),
|
|
(on) => calls.shape.push(on),
|
|
() => concrete,
|
|
);
|
|
setter(key);
|
|
return calls;
|
|
};
|
|
|
|
// ② 측점 길 형상 강조 — 맹암거는 id 대로 · 물넘이 콘크리트(pipe-…)는 안 건드림
|
|
class Node {
|
|
constructor(id, cls = "") {
|
|
this.attrs = { "data-structure-id": id, class: cls };
|
|
}
|
|
getAttribute(k) {
|
|
return this.attrs[k] ?? null;
|
|
}
|
|
get classList() {
|
|
const names = () => (this.attrs.class ?? "").split(" ").filter(Boolean);
|
|
return {
|
|
contains: (c) => names().includes(c),
|
|
toggle: (c, on) => {
|
|
const rest = names().filter((n) => n !== c);
|
|
this.attrs.class = (on ? [...rest, c] : rest).join(" ");
|
|
},
|
|
};
|
|
}
|
|
}
|
|
const drain = new Node("ud-1");
|
|
const concreteLit = new Node("pipe-90.00", "is-active"); // 형상 누름 「관」이 켠 콘크리트
|
|
const concreteOff = new Node("pipe-90.00");
|
|
const root = { querySelectorAll: () => [drain, concreteLit, concreteOff] };
|
|
shapePick.highlightShapes(root, "pipe-90.00"); // 물넘이포장 측점 길(알약 · 목록 · 측점선) = 알약 id
|
|
const byStationPath = {
|
|
concreteOff: concreteOff.classList.contains("is-active"),
|
|
concreteLitKept: concreteLit.classList.contains("is-active"),
|
|
};
|
|
shapePick.highlightShapes(root, "ud-1");
|
|
const drainLit = drain.classList.contains("is-active");
|
|
shapePick.highlightShapes(root, null); // 풂(Esc · 다른 것) — 콘크리트는 「관」 고름 풂이 끔
|
|
const afterRelease = {
|
|
drain: drain.classList.contains("is-active"),
|
|
concreteLit: concreteLit.classList.contains("is-active"),
|
|
};
|
|
|
|
// ③ 벽 고름 콘크리트 표식 — 관 카드(80) · 물넘이 제 카드(90 · 관 없음)
|
|
const stations = load(B("B06_Section_UI_Page_Station_Controls.ts"));
|
|
const sections = [
|
|
{ station_id: "s80", chainage_m: 80, culvert: { inlet: {}, outlet: {} }, samples: [] },
|
|
{ station_id: "s90", chainage_m: 90, ford_pavement: { chainage_m: 90 }, samples: [] },
|
|
];
|
|
let changes = 0;
|
|
const controls = stations.createStationControls({
|
|
sessionKey: () => null,
|
|
refreshCard: () => {},
|
|
detail: () => ({ cross_sections: sections }),
|
|
crossHalfWidth: () => undefined,
|
|
sampledHalfWidth: () => 20,
|
|
ensureSampledWidth: async () => true,
|
|
projectId: () => null,
|
|
});
|
|
const revet = controls.revetOffset;
|
|
revet.onSelectionChange = () => (changes += 1);
|
|
const flag = (chainageM, key, ownerM) => {
|
|
revet.select(chainageM, key, ownerM);
|
|
return {
|
|
shape: revet.shapePicked(),
|
|
selected: revet.selectedFor(sections[chainageM === 80 ? 0 : 1]),
|
|
};
|
|
};
|
|
const revetCases = {
|
|
pipeOnPipeCard: flag(80, "pipe"), // 관 그림 누름 = 관
|
|
concreteOnPipeCard: flag(80, "pipe", 90), // 연동 관 카드 콘크리트 누름 = 콘크리트
|
|
concreteOnOwnCard: flag(90, "pipe", 90), // 물넘이 제 카드 콘크리트 누름
|
|
handoffOnOwnCard: flag(90, "pipe"), // 3D 넘김 「관」(관 없는 카드) = 콘크리트
|
|
wall: flag(80, "inlet"),
|
|
released: flag(80, null),
|
|
changes: 0,
|
|
};
|
|
revetCases.changes = changes;
|
|
|
|
process.stdout.write(
|
|
JSON.stringify({
|
|
split: {
|
|
concretePipe: split(true, "pipe"),
|
|
pipePipe: split(false, "pipe"),
|
|
concreteWall: split(true, "inlet"),
|
|
none: split(false, null),
|
|
},
|
|
byStationPath,
|
|
drainLit,
|
|
afterRelease,
|
|
revetCases,
|
|
}),
|
|
);
|