事件与 API

图表组件在界面外观方面刻意保持无头(headless):它发出携带数据的事件,让宿主渲染菜单和对话框,然后暴露方法来驱动模型。正因如此,属性面板或上下文菜单是你自己的 UI,通过组件的事件连接起来。

事件

使用 diagram.on(event, handler) 订阅;它返回一个取消订阅的函数。

  • nodeAdded / nodeRemoved / nodeMoved — 节点生命周期。
  • linkAdded / linkRemoved / linkRelinked — 连线生命周期。
  • linkValidation — 每次尝试连接时返回 { allowed, reason }
  • selectionChanged / nodeSelected / linkSelected — 选择状态。
  • contextMenuRequested — 右键点击时返回 { x, y, node, link, port, commands }
  • fullscreenRequested{ fullscreen };由宿主应用布局。
const off = diagram.on('linkAdded', ({ links }) => console.log('已连接', links[0]));
// 稍后:
off();

上下文菜单

右键点击时,组件会绘制自己的菜单,同时发出 contextMenuRequested。这两种情况下事件都会到达,因此如果你要绘制自己的菜单,就必须关闭内置菜单——否则两者会叠在一起:

const diagram = new StockSharpDiagram(container, { showContextMenu: false });

事件会报告点击位置、光标下的对象,以及应当按其顺序绘制的菜单项列表。菜单项分为两种,区分它们要看有没有 group 字段:命令带有 command 并可以执行,子菜单带有 group 和自己的 commands 列表——它本身没有什么可执行的。

diagram.on('contextMenuRequested', ({ x, y, node, link, commands }) => {
  const menu = renderMenu(commands.filter(c => c.enabled), x, y);

  menu.onPick = item => {
    if ('group' in item) return;                       // 子菜单:展开它,而不是执行
    diagram.executeContextCommand(item.command);       // 若命令当前不可用则返回 false
  };
});

完整的命令列表:undoredocutcopypasteopendeleteexportDocumentexportPngexportSvgoverviewpropertieshelp。唯一的分组是 export,它把三个导出命令归到一起。

Note

导出命令是对宿主的请求,而不是组件的动作:它既不写文件也不打开对话框。请处理 exportRequested,并用你自己的参数执行 saveDocument()takeScreenshot()takeSvg()

连线校验

端口是带类型的,组件会拒绝不兼容或超额订阅的连线,并发出 linkValidation,附带 reasonincompatible-typeduplicate-linksource-limittarget-limitsame-node……)。使用 setLinkValidator 添加你自己的规则:

diagram.setLinkValidator(({ fromPort, toPort }) => fromPort.type === toPort.type);

保存与加载

const scheme = diagram.save();              // { nodes, links }
diagram.load(scheme.nodes, scheme.links);

const document = diagram.saveDocument();     // 带版本的文档
diagram.loadDocument(document);

撤销、重做与剪贴板

使用 diagram.undo() / redo(),并用 canUndo() / canRedo() 来控制按钮的可用状态;copySelection() / cutSelection() / pasteSelection()deleteSelection() 用于剪贴板操作。setReadOnly(true) 将图表锁定为预览状态。

撤销/重做的可用性由控件掌控,因此请跟踪其规范的 undoStackChanged 事件,以便针对每一个命令(删除、拖拽、重新连线、粘贴)保持按钮同步,而不仅仅是上面提到的模型变更事件:

diagram.on('undoStackChanged', ({ canUndo, canRedo }) => {
  undoButton.disabled = !canUndo;
  redoButton.disabled = !canRedo;
});

运行时状态与错误高亮

图表可以在方案之上叠加执行状态。setNodeError 会以动画脉冲(约 1 秒)闪烁节点的边框,并用红色高亮标记它 —— 用它来报告运行时故障。交互式编辑器中的 Error 按钮正是这么做的。

diagram.setNodeError('sma', 'SMA 失败:未配置数据源。');
diagram.setNodeError('sma', '警告', { animate: false }); // 标记它,但跳过初始闪烁

在加载时就已存在的错误会绘制成红色背景,而非闪烁 —— 将它们传给 load

diagram.load(nodes, links, { nodeErrors: { sma: '保存的周期值无效。' } });

其他运行时钩子:setActiveNode(id) 高亮当前正在执行的节点(调试器光标),setPortRuntimeState(id, direction, portId, patch) 标注单个端口,setGlobalError(message) 闪烁整个方案范围的错误。使用 clearRuntimeState() 清除所有内容。

参见