Skip to content

节点、连线与选择 ​

以下接口由SkyNoteEditor提供。Point中的坐标单位为画布世界单位,嵌套节点的创建坐标相对于父容器;屏幕坐标转换见视口API。

示例中的SkyNoteEditor及EntityRefs等类型从@skynote/editor导入,函数以已有Editor为输入;首次创建实例见快速开始。

创建节点 ​

接口返回值坐标与选区
createNode(request)string | null默认左上角定位,可提供parentId;不改变选区
insertNodeAtViewportCenter(request)string | null新节点中心对准当前视口中心,成功后选中新节点
insertNodeAt(request, point)string | null新节点中心对准给定世界坐标,成功后选中新节点

CreateNodeRequest<T>的公共参数:

参数默认 / 要求
nodeType必填,已注册的节点类型
x / ycreateNode必填;两个insert方法负责定位
origintop-left;可改为center
parentId缺省为根层级,只在createNode请求中使用
id缺省自动生成
width / height缺省使用节点类型创建内容的尺寸
rotation可选旋转角
options按nodeType从NodeCreateOptionsMap推导
label可选的撤销记录名称
autoWrap创建可接收子节点的容器时,默认自动收纳完全落入其中的同层节点

提交被拒绝时检查返回的null。创建请求成功不表示它必定在当前视口内;指定较远坐标后可调用fitContent()。

ts
export function addConnectedNotes(editor: SkyNoteEditor<HTMLElement>): string[] {
  const ids: string[] = [];
  editor.engine.documentStore.batch(() => {
    const first = editor.createNode({ nodeType: 'sticky', x: 0, y: 0, options: { text: '问题' } });
    const second = editor.createNode({ nodeType: 'shape', x: 280, y: 30, options: { label: '下一步' } });
    if (!first || !second) throw new Error('无法创建示例内容');
    ids.push(first, second);
    editor.engine.documentStore.createConnector({
      connectorType: 'curved',
      from: { nodeId: first },
      to: { nodeId: second }
    });
  }, '创建问题与下一步');
  editor.select(ids);
  return ids;
}

连线通过公开文档语义命令创建。内置路由id为straight、orthogonal、curved,端点可绑定nodeId或使用自由世界坐标position。移动节点后绑定连线随路由更新,不需要宿主在每次拖动时手动重建。

查询与可见范围 ​

接口返回值 / 用途
getNode(id) / getConnector(id)只读实体或undefined
getNodes() / getConnectors()当前实体数组;只适合低频全量查询
getChildIds(parentId?)直接子节点ID,缺省查询根层级
nodeCount节点总数,不等于当前可见数
isNodeVisible(id) / isConnectorVisible(id)当前展示可见性,包含布局折叠等影响
getNodeBounds(id)可见节点实际世界外框,不可见时可为undefined
getEntitiesBounds(refs)节点和连线整体世界外框,全部不存在时为undefined
nodeAt(point) / connectorAt(point)世界坐标处的命中实体
getNodeStyle(id) / getConnectorStyle(id)合并节点/路由默认值后的生效样式

折叠或隐藏的逻辑内容仍可能保留在文档查询中。工具栏定位应使用几何查询,不用x/y/width/height简单拼接旋转节点、分组或整张导图的世界范围。

选区 ​

select(nodeIds, connectorIds = [])替换当前选区;select([], [])清空。不可见实体被过滤,多选时锁定节点也会被过滤。selectedNodeIds和selectedConnectorIds是只读集合。

selectSubtree(rootId)表达布局公开的整体选择意图,只有布局允许时生效;文档写入仍以根节点为入口。selectedSubtreeNodeIds区分整图和单个主题选择,不能通过“选中了中心主题”自行推断整图。

selectAll()选择根层级可操作内容,容器后代随容器处理,不要求宿主枚举所有后代。

ts
export function duplicateSelection(editor: SkyNoteEditor<HTMLElement>): EntityRefs {
  return editor.duplicateEntities({ nodeIds: editor.selectedNodeIds, connectorIds: editor.selectedConnectorIds });
}

修改与几何 ​

接口参数与行为
updateNodes(ids, fields, options?)字段对象或逐节点函数;style/data默认合并,merge:false改为替换
updateNodeStyle(ids, style, options?)只改提供的样式项;透明色会拆为颜色与透明度字段
setNodeRadius(ids, radius, options?)四角统一,或通过corner只改某个角
setNodeSize(ids, {width?, height?}, options?)左上角保持,按节点比例锁定与缩放策略计算
setNodeRotation(ids, rotation, options?)各节点绕自身中心设置角度
rotateNodesBy(ids, degrees, options?)绕所选节点整体中心做增量旋转
fitNodesContent(ids)调整节点外框以适应内容,不支持或已适应者跳过
setLocked(refs, locked)一次事务修改节点与连线锁定
setAspectLocked(ids, locked)修改节点比例锁定

普通修改命令大多返回void,不把返回值当成功标记。只读、事务守卫、锁定或布局约束可能影响是否执行;UI先查询可用能力,再提交对应语义命令。

连续数值面板通过groupId合并历史;关闭/失焦调用endGeometryEdit(groupId),详见历史API。

组合、排列与删除 ​

接口返回值 / 条件
canGroupNodes(ids) / canUngroupNodes(ids)查询当前是否可执行
groupNodes(ids)新组合ID或null,成功后选中组合
ungroupNodes(ids)释放的子节点ID数组,并更新选区;也可解散有子节点的容器外壳
duplicateEntities(refs, offset?)顶层副本ID集合,默认偏移{x:20,y:20};含后代和内部连线
deleteEntities(refs, label?)级联删除节点后代及依附连线,一步撤销
alignNodes(ids, alignment)按世界外框对齐;受锁定或自动布局约束时可能不执行
distributeNodes(ids, axis)至少三个独立节点,固定两端,均分边缘间距
autoArrangeNodes(ids, options?)单次网格整理,不改变尺寸、朝向或父子关系

EntityRefs的nodeIds与connectorIds均为可选Iterable,缺省类别视为空。删除分组或容器会影响其内容,不能当作只删一个外框。

可组合的画布能力,从一个想法开始。