Untitled
unknown
plain_text
a year ago
4.5 kB
22
Indexable
Never
export function SetKnowledgeGraph({ graphRef, graphComponentRef, data, containerId, zoomValues }: IProps) { const graph = graphRef.current; const graphComponent = graphComponentRef.current; if (!graph || !graphComponent) { return; } // Clear the graph graph.clear(); const { width, height } = CalculateLayoutOptions(containerId, zoomValues); // Set default node and edge styles graph.nodeDefaults.style = new HtmlEditableNodeStyle(PerspectiveItem); graph.nodeDefaults.size = [width, height]; graph.edgeDefaults.style = new PolylineEdgeStyle({ stroke: '1px #3F3F46', targetArrow: new Arrow({ fill: '#3F3F46', stroke: '#3F3F46', type: ArrowType.TRIANGLE }) }); // Extract topics, documents, and edges const topics = data.items.filter(i => hasItemLabel(i, 'Topic')); const documents = data.documents.map(doc => ({ ...doc, graph, relations: data.relations.filter(d => d.documentId === doc.id) })); let edges = data.relations .map(item => ({ from: item.documentId, to: item.itemId, label: '' })) .filter(item => item.from !== item.to); const filtered = filteredItem.get(); const itemId = showItemModal.get()?.item?.id ?? filtered; if (filtered || itemId) { // Remove edges that are not related to the selected item edges = edges.filter(item => item.from === itemId || item.to === itemId); } const graphBuilder = new GraphBuilder(graph); graphBuilder.createNodesSource(topics, 'id'); graphBuilder.createNodesSource(documents, 'id'); graphBuilder.createNodesSource(data.subPerspectives, 'id'); graphBuilder.createEdgesSource(edges, 'from', 'to'); graphBuilder.buildGraph(); // Set up the layout and layering graphComponent.inputMode = new GraphViewerInputMode({}); const layout = new HierarchicLayout(); const layoutData = new HierarchicLayoutData(); layout.orthogonalRouting = true; layout.automaticEdgeGrouping = true; layout.backLoopRouting = false; const layering = layoutData.layerConstraints; const graphNodes = graphComponent.graph.nodes.toArray(); const documentLayer = 0; const parentTopicLayer = 1; const activeTopicLayer = 2; let topicLayer = 3; let index = 0; if (itemId || filtered) { graphNodes.forEach(node => { const nodeTag = node.tag; if (hasItemLabel(nodeTag, 'Document')) { nodeTag.layer = documentLayer; } else if (hasItemLabel(nodeTag, 'Topic')) { if (nodeTag.id === itemId) { nodeTag.layer = activeTopicLayer; } else { const incomingEdge = edges.find(e => e.from === nodeTag.id); const outgoingEdge = edges.find(e => e.to === nodeTag.id); if (incomingEdge) { nodeTag.layer = parentTopicLayer; } else if (outgoingEdge) { nodeTag.layer = topicLayer; index++; if (index % 5 === 0) { topicLayer++; } } } } else { nodeTag.layer = 0; } }); graphNodes.forEach(node => { layering.nodeComparables.mapper.set(node, node.tag.layer); }); } // Set up bus descriptors const busDescriptor = new HierarchicLayoutBusDescriptor(); const busIncomingEdges = graphComponent.graph.edges.filter(e => e.tag.to === itemId).toArray(); if (busIncomingEdges.length > 0) { const docDescriptor = new HierarchicLayoutBusDescriptor(); const topicDescriptor = new HierarchicLayoutBusDescriptor(); const docEdges = busIncomingEdges.filter(e => graphComponent.graph.nodes.find(n => n.tag.id === e.tag.from && hasItemLabel(n.tag, 'Document')) ); const topicEdges = busIncomingEdges.filter(e => graphComponent.graph.nodes.find(n => n.tag.id === e.tag.from && hasItemLabel(n.tag, 'Topic')) ); if (docEdges.length > 0) { layoutData.buses.add(docDescriptor).items = docEdges; } if (topicEdges.length > 0) { layoutData.buses.add(topicDescriptor).items = topicEdges; } } const busEdges = graphComponent.graph.edges.filter(e => e.tag.from === itemId).toArray(); if (busEdges.length > 0) { layoutData.buses.add(busDescriptor).items = busEdges; } // Apply layout to the graph graphComponent.graph.applyLayout(layout, layoutData); // Fit the graph bounds const limiter = graphComponent.viewportLimiter; limiter.honorBothDimensions = true; limiter.bounds = null; graphComponent.fitGraphBounds(); }