浮动工具栏(FloatingToolbar)
文档:
vjcad/doc/ui/index.md(floating-toolbar 段) 示例:vjcad/example/ui/15floatingtoolbar.js
1. 用途
FloatingToolbar 是悬浮在画布上的可拖动小工具栏。适合:
- 不希望占用 Ribbon / 菜单的"自定义快捷键面板"
- 测量 / 标注等"工作模式临时面板"
- 移动端 / 触屏简化操作面板
由全局工厂 createFloatingToolbar(id, options) 创建,单例:相同 id 第二次调用会返回已有实例(并顺手 show() 它,新传的 options 被忽略)。新建的工具栏默认是隐藏的,必须调 show()。
2. 最小示例
const { createFloatingToolbar, IconRegistry, IconCategory, Engine } = vjcad;
const tb = createFloatingToolbar('draw-tools', {
title: '绘图工具',
columns: 4,
iconSize: 30,
position: { top: '80px', right: '20px' },
items: [
{ id: 'line', icon: IconRegistry.getIcon('line', IconCategory.Commands),
tooltip: '直线 (LINE)', command: 'LINE' },
{ id: 'circle', icon: IconRegistry.getIcon('circle', IconCategory.Commands),
tooltip: '圆 (CIRCLE)', command: 'CIRCLE' },
{ id: 'arc', icon: IconRegistry.getIcon('arc', IconCategory.Commands),
tooltip: '圆弧 (ARC)', command: 'ARC' },
{ id: 'zoomext',
icon: '<svg viewBox="0 0 24 24" stroke="#58a6ff"><polyline points="15 3 21 3 21 9"/></svg>',
tooltip: '缩放全图',
onClick: () => Engine.zoomExtents() }
]
});
tb.show();
要点:
command字段直接走Engine.editor.executerWithOp(command)- 没注册过命令的项用
onClick回调 IconRegistry.getIcon(name, IconCategory.Commands)返回内置 SVG 字符串,找不到时返回undefined,自己 fallback
3. 配置项
interface FloatingToolbarOptions {
title?: string; // 标题,留空 → 不显示标题栏
showHeader?: boolean; // 强制显示 / 隐藏标题栏
position?: PanelPosition; // { top?/right?/bottom?/left? } CSS 定位
columns?: number; // 横向布局:每行多少列
rows?: number; // 纵向布局:每列多少行
iconSize?: number; // 图标按钮像素尺寸
items?: FloatingToolbarItem[];
}
interface FloatingToolbarItem {
id: string; // 唯一
icon: string; // 只能是内联 SVG 字符串(以 '<svg' 开头)或图片 URL;不查 IconRegistry,
// 写注册名会被当成 <img src="line"> 而裂图——要内置图标就 IconRegistry.getIcon(...) 取 SVG 串
tooltip: string; // ⚠️ 必填(不是可选)
command?: string; // 直接执行的 vjcad 命令
onClick?: () => void; // 自定义回调
disabled?: boolean;
}
FloatingToolbarOptions只有上面 7 个键——没有draggable/closeOnEsc。
columns 与 rows 互斥:填了 columns 是横式(行数自适应),填了 rows 是竖式(列数自适应)。
4. 实例管理 API
const tb = createFloatingToolbar('my-tools', { /* ... */ });
tb.show(); // 显示(新建后默认隐藏,必须调)
tb.hide();
tb.close(); // 与 hide() 完全相同,不触发任何事件
tb.destroy(); // 彻底销毁、从 DOM 移除、删 cache
tb.addItem({ id: 'spline', icon: '...', tooltip: '样条', command: 'SPLINE' });
tb.addItems([{ id: 'a', icon: '...', tooltip: 'A' }, { id: 'b', icon: '...', tooltip: 'B' }]);
tb.removeItem('spline');
tb.updateItem('line', { tooltip: '改了一下', disabled: true });
tb.resetPosition(); // 清掉持久化位置并复位到 options.position(没有 setPosition/toggle 方法)
tb.isVisible;
5. 单例特性
const t1 = createFloatingToolbar('draw-tools', { title: 'A', columns: 4 });
const t2 = createFloatingToolbar('draw-tools', { title: 'B' }); // 不会重建
console.log(t1 === t2); // true,title 仍是 'A'
需要"重新构建"时先 destroy 再 create:
tb.destroy();
const fresh = createFloatingToolbar('draw-tools', { title: '新建' });
6. 实战:根据当前命令切换工具栏
const drawTb = createFloatingToolbar('draw-tools', { /* 绘图项 */ });
const editTb = createFloatingToolbar('edit-tools', { /* 编辑项 */ });
const events = CadEventManager.getInstance();
events.on(CadEvents.SelectionChanged, () => {
const sel = ssGetFirst() ?? [];
if (sel.length > 0) { drawTb.hide(); editTb.show(); }
else { drawTb.show(); editTb.hide(); }
});
7. 可访问性 / 键盘
- 拖拽标题栏(或顶部 16px 拖动条)即可移动;拖动结束后位置持久化到 localStorage(键
vjcad-ftb-pos-<id>),下次同 id 创建时优先用缓存位置、忽略options.position resetPosition()删除该缓存并复位到options.position- 支持 tooltip 鼠标悬停出现
红旗
id全局唯一;与别的插件同 id 时后创建者直接拿到先创建者的实例(自己的 options/items 被忽略),不是互相覆盖——id 加插件前缀- 一次性创建过多浮动工具栏(>4 个)会让画布变挤;通常配合命令上下文动态显示
command字段必须是已注册的命令名;命令未注册时点击没反应tooltip是FloatingToolbarItem的必填字段position在窗口缩放后不会自动重排,自适应 要自己监听window.resize后用resetPosition()或重建;改了options.position却不生效,多半是 localStorage 里有旧的拖动位置,先resetPosition()destroy()会移除 DOM 但不会注销点击监听里的引用,自定义onClick中如有外部资源记得释放
参考(官方文档 MCP)
- 文档:
vjcad/doc/ui/index.md(floating-toolbar 段) - 示例:
vjcad/example/ui/15floatingtoolbar.js