UNPKG

@mermaid-js/layout-elk

Version:
5 lines 53.2 kB
{ "version": 3, "sources": ["../../../src/render.ts", "../../../src/find-common-ancestor.ts"], "sourcesContent": ["import { curveLinear } from 'd3';\nimport ELK from 'elkjs/lib/elk.bundled.js';\nimport type { InternalHelpers, LayoutData, RenderOptions, SVG, SVGGroup } from 'mermaid';\nimport { type TreeData, findCommonAncestor } from './find-common-ancestor.js';\n\ntype Node = LayoutData['nodes'][number];\n\ninterface LabelData {\n width: number;\n height: number;\n wrappingWidth?: number;\n labelNode?: SVGGElement | null;\n}\n\ninterface NodeWithVertex extends Omit<Node, 'domId'> {\n children?: unknown[];\n labelData?: LabelData;\n domId?: Node['domId'] | SVGGroup | d3.Selection<SVGAElement, unknown, Element | null, unknown>;\n}\n\nexport const render = async (\n data4Layout: LayoutData,\n svg: SVG,\n {\n common,\n getConfig,\n insertCluster,\n insertEdge,\n insertEdgeLabel,\n insertMarkers,\n insertNode,\n interpolateToCurve,\n labelHelper,\n log,\n positionEdgeLabel,\n }: InternalHelpers,\n { algorithm }: RenderOptions\n) => {\n const nodeDb: Record<string, any> = {};\n const clusterDb: Record<string, any> = {};\n\n const addVertex = async (\n nodeEl: SVGGroup,\n graph: { children: NodeWithVertex[] },\n nodeArr: Node[],\n node: Node\n ) => {\n const labelData: LabelData = { width: 0, height: 0 };\n\n const config = getConfig();\n\n // Add the element to the DOM\n if (!node.isGroup) {\n const child: NodeWithVertex = {\n ...node,\n };\n graph.children.push(child);\n nodeDb[node.id] = child;\n\n const childNodeEl = await insertNode(nodeEl, node, { config, dir: node.dir });\n const boundingBox = childNodeEl.node()!.getBBox();\n child.domId = childNodeEl;\n child.width = boundingBox.width;\n child.height = boundingBox.height;\n } else {\n // A subgraph\n const child: NodeWithVertex & { children: NodeWithVertex[] } = {\n ...node,\n children: [],\n };\n graph.children.push(child);\n nodeDb[node.id] = child;\n await addVertices(nodeEl, nodeArr, child, node.id);\n\n if (node.label) {\n // @ts-ignore TODO: fix this\n const { shapeSvg, bbox } = await labelHelper(nodeEl, node, undefined, true);\n labelData.width = bbox.width;\n labelData.wrappingWidth = config.flowchart!.wrappingWidth;\n // Give some padding for elk\n labelData.height = bbox.height - 2;\n labelData.labelNode = shapeSvg.node();\n // We need the label hight to be able to size the subgraph;\n shapeSvg.remove();\n } else {\n // Subgraph without label\n labelData.width = 0;\n labelData.height = 0;\n }\n child.labelData = labelData;\n child.domId = nodeEl;\n }\n };\n\n const addVertices = async function (\n nodeEl: SVGGroup,\n nodeArr: Node[],\n graph: { children: NodeWithVertex[] },\n parentId?: string\n ) {\n const siblings = nodeArr.filter((node) => node?.parentId === parentId);\n log.info('addVertices APA12', siblings, parentId);\n // Iterate through each item in the vertex object (containing all the vertices found) in the graph definition\n await Promise.all(\n siblings.map(async (node) => {\n await addVertex(nodeEl, graph, nodeArr, node);\n })\n );\n return graph;\n };\n\n const drawNodes = async (\n relX: number,\n relY: number,\n nodeArray: any[],\n svg: any,\n subgraphsEl: SVGGroup,\n depth: number\n ) => {\n await Promise.all(\n nodeArray.map(async function (node: {\n id: string | number;\n x: any;\n y: any;\n width: number;\n labels: { width: any }[];\n height: number;\n isGroup: any;\n labelData: any;\n offset: { posX: number; posY: number };\n shape: any;\n domId: { node: () => any; attr: (arg0: string, arg1: string) => void };\n }) {\n if (node) {\n nodeDb[node.id] = node;\n nodeDb[node.id].offset = {\n posX: node.x + relX,\n posY: node.y + relY,\n x: relX,\n y: relY,\n depth,\n width: Math.max(node.width, node.labels ? node.labels[0]?.width || 0 : 0),\n height: node.height,\n };\n if (node.isGroup) {\n log.debug('Id abc88 subgraph = ', node.id, node.x, node.y, node.labelData);\n const subgraphEl = subgraphsEl.insert('g').attr('class', 'subgraph');\n // TODO use faster way of cloning\n const clusterNode = JSON.parse(JSON.stringify(node));\n clusterNode.x = node.offset.posX + node.width / 2;\n clusterNode.y = node.offset.posY + node.height / 2;\n clusterNode.width = Math.max(clusterNode.width, node.labelData.width);\n await insertCluster(subgraphEl, clusterNode);\n\n log.debug('Id (UIO)= ', node.id, node.width, node.shape, node.labels);\n } else {\n log.info(\n 'Id NODE = ',\n node.id,\n node.x,\n node.y,\n relX,\n relY,\n node.domId.node(),\n `translate(${node.x + relX + node.width / 2}, ${node.y + relY + node.height / 2})`\n );\n node.domId.attr(\n 'transform',\n `translate(${node.x + relX + node.width / 2}, ${node.y + relY + node.height / 2})`\n );\n }\n }\n })\n );\n\n await Promise.all(\n nodeArray.map(async function (node: { isGroup: any; x: any; y: any; children: any }) {\n if (node?.isGroup) {\n await drawNodes(relX + node.x, relY + node.y, node.children, svg, subgraphsEl, depth + 1);\n }\n })\n );\n };\n\n const addSubGraphs = (nodeArr: any[]): TreeData => {\n const parentLookupDb: TreeData = { parentById: {}, childrenById: {} };\n const subgraphs = nodeArr.filter((node: { isGroup: any }) => node.isGroup);\n log.info('Subgraphs - ', subgraphs);\n subgraphs.forEach((subgraph: { id: string }) => {\n const children = nodeArr.filter((node: { parentId: any }) => node.parentId === subgraph.id);\n children.forEach((node: any) => {\n parentLookupDb.parentById[node.id] = subgraph.id;\n if (parentLookupDb.childrenById[subgraph.id] === undefined) {\n parentLookupDb.childrenById[subgraph.id] = [];\n }\n parentLookupDb.childrenById[subgraph.id].push(node);\n });\n });\n\n subgraphs.forEach(function (subgraph: { id: string | number }) {\n const data: any = { id: subgraph.id };\n if (parentLookupDb.parentById[subgraph.id] !== undefined) {\n data.parent = parentLookupDb.parentById[subgraph.id];\n }\n });\n return parentLookupDb;\n };\n\n const getEdgeStartEndPoint = (edge: any) => {\n const source: any = edge.start;\n const target: any = edge.end;\n\n // Save the original source and target\n const sourceId = source;\n const targetId = target;\n\n const startNode = nodeDb[edge.start.id];\n const endNode = nodeDb[edge.end.id];\n\n if (!startNode || !endNode) {\n return { source, target };\n }\n\n // Add the edge to the graph\n return { source, target, sourceId, targetId };\n };\n\n const calcOffset = function (src: string, dest: string, parentLookupDb: TreeData) {\n const ancestor = findCommonAncestor(src, dest, parentLookupDb);\n if (ancestor === undefined || ancestor === 'root') {\n return { x: 0, y: 0 };\n }\n\n const ancestorOffset = nodeDb[ancestor].offset;\n return { x: ancestorOffset.posX, y: ancestorOffset.posY };\n };\n\n /**\n * Add edges to graph based on parsed graph definition\n */\n const addEdges = async function (\n dataForLayout: { edges: any; direction?: string },\n graph: {\n id?: string;\n layoutOptions?: {\n 'elk.hierarchyHandling': string;\n 'elk.algorithm': any;\n 'nodePlacement.strategy': any;\n 'elk.layered.mergeEdges': any;\n 'elk.direction': string;\n 'spacing.baseValue': number;\n };\n children?: never[];\n edges: any;\n },\n svg: SVG\n ) {\n log.info('abc78 DAGA edges = ', dataForLayout);\n const edges = dataForLayout.edges;\n const labelsEl = svg.insert('g').attr('class', 'edgeLabels');\n const linkIdCnt: any = {};\n const dir = dataForLayout.direction || 'DOWN';\n let defaultStyle: string | undefined;\n let defaultLabelStyle: string | undefined;\n\n await Promise.all(\n edges.map(async function (edge: {\n id: string;\n start: string;\n end: string;\n length: number;\n text: undefined;\n label: any;\n type: string;\n stroke: any;\n interpolate: undefined;\n style: undefined;\n labelType: any;\n startLabelRight?: string;\n endLabelLeft?: string;\n }) {\n // Identify Link\n const linkIdBase = edge.id; // 'L-' + edge.start + '-' + edge.end;\n // count the links from+to the same node to give unique id\n if (linkIdCnt[linkIdBase] === undefined) {\n linkIdCnt[linkIdBase] = 0;\n log.info('abc78 new entry', linkIdBase, linkIdCnt[linkIdBase]);\n } else {\n linkIdCnt[linkIdBase]++;\n log.info('abc78 new entry', linkIdBase, linkIdCnt[linkIdBase]);\n }\n const linkId = linkIdBase + '_' + linkIdCnt[linkIdBase];\n edge.id = linkId;\n log.info('abc78 new link id to be used is', linkIdBase, linkId, linkIdCnt[linkIdBase]);\n const linkNameStart = 'LS_' + edge.start;\n const linkNameEnd = 'LE_' + edge.end;\n\n const edgeData: any = { style: '', labelStyle: '' };\n edgeData.minlen = edge.length || 1;\n edge.text = edge.label;\n // Set link type for rendering\n if (edge.type === 'arrow_open') {\n edgeData.arrowhead = 'none';\n } else {\n edgeData.arrowhead = 'normal';\n }\n\n // Check of arrow types, placed here in order not to break old rendering\n edgeData.arrowTypeStart = 'arrow_open';\n edgeData.arrowTypeEnd = 'arrow_open';\n\n /* eslint-disable no-fallthrough */\n switch (edge.type) {\n case 'double_arrow_cross':\n edgeData.arrowTypeStart = 'arrow_cross';\n case 'arrow_cross':\n edgeData.arrowTypeEnd = 'arrow_cross';\n break;\n case 'double_arrow_point':\n edgeData.arrowTypeStart = 'arrow_point';\n case 'arrow_point':\n edgeData.arrowTypeEnd = 'arrow_point';\n break;\n case 'double_arrow_circle':\n edgeData.arrowTypeStart = 'arrow_circle';\n case 'arrow_circle':\n edgeData.arrowTypeEnd = 'arrow_circle';\n break;\n }\n\n let style = '';\n let labelStyle = '';\n\n edgeData.startLabelRight = edge.startLabelRight;\n edgeData.endLabelLeft = edge.endLabelLeft;\n\n switch (edge.stroke) {\n case 'normal':\n style = 'fill:none;';\n if (defaultStyle !== undefined) {\n style = defaultStyle;\n }\n if (defaultLabelStyle !== undefined) {\n labelStyle = defaultLabelStyle;\n }\n edgeData.thickness = 'normal';\n edgeData.pattern = 'solid';\n break;\n case 'dotted':\n edgeData.thickness = 'normal';\n edgeData.pattern = 'dotted';\n edgeData.style = 'fill:none;stroke-width:2px;stroke-dasharray:3;';\n break;\n case 'thick':\n edgeData.thickness = 'thick';\n edgeData.pattern = 'solid';\n edgeData.style = 'stroke-width: 3.5px;fill:none;';\n break;\n }\n\n edgeData.style = edgeData.style += style;\n edgeData.labelStyle = edgeData.labelStyle += labelStyle;\n\n const conf = getConfig();\n if (edge.interpolate !== undefined) {\n edgeData.curve = interpolateToCurve(edge.interpolate, curveLinear);\n } else if (edges.defaultInterpolate !== undefined) {\n edgeData.curve = interpolateToCurve(edges.defaultInterpolate, curveLinear);\n } else {\n // @ts-ignore TODO: fix this\n edgeData.curve = interpolateToCurve(conf.curve, curveLinear);\n }\n\n if (edge.text === undefined) {\n if (edge.style !== undefined) {\n edgeData.arrowheadStyle = 'fill: #333';\n }\n } else {\n edgeData.arrowheadStyle = 'fill: #333';\n edgeData.labelpos = 'c';\n }\n\n edgeData.labelType = edge.labelType;\n edgeData.label = (edge?.text || '').replace(common.lineBreakRegex, '\\n');\n\n if (edge.style === undefined) {\n edgeData.style = edgeData.style || 'stroke: #333; stroke-width: 1.5px;fill:none;';\n }\n\n edgeData.labelStyle = edgeData.labelStyle.replace('color:', 'fill:');\n\n edgeData.id = linkId;\n edgeData.classes = 'flowchart-link ' + linkNameStart + ' ' + linkNameEnd;\n\n const labelEl = await insertEdgeLabel(labelsEl, edgeData);\n\n // calculate start and end points of the edge, note that the source and target\n // can be modified for shapes that have ports\n // @ts-ignore TODO: fix this\n const { source, target, sourceId, targetId } = getEdgeStartEndPoint(edge, dir);\n log.debug('abc78 source and target', source, target);\n // Add the edge to the graph\n graph.edges.push({\n // @ts-ignore TODO: fix this\n id: 'e' + edge.start + edge.end,\n ...edge,\n sources: [source],\n targets: [target],\n sourceId,\n targetId,\n labelEl: labelEl,\n labels: [\n {\n width: edgeData.width,\n height: edgeData.height,\n orgWidth: edgeData.width,\n orgHeight: edgeData.height,\n text: edgeData.label,\n layoutOptions: {\n 'edgeLabels.inline': 'true',\n 'edgeLabels.placement': 'CENTER',\n },\n },\n ],\n edgeData,\n });\n })\n );\n return graph;\n };\n\n function dir2ElkDirection(dir: any) {\n switch (dir) {\n case 'LR':\n return 'RIGHT';\n case 'RL':\n return 'LEFT';\n case 'TB':\n return 'DOWN';\n case 'BT':\n return 'UP';\n default:\n return 'DOWN';\n }\n }\n\n function setIncludeChildrenPolicy(nodeId: string, ancestorId: string) {\n const node = nodeDb[nodeId];\n\n if (!node) {\n return;\n }\n if (node?.layoutOptions === undefined) {\n node.layoutOptions = {};\n }\n node.layoutOptions['elk.hierarchyHandling'] = 'INCLUDE_CHILDREN';\n if (node.id !== ancestorId) {\n setIncludeChildrenPolicy(node.parentId, ancestorId);\n }\n }\n\n function intersectLine(\n p1: { y: number; x: number },\n p2: { y: number; x: number },\n q1: { x: any; y: any },\n q2: { x: any; y: any }\n ) {\n log.debug('UIO intersectLine', p1, p2, q1, q2);\n // Algorithm from J. Avro, (ed.) Graphics Gems, No 2, Morgan Kaufmann, 1994,\n // p7 and p473.\n\n // let a1, a2, b1, b2, c1, c2;\n // let r1, r2, r3, r4;\n // let denom, offset, num;\n // let x, y;\n\n // Compute a1, b1, c1, where line joining points 1 and 2 is F(x,y) = a1 x +\n // b1 y + c1 = 0.\n const a1 = p2.y - p1.y;\n const b1 = p1.x - p2.x;\n const c1 = p2.x * p1.y - p1.x * p2.y;\n\n // Compute r3 and r4.\n const r3 = a1 * q1.x + b1 * q1.y + c1;\n const r4 = a1 * q2.x + b1 * q2.y + c1;\n\n const epsilon = 1e-6;\n\n // Check signs of r3 and r4. If both point 3 and point 4 lie on\n // same side of line 1, the line segments do not intersect.\n if (r3 !== 0 && r4 !== 0 && sameSign(r3, r4)) {\n return /*DON'T_INTERSECT*/;\n }\n\n // Compute a2, b2, c2 where line joining points 3 and 4 is G(x,y) = a2 x + b2 y + c2 = 0\n const a2 = q2.y - q1.y;\n const b2 = q1.x - q2.x;\n const c2 = q2.x * q1.y - q1.x * q2.y;\n\n // Compute r1 and r2\n const r1 = a2 * p1.x + b2 * p1.y + c2;\n const r2 = a2 * p2.x + b2 * p2.y + c2;\n\n // Check signs of r1 and r2. If both point 1 and point 2 lie\n // on same side of second line segment, the line segments do\n // not intersect.\n if (Math.abs(r1) < epsilon && Math.abs(r2) < epsilon && sameSign(r1, r2)) {\n return /*DON'T_INTERSECT*/;\n }\n\n // Line segments intersect: compute intersection point.\n const denom = a1 * b2 - a2 * b1;\n if (denom === 0) {\n return /*COLLINEAR*/;\n }\n\n const offset = Math.abs(denom / 2);\n\n // The denom/2 is to get rounding instead of truncating. It\n // is added or subtracted to the numerator, depending upon the\n // sign of the numerator.\n let num = b1 * c2 - b2 * c1;\n const x = num < 0 ? (num - offset) / denom : (num + offset) / denom;\n\n num = a2 * c1 - a1 * c2;\n const y = num < 0 ? (num - offset) / denom : (num + offset) / denom;\n\n return { x: x, y: y };\n }\n\n function sameSign(r1: number, r2: number) {\n return r1 * r2 > 0;\n }\n const diamondIntersection = (\n bounds: { x: any; y: any; width: any; height: any },\n outsidePoint: { x: number; y: number },\n insidePoint: any\n ) => {\n const x1 = bounds.x;\n const y1 = bounds.y;\n\n const w = bounds.width; //+ bounds.padding;\n const h = bounds.height; // + bounds.padding;\n\n const polyPoints = [\n { x: x1, y: y1 - h / 2 },\n { x: x1 + w / 2, y: y1 },\n { x: x1, y: y1 + h / 2 },\n { x: x1 - w / 2, y: y1 },\n ];\n log.debug(\n `APA16 diamondIntersection calc abc89:\n outsidePoint: ${JSON.stringify(outsidePoint)}\n insidePoint : ${JSON.stringify(insidePoint)}\n node-bounds : x:${bounds.x} y:${bounds.y} w:${bounds.width} h:${bounds.height}`,\n JSON.stringify(polyPoints)\n );\n\n const intersections = [];\n\n let minX = Number.POSITIVE_INFINITY;\n let minY = Number.POSITIVE_INFINITY;\n\n polyPoints.forEach(function (entry) {\n minX = Math.min(minX, entry.x);\n minY = Math.min(minY, entry.y);\n });\n\n const left = x1 - w / 2 - minX;\n const top = y1 - h / 2 - minY;\n\n for (let i = 0; i < polyPoints.length; i++) {\n const p1 = polyPoints[i];\n const p2 = polyPoints[i < polyPoints.length - 1 ? i + 1 : 0];\n const intersect = intersectLine(\n bounds,\n outsidePoint,\n { x: left + p1.x, y: top + p1.y },\n { x: left + p2.x, y: top + p2.y }\n );\n\n if (intersect) {\n intersections.push(intersect);\n }\n }\n\n if (!intersections.length) {\n return bounds;\n }\n\n log.debug('UIO intersections', intersections);\n\n if (intersections.length > 1) {\n // More intersections, find the one nearest to edge end point\n intersections.sort(function (p, q) {\n const pdx = p.x - outsidePoint.x;\n const pdy = p.y - outsidePoint.y;\n const distp = Math.sqrt(pdx * pdx + pdy * pdy);\n\n const qdx = q.x - outsidePoint.x;\n const qdy = q.y - outsidePoint.y;\n const distq = Math.sqrt(qdx * qdx + qdy * qdy);\n\n return distp < distq ? -1 : distp === distq ? 0 : 1;\n });\n }\n\n return intersections[0];\n };\n\n const intersection = (\n node: { x: any; y: any; width: number; height: number },\n outsidePoint: { x: number; y: number },\n insidePoint: { x: number; y: number }\n ) => {\n log.debug(`intersection calc abc89:\n outsidePoint: ${JSON.stringify(outsidePoint)}\n insidePoint : ${JSON.stringify(insidePoint)}\n node : x:${node.x} y:${node.y} w:${node.width} h:${node.height}`);\n const x = node.x;\n const y = node.y;\n\n const dx = Math.abs(x - insidePoint.x);\n // const dy = Math.abs(y - insidePoint.y);\n const w = node.width / 2;\n let r = insidePoint.x < outsidePoint.x ? w - dx : w + dx;\n const h = node.height / 2;\n\n const Q = Math.abs(outsidePoint.y - insidePoint.y);\n const R = Math.abs(outsidePoint.x - insidePoint.x);\n\n if (Math.abs(y - outsidePoint.y) * w > Math.abs(x - outsidePoint.x) * h) {\n // Intersection is top or bottom of rect.\n const q = insidePoint.y < outsidePoint.y ? outsidePoint.y - h - y : y - h - outsidePoint.y;\n r = (R * q) / Q;\n const res = {\n x: insidePoint.x < outsidePoint.x ? insidePoint.x + r : insidePoint.x - R + r,\n y: insidePoint.y < outsidePoint.y ? insidePoint.y + Q - q : insidePoint.y - Q + q,\n };\n\n if (r === 0) {\n res.x = outsidePoint.x;\n res.y = outsidePoint.y;\n }\n if (R === 0) {\n res.x = outsidePoint.x;\n }\n if (Q === 0) {\n res.y = outsidePoint.y;\n }\n\n log.debug(`abc89 topp/bott calc, Q ${Q}, q ${q}, R ${R}, r ${r}`, res); // cspell: disable-line\n\n return res;\n } else {\n // Intersection onn sides of rect\n if (insidePoint.x < outsidePoint.x) {\n r = outsidePoint.x - w - x;\n } else {\n // r = outsidePoint.x - w - x;\n r = x - w - outsidePoint.x;\n }\n const q = (Q * r) / R;\n // OK let _x = insidePoint.x < outsidePoint.x ? insidePoint.x + R - r : insidePoint.x + dx - w;\n // OK let _x = insidePoint.x < outsidePoint.x ? insidePoint.x + R - r : outsidePoint.x + r;\n let _x = insidePoint.x < outsidePoint.x ? insidePoint.x + R - r : insidePoint.x - R + r;\n // let _x = insidePoint.x < outsidePoint.x ? insidePoint.x + R - r : outsidePoint.x + r;\n let _y = insidePoint.y < outsidePoint.y ? insidePoint.y + q : insidePoint.y - q;\n log.debug(`sides calc abc89, Q ${Q}, q ${q}, R ${R}, r ${r}`, { _x, _y });\n if (r === 0) {\n _x = outsidePoint.x;\n _y = outsidePoint.y;\n }\n if (R === 0) {\n _x = outsidePoint.x;\n }\n if (Q === 0) {\n _y = outsidePoint.y;\n }\n\n return { x: _x, y: _y };\n }\n };\n const outsideNode = (\n node: { x: any; y: any; width: number; height: number },\n point: { x: number; y: number }\n ) => {\n const x = node.x;\n const y = node.y;\n const dx = Math.abs(point.x - x);\n const dy = Math.abs(point.y - y);\n const w = node.width / 2;\n const h = node.height / 2;\n if (dx >= w || dy >= h) {\n return true;\n }\n return false;\n };\n /**\n * This function will page a path and node where the last point(s) in the path is inside the node\n * and return an update path ending by the border of the node.\n */\n const cutPathAtIntersect = (\n _points: any[],\n bounds: { x: any; y: any; width: any; height: any; padding: any },\n isDiamond: boolean\n ) => {\n log.debug('APA18 cutPathAtIntersect Points:', _points, 'node:', bounds, 'isDiamond', isDiamond);\n const points: any[] = [];\n let lastPointOutside = _points[0];\n let isInside = false;\n _points.forEach((point: any) => {\n // check if point is inside the boundary rect\n if (!outsideNode(bounds, point) && !isInside) {\n // First point inside the rect found\n // Calc the intersection coord between the point anf the last point outside the rect\n let inter;\n\n if (isDiamond) {\n const inter2 = diamondIntersection(bounds, lastPointOutside, point);\n const distance = Math.sqrt(\n (lastPointOutside.x - inter2.x) ** 2 + (lastPointOutside.y - inter2.y) ** 2\n );\n if (distance > 1) {\n inter = inter2;\n }\n }\n if (!inter) {\n inter = intersection(bounds, lastPointOutside, point);\n }\n\n // Check case where the intersection is the same as the last point\n let pointPresent = false;\n points.forEach((p) => {\n pointPresent = pointPresent || (p.x === inter.x && p.y === inter.y);\n });\n // if (!pointPresent) {\n if (!points.some((e) => e.x === inter.x && e.y === inter.y)) {\n points.push(inter);\n } else {\n log.debug('abc88 no intersect', inter, points);\n }\n // points.push(inter);\n isInside = true;\n } else {\n // Outside\n log.debug('abc88 outside', point, lastPointOutside, points);\n lastPointOutside = point;\n // points.push(point);\n if (!isInside) {\n points.push(point);\n }\n }\n });\n return points;\n };\n\n // @ts-ignore - ELK is not typed\n const elk = new ELK();\n const element = svg.select('g');\n // Add the arrowheads to the svg\n insertMarkers(element, data4Layout.markers, data4Layout.type, data4Layout.diagramId);\n\n // Setup the graph with the layout options and the data for the layout\n let elkGraph: any = {\n id: 'root',\n layoutOptions: {\n 'elk.hierarchyHandling': 'INCLUDE_CHILDREN',\n 'elk.algorithm': algorithm,\n 'nodePlacement.strategy': data4Layout.config.elk?.nodePlacementStrategy,\n 'elk.layered.mergeEdges': data4Layout.config.elk?.mergeEdges,\n 'elk.direction': 'DOWN',\n 'spacing.baseValue': 35,\n 'elk.layered.unnecessaryBendpoints': true,\n 'elk.layered.cycleBreaking.strategy': data4Layout.config.elk?.cycleBreakingStrategy,\n // 'spacing.nodeNode': 20,\n // 'spacing.nodeNodeBetweenLayers': 25,\n // 'spacing.edgeNode': 20,\n // 'spacing.edgeNodeBetweenLayers': 10,\n // 'spacing.edgeEdge': 10,\n // 'spacing.edgeEdgeBetweenLayers': 20,\n // 'spacing.nodeSelfLoop': 20,\n\n // Tweaking options\n // 'elk.layered.nodePlacement.favorStraightEdges': true,\n // 'nodePlacement.feedbackEdges': true,\n // 'elk.layered.wrapping.multiEdge.improveCuts': true,\n // 'elk.layered.wrapping.multiEdge.improveWrappedEdges': true,\n // 'elk.layered.wrapping.strategy': 'MULTI_EDGE',\n // 'elk.layered.edgeRouting.selfLoopDistribution': 'EQUALLY',\n // 'elk.layered.mergeHierarchyEdges': true,\n // 'elk.layered.feedbackEdges': true,\n // 'elk.layered.crossingMinimization.semiInteractive': true,\n // 'elk.layered.edgeRouting.splines.sloppy.layerSpacingFactor': 1,\n // 'elk.layered.edgeRouting.polyline.slopedEdgeZoneWidth': 4.0,\n // 'elk.layered.wrapping.validify.strategy': 'LOOK_BACK',\n // 'elk.insideSelfLoops.activate': true,\n // 'elk.alg.layered.options.EdgeStraighteningStrategy': 'NONE',\n // 'elk.layered.considerModelOrder.strategy': 'NODES_AND_EDGES', // NODES_AND_EDGES\n // 'elk.layered.wrapping.cutting.strategy': 'ARD', // NODES_AND_EDGES\n },\n children: [],\n edges: [],\n };\n\n log.info('Drawing flowchart using v4 renderer', elk);\n\n // Set the direction of the graph based on the parsed information\n const dir = data4Layout.direction || 'DOWN';\n elkGraph.layoutOptions['elk.direction'] = dir2ElkDirection(dir);\n\n // Create the lookup db for the subgraphs and their children to used when creating\n // the tree structured graph\n const parentLookupDb: any = addSubGraphs(data4Layout.nodes);\n\n // Add elements in the svg to be used to hold the subgraphs container\n // elements and the nodes\n const subGraphsEl = svg.insert('g').attr('class', 'subgraphs');\n\n const nodeEl = svg.insert('g').attr('class', 'nodes');\n\n // Add the nodes to the graph, this will entail creating the actual nodes\n // in order to get the size of the node. You can't get the size of a node\n // that is not in the dom so we need to add it to the dom, get the size\n // we will position the nodes when we get the layout from elkjs\n elkGraph = await addVertices(nodeEl, data4Layout.nodes, elkGraph);\n // Time for the edges, we start with adding an element in the node to hold the edges\n const edgesEl = svg.insert('g').attr('class', 'edges edgePaths');\n\n // Add the edges to the elk graph, this will entail creating the actual edges\n elkGraph = await addEdges(data4Layout, elkGraph, svg);\n\n // Iterate through all nodes and add the top level nodes to the graph\n const nodes = data4Layout.nodes;\n nodes.forEach((n: { id: string | number }) => {\n const node = nodeDb[n.id];\n\n // Subgraph\n if (parentLookupDb.childrenById[node.id] !== undefined) {\n node.labels = [\n {\n text: node.label,\n width: node?.labelData?.width || 50,\n height: node?.labelData?.height || 50,\n },\n (node.width = node.width + 2 * node.padding),\n log.debug('UIO node label', node?.labelData?.width, node.padding),\n ];\n node.layoutOptions = {\n 'spacing.baseValue': 30,\n 'nodeLabels.placement': '[H_CENTER V_TOP, INSIDE]',\n };\n if (node.dir) {\n node.layoutOptions = {\n ...node.layoutOptions,\n 'elk.algorithm': algorithm,\n 'elk.direction': dir2ElkDirection(node.dir),\n 'nodePlacement.strategy': data4Layout.config.elk?.nodePlacementStrategy,\n 'elk.layered.mergeEdges': data4Layout.config.elk?.mergeEdges,\n 'elk.hierarchyHandling': 'SEPARATE_CHILDREN',\n };\n }\n delete node.x;\n delete node.y;\n delete node.width;\n delete node.height;\n }\n });\n elkGraph.edges.forEach((edge: any) => {\n const source = edge.sources[0];\n const target = edge.targets[0];\n\n if (nodeDb[source].parentId !== nodeDb[target].parentId) {\n const ancestorId = findCommonAncestor(source, target, parentLookupDb);\n // an edge that breaks a subgraph has been identified, set configuration accordingly\n setIncludeChildrenPolicy(source, ancestorId);\n setIncludeChildrenPolicy(target, ancestorId);\n }\n });\n\n const g = await elk.layout(elkGraph);\n\n // debugger;\n await drawNodes(0, 0, g.children, svg, subGraphsEl, 0);\n g.edges?.map(\n (edge: {\n sources: (string | number)[];\n targets: (string | number)[];\n start: any;\n end: any;\n sections: { startPoint: any; endPoint: any; bendPoints: any }[];\n points: any[];\n x: any;\n labels: { height: number; width: number; x: number; y: number }[];\n y: any;\n }) => {\n // (elem, edge, clusterDb, diagramType, graph, id)\n const startNode = nodeDb[edge.sources[0]];\n const startCluster = parentLookupDb[edge.sources[0]];\n const endNode = nodeDb[edge.targets[0]];\n const sourceId = edge.start;\n const targetId = edge.end;\n\n const offset = calcOffset(sourceId, targetId, parentLookupDb);\n log.debug(\n 'APA18 offset',\n offset,\n sourceId,\n ' ==> ',\n targetId,\n 'edge:',\n edge,\n 'cluster:',\n startCluster,\n startNode\n );\n if (edge.sections) {\n const src = edge.sections[0].startPoint;\n const dest = edge.sections[0].endPoint;\n const segments = edge.sections[0].bendPoints ? edge.sections[0].bendPoints : [];\n\n const segPoints = segments.map((segment: { x: any; y: any }) => {\n return { x: segment.x + offset.x, y: segment.y + offset.y };\n });\n edge.points = [\n { x: src.x + offset.x, y: src.y + offset.y },\n ...segPoints,\n { x: dest.x + offset.x, y: dest.y + offset.y },\n ];\n\n let sw = startNode.width;\n let ew = endNode.width;\n if (startNode.isGroup) {\n const bbox = startNode.domId.node().getBBox();\n // sw = Math.max(bbox.width, startNode.width, startNode.labels[0].width);\n sw = Math.max(startNode.width, startNode.labels[0].width + startNode.padding);\n // sw = startNode.width;\n log.debug(\n 'UIO width',\n startNode.id,\n startNode.with,\n 'bbox.width=',\n bbox.width,\n 'lw=',\n startNode.labels[0].width,\n 'node:',\n startNode.width,\n 'SW = ',\n sw\n // 'HTML:',\n // startNode.domId.node().innerHTML\n );\n }\n if (endNode.isGroup) {\n const bbox = endNode.domId.node().getBBox();\n ew = Math.max(endNode.width, endNode.labels[0].width + endNode.padding);\n\n log.debug(\n 'UIO width',\n startNode.id,\n startNode.with,\n bbox.width,\n 'EW = ',\n ew,\n 'HTML:',\n startNode.innerHTML\n );\n }\n if (startNode.shape === 'diamond' || startNode.shape === 'diam') {\n edge.points.unshift({\n x: startNode.offset.posX + startNode.width / 2,\n y: startNode.offset.posY + startNode.height / 2,\n });\n }\n if (endNode.shape === 'diamond' || endNode.shape === 'diam') {\n edge.points.push({\n x: endNode.offset.posX + endNode.width / 2,\n y: endNode.offset.posY + endNode.height / 2,\n });\n }\n\n edge.points = cutPathAtIntersect(\n edge.points.reverse(),\n {\n x: startNode.offset.posX + startNode.width / 2,\n y: startNode.offset.posY + startNode.height / 2,\n width: sw,\n height: startNode.height,\n padding: startNode.padding,\n },\n startNode.shape === 'diamond' || startNode.shape === 'diam'\n ).reverse();\n\n edge.points = cutPathAtIntersect(\n edge.points,\n {\n x: endNode.offset.posX + endNode.width / 2,\n y: endNode.offset.posY + endNode.height / 2,\n width: ew,\n height: endNode.height,\n padding: endNode.padding,\n },\n endNode.shape === 'diamond' || endNode.shape === 'diam'\n );\n\n const paths = insertEdge(\n edgesEl,\n edge,\n clusterDb,\n data4Layout.type,\n startNode,\n endNode,\n data4Layout.diagramId\n );\n log.info('APA12 edge points after insert', JSON.stringify(edge.points));\n\n edge.x = edge.labels[0].x + offset.x + edge.labels[0].width / 2;\n edge.y = edge.labels[0].y + offset.y + edge.labels[0].height / 2;\n positionEdgeLabel(edge, paths);\n }\n }\n );\n};\n", "export interface TreeData {\n parentById: Record<string, string>;\n childrenById: Record<string, string[]>;\n}\n\nexport const findCommonAncestor = (id1: string, id2: string, { parentById }: TreeData) => {\n const visited = new Set();\n let currentId = id1;\n\n // Edge case with self edges\n if (id1 === id2) {\n return parentById[id1] || 'root';\n }\n\n while (currentId) {\n visited.add(currentId);\n if (currentId === id2) {\n return currentId;\n }\n currentId = parentById[currentId];\n }\n\n currentId = id2;\n while (currentId) {\n if (visited.has(currentId)) {\n return currentId;\n }\n currentId = parentById[currentId];\n }\n\n return 'root';\n};\n"], "mappings": "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