Untitled

mail@pastecode.io avatar
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();
}