Appearance
<fmb-context-menu>
右键菜单。对当前选中的节点执行 Isolate / Hide / Show all / Copy reference 等动作,并把动作以事件形式通知宿主。组件只负责菜单本身——何时出现、出现在哪由宿主控制(经 x / y 定位、hidden 显隐)。
最小用法
html
<fmb-viewer-context id="ctx">
<div id="viewport"><canvas id="canvas"></canvas></div>
<!-- 初始隐藏,由宿主在 contextmenu 事件里定位并显示 -->
<fmb-context-menu id="ctxmenu" hidden></fmb-context-menu>
</fmb-viewer-context>属性
| 名称 | 类型 | property / attribute | 默认值 | 说明 |
|---|---|---|---|---|
viewer | Viewer | undefined | 仅 property(attribute: false) | undefined | 通常经 <fmb-viewer-context> 注入 |
x | number | property + attribute(type: Number) | 0 | 菜单左上角视口 X 坐标(px),写入 :host 的 left |
y | number | property + attribute(type: Number) | 0 | 菜单左上角视口 Y 坐标(px),写入 :host 的 top |
显隐用 HTML 全局 hidden 属性即可(组件未自定义)。
事件
| 事件 | detail | 冒泡 | 触发时机 |
|---|---|---|---|
fmb-ctx-action | { action: string; nodeIds: number[] } | bubbles: true, composed: true | 点击 Isolate / Hide / Show all / Copy reference / Properties 时;action 为 "isolate" | "hide" | "showAll" | "copy" | "properties",nodeIds 是动作针对的选中节点 id |
fmb-ctx-close | 无 | bubbles: true, composed: true | 任意菜单项执行完毕后(宿主据此隐藏菜单) |
行为细节
- 菜单项(固定清单):Isolate(I)、Hide(H)、Show all、Make transparent(禁用占位)、Measure from…(禁用占位)、Copy reference(⌘C)、Properties…(⌥↵)。快捷键仅为展示文案,组件不注册键盘监听。
- 动作对象:执行时从
viewer.selection.getSelection()取 Node 类型条目的 id 集合;选中为空时除 Show all 外的条目全部禁用(Show all 不依赖选中集,其fmb-ctx-action带空nodeIds发出)。 - Hide:
model.setNodesVisibility(ids, false)。 - Isolate:经共享 helper
isolateZoom.isolate——model.isolateNodes(ids)只留选中子树(装配自动展开,其余叶子隐藏),首次 isolate 保存相机位姿,然后 fit 到保留集。 - Show all:经
isolateZoom.showAll——model.resetNodesVisibility()全部复显;有保存的 isolate 前相机位姿则还原并清除。 - Copy reference:把选中节点名称(逗号连接)写入剪贴板(
navigator.clipboard,失败静默)。 - Properties:组件自身不做任何事,只发
fmb-ctx-action——打开属性面板等响应由宿主实现。 - 定位:
:host为position: fixed(z-index: 1000),x/y在挂载与每次更新时写入left/top;坐标语义是视口坐标(配合contextmenu事件的clientX/Y)。 - 每个动作执行后都会发
fmb-ctx-close;菜单不自带外点/Escape 关闭逻辑,需宿主接线(见下)。
宿主接线示例
最小接线如下:右键打开并把坐标 clamp 进视口,外点 / Escape / fmb-ctx-close 关闭(同一份逻辑在完整集成示例的页面上下文里也有展示)。viewer-ui 另导出功能更全的共享接线 wireContextMenu(@fmb/viewer 阅读器实际所用),在此之上还做右键目标解析(资源管理器惯例:命中已选中者保持、未选中者替换选择、空白清空不弹)与右键拖拽分离:
ts
type MenuEl = HTMLElement & { x: number; y: number };
function clampMenuPosition(x: number, y: number, menuW: number, menuH: number, vw: number, vh: number) {
return { x: Math.max(0, Math.min(x, vw - menuW)), y: Math.max(0, Math.min(y, vh - menuH)) };
}
export function wireMenu(triggers: Element[], menu: MenuEl): void {
const open = (e: Event) => {
const me = e as MouseEvent;
e.preventDefault();
const pos = clampMenuPosition(me.clientX, me.clientY, 220, 290, window.innerWidth, window.innerHeight);
menu.x = pos.x;
menu.y = pos.y;
menu.hidden = false;
};
const close = () => {
menu.hidden = true;
};
for (const t of triggers) t.addEventListener("contextmenu", open);
document.addEventListener("click", (e) => {
if (!menu.contains(e.target as Node)) close();
});
document.addEventListener("keydown", (e) => {
if ((e as KeyboardEvent).key === "Escape") close();
});
menu.addEventListener("fmb-ctx-close", close);
}
// 视口与结构树都可唤出菜单
wireMenu([viewportEl, treeEl], document.getElementById("ctxmenu") as MenuEl);可定制点
菜单表面/边框/圆角/阴影走 --fmb-surface、--fmb-border、--fmb-radius-lg、--fmb-shadow-lg;hover 行底色走 --fmb-accent;文字走 --fmb-fg-1(禁用项 --fmb-fg-4,快捷键 --fmb-fg-3 + --fmb-mono)。全表见主题定制。