- 흐림 판 [업데이트] 아래 관 표지가 있으면 setPointerCapture 로 단추가 click 못 받던 것 - 시험 test_369_3_update_press(가짜 표지 + pointer 사건 차례) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VmC34fsxxbweEG3RUjs3Mn
148 lines
5.1 KiB
JavaScript
148 lines
5.1 KiB
JavaScript
/* 369-3 [업데이트] 진짜 누름 헬퍼 — `B05_Profile_UI_Drainage_Interact.ts` 를 그 자리에서
|
|
* 트랜스파일해 가짜 viewport · 단추 · 관 표지로 pointerdown → pointerup → click 차례를 돌림.
|
|
* 사로잡기(setPointerCapture)가 걸리면 pointerup · click 은 viewport 로 감(브라우저와 같음).
|
|
*/
|
|
const fs = require("fs");
|
|
const path = require("path");
|
|
const ts = require(path.join(__dirname, "..", "..", "config", "node_modules", "typescript"));
|
|
|
|
const B05 = path.join(__dirname, "..", "..", "B05_Profile");
|
|
|
|
class Element {
|
|
constructor(tag, parent = null) {
|
|
this.tag = tag;
|
|
this.parent = parent;
|
|
this.className = "";
|
|
this.listeners = {};
|
|
}
|
|
matches(selector) {
|
|
return selector.split(",").some((part) => {
|
|
const s = part.trim();
|
|
return s.startsWith(".") ? this.className.split(" ").includes(s.slice(1)) : s === this.tag;
|
|
});
|
|
}
|
|
closest(selector) {
|
|
for (let node = this; node; node = node.parent) if (node.matches(selector)) return node;
|
|
return null;
|
|
}
|
|
addEventListener(type, fn) {
|
|
(this.listeners[type] ??= []).push(fn);
|
|
}
|
|
fire(type, event) {
|
|
(this.listeners[type] ?? []).forEach((fn) => fn(event));
|
|
}
|
|
}
|
|
global.Element = Element;
|
|
|
|
const stubs = {
|
|
"../A00_Common/touch_bridge": { wheelZoomsIn: () => true },
|
|
"../B04_PreProcess/B04_PreProcess_UI_MapRender": {
|
|
computeMaxScale: () => 10,
|
|
lonLatToScreen: () => ({ x: 0, y: 0 }),
|
|
},
|
|
"../B04_PreProcess/B04_PreProcess_UI_MapOverlays": { pointInRings: () => true },
|
|
"./B05_Profile_UI_Drainage_ZoomRange": { clampWheelScale: (value) => value },
|
|
};
|
|
const file = path.join(B05, "B05_Profile_UI_Drainage_Interact.ts");
|
|
const js = ts.transpileModule(fs.readFileSync(file, "utf8"), {
|
|
compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020 },
|
|
}).outputText;
|
|
const box = { exports: {} };
|
|
new Function("exports", "module", "require", js)(
|
|
box.exports,
|
|
box,
|
|
(name) => stubs[name] ?? require(name),
|
|
);
|
|
|
|
function setup() {
|
|
const viewport = new Element("div");
|
|
viewport.className = "b05-drainage__viewport";
|
|
viewport.style = { removeProperty() {} };
|
|
viewport.getBoundingClientRect = () => ({ left: 0, top: 0, width: 400, height: 300 });
|
|
viewport.captured = null;
|
|
viewport.setPointerCapture = (id) => (viewport.captured = id);
|
|
const canvas = new Element("canvas", viewport);
|
|
const veil = new Element("div", viewport);
|
|
veil.className = "b05-drainage__veil";
|
|
const update = new Element("button", veil);
|
|
update.className = "b05-drainage__analyze b05-drainage__update";
|
|
const log = { live: 0, grabs: 0, picks: 0 };
|
|
update.addEventListener("click", () => log.live++); // [업데이트] = drainage/live 한 번
|
|
let dragging = false;
|
|
const state = { scale: 1, offset: { x: 0, y: 0 } };
|
|
box.exports.bindDrainageInteractions({
|
|
viewport,
|
|
contextMenu: { contains: () => false, close() {} },
|
|
// 가짜 표지 — 단추 바로 아래(어디를 눌러도 집힘)
|
|
pipeEditor: {
|
|
handleDown: () => ((dragging = true), log.grabs++, true),
|
|
handleMove: () => dragging,
|
|
handleUp: () => ((dragging = false), false),
|
|
},
|
|
currentView: () => ({ mapRect: { width: 400 }, width: 400 }),
|
|
getScale: () => state.scale,
|
|
setScale: (v) => (state.scale = v),
|
|
getMeta: () => null,
|
|
getMinScale: () => 0.1,
|
|
getOffset: () => state.offset,
|
|
setOffset: (x, y) => (state.offset = { x, y }),
|
|
scheduleDraw() {},
|
|
getNormalizer: () => ({}),
|
|
getBasins: () => [
|
|
{
|
|
index: 0,
|
|
polygon_lonlat: [
|
|
[0, 0],
|
|
[1, 0],
|
|
[1, 1],
|
|
],
|
|
area_m2: 1,
|
|
},
|
|
],
|
|
getSelectedBasin: () => null,
|
|
selectBasin: () => log.picks++,
|
|
});
|
|
return { viewport, canvas, update, log, state };
|
|
}
|
|
|
|
/** 진짜 마우스 누름 — 사건은 target 에서 viewport 로 거품 · 사로잡히면 up · click 이 viewport 로. */
|
|
function press(world, target, button = 0) {
|
|
const event = { target, button, pointerId: 1, pointerType: "mouse", clientX: 200, clientY: 150 };
|
|
const bubble = (type, from) => {
|
|
for (let node = from; node; node = node.parent)
|
|
node.fire(type, { ...event, preventDefault() {} });
|
|
};
|
|
world.viewport.captured = null;
|
|
bubble("pointerdown", target);
|
|
const upTarget = world.viewport.captured !== null ? world.viewport : target;
|
|
bubble("pointerup", upTarget);
|
|
bubble("click", upTarget);
|
|
}
|
|
|
|
const onButton = setup();
|
|
press(onButton, onButton.update);
|
|
const onMap = setup();
|
|
press(onMap, onMap.canvas);
|
|
const panMap = setup();
|
|
const panEvent = {
|
|
target: panMap.canvas,
|
|
button: 1,
|
|
pointerId: 2,
|
|
pointerType: "mouse",
|
|
preventDefault() {},
|
|
};
|
|
panMap.viewport.fire("pointerdown", { ...panEvent, clientX: 0, clientY: 0 });
|
|
panMap.viewport.fire("pointermove", { ...panEvent, clientX: 30, clientY: 40 });
|
|
|
|
process.stdout.write(
|
|
JSON.stringify({
|
|
button: {
|
|
...onButton.log,
|
|
captured: onButton.viewport.captured,
|
|
offset: onButton.state.offset,
|
|
},
|
|
map: { ...onMap.log, captured: onMap.viewport.captured },
|
|
pan: { captured: panMap.viewport.captured, offset: panMap.state.offset },
|
|
}),
|
|
);
|