mermaid
Version:
Markdown-ish syntax for generating flowcharts, mindmaps, sequence diagrams, class diagrams, gantt charts, git graphs and more.
8 lines (7 loc) • 22.2 kB
Source Map (JSON)
{
"version": 3,
"sources": ["../../../src/rendering-util/layout-algorithms/cose-bilkent/cytoscape-setup.ts", "../../../src/rendering-util/layout-algorithms/cose-bilkent/layout.ts", "../../../src/rendering-util/layout-algorithms/cose-bilkent/render.ts", "../../../src/rendering-util/layout-algorithms/cose-bilkent/index.ts"],
"sourcesContent": ["import cytoscape from 'cytoscape';\nimport coseBilkent from 'cytoscape-cose-bilkent';\nimport { select } from 'd3';\nimport { log } from '../../../logger.js';\nimport type { LayoutData, Node, Edge } from '../../types.js';\nimport type { CytoscapeLayoutConfig, PositionedNode, PositionedEdge } from './types.js';\n\n// Inject the layout algorithm into cytoscape\ncytoscape.use(coseBilkent);\n\n/**\n * Declare module augmentation for cytoscape edge types\n */\ndeclare module 'cytoscape' {\n interface EdgeSingular {\n _private: {\n bodyBounds: unknown;\n rscratch: {\n startX: number;\n startY: number;\n midX: number;\n midY: number;\n endX: number;\n endY: number;\n };\n };\n }\n}\n\n/**\n * Add nodes to cytoscape instance from provided node array\n * This function processes only the nodes provided in the data structure\n * @param nodes - Array of nodes to add\n * @param cy - The cytoscape instance\n */\nexport function addNodes(nodes: Node[], cy: cytoscape.Core): void {\n nodes.forEach((node) => {\n const nodeData: Record<string, unknown> = {\n id: node.id,\n labelText: node.label,\n height: node.height,\n width: node.width,\n padding: node.padding ?? 0,\n };\n\n // Add any additional properties from the node\n Object.keys(node).forEach((key) => {\n if (!['id', 'label', 'height', 'width', 'padding', 'x', 'y'].includes(key)) {\n nodeData[key] = (node as unknown as Record<string, unknown>)[key];\n }\n });\n\n cy.add({\n group: 'nodes',\n data: nodeData,\n position: {\n x: node.x ?? 0,\n y: node.y ?? 0,\n },\n });\n });\n}\n\n/**\n * Add edges to cytoscape instance from provided edge array\n * This function processes only the edges provided in the data structure\n * @param edges - Array of edges to add\n * @param cy - The cytoscape instance\n */\nexport function addEdges(edges: Edge[], cy: cytoscape.Core): void {\n edges.forEach((edge) => {\n const edgeData: Record<string, unknown> = {\n id: edge.id,\n source: edge.start,\n target: edge.end,\n };\n\n // Add any additional properties from the edge\n Object.keys(edge).forEach((key) => {\n if (!['id', 'start', 'end'].includes(key)) {\n edgeData[key] = (edge as unknown as Record<string, unknown>)[key];\n }\n });\n\n cy.add({\n group: 'edges',\n data: edgeData,\n });\n });\n}\n\n/**\n * Create and configure cytoscape instance\n * @param data - Layout data containing nodes and edges\n * @returns Promise resolving to configured cytoscape instance\n */\nexport function createCytoscapeInstance(data: LayoutData): Promise<cytoscape.Core> {\n return new Promise((resolve) => {\n // Add temporary render element\n const renderEl = select('body').append('div').attr('id', 'cy').attr('style', 'display:none');\n\n const cy = cytoscape({\n container: document.getElementById('cy'), // container to render in\n style: [\n {\n selector: 'edge',\n style: {\n 'curve-style': 'bezier',\n },\n },\n ],\n });\n\n // Remove element after layout\n renderEl.remove();\n\n // Add all nodes and edges to cytoscape using the generic functions\n addNodes(data.nodes, cy);\n addEdges(data.edges, cy);\n\n // Make cytoscape care about the dimensions of the nodes\n cy.nodes().forEach(function (n) {\n n.layoutDimensions = () => {\n const nodeData = n.data();\n return { w: nodeData.width, h: nodeData.height };\n };\n });\n\n // Configure and run the cose-bilkent layout\n const layoutConfig: CytoscapeLayoutConfig = {\n name: 'cose-bilkent',\n // @ts-ignore Types for cose-bilkent are not correct?\n quality: 'proof',\n styleEnabled: false,\n animate: false,\n };\n\n cy.layout(layoutConfig).run();\n\n cy.ready((e) => {\n log.info('Cytoscape ready', e);\n resolve(cy);\n });\n });\n}\n\n/**\n * Extract positioned nodes from cytoscape instance\n * @param cy - The cytoscape instance after layout\n * @returns Array of positioned nodes\n */\nexport function extractPositionedNodes(cy: cytoscape.Core): PositionedNode[] {\n return cy.nodes().map((node) => {\n const data = node.data();\n const position = node.position();\n\n // Create a positioned node with all original data plus position\n const positionedNode: PositionedNode = {\n id: data.id,\n x: position.x,\n y: position.y,\n };\n\n // Add all other properties from the original data\n Object.keys(data).forEach((key) => {\n if (key !== 'id') {\n positionedNode[key] = data[key];\n }\n });\n\n return positionedNode;\n });\n}\n\n/**\n * Extract positioned edges from cytoscape instance\n * @param cy - The cytoscape instance after layout\n * @returns Array of positioned edges\n */\nexport function extractPositionedEdges(cy: cytoscape.Core): PositionedEdge[] {\n return cy.edges().map((edge) => {\n const data = edge.data();\n const rscratch = edge._private.rscratch;\n\n // Create a positioned edge with all original data plus position\n const positionedEdge: PositionedEdge = {\n id: data.id,\n source: data.source,\n target: data.target,\n startX: rscratch.startX,\n startY: rscratch.startY,\n midX: rscratch.midX,\n midY: rscratch.midY,\n endX: rscratch.endX,\n endY: rscratch.endY,\n };\n\n // Add all other properties from the original data\n Object.keys(data).forEach((key) => {\n if (!['id', 'source', 'target'].includes(key)) {\n positionedEdge[key] = data[key];\n }\n });\n\n return positionedEdge;\n });\n}\n", "import type { MermaidConfig } from '../../../config.type.js';\nimport { log } from '../../../logger.js';\nimport type { LayoutData } from '../../types.js';\nimport type { LayoutResult } from './types.js';\nimport {\n createCytoscapeInstance,\n extractPositionedNodes,\n extractPositionedEdges,\n} from './cytoscape-setup.js';\n\n/**\n * Execute the cose-bilkent layout algorithm on generic layout data\n *\n * This function takes layout data and uses Cytoscape with the cose-bilkent\n * algorithm to calculate optimal node positions and edge paths.\n *\n * @param data - The layout data containing nodes, edges, and configuration\n * @param config - Mermaid configuration object\n * @returns Promise resolving to layout result with positioned nodes and edges\n */\nexport async function executeCoseBilkentLayout(\n data: LayoutData,\n _config: MermaidConfig\n): Promise<LayoutResult> {\n log.debug('Starting cose-bilkent layout algorithm');\n\n try {\n // Validate layout data structure\n validateLayoutData(data);\n\n // Create and configure cytoscape instance\n const cy = await createCytoscapeInstance(data);\n\n // Extract positioned nodes and edges after layout\n const positionedNodes = extractPositionedNodes(cy);\n const positionedEdges = extractPositionedEdges(cy);\n\n log.debug(`Layout completed: ${positionedNodes.length} nodes, ${positionedEdges.length} edges`);\n\n return {\n nodes: positionedNodes,\n edges: positionedEdges,\n };\n } catch (error) {\n log.error('Error in cose-bilkent layout algorithm:', error);\n throw error;\n }\n}\n\n/**\n * Validate layout data structure\n * @param data - The data to validate\n * @returns True if data is valid, throws error otherwise\n */\nexport function validateLayoutData(data: LayoutData): boolean {\n if (!data) {\n throw new Error('Layout data is required');\n }\n\n if (!data.config) {\n throw new Error('Configuration is required in layout data');\n }\n\n if (!data.rootNode) {\n throw new Error('Root node is required');\n }\n\n if (!data.nodes || !Array.isArray(data.nodes)) {\n throw new Error('No nodes found in layout data');\n }\n\n if (!Array.isArray(data.edges)) {\n throw new Error('Edges array is required in layout data');\n }\n\n return true;\n}\n", "import type { InternalHelpers, LayoutData, RenderOptions, SVG, SVGGroup } from 'mermaid';\nimport { executeCoseBilkentLayout } from './layout.js';\nimport type { D3Selection } from '../../../types.js';\n\ntype Node = Record<string, unknown>;\n\ninterface NodeWithPosition extends Node {\n x?: number;\n y?: number;\n domId?: string | SVGGroup | D3Selection<SVGAElement>;\n width?: number;\n height?: number;\n id?: string;\n}\n\n/**\n * Render function for cose-bilkent layout algorithm\n *\n * This follows the same pattern as ELK and dagre renderers:\n * 1. Insert nodes into DOM to get their actual dimensions\n * 2. Run the layout algorithm to calculate positions\n * 3. Position the nodes and edges based on layout results\n */\nexport const render = async (\n data4Layout: LayoutData,\n svg: SVG,\n {\n insertCluster,\n insertEdge,\n insertEdgeLabel,\n insertMarkers,\n insertNode,\n log,\n positionEdgeLabel,\n }: InternalHelpers,\n { algorithm: _algorithm }: RenderOptions\n) => {\n const nodeDb: Record<string, NodeWithPosition> = {};\n const clusterDb: Record<string, any> = {};\n\n // Insert markers for edges\n const element = svg.select('g');\n insertMarkers(element, data4Layout.markers, data4Layout.type, data4Layout.diagramId);\n\n // Create container groups\n const subGraphsEl = element.insert('g').attr('class', 'subgraphs');\n const edgePaths = element.insert('g').attr('class', 'edgePaths');\n const edgeLabels = element.insert('g').attr('class', 'edgeLabels');\n const nodes = element.insert('g').attr('class', 'nodes');\n\n // Step 1: Insert nodes into DOM to get their actual dimensions\n log.debug('Inserting nodes into DOM for dimension calculation');\n\n await Promise.all(\n data4Layout.nodes.map(async (node) => {\n if (node.isGroup) {\n // Handle subgraphs/clusters\n const clusterNode: NodeWithPosition = { ...node };\n clusterDb[node.id] = clusterNode;\n nodeDb[node.id] = clusterNode;\n\n // Insert cluster to get dimensions\n await insertCluster(subGraphsEl, node);\n } else {\n // Handle regular nodes\n const nodeWithPosition: NodeWithPosition = { ...node };\n nodeDb[node.id] = nodeWithPosition;\n\n // Insert node to get actual dimensions\n const nodeEl = await insertNode(nodes, node, {\n config: data4Layout.config,\n dir: data4Layout.direction || 'TB',\n });\n\n // Get the actual bounding box after insertion\n const boundingBox = nodeEl.node()!.getBBox();\n nodeWithPosition.width = boundingBox.width;\n nodeWithPosition.height = boundingBox.height;\n nodeWithPosition.domId = nodeEl;\n\n log.debug(`Node ${node.id} dimensions: ${boundingBox.width}x${boundingBox.height}`);\n }\n })\n );\n\n // Step 2: Run the cose-bilkent layout algorithm\n log.debug('Running cose-bilkent layout algorithm');\n\n // Update the layout data with actual dimensions\n const updatedLayoutData = {\n ...data4Layout,\n nodes: data4Layout.nodes.map((node) => {\n const nodeWithDimensions = nodeDb[node.id];\n return {\n ...node,\n width: nodeWithDimensions.width,\n height: nodeWithDimensions.height,\n };\n }),\n };\n\n const layoutResult = await executeCoseBilkentLayout(updatedLayoutData, data4Layout.config);\n\n // Step 3: Position the nodes based on layout results\n log.debug('Positioning nodes based on layout results');\n\n layoutResult.nodes.forEach((positionedNode) => {\n const node = nodeDb[positionedNode.id];\n if (node?.domId) {\n // Position the node at the calculated coordinates\n // The positionedNode.x/y represents the center of the node, so use directly\n (node.domId as D3Selection<SVGAElement>).attr(\n 'transform',\n `translate(${positionedNode.x}, ${positionedNode.y})`\n );\n\n // Store the final position\n node.x = positionedNode.x;\n node.y = positionedNode.y;\n\n log.debug(`Positioned node ${node.id} at center (${positionedNode.x}, ${positionedNode.y})`);\n }\n });\n\n layoutResult.edges.forEach((positionedEdge) => {\n const edge = data4Layout.edges.find((e) => e.id === positionedEdge.id);\n if (edge) {\n // Update the edge data with positioned coordinates\n edge.points = [\n { x: positionedEdge.startX, y: positionedEdge.startY },\n { x: positionedEdge.midX, y: positionedEdge.midY },\n { x: positionedEdge.endX, y: positionedEdge.endY },\n ];\n }\n });\n\n // Step 4: Insert and position edges\n log.debug('Inserting and positioning edges');\n\n await Promise.all(\n data4Layout.edges.map(async (edge) => {\n // Insert edge label first\n const _edgeLabel = await insertEdgeLabel(edgeLabels, edge);\n\n // Get start and end nodes\n const startNode = nodeDb[edge.start ?? ''];\n const endNode = nodeDb[edge.end ?? ''];\n\n if (startNode && endNode) {\n // Find the positioned edge data\n const positionedEdge = layoutResult.edges.find((e) => e.id === edge.id);\n\n if (positionedEdge) {\n log.debug('APA01 positionedEdge', positionedEdge);\n // Create edge path with positioned coordinates\n const edgeWithPath = { ...edge };\n\n // Insert the edge path\n const paths = insertEdge(\n edgePaths,\n edgeWithPath,\n clusterDb,\n data4Layout.type,\n startNode,\n endNode,\n data4Layout.diagramId\n );\n\n // Position the edge label\n positionEdgeLabel(edgeWithPath, paths);\n } else {\n // Fallback: create a simple straight line between nodes\n const edgeWithPath = {\n ...edge,\n points: [\n { x: startNode.x || 0, y: startNode.y || 0 },\n { x: endNode.x || 0, y: endNode.y || 0 },\n ],\n };\n\n const paths = insertEdge(\n edgePaths,\n edgeWithPath,\n clusterDb,\n data4Layout.type,\n startNode,\n endNode,\n data4Layout.diagramId\n );\n positionEdgeLabel(edgeWithPath, paths);\n }\n }\n })\n );\n\n log.debug('Cose-bilkent rendering completed');\n};\n", "import { render as renderWithCoseBilkent } from './render.js';\n\n/**\n * Cose-Bilkent Layout Algorithm for Generic Diagrams\n *\n * This module provides a layout algorithm implementation using Cytoscape\n * with the cose-bilkent algorithm for positioning nodes and edges.\n *\n * The algorithm follows the unified rendering pattern and can be used\n * by any diagram type that provides compatible LayoutData.\n */\n\n/**\n * Render function for the cose-bilkent layout algorithm\n *\n * This function follows the unified rendering pattern used by all layout algorithms.\n * It takes LayoutData, inserts nodes into DOM, runs the cose-bilkent layout algorithm,\n * and renders the positioned elements to the SVG.\n *\n * @param layoutData - Layout data containing nodes, edges, and configuration\n * @param svg - SVG element to render to\n * @param helpers - Internal helper functions for rendering\n * @param options - Rendering options\n */\nexport const render = renderWithCoseBilkent;\n"],
"mappings": "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",
"names": ["log", "render"]
}