UI 与插件系统
Ribbon 工具栏、内置对话框、上下文菜单、插件系统。
如需创建独立插件项目,请参阅 plugin-development.md。
如需创建自定义对话框,请参阅 custom-dialog.md。
Ribbon 工具栏
添加自定义标签页
const { RibbonConfigManager, CommandRegistry, CommandDefinition, CommandOptions } = vjcad;
// 1. 先注册命令
class MyToolCommand {
async main() {
console.log('执行我的工具');
}
}
const opt = new CommandOptions();
opt.useAutoComplete = true;
CommandRegistry.regist(new CommandDefinition('MYTOOL', '我的工具', MyToolCommand, opt));
// 2. 创建标签页配置
const newTab = {
id: 'my-tab',
label: '自定义',
groups: [{
id: 'my-tools',
label: '我的工具',
primaryButtons: [
{
cmd: 'MYTOOL',
icon: 'circle',
label: '创建圆',
prompt: '创建一个圆' // Ribbon 按钮的悬停提示字段是 prompt(没有 tooltip)
}
],
moreButtons: [
{ cmd: 'ZOOM', icon: 'zoom', label: '缩放' }
]
}]
};
// 3. 添加到配置并刷新
const currentConfig = RibbonConfigManager.getConfig();
currentConfig.tabs.push(newTab);
RibbonConfigManager.refresh();
添加到现有标签页
// 添加组到现有标签页
Engine.view.ribbonBar.addGroup('plugins', {
id: 'my-plugin-group',
label: '我的插件',
pinnable: true,
primaryButtons: [
{
icon: 'mygrid',
cmd: 'MYGRID',
prompt: '绘制网格',
type: 'large' // 'large' | 'small'
}
]
});
// 移除组
Engine.view.ribbonBar.removeGroup('plugins', 'my-plugin-group');
侧边栏面板扩展(SidebarPanel)
用于在左 / 右侧侧边栏中加入自定义面板,例如工具面板、信息面板。
const { BasePanelComponent, registerSidebarPanel, unregisterSidebarPanel, activateSidebarPanel } = vjcad;
// 1. 定义面板组件(继承 BasePanelComponent)
class MyToolsPanel extends BasePanelComponent {
static styles = [BasePanelComponent.baseStyles];
render() {
return html`<div class="panel-title">我的工具</div>`;
}
}
// 2. 注册到侧边栏
registerSidebarPanel({
name: "my-tools",
label: "我的工具",
icon: "./images/actbar/actbar-draw-settings.svg",
position: "left", // "left" | "right"
panelClass: MyToolsPanel,
order: 10 // ⚠️ 1.0.16 不生效:实际按注册顺序排列
});
// 3. 激活 / 注销
activateSidebarPanel("my-tools"); // 切换到该面板
// unregisterSidebarPanel("my-tools"); // 注销面板
控制属性面板与内置面板位置
const { MainView } = vjcad;
const cadView = new MainView({
// ... 其他配置
// 选择实体时是否自动切换到特性面板
autoActivatePropertyPanel: false,
// 配置 7 个内置面板的左右位置
// 可用名称: "props" | "blocks" | "images" | "dsettings" | "commands" | "alias" | "history"
leftPanels: ["props", "dsettings"], // 左侧
rightPanels: ["blocks", "images", "commands", "alias", "history"], // 右侧
});
浮动工具栏(FloatingToolbar)
可拖动的图标工具栏,支持横式/竖式布局、标题栏、单例管理。
const { createFloatingToolbar, IconRegistry, IconCategory } = vjcad;
// 获取内置图标(不存在时返回 undefined)
function cmdIcon(name) {
return IconRegistry.getIcon(name, IconCategory.Commands);
}
// 创建横式工具栏(4列,带标题)
const toolbar = createFloatingToolbar('draw-tools', {
title: '绘图工具', // 设置后显示标题栏;空字符串或省略则无标题
columns: 4, // 固定列数(横式);用 rows 则为竖式
iconSize: 30, // 图标按钮尺寸(px)
position: { top: '80px', right: '20px' }, // 初始位置
items: [
{ id: 'line', icon: cmdIcon('line'), tooltip: '直线', command: 'LINE' },
{ id: 'circle', icon: cmdIcon('circle'), tooltip: '圆', command: 'CIRCLE' },
{ id: 'arc', icon: cmdIcon('arc'), tooltip: '圆弧', command: 'ARC' },
// 自定义 onClick 代替 command
{ id: 'zoomext', icon: '<svg>...</svg>', tooltip: '缩放全图',
onClick: () => Engine.zoomExtents() },
],
});
toolbar.show();
// 动态增删
toolbar.addItem({ id: 'spline', icon: cmdIcon('spline'), tooltip: '样条曲线', command: 'SPLINE' });
toolbar.removeItem('spline');
// 同 id 重复调用返回已有实例(单例)
const same = createFloatingToolbar('draw-tools', {}); // === toolbar
// 管理方法
toolbar.hide(); // 隐藏
toolbar.show(); // 显示
toolbar.destroy(); // 销毁
消息输出
const { writeMessage, message } = vjcad;
// 输出到命令行(支持 HTML)
writeMessage("普通消息");
writeMessage("<br/>换行消息");
writeMessage("<br/><span style='color:red'>红色警告</span>");
writeMessage("<br/><b>粗体消息</b>");
// 页面顶部居中的浮动提示(toast,默认 3 秒自动消失;不是控制台输出)
message.info("信息提示");
对话框
确认对话框
const { showConfirm, showWarningConfirm, showInfo, showError } = vjcad;
// 简单确认
const ok = await showConfirm("确定要删除吗?", "确认删除");
// ok: boolean(true=确定)
// 警告确认(同样返回 boolean)
const ok2 = await showWarningConfirm("此操作不可恢复!", "警告");
// 信息提示
await showInfo("操作已完成", "提示");
// 错误提示
await showError("操作失败:文件不存在", "错误");
高级确认对话框
const { YesNoDialog, YesNoDialogConfig } = vjcad;
const config = new YesNoDialogConfig({
title: "保存更改",
message: "文件已修改,是否保存更改?",
type: "warning", // 'info' | 'warning' | 'error' | 'confirm'
yesTitle: "保存(S)",
noTitle: "不保存(N)",
showCancel: true,
cancelTitle: "取消"
});
const dialog = new YesNoDialog();
const result = await dialog.showMessageBox(config);
// result: 'yes' | 'no' | 'cancel' | undefined(直接关闭时)
输入对话框
const { showPrompt, showInputDialog, showSelectDialog } = vjcad;
// 简单输入
const name = await showPrompt("请输入名称:", "默认值", "输入");
// 返回字符串或 null
// 带验证的输入
const result = await showInputDialog({
title: "设置圆半径",
label: "请输入半径值 (1-100):",
placeholder: "输入数字...",
defaultValue: "25",
required: true,
type: "text", // 'text' | 'password'
validator: (value) => {
const num = parseFloat(value);
if (isNaN(num)) return "请输入有效数字";
if (num < 1 || num > 100) return "半径必须在 1-100 之间";
return null; // null 表示验证通过
},
description: "输入的半径将用于创建新圆形"
});
if (result.confirmed) {
const radius = parseFloat(result.value);
}
// 下拉选择
const sel = await showSelectDialog({
title: "选择线型",
label: "请选择线型:",
options: [
{ value: "Continuous", label: "Continuous (实线)" },
{ value: "DASHED", label: "DASHED (虚线)" },
{ value: "CENTER", label: "CENTER (中心线)" }
],
defaultValue: "Continuous",
description: "选择的线型将应用于新创建的直线"
});
上下文菜单
基本用法
const { CadEventManager, CadEvents, Engine } = vjcad;
const events = CadEventManager.getInstance();
events.on(CadEvents.ContextMenuOpening, (args) => {
// 在默认菜单之前添加
args.prependItems.push({
label: "我的工具",
icon: "tool",
submenu: [
{
label: "画圆",
icon: "circle",
callback: () => Engine.editor.executerWithOp('CIRCLE')
},
{
label: "画线",
icon: "line",
callback: () => Engine.editor.executerWithOp('LINE')
}
]
});
// 分隔线
args.prependItems.push({ isSeparator: true });
// 在默认菜单之后添加
args.appendItems.push({
label: "缩放全图",
shortcut: "Z+E",
callback: () => Engine.zoomExtents()
});
});
根据命令状态定制
events.on(CadEvents.ContextMenuOpening, (args) => {
if (args.isCommandActive) {
// 有命令执行中
if (args.activeCommandName === 'LINE') {
args.appendItems.push({
label: "闭合",
callback: () => writeMessage("<br/>C")
});
}
} else {
// 空闲状态
args.prependItems.push({
label: "快捷命令",
submenu: [
{ label: "画线", command: "LINE" },
{ label: "画圆", command: "CIRCLE" }
]
});
}
});
完全自定义菜单
events.on(CadEvents.ContextMenuOpening, (args) => {
args.useDefaultItems = false; // 禁用默认项
args.prependItems.push({
label: "自定义菜单",
callback: () => { /* ... */ }
});
});
禁止右键菜单
events.on(CadEvents.ContextMenuOpening, (args) => {
args.cancel = true;
});
菜单项属性
| 属性 | 说明 |
|---|---|
label |
菜单文本 |
icon |
图标名称 |
shortcut |
快捷键文本 |
callback |
点击回调函数 |
command |
命令名称 |
submenu |
子菜单数组 |
isSeparator |
是否为分隔线 |
disabled |
是否禁用 |
插件系统
插件基本结构
class MyPlugin {
constructor() {
this.name = "MyPlugin";
this.version = "1.0.0";
this.description = "示例插件";
this.commands = [];
this.eventHandlers = [];
}
install() {
this.registerCommands();
this.addEventListeners();
this.initUI();
}
uninstall() {
// 移除事件监听
this.eventHandlers.forEach(handler => {
Engine.eventManager.off(handler.event, handler.callback);
});
// 注销命令
this.commands.forEach(cmdName => {
CommandRegistry.unregist(cmdName);
});
// 移除 UI
Engine.view.ribbonBar.removeGroup('plugins', 'my-plugin-group');
}
registerCommands() {
class DrawGridCommand {
async main() {
// 绘制网格逻辑
}
}
CommandRegistry.regist(
new CommandDefinition('MYGRID', '绘制网格', DrawGridCommand)
);
this.commands.push('MYGRID');
}
addEventListeners() {
const onEntityAdded = (args) => {
console.log('实体已添加:', args.entity.type);
};
Engine.eventManager.on(CadEvents.EntityAdded, onEntityAdded);
this.eventHandlers.push({
event: CadEvents.EntityAdded,
callback: onEntityAdded
});
}
initUI() {
// 注册图标
IconRegistry.registerCommandIcon('MYGRID', '<svg>...</svg>');
// 添加 Ribbon 组
Engine.view.ribbonBar.addGroup('plugins', {
id: 'my-plugin-group',
label: '我的插件',
primaryButtons: [
{ icon: 'mygrid', cmd: 'MYGRID', prompt: '绘制网格', type: 'large' }
]
});
}
}
// 安装插件
const plugin = new MyPlugin();
plugin.install();
标准插件结构(Plugin 接口)
export default {
manifest: {
id: 'my-demo-plugin',
name: '示例插件',
version: '1.0.0',
author: 'vjmap.com',
description: '演示标准插件结构',
keywords: ['demo', 'grid']
},
onLoad(context) {
console.log('插件已加载');
},
onActivate(context) {
// 注册图标
context.registerIcon('MYGRID', '<svg>...</svg>');
// 注册命令
context.registerCommand('MYGRID', '绘制网格', DrawGridCommand);
// 添加菜单项
context.addMenuItem('tool', { command: 'MYGRID' });
// 添加 Ribbon 组
context.addRibbonGroup('plugins', {
id: 'my-demo',
label: '示例工具',
primaryButtons: [
{ icon: 'mygrid', cmd: 'MYGRID', prompt: '绘制网格', type: 'large' }
]
});
},
onDeactivate(context) {
console.log('插件已停用');
},
onUnload(context) {
console.log('插件已卸载');
}
};
PluginManager API
const { PluginManager } = vjcad;
const pm = PluginManager.getInstance();
// 加载插件
await pm.loadFromContent(jsContent, cssContent); // 从代码内容
await pm.loadFromUrl(jsUrl, cssUrl); // 从 URL
await pm.loadFromPath(jsPath, cssPath); // 从本地路径
// 插件管理
pm.getLoadedPlugins(); // 获取已加载插件列表
pm.getPluginInfo(id); // 获取指定插件信息
pm.isLoaded(id); // 检查是否已加载
pm.isActive(id); // 检查是否已激活
pm.activate(id); // 激活插件
pm.deactivate(id); // 停用插件
pm.unload(id); // 卸载插件
插件生命周期
onLoad- 插件加载时调用(只调用一次)onActivate- 插件激活时调用(可多次调用)onDeactivate- 插件停用时调用(可多次调用)onUnload- 插件卸载时调用(只调用一次)