From 1b29135cc1cc2ac1a27848f514f3bca6d391cdc6 Mon Sep 17 00:00:00 2001 From: Knut Sveidqvist Date: Fri, 7 Jun 2024 20:23:44 +0200 Subject: [PATCH 1/2] #5237 Enabling subgraphs using the unified renderer for flowcharts --- cypress/platform/knsv2.html | 18 +++--- .../mermaid/src/diagrams/flowchart/flowDb.ts | 24 +++++++- .../dagre/mermaid-graphlib.js | 4 +- .../rendering-elements/clusters.js | 60 ++++++++++++++----- 4 files changed, 77 insertions(+), 29 deletions(-) diff --git a/cypress/platform/knsv2.html b/cypress/platform/knsv2.html index 99836dd1c..514f98409 100644 --- a/cypress/platform/knsv2.html +++ b/cypress/platform/knsv2.html @@ -84,13 +84,17 @@ stateDiagram-v2 if_state --> True : if n >= 0 -
+    
 flowchart LR
-    A[Start] --> B{Is it?} --> B1 & B2
+    subgraph Apa
+      A[Start] --> B
+    end
+    Apa --> C
+    A --> C
 
       
-
+    
       %%{init: {"layout": "dagre", "mergeEdges": false} }%%
 flowchart LR
       A ==> B(This is B)
