Appearance
<fmb-toolbar>
浮动工具层。组件本身是一个全视口浮层(:host 撑满宿主容器,pointer-events: none 让空白区域透传给画布),内部自下而上分三层:
- 工具坞(底部居中):一排工具按钮——Select / Orbit / Pan、取景适配、渲染模式(菜单)、剖切与爆炸(纯开关)、SVG 导出(瞬时动作)。
- 状态条(工具坞上方,单行分段):活跃状态的唯一归宿——Select 工具的拾取范围 chip、剖切的当前平面与 ⚙/✕、爆炸的百分比与 ⚙/✕。
- 可拖配置卡片:剖切与爆炸的详细配置(加平面 / Capping / Gizmo / 滑杆 / 预设),按住卡片头部可拖到任意位置。
最小用法
把组件放进一个铺满视口的 overlay 容器(inset: 0; pointer-events: none),让它能量到视口宽度做自适应:
html
<fmb-viewer-context id="ctx">
<div class="viewport">
<canvas id="canvas"></canvas>
<!-- 全视口浮层:工具坞/状态条/卡片由组件内部布局 -->
<div class="toolbar-overlay"><fmb-toolbar dock></fmb-toolbar></div>
</div>
</fmb-viewer-context>css
.viewport {
position: relative;
}
.toolbar-overlay {
position: absolute;
inset: 0;
z-index: 11;
pointer-events: none; /* 仅 fmb-toolbar 内部元素接收点击,空白透传画布 */
}这是 @fmb/viewer 阅读器与 @fmb/desktop 的真实接法。不要把组件塞进一个只有工具条那么大的窄容器——组件用 ResizeObserver 测量自身宽度决定档位,容器太窄会被误判为需要收纳。
属性
| 名称 | 类型 | property / attribute | 默认值 | 说明 |
|---|---|---|---|---|
viewer | Viewer | undefined | 仅 property(attribute: false) | undefined | 通常经 <fmb-viewer-context> 注入 |
dock | boolean | 响应式 property({ type: Boolean }) | false | 大按钮档(dock)的准入开关:允许在宽度足够时升到 52px 大按钮档;实际档位由测量决定,见下「三档自适应」 |
profile | "review" | "share" | property + attribute | "review" | 装配形态,决定装哪些工具与参数怎么呈现,见下「形态」 |
hideTools | string[] | property + hide-tools attribute | [](全开) | 按 id 关掉某些工具,见下「按需裁剪」 |
iconSize | number | null | property + icon-size attribute | null | 图标边长(px),按钮跟着等比变;缺省按档位走内置值,见下「尺寸适配」 |
dock 是标准的 Lit Boolean property:HTML 里写 attribute(<fmb-toolbar dock>)、JS 里直接赋值(toolbar.dock = true)都生效。组件还会把测量出的实际档位反射到 tier attribute(dock / compact / overflow),只读、供样式调试观察。
形态(profile)
同一个组件,两种装配。差的是参数深度,不是动作 —— 两档都能选、能转、能剖、能爆炸。
review(默认) | share | |
|---|---|---|
| 工具 | select / orbit / hand / fit / projection / display / section / explode / measure / snapshot | tree / fit / section / explode / showAll / reset / snapshot / share |
| 选择粒度 | 状态条上可切 Part/Face/Edge/All | 不给(宿主自行固定为 Part) |
| 显示模式、投影 | 有 | 不给 |
| 剖切/爆炸参数 | 可拖配置卡 + 状态条 | 一根滑杆(strip)贴在条上方,无卡片、无状态条 |
| 文案 | 工程术语 | 人话(「切开看」「拆开看」「看全整机」) |
share 档多两个交给宿主的动作(见「事件」):tree 开结构树抽屉、share 复制链接。showAll 只在有隐藏项时出现并带计数徽标 —— 按钮出现本身就是「有东西被藏了」的信号。
变换编辑不在这里 transform 曾经是工具条的一项,现已移除 —— 那是编辑器能力,viewer 是只读消费端。引擎 API 仍在,宿主调 transform.setEditMode(true) 照样能唤起参数卡。:::
尺寸适配(iconSize)
工具条按钮的尺寸 = 图标边长 + 固定内边距,所以只需给一个图标尺寸,整条按比例变大变小:
html
<fmb-toolbar icon-size="26"></fmb-toolbar>ts
toolbar.iconSize = 26; // Vue: :iconSize.prop="26"(注意 camelCase,见上面的 warning)缺省按档位走内置值:compact 19px、dock 24px。实测(compact 档):
icon-size | 图标 | 按钮 |
|---|---|---|
| 缺省 | 19×19 | 33×28 |
| 26 | 26×26 | 40×35 |
| 32 | 32×32 | 46×41 |
| 14 | 14×14 | 28×23 |
也可以只用 CSS
组件把尺寸暴露成 CSS 变量 --fmb-toolbar-icon-size,宿主直接写样式即可 —— 按分辨率做响应式时这条路最顺,不用把断点逻辑写进 JS:
css
fmb-toolbar {
--fmb-toolbar-icon-size: 22px;
}
@media (min-width: 2560px) {
fmb-toolbar {
--fmb-toolbar-icon-size: 30px;
}
}优先级
iconSize 属性写的是内联样式,会压过宿主的外部 CSS 规则。两者都想用时,让属性只在需要覆盖的场景设值(其余保持 null)。
宽度预算会跟着 iconSize 走 —— 放大图标后按钮变宽,三档自适应会相应更早把非 core 工具收进 ⋯,不会溢出到条外。
按需裁剪(hideTools)
默认全开。要关掉某几个功能,按 id 列出即可:
html
<!-- attribute:逗号分隔字符串(容忍空格)。静态配置用这个最省心 -->
<fmb-toolbar hide-tools="snapshot,share"></fmb-toolbar>ts
// property:直接给数组
toolbar.hideTools = ["measure", "projection"];可用 id 见上面「形态」表格的「工具」一行。未知 id 会被忽略。
框架里绑 property 时注意大小写 property 名是 hideTools(camelCase),attribute 名是 hide-tools(kebab-case) —— 别混。Vue 的 .prop 修饰符是照原样执行 el[key] = value,不做 camelCase 转换:
vue
<fmb-toolbar :hide-tools.prop="[...]"> <!-- ✗ 设到 el["hide-tools"],组件不看这个键 -->
<fmb-toolbar :hideTools.prop="[...]"> <!-- ✓ 设到 el.hideTools -->
<fmb-toolbar hide-tools="snapshot,share"> <!-- ✓ 走 attribute,kebab-case 才对 -->React 19+ 同理:<fmb-toolbar hideTools={[...]} /> 走 property,hide-tools="…" 走 attribute。:::
关掉的是入口不是能力 —— 引擎 API 照常可用,宿主随时能自己调起来。被关掉的工具也不再参与宽度分配,不会白占位置。
事件
绝大多数按钮直接作用于 Viewer 实例,不经宿主。只有组件不该替宿主决定的事会交回来 —— 开哪个抽屉、链接长什么样是宿主的策略,不是组件的:
ts
toolbar.addEventListener("fmb-toolbar-action", (e) => {
switch ((e as CustomEvent<{ action: string }>).detail.action) {
case "tree":
/* 开/关结构树抽屉 */ break;
case "share":
/* 生成并复制链接 */ break;
case "snapshot-saved":
/* 截图已存,给个回执 */ break;
}
});detail.action | 何时发 |
|---|---|
tree | 点「零件清单」(仅 share 档) |
share | 点「复制链接」(仅 share 档) |
snapshot-saved | 「存一张图」已把 PNG 交给浏览器下载 |
事件带 bubbles + composed,可在祖先节点上监听。
行为细节
工具坞
- Select:激活选择工具——导航设为
camera.setNavMode("orbit"),并开启画布点击选中与悬停高亮(selection.setAutoSelectOnClick(true)/setAutoHoverOnMove(true))。拾取范围不在这里选,见下「状态条」。 - Orbit / Pan:分别
setNavMode("orbit")/setNavMode("pan"),同时关闭画布点击选中与悬停——它们是纯导航工具,只有 Select 工具会拾取。 - 取景适配:调
camera.fitView()。 - 渲染模式(带角标的菜单按钮):Shaded with edges(默认勾选)/ Shaded / Wireframe / Hidden Line,经
viewer.renderMode.set()切换;X-ray 为占位项,禁用。 - 剖切(纯开关):开——
section.create({ boolean: "intersection" })+ 加一个 Z 轴平面 +activate(),盖面与 gizmo 按当前勾选状态应用,并自动打开 Section 配置卡;关——section.clear()。加平面、Capping、Gizmo、Flip、Remove 全部在配置卡里,按钮本身不带弹层。按钮亮灭订阅引擎section-changed事件(getActiveSectionCount() > 0),代码侧改剖切也会同步。剖切语义(上限/boolean 组合)见剖切。 - 爆炸(纯开关):在 0 与 50% 之间切换(
viewer.explode.set(0.5)),开启时自动打开 Explode 配置卡。爆炸语义见爆炸视图。 - 测量:占位项,禁用("coming soon")。
- SVG 导出:调
viewer.export.downloadSvg("snapshot.svg"),以当前视角生成矢量 SVG 并触发浏览器下载。导出选项见截图导出。
状态条
只在有活跃状态时出现,各段之间竖线分隔:
- Select 段(Select 工具激活时):显示 "Pick mode" chip,点击弹出拾取范围菜单——单选 Part(
SelectionMask.Node)/ Face / Edge / All,经selection.setPickableMask()生效;接到viewer时用getPickableMask()初始化勾选项。拾取语义见选择与拾取。 - Section 段(剖切开启时):显示当前平面(单平面显示轴向如
+Z,多平面显示N planes)、⚙ 重新打开配置卡、✕ 关闭剖切(section.clear())。注意:若剖切是代码侧(绕过工具条)激活的,组件没有 section handle,此时段内只有 ✕,不显示值与 ⚙。 - Explode 段(爆炸 > 0 时):显示百分比、⚙ 重新打开配置卡、✕ 归零并收卡。
配置卡片
- Section 卡(默认锚在视口左上):按 X / Y / Z 加平面(到达
section.capacity上限后禁用)、Capping / Gizmo 复选框(setCappingStyle({ visible })/setInteractive())、逐平面 Flip / Remove;移除最后一个平面时整组剖切自动清除(连带收卡)。 - Explode 卡(默认锚在视口右上,避开 ViewCube):0–100 滑杆实时调
viewer.explode.set(n / 100),下方 0 / 25 / 50 / 75 / 100 快捷预设。滑到 0 在松手提交(change 事件)或点预设 Off 时收卡。 - 卡片头部可拖(✕ 按钮除外),松手后停在拖到的位置;关闭再打开回默认锚位。
瞬态菜单 vs 持久卡片
两类浮层的关闭规则不同:
- 瞬态菜单(渲染模式、Pick mode、溢出 ⋯):点外面、按 Esc、再点同一按钮即关;同一时刻最多展开一个。
- 持久配置卡(Section / Explode):只在点卡片 ✕、对应工具关闭、或更换
viewer时收起,点画布不收。
三档自适应
组件用 ResizeObserver 测量自身宽度,在三档之间自动切换(反射到 tier attribute):
- dock:52px 大按钮——仅当宿主设了
dock且宽度放得下全部按钮。 - compact:36px 紧凑条——dock 放不下(或未设
dock)时的常规档。 - compact + ⋯ 溢出:紧凑条也放不下时,非核心组按 priority 从低频到高频收进 "⋯" 溢出菜单(snapshot → measure → explode → section → display);Select / Orbit / Pan / 取景适配是核心组,永不收纳。
空态与 viewer 更换
viewer 未注入时剖切按钮禁用,其余按钮点击为安全空操作(可选链)。更换 viewer 时重置剖切与爆炸状态、收起配置卡,并退订旧实例事件、重读新实例的拾取范围。
可定制点
条体/状态条/卡片表面与边框走 --fmb-surface、--fmb-border、--fmb-radius-xl、--fmb-shadow-pop;菜单走 --fmb-radius-lg、--fmb-shadow-lg;激活态走 --fmb-accent、--fmb-accent-soft、--fmb-accent-fg;禁用态走 --fmb-fg-4;Pick mode chip 与滑杆轨道走 --fmb-surface-3;状态条 ✕ hover 与剖切面 Remove 按钮走 --fmb-danger;百分比/平面值等数字走 --fmb-mono。全表见主题定制。