Files
Aislo/resources/tester/helper_150_detail_pick.cjs
T

135 lines
4.7 KiB
JavaScript
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.
/* PLAN 150-4 단위검증 헬퍼 — [상세] 수량표 칸 → 그림 복제 강조(`B06_Section_UI_Cross_Detail_Pick.ts`).
* 화면 TS 를 그 자리에서 트랜스파일해 Node 로 돌림 · 결과 = 표준출력 JSON 한 벌. 짝 = `test_150_detail_pick.py`.
*/
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();
// 조정창 공용 부품(Design_Pick → Cross_Panel_Base · 151-3)이 불러올 때 문서에 귀를 닮
globalThis.document = { addEventListener: () => {}, removeEventListener: () => {} };
const resolve = (base) => (fs.existsSync(`${base}.ts`) ? `${base}.ts` : base);
function loadTs(full) {
if (cache.has(full)) return cache.get(full);
const js = ts.transpileModule(fs.readFileSync(full, "utf8"), {
compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020 },
}).outputText;
const box = { exports: {} };
cache.set(full, box.exports);
const localRequire = (request) => {
if (request.endsWith(".css")) return {};
if (request.startsWith("@util/"))
return loadTs(resolve(path.join(ROOT, "common_util", request.slice(6))));
return loadTs(resolve(path.join(path.dirname(full), request)));
};
new Function("exports", "module", "require", js)(box.exports, box, localRequire);
cache.set(full, box.exports);
return box.exports;
}
const pick = loadTs(path.join(ROOT, "B06_Section", "B06_Section_UI_Cross_Detail_Pick.ts"));
// ── 그림 복제 흉내 — 평평한 요소 목록 · 「tag.class」 · 「.class」 · 「g.class line」 만 ──
function node(tag, classes, attrs = {}, parent = null) {
const set = new Set(classes);
return {
tag,
parent,
set,
getAttribute: (name) => attrs[name] ?? null,
classList: {
add: (c) => set.add(c),
remove: (c) => set.delete(c),
contains: (c) => set.has(c),
},
};
}
const one = (el, part) => {
const [tag, ...cls] = part.split(".");
return (!tag || el.tag === tag) && cls.every((c) => el.set.has(c));
};
const matches = (el, selector) => {
const parts = selector.split(" ");
if (!one(el, parts.at(-1))) return false;
return parts.length === 1 || (el.parent !== null && one(el.parent, parts[0]));
};
function fakeSvg(ppm, x0) {
const center = node("g", ["b06-chart__center"]);
const els = [
center,
node("line", [], { x1: String(x0) }, center),
node("g", ["b06-chart__area", "b06-chart__area--cut_soil"]),
node("g", ["b06-chart__area", "b06-chart__area--cut_rock", "b06-chart__area--cut_rr"]),
node("g", ["b06-chart__area", "b06-chart__area--fill", "is-active"]), // 카드에서 묻어 온 강조
node("polyline", ["b06-chart__spoil-fill"]),
];
// 판정 선: offset 구간(m) → 화면 x = x0 − offset × ppm
const hit = (a, b) =>
node("polyline", ["b06-chart__design-hit"], {
points: `${x0 - a * ppm},10 ${x0 - b * ppm},20`,
});
const hits = {
road: hit(-2, 2),
ditch: hit(2.5, 3.0),
cutSlope: hit(3.0, 6.0),
fillSlope: hit(-2.5, -6.0),
};
els.push(...Object.values(hits));
return {
els,
hits,
getAttribute: (name) => (name === "data-px-per-m" ? String(ppm) : null),
querySelectorAll: (sel) =>
els.filter((el) => sel.split(",").some((s) => matches(el, s.trim()))),
querySelector: (sel) => els.find((el) => matches(el, sel)) ?? null,
};
}
const design = {
road_edges: {
left: { offset_m: 2.5, elevation_m: 99.95 },
right: { offset_m: -2.5, elevation_m: 99.95 },
},
ditch: { type: "standard", top_width_m: 0.5, bottom_width_m: 0.2, depth_m: 0.3 },
ditch_side: "left",
ditch_enabled: true,
section_mode: "left_cut",
};
const activeOf = (svg) => {
const names = [];
for (const [name, el] of Object.entries(svg.hits)) if (el.set.has("is-active")) names.push(name);
for (const el of svg.els)
if (el.set.has("is-active") && !el.set.has("b06-chart__design-hit"))
names.push(
[...el.set].find(
(c) => c.includes("--") || c === "b06-chart__center" || c === "b06-chart__spoil-fill",
),
);
return names;
};
const out = { targets: Object.keys(pick.DETAIL_TARGETS), zone: {}, active: {} };
out.zone = {
road: pick.lineZone(design, 0),
ditch: pick.lineZone(design, 2.8),
cutSlope: pick.lineZone(design, 4),
fillSlope: pick.lineZone(design, -4),
};
for (const key of [
null,
"cut_soil",
"cut_rock",
"embankment",
"spoil_fill",
"ground",
"ditch_soil",
"grading_cut",
"grading_fill",
"road_compaction",
"fence",
]) {
const svg = fakeSvg(20, 300);
pick.highlightDetail(svg, design, key);
out.active[String(key)] = activeOf(svg);
}
process.stdout.write(JSON.stringify(out));