@@ -213,12 +217,12 @@ stateDiagram-v2
       mermaid.initialize({
         // theme: 'base',
         // handdrawnSeed: 12,
-        // look: 'handdrawn',
-        'elk.nodePlacement.strategy': 'NETWORK_SIMPLEX',
-        layout: 'dagre',
+        look: 'handdrawn',
+        // 'elk.nodePlacement.strategy': 'NETWORK_SIMPLEX',
+        // layout: 'dagre',
         // layout: 'elk',
         // layout: 'fixed',
-        htmlLabels: false,
+        // htmlLabels: false,
         flowchart: { titleTopMargin: 10 },
         // fontFamily: 'Caveat',
         fontFamily: 'Kalam',
diff --git a/packages/mermaid/src/diagrams/flowchart/flowDb.ts b/packages/mermaid/src/diagrams/flowchart/flowDb.ts
index bb4f4ecf2..b3976adf5 100644
--- a/packages/mermaid/src/diagrams/flowchart/flowDb.ts
+++ b/packages/mermaid/src/diagrams/flowchart/flowDb.ts
@@ -775,20 +775,39 @@ export const getData = () => {
   // extract(getRootDocV2());
   // const diagramStates = getStates();
   const useRough = config.look === 'handdrawn';
+  const subGraphs = getSubGraphs();
+  log.info('Subgraphs - ', subGraphs);
+  const parentDB = new Map();
+  const subGraphDB = new Map();
+
+  for (let i = subGraphs.length - 1; i >= 0; i--) {
+    const subGraph = subGraphs[i];
+    if (subGraph.nodes.length > 0) {
+      subGraphDB.set(subGraph.id, true);
+    }
+    subGraph.nodes.forEach((id) => {
+      parentDB.set(id, subGraph.id);
+    });
+  }
+
   const n = getVertices();
   n.forEach((vertex) => {
+    let parentId = parentDB.get(vertex.id);
+    let isGroup = subGraphDB.get(vertex.id) || false;
+
     const node: Node = {
       id: vertex.id,
       label: vertex.text,
       labelStyle: '',
+      parentId,
       padding: config.flowchart?.padding || 8,
       cssStyles: vertex.styles.join(' '),
       cssClasses: vertex.classes.join(' '),
       shape: getTypeFromVertex(vertex),
       dir: vertex.dir,
       domId: vertex.domId,
-      type: undefined,
-      isGroup: false,
+      type: isGroup ? 'group' : undefined,
+      isGroup,
       useRough,
     };
     nodes.push(node);
@@ -823,7 +842,6 @@ export const getData = () => {
     // console.log('rawEdge SPLIT', rawEdge, index);
     edges.push(edge);
   });
-  console.log('edges SPLIT', edges);
 
   //const useRough = config.look === 'handdrawn';
 
diff --git a/packages/mermaid/src/rendering-util/layout-algorithms/dagre/mermaid-graphlib.js b/packages/mermaid/src/rendering-util/layout-algorithms/dagre/mermaid-graphlib.js
index f56cba285..73b6797df 100644
--- a/packages/mermaid/src/rendering-util/layout-algorithms/dagre/mermaid-graphlib.js
+++ b/packages/mermaid/src/rendering-util/layout-algorithms/dagre/mermaid-graphlib.js
@@ -159,10 +159,8 @@ export const validate = (graph) => {
  * @param {any} graph
  */
 export const findNonClusterChild = (id, graph) => {
-  // const node = graph.node(id);
   log.trace('Searching', id);
-  // const children = graph.children(id).reverse();
-  const children = graph.children(id); //.reverse();
+  const children = graph.children(id).reverse();
   log.trace('Searching children of id ', id, children);
   if (children.length < 1) {
     log.trace('This is a valid node', id);
diff --git a/packages/mermaid/src/rendering-util/rendering-elements/clusters.js b/packages/mermaid/src/rendering-util/rendering-elements/clusters.js
index a4b8f896d..2a197993a 100644
--- a/packages/mermaid/src/rendering-util/rendering-elements/clusters.js
+++ b/packages/mermaid/src/rendering-util/rendering-elements/clusters.js
@@ -8,17 +8,18 @@ import { createText } from '../createText.ts';
 import intersectRect from '../rendering-elements/intersect/intersect-rect.js';
 import createLabel from './createLabel.js';
 import { createRoundedRectPathD } from './shapes/roundedRectPath.ts';
+import { userNodeOverrides } from '$root/rendering-util/rendering-elements/shapes/handdrawnStyles.js';
 
 const rect = (parent, node) => {
   log.info('Creating subgraph rect for ', node.id, node);
   const siteConfig = getConfig();
+  const { themeVariables, handdrawnSeed } = siteConfig;
+  const { clusterBkg, clusterBorder } = themeVariables;
+  let { useRough } = node;
 
   // Add outer g element
   const shapeSvg = parent.insert('g').attr('class', 'cluster').attr('id', node.id);
 
-  // add the rect
-  const rect = shapeSvg.insert('rect', ':first-child');
-
   const useHtmlLabels = evaluate(siteConfig.flowchart.htmlLabels);
 
   // Create the label and insert it after the rect
@@ -44,7 +45,6 @@ const rect = (parent, node) => {
   }
 
   const padding = 0 * node.padding;
-  const halfPadding = padding / 2;
 
   const width = node.width <= bbox.width + padding ? bbox.width + padding : node.width;
   if (node.width <= bbox.width + padding) {
@@ -53,17 +53,45 @@ const rect = (parent, node) => {
     node.diff = -node.padding / 2;
   }
 
-  log.trace('Data ', node, JSON.stringify(node));
-  // center the rect around its coordinate
-  rect
-    .attr('style', node.cssStyles)
-    .attr('rx', node.rx)
-    .attr('ry', node.ry)
-    .attr('x', node.x - width / 2)
-    .attr('y', node.y - node.height / 2 - halfPadding)
-    .attr('width', width)
-    .attr('height', node.height + padding);
+  const totalWidth = width + padding;
+  const totalHeight = node.height + padding;
+  const x = node.x - totalWidth / 2;
+  const y = node.y - totalHeight / 2;
 
+  log.trace('Data ', node, JSON.stringify(node));
+  let rect;
+  if (useRough) {
+    // @ts-ignore TODO: Fix rough typings
+    const rc = rough.svg(shapeSvg);
+    const options = userNodeOverrides(node, {
+      roughness: 0.7,
+      fill: clusterBkg,
+      // fill: 'red',
+      stroke: clusterBorder,
+      fillWeight: 3,
+      seed: handdrawnSeed,
+      stroke: clusterBorder,
+    });
+    const roughNode = rc.path(createRoundedRectPathD(x, y, totalWidth, totalHeight, 0), options);
+    // console.log('Rough node insert CXC', roughNode);
+
+    rect = shapeSvg.insert(() => {
+      console.log('Rough node insert CXC', roughNode);
+      return roughNode;
+    }, ':first-child');
+  } else {
+    // add the rect
+    rect = shapeSvg.insert('rect', ':first-child');
+    // center the rect around its coordinate
+    rect
+      .attr('style', node.cssStyles)
+      .attr('rx', node.rx)
+      .attr('ry', node.ry)
+      .attr('x', x)
+      .attr('y', y)
+      .attr('width', totalWidth)
+      .attr('height', totalHeight);
+  }
   const { subGraphTitleTopMargin } = getSubGraphTitleMargins(siteConfig);
   if (useHtmlLabels) {
     labelEl.attr(
@@ -303,8 +331,8 @@ const divider = (parent, node) => {
 
   return { cluster: shapeSvg, labelBBox: { width: 0, height: 0 } };
 };
-
-const shapes = { rect, roundedWithTitle, noteGroup, divider };
+const squareRect = rect;
+const shapes = { rect, squareRect, roundedWithTitle, noteGroup, divider };
 
 let clusterElems = {};
 

From 7fbe1661ec62b677efb27c028e4276bcca9faafe Mon Sep 17 00:00:00 2001
From: Knut Sveidqvist 
Date: Sun, 9 Jun 2024 15:32:28 +0200
Subject: [PATCH 2/2] #5237 Fix for edges in when using elk and subgraphs
 regarding offset and direction of marker in some edge cases

---
 cypress/platform/knsv2.html                   | 36 ++++---
 packages/mermaid-layout-elk/src/render.ts     | 17 ++--
 .../mermaid/src/diagrams/flowchart/flowDb.ts  | 95 +++++++++++++------
 packages/mermaid/src/rendering-util/render.ts |  4 +
 .../rendering-elements/edges.js               | 20 ++--
 .../rendering-elements/markers.js             | 12 +--
 packages/mermaid/src/utils/lineWithOffset.ts  |  2 +-
 7 files changed, 119 insertions(+), 67 deletions(-)

diff --git a/cypress/platform/knsv2.html b/cypress/platform/knsv2.html
index 514f98409..b2598bfbc 100644
--- a/cypress/platform/knsv2.html
+++ b/cypress/platform/knsv2.html
@@ -75,22 +75,28 @@
     
   
   
-    
-stateDiagram-v2
-    state if_state <>
-    [*] --> IsPositive
-    IsPositive --> if_state
-    if_state --> False: if n < 0
-    if_state --> True : if n >= 0
+    
+stateDiagram
+direction LR
+      state Gorilla0 {
+        state Apa0 {
+          A0 --> B0
+        }
+
+      }
+      Apa0 --> C0
+      A0 --> C0
       
 flowchart LR
-    subgraph Apa
-      A[Start] --> B
+    subgraph Gorilla
+      subgraph Apa
+        A[A] --- B
+      end
     end
-    Apa --> C
-    A --> C
+    Apa --- C
+    A --x C
 
       
@@ -117,7 +123,7 @@ flowchart LR if_state --> True : if n >= 0
-
+    
       %%{init: {"layout": "elk", "mergeEdges": false, "elk.nodePlacement.strategy": "SIMPLE"} }%%
       stateDiagram
     state if_state <<choice>>
@@ -132,8 +138,10 @@ flowchart LR
 stateDiagram
   direction TB
   State T1 {
-    T11
+    T11 --> T12
   }
+  T1 --> T2
+  T11 --> T2
       
@@ -220,7 +228,7 @@ stateDiagram-v2
         look: 'handdrawn',
         // 'elk.nodePlacement.strategy': 'NETWORK_SIMPLEX',
         // layout: 'dagre',
-        // layout: 'elk',
+        layout: 'elk',
         // layout: 'fixed',
         // htmlLabels: false,
         flowchart: { titleTopMargin: 10 },
diff --git a/packages/mermaid-layout-elk/src/render.ts b/packages/mermaid-layout-elk/src/render.ts
index b5ed9a8d3..379cffefd 100644
--- a/packages/mermaid-layout-elk/src/render.ts
+++ b/packages/mermaid-layout-elk/src/render.ts
@@ -60,7 +60,7 @@ export const addVertex = async (nodeEl, graph, nodeArr, node) => {
   graph.children.push(child);
   nodeDb[node.id] = child;
 
-  //     // Add the element to the DOM
+  // Add the element to the DOM
   if (!node.isGroup) {
     const childNodeEl = await insertNode(nodeEl, node, node.dir);
     boundingBox = childNodeEl.node().getBBox();
@@ -93,7 +93,7 @@ export const addVertex = async (nodeEl, graph, nodeArr, node) => {
 
 export const addVertices = async function (nodeEl, nodeArr, graph, parentId) {
   const siblings = nodeArr.filter((node) => node.parentId === parentId);
-  log.info('addVertices DAGA', siblings, parentId);
+  log.info('addVertices APA12', siblings, parentId);
   // Iterate through each item in the vertex object (containing all the vertices found) in the graph definition
   await Promise.all(
     siblings.map(async (node) => {
@@ -512,9 +512,7 @@ export const render = async (data4Layout, svg, element, algorithm) => {
     const node = nodeDb[n.id];
 
     // Subgraph
-    console.log('Subgraph XCX before');
     if (parentLookupDb.childrenById[node.id] !== undefined) {
-      console.log('Subgraph XCX', node.id, node, node.labelData);
       node.labels = [
         {
           text: node.labelText,
@@ -553,9 +551,9 @@ export const render = async (data4Layout, svg, element, algorithm) => {
     }
   });
 
-  console.log('before layout', JSON.stringify(elkGraph, null, 2));
+  // log.info('before layout', JSON.stringify(elkGraph, null, 2));
   const g = await elk.layout(elkGraph);
-  log.info('after layout', JSON.stringify(g));
+  // log.info('after layout', JSON.stringify(g));
 
   // debugger;
   drawNodes(0, 0, g.children, svg, subGraphsEl, 0);
@@ -563,11 +561,11 @@ export const render = async (data4Layout, svg, element, algorithm) => {
     // (elem, edge, clusterDb, diagramType, graph, id)
     const startNode = nodeDb[edge.sources[0]];
     const endNode = nodeDb[edge.targets[0]];
-    const sourceId = edge.start.id;
-    const targetId = edge.end.id;
+    const sourceId = edge.start;
+    const targetId = edge.end;
 
     const offset = calcOffset(sourceId, targetId, parentLookupDb);
-
+    log.info('APA12 offset', offset, sourceId, targetId, edge);
     if (edge.sections) {
       const src = edge.sections[0].startPoint;
       const dest = edge.sections[0].endPoint;
@@ -590,6 +588,7 @@ export const render = async (data4Layout, svg, element, algorithm) => {
         endNode,
         data4Layout.diagramId
       );
+      log.info('APA12 edge points after insert', JSON.stringify(edge.points));
 
       edge.x = edge.labels[0].x + offset.x + edge.labels[0].width / 2;
       edge.y = edge.labels[0].y + offset.y + edge.labels[0].height / 2;
diff --git a/packages/mermaid/src/diagrams/flowchart/flowDb.ts b/packages/mermaid/src/diagrams/flowchart/flowDb.ts
index b3976adf5..b2c38efe8 100644
--- a/packages/mermaid/src/diagrams/flowchart/flowDb.ts
+++ b/packages/mermaid/src/diagrams/flowchart/flowDb.ts
@@ -767,35 +767,22 @@ const getTypeFromVertex = (vertex: FlowVertex) => {
   return vertex.type || 'squareRect';
 };
 
-export const getData = () => {
-  const config = getConfig();
-  const nodes: Node[] = [];
-  const edges: Edge[] = [];
+const findNode = (nodes: Node[], id: string) => nodes.find((node) => node.id === id);
 
-  // extract(getRootDocV2());
-  // const diagramStates = getStates();
-  const useRough = config.look === 'handdrawn';
-  const subGraphs = getSubGraphs();
-  log.info('Subgraphs - ', subGraphs);
-  const parentDB = new Map();
-  const subGraphDB = new Map();
+const addNodeFromVertex = (
+  vertex: FlowVertex,
+  nodes: Node[],
+  parentDB: Map,
+  subGraphDB: Map,
+  config: any,
+  useRough: boolean
+): Node => {
+  let parentId = parentDB.get(vertex.id);
+  let isGroup = subGraphDB.get(vertex.id) || false;
 
-  for (let i = subGraphs.length - 1; i >= 0; i--) {
-    const subGraph = subGraphs[i];
-    if (subGraph.nodes.length > 0) {
-      subGraphDB.set(subGraph.id, true);
-    }
-    subGraph.nodes.forEach((id) => {
-      parentDB.set(id, subGraph.id);
-    });
-  }
-
-  const n = getVertices();
-  n.forEach((vertex) => {
-    let parentId = parentDB.get(vertex.id);
-    let isGroup = subGraphDB.get(vertex.id) || false;
-
-    const node: Node = {
+  let node = findNode(nodes, vertex.id);
+  if (!node) {
+    nodes.push({
       id: vertex.id,
       label: vertex.text,
       labelStyle: '',
@@ -809,10 +796,59 @@ export const getData = () => {
       type: isGroup ? 'group' : undefined,
       isGroup,
       useRough,
-    };
-    nodes.push(node);
+    });
+  }
+};
+
+export const getData = () => {
+  const config = getConfig();
+  const nodes: Node[] = [];
+  const edges: Edge[] = [];
+
+  // extract(getRootDocV2());
+  // const diagramStates = getStates();
+  const useRough = config.look === 'handdrawn';
+  const subGraphs = getSubGraphs();
+  log.info('Subgraphs - APA12', subGraphs);
+  const parentDB = new Map();
+  const subGraphDB = new Map();
+
+  for (let i = subGraphs.length - 1; i >= 0; i--) {
+    const subGraph = subGraphs[i];
+    if (subGraph.nodes.length > 0) {
+      subGraphDB.set(subGraph.id, true);
+    }
+    subGraph.nodes.forEach((id) => {
+      parentDB.set(id, subGraph.id);
+    });
+    nodes.push({
+      id: subGraph.id,
+      label: subGraph.title,
+      labelStyle: '',
+      parentId: parentDB.get(subGraph.id),
+      padding: config.flowchart?.padding || 8,
+      cssStyles: '',
+      cssClasses: '',
+      shape: 'rect',
+      dir: subGraph.dir,
+      domId: subGraph.domId,
+      type: 'group',
+      isGroup: true,
+      useRough,
+    });
+  }
+  console.log('APA12 nodes - 1', nodes.length);
+
+  const n = getVertices();
+  n.forEach((vertex) => {
+    const node = addNodeFromVertex(vertex, nodes, parentDB, subGraphDB, config, useRough);
+    if (node) {
+      nodes.push(node);
+    }
   });
 
+  console.log('APA12 nodes', nodes.length);
+
   const e = getEdges();
   e.forEach((rawEdge, index) => {
     const edge: Edge = {
@@ -829,6 +865,7 @@ export const getData = () => {
       classes: 'edge-thickness-normal edge-pattern-solid flowchart-link',
       arrowhead: 'none',
       arrowTypeEnd: 'arrow_point',
+      // arrowTypeEnd: 'arrow_barb',
       arrowheadStyle: 'fill: #333',
       // stroke: rawEdge.pattern,
       pattern: rawEdge.stroke,
diff --git a/packages/mermaid/src/rendering-util/render.ts b/packages/mermaid/src/rendering-util/render.ts
index 489e6ba58..442780c75 100644
--- a/packages/mermaid/src/rendering-util/render.ts
+++ b/packages/mermaid/src/rendering-util/render.ts
@@ -24,6 +24,10 @@ const registerDefaultLayoutLoaders = () => {
       name: 'dagre',
       loader: async () => await import('./layout-algorithms/dagre/index.js'),
     },
+    // {
+    //   name: 'elk',
+    //   loader: async () => await import('../../../mermaid-layout-elk/src/render.js'),
+    // },
   ]);
 };
 
diff --git a/packages/mermaid/src/rendering-util/rendering-elements/edges.js b/packages/mermaid/src/rendering-util/rendering-elements/edges.js
index 8b9e03fc7..cf1da0909 100644
--- a/packages/mermaid/src/rendering-util/rendering-elements/edges.js
+++ b/packages/mermaid/src/rendering-util/rendering-elements/edges.js
@@ -533,14 +533,14 @@ export const insertEdge = function (elem, edge, clusterDb, diagramType, startNod
   let lineData = points.filter((p) => !Number.isNaN(p.y));
   const { cornerPoints, cornerPointPositions } = extractCornerPoints(lineData);
   lineData = fixCorners(lineData);
-  let lastPoint = lineData[0];
+  let lastPoint = lineData[lineData.length - 1];
   if (lineData.length > 1) {
     lastPoint = lineData[lineData.length - 1];
     const secondLastPoint = lineData[lineData.length - 2];
     // Calculate the mid point of the last two points
-    const diffX = (lastPoint.x - secondLastPoint.x) / 4;
-    const diffY = (lastPoint.y - secondLastPoint.y) / 4;
-    const midPoint = { x: secondLastPoint.x + 3 * diffX, y: secondLastPoint.y + 3 * diffY };
+    const diffX = (lastPoint.x - secondLastPoint.x) / 2;
+    const diffY = (lastPoint.y - secondLastPoint.y) / 2;
+    const midPoint = { x: secondLastPoint.x + diffX, y: secondLastPoint.y + diffY };
     lineData.splice(-1, 0, midPoint);
   }
   // This is the accessor function we talked about above
@@ -596,11 +596,16 @@ export const insertEdge = function (elem, edge, clusterDb, diagramType, startNod
   let useRough = edge.useRough;
   let svgPath;
   let path = '';
-
+  let linePath = lineFunction(lineData);
   if (useRough) {
     const rc = rough.svg(elem);
     const ld = Object.assign([], lineData);
-    const svgPathNode = rc.path(lineFunction(ld.splice(0, ld.length - 1)), {
+    // const svgPathNode = rc.path(lineFunction(ld.splice(0, ld.length-1)), {
+    // const svgPathNode = rc.path(lineFunction(ld), {
+    //   roughness: 0.3,
+    //   seed: handdrawnSeed,
+    // });
+    const svgPathNode = rc.path(linePath, {
       roughness: 0.3,
       seed: handdrawnSeed,
     });
@@ -614,13 +619,12 @@ export const insertEdge = function (elem, edge, clusterDb, diagramType, startNod
       .attr('class', ' ' + strokeClasses + (edge.classes ? ' ' + edge.classes : ''))
       .attr('style', edge.style);
     let d = svgPath.attr('d');
-    d = d + ' L ' + lastPoint.x + ' ' + lastPoint.y;
     svgPath.attr('d', d);
     elem.node().appendChild(svgPath.node());
   } else {
     svgPath = elem
       .append('path')
-      .attr('d', lineFunction(lineData))
+      .attr('d', linePath)
       .attr('id', edge.id)
       .attr('class', ' ' + strokeClasses + (edge.classes ? ' ' + edge.classes : ''))
       .attr('style', edge.style);
diff --git a/packages/mermaid/src/rendering-util/rendering-elements/markers.js b/packages/mermaid/src/rendering-util/rendering-elements/markers.js
index c7cfcfe7f..00d45e47d 100644
--- a/packages/mermaid/src/rendering-util/rendering-elements/markers.js
+++ b/packages/mermaid/src/rendering-util/rendering-elements/markers.js
@@ -159,11 +159,11 @@ const point = (elem, type, id) => {
     .attr('id', id + '_' + type + '-pointEnd')
     .attr('class', 'marker ' + type)
     .attr('viewBox', '0 0 10 10')
-    .attr('refX', 6)
+    .attr('refX', 5)
     .attr('refY', 5)
     .attr('markerUnits', 'userSpaceOnUse')
-    .attr('markerWidth', 12)
-    .attr('markerHeight', 12)
+    .attr('markerWidth', 8)
+    .attr('markerHeight', 8)
     .attr('orient', 'auto')
     .append('path')
     .attr('d', 'M 0 0 L 10 5 L 0 10 z')
@@ -178,8 +178,8 @@ const point = (elem, type, id) => {
     .attr('refX', 4.5)
     .attr('refY', 5)
     .attr('markerUnits', 'userSpaceOnUse')
-    .attr('markerWidth', 12)
-    .attr('markerHeight', 12)
+    .attr('markerWidth', 11)
+    .attr('markerHeight', 11)
     .attr('orient', 'auto')
     .append('path')
     .attr('d', 'M 0 5 L 10 10 L 10 0 z')
@@ -272,7 +272,7 @@ const barb = (elem, type, id) => {
     .attr('refY', 7)
     .attr('markerWidth', 20)
     .attr('markerHeight', 14)
-    .attr('markerUnits', 'strokeWidth')
+    .attr('markerUnits', 'userSpaceOnUse')
     .attr('orient', 'auto')
     .append('path')
     .attr('d', 'M 19,7 L9,13 L14,7 L9,1 Z');
diff --git a/packages/mermaid/src/utils/lineWithOffset.ts b/packages/mermaid/src/utils/lineWithOffset.ts
index af0cd3b46..8f82111f9 100644
--- a/packages/mermaid/src/utils/lineWithOffset.ts
+++ b/packages/mermaid/src/utils/lineWithOffset.ts
@@ -9,7 +9,7 @@ const markerOffsets = {
   composition: 18,
   dependency: 6,
   lollipop: 13.5,
-  arrow_point: 5.3,
+  arrow_point: 4,
 } as const;
 
 /**