ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

G6 数据操作 API 完全指南:从查询、增删改到层级遍历

G6 数据操作 API 完全指南:从查询、增删改到层级遍历 G6 数据操作 API 完全指南从查询、增删改到层级遍历【免费下载链接】G6♾ A Graph Visualization Framework in JavaScript.项目地址: https://gitcode.com/gh_mirrors/g6/G6导读本文以 G6JavaScript 图可视化框架官方数据 API 文档packages/site/docs/api/data.zh.md为主体系统梳理图数据从查询、写入到层级遍历的完整生命周期操作。读者学完本文后将掌握getData/getNodeData等 29 个数据 API 的签名、参数、返回值与函数式写法理解setData差异更新、addChildrenData自动建边、节点删除级联清理等底层实现原理并能在实际项目中正确组织节点、边、组合数据。一、G6 数据模型与核心类型G6 是数据驱动的图可视化引擎使用标准 JSON 描述图结构。图数据GraphData由三部分组成nodes节点数据、edges边数据、combos组合数据其类型定义位于 packages/g6/src/spec/data.tsinterface GraphData { nodes?: NodeData[]; // 节点数据 edges?: EdgeData[]; // 边数据 combos?: ComboData[]; // 组合数据 }1.1 节点数据NodeDatainterface NodeData { id: string; // 节点 ID必选唯一标识 type?: string; // 节点类型内置或自定义节点名称 data?: Recordstring, any; // 自定义业务数据可在样式映射回调中获取 style?: Recordstring, any; // 节点样式位置、大小、颜色等 states?: string[]; // 节点初始状态 combo?: string | null; // 所属组合 ID无则为 null children?: string[]; // 子节点 ID 数组仅树图场景 depth?: number; // 节点深度仅树图场景 }完整字段说明可参考 数据使用手册。注意combo与children是两种相互独立的层级结构combo表达组合层级节点归属哪个组合children表达树层级树图中父子节点关系。1.2 边数据EdgeDatainterface EdgeData { source: string; // 起点 ID必选 target: string; // 终点 ID必选 id?: string; // 边 ID可选 type?: string; // 边类型 data?: Recordstring, any; // 自定义业务数据 style?: Recordstring, any; // 边样式线条颜色、宽度、箭头等 states?: string[]; // 边初始状态 }边 ID 的生成规则当边数据未显式提供id时G6 会通过idOf工具函数以${source}-${target}作为默认边 ID见 packages/g6/src/utils/id.ts。因此graph.removeEdgeData([node1-node2])可以直接删除由node1、node2构成的默认 ID 边。1.3 组合数据ComboDatainterface ComboData { id: string; // 组合 ID必选 type?: string; // 组合类型 data?: Recordstring, any; // 组合自定义数据 style?: Recordstring, any; // 组合样式 states?: string[]; // 组合初始状态 combo?: string | null; // 父组合 ID支持嵌套 }1.4 操作辅助类型除三种元素数据外数据 API 还涉及以下类型定义于 packages/g6/src/types/data.ts类型定义用途IDstring元素 IDDataID{ nodes?: ID[]; edges?: ID[]; combos?: ID[] }批量删除时按类型组织 IDElementDatumNodeData \| EdgeData \| ComboData通用元素数据忽略类型NodeLikeDataNodeData \| ComboData节点或组合数据PartialNodeLikeDataTPartialT PickT, id更新数据必须含id其余字段可选PartialEdgeDataT(PartialT PickT,source\|target) \| (PartialT PickT,id)更新边数据必须含sourcetarget或含idPartialGraphData{ nodes?; edges?; combos? }均为 Partial 类型部分图数据更新HierarchyKeytree \| combo指定层级类型树层级或组合层级最佳实践详见 数据使用手册避免使用与 G6 内部字段id、type、style等同名的业务标识符将业务数据放入data字段通过样式映射回调根据业务数据动态设置视觉属性实现数据与样式分离。二、数据查询 API2.1 Graph.getData()获取完整图数据getData(): RequiredGraphData;返回值包含全部节点、边、组合数据的完整图数据。从底层实现看它分别委托getNodeData()、getEdgeData()、getComboData()组装结果见 packages/g6/src/runtime/data.ts。const graphData graph.getData(); console.log(节点数据:, graphData.nodes); console.log(边数据:, graphData.edges); console.log(组合数据:, graphData.combos);2.2 getNodeData / getEdgeData / getComboData按类型查询三个 API 均支持无参全量、单 ID、ID 数组三种调用方式签名完全对称// 节点 getNodeData(): NodeData[]; getNodeData(id: ID): NodeData; getNodeData(ids: ID[]): NodeData[]; // 边 getEdgeData(): EdgeData[]; getEdgeData(id: ID): EdgeData; getEdgeData(ids: ID[]): EdgeData[]; // 组合 getComboData(): ComboData[]; getComboData(id: ID): ComboData; getComboData(ids: ID[]): ComboData[];参数说明参数描述类型默认值必选id元素 IDstring-二选一ids元素 ID 数组string[]-二选一注意事项查询单个元素时传入的id必须真实存在否则会抛出异常从源码看getNodeData(id)走model.getNode(id)不存在即报错见 packages/g6/src/runtime/graph.ts。// 获取所有节点 const nodes graph.getNodeData(); // 获取单个节点 const node graph.getNodeData(node1); console.log(节点位置:, node.style.x, node.style.y); // 获取多个节点 const [node1, node2] graph.getNodeData([node1, node2]); // 边的起点和终点 const edge graph.getEdgeData(edge1); console.log(边的起点和终点:, edge.source, edge.target); // 组合包含的节点 const combo graph.getComboData(combo1); console.log(组合包含的节点:, combo.children);2.3 Graph.getElementData()忽略类型的通用查询getElementData(id: ID): ElementDatum; getElementData(ids: ID[]): ElementDatum[];⚠️注意此 API 直接获取元素的数据而不必考虑元素类型。底层通过getElementType(id)判断元素是 node、edge 还是 combo 后再取对应数据见 packages/g6/src/runtime/data.ts因此可以混传节点与边的 ID。const element graph.getElementData(node-1); console.log(元素数据:, element); const elements graph.getElementData([node-1, edge-1]); console.log(多个元素数据:, elements);2.4 Graph.getElementDataByState()按状态查询getElementDataByState(elementType: node, state: string): NodeData[]; getElementDataByState(elementType: edge, state: string): EdgeData[]; getElementDataByState(elementType: combo, state: string): ComboData[];参数描述类型默认值必选elementType元素类型node \| edge \| combo-✓state状态string-✓实现上该 API 先取回指定类型全部数据再按datum.states?.includes(state)过滤见 packages/g6/src/runtime/data.ts。内置状态G6 内置主题已为以下状态预置了样式见 packages/g6/src/themes/base.tsselected选中显示 halo 光圈、加粗描边highlight高亮加粗描边active激活显示 haloinactive非激活降低透明度disabled禁用降低透明度与填充色const selectedNodes graph.getElementDataByState(node, selected); console.log(选中的节点:, selectedNodes); const selectedEdges graph.getElementDataByState(edge, selected); console.log(选中的边:, selectedEdges); const selectedCombos graph.getElementDataByState(combo, selected); console.log(选中的组合:, selectedCombos);2.5 关系查询getNeighborNodesData 与 getRelatedEdgesData获取一跳邻居节点getNeighborNodesData(id: ID): NodeData[];参数描述类型默认值必选id节点或组合的 IDstring-✓底层调用 graphlib 的getNeighbors(id)获取与指定节点直接相连的所有节点packages/g6/src/runtime/data.ts。对应单元测试见 packages/g6/tests/unit/runtime/data.spec.ts。const neighbors graph.getNeighborNodesData(node-1); console.log(邻居节点:, neighbors);获取关联边getRelatedEdgesData(id: ID, direction?: EdgeDirection): EdgeData[];参数描述类型默认值必选id节点或组合的 IDstring-✓direction边的方向in \| out \| bothbothdirection为in表示入边以该节点为 targetout表示出边以该节点为 sourceboth为全部关联边。测试用例验证了方向过滤行为packages/g6/tests/unit/runtime/data.spec.ts。const relatedEdges graph.getRelatedEdgesData(node-1); console.log(关联边:, relatedEdges);2.6 层级查询父子、祖先、后代G6 中树形层级tree与组合层级combo相互独立对应不同的数据结构因此部分层级 API 需要显式指定HierarchyKey见 packages/g6/src/types/data.ts。getParentData()获取父元素getParentData(id: ID, hierarchy: HierarchyKey): NodeLikeData | undefined;参数描述类型默认值必选id节点或组合的 IDstring-✓hierarchy指定层级关系类型tree \| combo-返回值父元素数据NodeData或ComboData不存在则返回undefined。底层要求指定层级结构必须已存在model.hasTreeStructure否则同样返回undefinedpackages/g6/src/runtime/data.ts。// 获取树图中节点的父节点 const treeParent graph.getParentData(node1, tree); // 获取组合中节点的父组合 const comboParent graph.getParentData(node1, combo);getChildrenData()获取子元素getChildrenData(id: ID): (NodeData | ComboData)[];参数描述类型默认值必选id节点或组合的 IDstring-✓注意查询 combo 的子元素如果id对应的是 combo 元素可直接通过此 API 获取其所有子元素。查询节点的子元素如果id对应的是节点仅当图数据为树结构节点数据维护children字段时才能获取到子元素否则返回空数组。从源码看该 API 会根据元素类型自动选择层级结构节点走TREE_KEY组合走COMBO_KEYpackages/g6/src/runtime/data.ts。测试中getChildrenData(combo-1)正确返回了 combo 下所有节点packages/g6/tests/unit/runtime/data.spec.ts。// 获取组合的子元素 const children graph.getChildrenData(combo1); console.log(子节点数量:, children.length); // 处理每个子元素 children.forEach((child) { console.log(子元素ID:, child.id); });getAncestorsData()获取全部祖先getAncestorsData(id: ID, hierarchy: HierarchyKey): NodeLikeData[];参数描述类型默认值必选id节点或组合的 IDstring-✓hierarchy指定层级关系类型tree \| combo-✓返回值祖先元素数据数组从父节点到根节点的顺序排列。对应测试验证了getAncestorsData(Logistic regression, tree)返回[Classification, Modeling Methods]packages/g6/tests/unit/runtime/data.spec.ts。// 获取树图中节点的所有祖先节点 const treeAncestors graph.getAncestorsData(node1, tree); console.log( 祖先节点路径:, treeAncestors.map((node) node.id), ); // 获取组合中节点的所有父组合 const comboAncestors graph.getAncestorsData(node1, combo);getDescendantsData()获取全部后代getDescendantsData(id: ID): NodeLikeData[];参数描述类型默认值必选id节点或组合的 IDstring-✓返回值后代元素数据数组NodeData[]或ComboData[]。从源码看实现基于深度优先遍历DFS自动向下递归getChildrenData收集所有后代且不含元素自身packages/g6/src/runtime/data.ts。// 获取节点的所有后代 const descendants graph.getDescendantsData(node1); console.log(后代数量:, descendants.length); // 处理所有后代元素 descendants.forEach((descendant) { console.log(后代元素ID:, descendant.id); });三、数据写入 API3.1 Graph.setData()全量设置数据setData(data: GraphData | ((prev: GraphData) GraphData)): void;参数描述类型默认值必选data新的图数据或返回新图数据的函数GraphData \| ((prev: GraphData) GraphData)-✓全量替换 自动差异计算设置全量数据会替换当前图中的所有数据G6 会自动对比新旧数据的差异进入/更新/退出三集合见 packages/g6/src/runtime/data.ts只对发生变化的元素执行新增、更新或删除避免整图重绘。// 直接设置数据 graph.setData({ nodes: [ { id: node1, style: { x: 100, y: 100 } }, { id: node2, style: { x: 200, y: 200 } }, ], edges: [{ id: edge1, source: node1, target: node2 }], }); // 使用函数式增量更新获取当前图数据并返回新的图数据 graph.setData((prev) ({ ...prev, nodes: [...prev.nodes, { id: node3, style: { x: 300, y: 300 } }], }));3.2 新增数据addData 与按类型添加addData()新增元素数据addData(data: GraphData | ((prev: GraphData) GraphData)): void;参数描述类型默认值必选data需要添加的图数据或返回新图数据的函数GraphData \| ((prev: GraphData) GraphData)-✓从源码看addData内部会先添加 combo、再添加 node、最后添加 edge以确保组合关系与边的端点先就绪packages/g6/src/runtime/data.ts。graph.addData({ nodes: [{ id: node-1 }, { id: node-2 }], edges: [{ source: node-1, target: node-2 }], });addNodeData()新增节点addNodeData(data: NodeData[] | ((prev: NodeData[]) NodeData[])): void;参数描述类型默认值必选data要添加的节点数据或返回节点数据的函数NodeData[] \| (prev: NodeData[]) NodeData[]-✓// 添加单个节点 graph.addNodeData([ { id: node1, style: { x: 100, y: 100 }, data: { label: 节点 1 }, }, ]); // 批量添加节点 graph.addNodeData([ { id: node2, style: { x: 200, y: 200 } }, { id: node3, style: { x: 300, y: 300 } }, ]); // 函数式添加 graph.addNodeData((prev) [...prev, { id: node4, style: { x: 400, y: 400 } }]);addEdgeData()新增边addEdgeData(data: EdgeData[] | ((prev: EdgeData[]) EdgeData[])): void;参数描述类型默认值必选data要添加的边数据或返回边数据的函数EdgeData[] \| ((prev: EdgeData[]) EdgeData[])-✓// 添加单条边 graph.addEdgeData([ { id: edge1, source: node1, target: node2, data: { weight: 1, label: 关系, }, }, ]); // 批量添加边 graph.addEdgeData([ { id: edge2, source: node2, target: node3 }, { id: edge3, source: node3, target: node1 }, ]); // 函数式添加 graph.addEdgeData((prev) [...prev, { id: edge4, source: node1, target: node4 }]);addComboData()新增组合addComboData(data: ComboData[] | ((prev: ComboData[]) ComboData[])): void;参数描述类型默认值必选data要添加的组合数据或返回组合数据的函数ComboData[] \| (prev: ComboData[]) ComboData[]-✓graph.addComboData([{ id: combo1, children: [node1, node2] }]);也可以通过combo字段直接建立嵌套组合组合的combo指向父组合详细组合操作示例见 数据使用手册。addChildrenData()为树图节点添加子节点addChildrenData(parentId: ID, childrenData: NodeData[]): void;参数描述类型默认值必选parentId父节点 IDstring-✓childrenData子节点数据NodeData[]-✓⚠️注意为组合添加子节点请使用addNodeData/addComboData方法本方法仅用于树图节点。底层自动完成三件事新增子节点 → 更新父节点的children数组 → 自动为父子创建边{ source: parentId, target: childId }见 packages/g6/src/runtime/data.ts。graph.addChildrenData(node1, [{ id: node2 }]);3.3 更新数据局部更新 浅合并更新类 API 的共同约定只需要传入需要更新的字段不必传入完整数据。底层通过mergeElementsData进行第一层浅合并——顶层属性逐字段合并data、style下的二级数据则整体覆盖见 packages/g6/src/utils/data.ts。// 通用更新可同时更新节点与边 updateData(data: PartialGraphData | ((prev: GraphData) PartialGraphData)): void; // 按类型更新 updateNodeData(data: NodeData[] | ((prev: NodeData[]) NodeData[])): void; updateEdgeData(data: (PartialEdgeDataEdgeData[] | ((prev: EdgeData[]) PartialEdgeDataEdgeData[]))): void; updateComboData(data: (ComboData[] | ((prev: ComboData[]) ComboData[]))): void;参数描述类型默认值必选data要更新的元素数据或返回元素数据的函数见各签名-✓更新边数据的特殊约束updateEdgeData传入的每条数据必须满足含sourcetarget或含id二者之一PartialEdgeData类型约束若修改了source/target底层会调用updateEdgeSource/updateEdgeTarget重新接线packages/g6/src/runtime/data.ts。// 通用更新 graph.updateData({ nodes: [{ id: node-1, style: { x: 100, y: 100 } }], edges: [{ id: edge-1, style: { lineWidth: 2 } }], }); // 更新节点位置 graph.updateNodeData([{ id: node-1, style: { x: 100, y: 100 } }]); // 更新边样式 graph.updateEdgeData([{ id: edge-1, style: { lineWidth: 2 } }]); // 更新组合位置 graph.updateComboData([{ id: combo-1, style: { x: 100, y: 100 } }]);3.4 删除数据级联清理// 通用删除按类型组织 ID removeData(ids: DataID | ((data: GraphData) DataID)): void; // 按类型删除 removeNodeData(ids: ID[] | ((data: NodeData[]) ID[])): void; removeEdgeData(ids: ID[] | ((data: EdgeData[]) ID[])): void; removeComboData(ids: ID[] | ((data: ComboData[]) ID[])): void;参数描述类型默认值必选ids要删除的元素 ID 或返回元素 ID 的函数见各签名-✓级联删除行为源码实现见 packages/g6/src/runtime/data.tsremoveData内部先删边、再删节点、最后删组合保证删除节点时关联边已先行清理removeNodeData删除节点时会自动移除与该节点关联的所有边removeEdgeData(this.getRelatedEdgesData(id).map(idOf))避免产生悬挂边删除组合时其子节点会被移动到父组合的children列表中removeNodeLikeHierarchy逻辑。// 通用删除 graph.removeData({ nodes: [node-1, node-2], edges: [edge-1], }); // 删除节点自动清理关联边 graph.removeNodeData([node-1, node-2]); // 删除边支持默认 ID即 source-target 形式 graph.removeEdgeData([edge-1]); // 删除组合 graph.removeComboData([combo-1]);3.5 存在性判断hasNode / hasEdge / hasCombo三个方法用于在操作前判断元素是否存在避免对不存在的元素执行操作而抛出异常hasNode(id: ID): boolean; // 判断节点是否存在 hasEdge(id: ID): boolean; // 判断边是否存在 hasCombo(id: ID): boolean; // 判断组合是否存在参数描述类型默认值必选id需要判断的元素 IDID-✓从源码看hasNode内部会排除 combomodel.hasNode(id) !this.isCombo(id)hasCombo则要求既是节点又是 combopackages/g6/src/runtime/data.ts。对应单元测试覆盖了存在/不存在两种场景packages/g6/tests/unit/runtime/data.spec.ts。if (graph.hasNode(node-1)) { console.log(节点存在); } if (graph.hasEdge(edge-1)) { console.log(边存在); } if (graph.hasCombo(combo-1)) { console.log(组合存在); }四、底层实现与实战建议4.1 数据 API 的调用链Graph 上所有数据 API 均为薄封装真正实现集中在DataControllerpackages/g6/src/runtime/data.ts其内部基于antv/graphlib的图模型维护节点、边与两套层级结构graph.getData() / setData() / addNodeData() ... └─ Graph 实例方法packages/g6/src/runtime/graph.ts └─ DataControllerpackages/g6/src/runtime/data.ts └─ GraphLib 图模型 变更记录changes所有变更都会被记录到changes数组中pushChange供元素控制器驱动后续绘制更新batch()将多次变更合并为一次批处理silence()则用于运行时调整元素而不留下变更记录如拖拽节点时同步位置见 packages/g6/src/runtime/data.ts。4.2 自动 zIndex 维护新增、更新数据后DataController会自动计算元素的zIndex组合与节点按所属层级逐层递增子元素 zIndex 父元素 zIndex 1边取两端节点 zIndex 的最大值再减一packages/g6/src/runtime/data.ts。因此在业务代码中通常无需手动维护层级顺序。4.3 函数式更新的适用场景setData、addData、updateData及按类型的增删改方法均支持函数式参数(prev) newData这在需要基于当前数据做条件判断时非常实用例如// 仅当节点不存在时才添加 graph.addNodeData((prev) prev.some((n) n.id node1) ? prev : [...prev, { id: node1 }], );4.4 综合示例完整的 CRUD 流程import { Graph } from antv/g6; const graph new Graph({ container: container, data: { nodes: [{ id: node1 }, { id: node2 }], edges: [{ source: node1, target: node2 }], }, }); await graph.render(); // 查询 const all graph.getData(); // 全量数据 const node1 graph.getNodeData(node1); // 单个节点 const neighbors graph.getNeighborNodesData(node1); // 邻居节点 // 新增 graph.addNodeData([{ id: node3, data: { label: 新节点 } }]); graph.addEdgeData([{ source: node1, target: node3 }]); // 更新 graph.updateNodeData([{ id: node1, style: { x: 300, y: 300 } }]); // 删除自动清理 node3 的关联边 graph.removeNodeData([node3]); // 树图子节点操作 graph.addChildrenData(node1, [{ id: node4 }]); // 自动建边 node1 - node4 const descendants graph.getDescendantsData(node1); await graph.draw(); // 数据变更后重新绘制五、小结G6 的数据 API 覆盖了图数据操作的全生命周期getData/getNodeData/getEdgeData/getComboData/getElementData负责按范围与类型查询getElementDataByState支持按状态筛选getNeighborNodesData/getRelatedEdgesData处理关系查询getParentData/getChildrenData/getAncestorsData/getDescendantsData完成树与组合的层级遍历写入侧则通过setData差异更新、add*、update*局部浅合并、remove*级联清理与hasNode/hasEdge/hasCombo构成完备的增删改查体系。结合 DataController 源码 与 单元测试 可以更深入地理解其批处理、差异计算与层级维护机制从而在复杂图应用中编写高效、可靠的数据操作代码。【免费下载链接】G6♾ A Graph Visualization Framework in JavaScript.项目地址: https://gitcode.com/gh_mirrors/g6/G6创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表