From 836d3a87beb2b585fad9ac6e5b90f835fb876222 Mon Sep 17 00:00:00 2001 From: Knut Sveidqvist Date: Thu, 14 Sep 2023 10:11:43 +0200 Subject: [PATCH] WIP --- cypress/platform/knsv2.html | 12 ++- packages/mermaid/src/dagre-wrapper/nodes.js | 98 +++++++++---------- .../src/diagrams/block/blockRenderer.ts | 22 +++-- packages/mermaid/src/diagrams/block/layout.ts | 19 ++-- .../src/diagrams/block/renderHelpers.ts | 3 +- 5 files changed, 84 insertions(+), 70 deletions(-) diff --git a/cypress/platform/knsv2.html b/cypress/platform/knsv2.html index 4609331dd..36afc1d03 100644 --- a/cypress/platform/knsv2.html +++ b/cypress/platform/knsv2.html @@ -26,6 +26,8 @@ } .mermaid { border: 1px solid #ddd; + margin: 10px; + background: pink; } .mermaid2 { display: none; @@ -38,6 +40,7 @@ background-size: 20px 20px; background-position: 0 0, 10px 10px; background-repeat: repeat; + border: 1px solid red; } .malware { position: fixed; @@ -62,10 +65,13 @@
 block-beta
-  id1("Wide 1")
+  %% id1("Wide 1")
   id2("2")
-  id3("3")
-  id4("A final one")
+  block
+      id3
+      id4
+  end
+  %% id4("A final one")
 
     
diff --git a/packages/mermaid/src/dagre-wrapper/nodes.js b/packages/mermaid/src/dagre-wrapper/nodes.js
index e9324171b..9e57fb2b0 100644
--- a/packages/mermaid/src/dagre-wrapper/nodes.js
+++ b/packages/mermaid/src/dagre-wrapper/nodes.js
@@ -27,7 +27,7 @@ const question = async (parent, node) => {
   questionElem.attr('style', node.style);
   updateNodeBounds(node, questionElem);
 
-  node.intersect = function (point) {
+  node.intersect = function(point) {
     log.warn('Intersect called');
     return intersect.polygon(node, points, point);
   };
@@ -52,7 +52,7 @@ const choice = (parent, node) => {
   const choice = shapeSvg.insert('polygon', ':first-child').attr(
     'points',
     points
-      .map(function (d) {
+      .map(function(d) {
         return d.x + ',' + d.y;
       })
       .join(' ')
@@ -62,7 +62,7 @@ const choice = (parent, node) => {
   node.width = 28;
   node.height = 28;
 
-  node.intersect = function (point) {
+  node.intersect = function(point) {
     return intersect.circle(node, 14, point);
   };
 
@@ -89,7 +89,7 @@ const hexagon = async (parent, node) => {
   hex.attr('style', node.style);
   updateNodeBounds(node, hex);
 
-  node.intersect = function (point) {
+  node.intersect = function(point) {
     return intersect.polygon(node, points, point);
   };
 
@@ -115,7 +115,7 @@ const rect_left_inv_arrow = async (parent, node) => {
   node.width = w + h;
   node.height = h;
 
-  node.intersect = function (point) {
+  node.intersect = function(point) {
     return intersect.polygon(node, points, point);
   };
 
@@ -138,7 +138,7 @@ const lean_right = async (parent, node) => {
   el.attr('style', node.style);
   updateNodeBounds(node, el);
 
-  node.intersect = function (point) {
+  node.intersect = function(point) {
     return intersect.polygon(node, points, point);
   };
 
@@ -161,7 +161,7 @@ const lean_left = async (parent, node) => {
   el.attr('style', node.style);
   updateNodeBounds(node, el);
 
-  node.intersect = function (point) {
+  node.intersect = function(point) {
     return intersect.polygon(node, points, point);
   };
 
@@ -184,7 +184,7 @@ const trapezoid = async (parent, node) => {
   el.attr('style', node.style);
   updateNodeBounds(node, el);
 
-  node.intersect = function (point) {
+  node.intersect = function(point) {
     return intersect.polygon(node, points, point);
   };
 
@@ -207,7 +207,7 @@ const inv_trapezoid = async (parent, node) => {
   el.attr('style', node.style);
   updateNodeBounds(node, el);
 
-  node.intersect = function (point) {
+  node.intersect = function(point) {
     return intersect.polygon(node, points, point);
   };
 
@@ -231,7 +231,7 @@ const rect_right_inv_arrow = async (parent, node) => {
   el.attr('style', node.style);
   updateNodeBounds(node, el);
 
-  node.intersect = function (point) {
+  node.intersect = function(point) {
     return intersect.polygon(node, points, point);
   };
 
@@ -281,7 +281,7 @@ const cylinder = async (parent, node) => {
 
   updateNodeBounds(node, el);
 
-  node.intersect = function (point) {
+  node.intersect = function(point) {
     const pos = intersect.rect(node, point);
     const x = pos.x - node.x;
 
@@ -325,17 +325,13 @@ const rect = async (parent, node) => {
   // const totalHeight = bbox.height + node.padding * 2;
   const totalWidth = node.positioned ? node.width : bbox.width + node.padding;
   const totalHeight = node.positioned ? node.height : bbox.height + node.padding;
-  const x = node.positioned ? node.x - node.width / 2 - halfPadding : -bbox.width / 2 - halfPadding;
-  const y = node.positioned
-    ? node.y - node.height / 2 - halfPadding
-    : -bbox.height / 2 - halfPadding;
+  const x = node.positioned ? -totalWidth / 2 : -bbox.width / 2 - halfPadding;
+  const y = node.positioned ? -totalHeight / 2 : -bbox.height / 2 - halfPadding;
   rect
     .attr('class', 'basic label-container')
     .attr('style', node.style)
     .attr('rx', node.rx)
     .attr('ry', node.ry)
-    // .attr('x', -bbox.width / 2 - node.padding)
-    // .attr('y', -bbox.height / 2 - node.padding)
     .attr('x', x)
     .attr('y', y)
     .attr('width', totalWidth)
@@ -354,7 +350,7 @@ const rect = async (parent, node) => {
 
   updateNodeBounds(node, rect);
 
-  node.intersect = function (point) {
+  node.intersect = function(point) {
     return intersect.rect(node, point);
   };
 
@@ -387,7 +383,7 @@ const labelRect = async (parent, node) => {
 
   updateNodeBounds(node, rect);
 
-  node.intersect = function (point) {
+  node.intersect = function(point) {
     return intersect.rect(node, point);
   };
 
@@ -499,20 +495,20 @@ const rectWithTitle = (parent, node) => {
   select(descr).attr(
     'transform',
     'translate( ' +
-      // (titleBox.width - bbox.width) / 2 +
-      (bbox.width > titleBox.width ? 0 : (titleBox.width - bbox.width) / 2) +
-      ', ' +
-      (titleBox.height + halfPadding + 5) +
-      ')'
+    // (titleBox.width - bbox.width) / 2 +
+    (bbox.width > titleBox.width ? 0 : (titleBox.width - bbox.width) / 2) +
+    ', ' +
+    (titleBox.height + halfPadding + 5) +
+    ')'
   );
   select(text).attr(
     'transform',
     'translate( ' +
-      // (titleBox.width - bbox.width) / 2 +
-      (bbox.width < titleBox.width ? 0 : -(titleBox.width - bbox.width) / 2) +
-      ', ' +
-      0 +
-      ')'
+    // (titleBox.width - bbox.width) / 2 +
+    (bbox.width < titleBox.width ? 0 : -(titleBox.width - bbox.width) / 2) +
+    ', ' +
+    0 +
+    ')'
   );
   // Get the size of the label
 
@@ -541,7 +537,7 @@ const rectWithTitle = (parent, node) => {
 
   updateNodeBounds(node, rect);
 
-  node.intersect = function (point) {
+  node.intersect = function(point) {
     return intersect.rect(node, point);
   };
 
@@ -567,7 +563,7 @@ const stadium = async (parent, node) => {
 
   updateNodeBounds(node, rect);
 
-  node.intersect = function (point) {
+  node.intersect = function(point) {
     return intersect.rect(node, point);
   };
 
@@ -591,7 +587,7 @@ const circle = async (parent, node) => {
 
   updateNodeBounds(node, circle);
 
-  node.intersect = function (point) {
+  node.intersect = function(point) {
     log.info('Circle intersect', node, bbox.width / 2 + halfPadding, point);
     return intersect.circle(node, bbox.width / 2 + halfPadding, point);
   };
@@ -629,7 +625,7 @@ const doublecircle = async (parent, node) => {
 
   updateNodeBounds(node, outerCircle);
 
-  node.intersect = function (point) {
+  node.intersect = function(point) {
     log.info('DoubleCircle intersect', node, bbox.width / 2 + halfPadding + gap, point);
     return intersect.circle(node, bbox.width / 2 + halfPadding + gap, point);
   };
@@ -659,7 +655,7 @@ const subroutine = async (parent, node) => {
   el.attr('style', node.style);
   updateNodeBounds(node, el);
 
-  node.intersect = function (point) {
+  node.intersect = function(point) {
     return intersect.polygon(node, points, point);
   };
 
@@ -678,7 +674,7 @@ const start = (parent, node) => {
 
   updateNodeBounds(node, circle);
 
-  node.intersect = function (point) {
+  node.intersect = function(point) {
     return intersect.circle(node, 7, point);
   };
 
@@ -710,7 +706,7 @@ const forkJoin = (parent, node, dir) => {
   updateNodeBounds(node, shape);
   node.height = node.height + node.padding / 2;
   node.width = node.width + node.padding / 2;
-  node.intersect = function (point) {
+  node.intersect = function(point) {
     return intersect.rect(node, point);
   };
 
@@ -731,7 +727,7 @@ const end = (parent, node) => {
 
   updateNodeBounds(node, circle);
 
-  node.intersect = function (point) {
+  node.intersect = function(point) {
     return intersect.circle(node, 7, point);
   };
 
@@ -896,10 +892,10 @@ const class_box = (parent, node) => {
   select(classTitleLabel).attr(
     'transform',
     'translate( ' +
-      ((-1 * maxWidth) / 2 + diffX) +
-      ', ' +
-      ((-1 * maxHeight) / 2 + verticalPos) +
-      ')'
+    ((-1 * maxWidth) / 2 + diffX) +
+    ', ' +
+    ((-1 * maxHeight) / 2 + verticalPos) +
+    ')'
   );
   verticalPos += classTitleBBox.height + rowPadding;
 
@@ -916,10 +912,10 @@ const class_box = (parent, node) => {
     select(lbl).attr(
       'transform',
       'translate( ' +
-        -maxWidth / 2 +
-        ', ' +
-        ((-1 * maxHeight) / 2 + verticalPos + lineHeight / 2) +
-        ')'
+      -maxWidth / 2 +
+      ', ' +
+      ((-1 * maxHeight) / 2 + verticalPos + lineHeight / 2) +
+      ')'
     );
     //get the height of the bounding box of each member if exists
     const memberBBox = lbl?.getBBox();
@@ -954,7 +950,7 @@ const class_box = (parent, node) => {
 
   updateNodeBounds(node, rect);
 
-  node.intersect = function (point) {
+  node.intersect = function(point) {
     return intersect.rect(node, point);
   };
 
@@ -1030,8 +1026,8 @@ export const clear = () => {
 };
 
 export const positionNode = (node) => {
+  console.log('Node id = ', node.id);
   const el = nodeElems[node.id];
-
   log.trace(
     'Transforming node',
     node.diff,
@@ -1044,10 +1040,10 @@ export const positionNode = (node) => {
     el.attr(
       'transform',
       'translate(' +
-        (node.x + diff - node.width / 2) +
-        ', ' +
-        (node.y - node.height / 2 - padding) +
-        ')'
+      (node.x + diff - node.width / 2) +
+      ', ' +
+      (node.y - node.height / 2 - padding) +
+      ')'
     );
   } else {
     el.attr('transform', 'translate(' + node.x + ', ' + node.y + ')');
diff --git a/packages/mermaid/src/diagrams/block/blockRenderer.ts b/packages/mermaid/src/diagrams/block/blockRenderer.ts
index 932537786..a8bf1fe49 100644
--- a/packages/mermaid/src/diagrams/block/blockRenderer.ts
+++ b/packages/mermaid/src/diagrams/block/blockRenderer.ts
@@ -16,6 +16,7 @@ import type { Block } from './blockTypes.js';
 // import { diagram as BlockDiagram } from './blockDiagram.js';
 import { configureSvgSize } from '../../setupGraphViewbox.js';
 import { Uid } from '../../rendering-util/uid.js';
+import { pad } from 'lodash';
 
 export const draw = async function (
   text: string,
@@ -42,19 +43,28 @@ export const draw = async function (
   const nodes = svg.insert('g').attr('class', 'block');
   await calculateBlockSizes(nodes, bl, db);
   const bounds = layout(db);
+  console.log('Here blocks', bl);
   await insertBlocks(nodes, bl, db);
 
-  console.log('Here', bl);
+  // console.log('Here', bl);
 
   // Establish svg dimensions and get width and height
   //
-  // const bounds = nodes.node().getBoundingClientRect();
-  const height = bounds.height + 600;
-  const width = bounds.width + 699;
+  // const bounds2 = nodes.node().getBoundingClientRect();
+  const bounds2 = bounds;
+  const padding = 10;
+  // Why, oh why ????
+  const magicFactor = Math.max(1, Math.round(0.125 * (bounds2.width / bounds2.height)));
+  const height = bounds2.height + magicFactor + 10;
+  const width = bounds2.width + 10;
   const useMaxWidth = false;
   configureSvgSize(svg, height, width, useMaxWidth);
-  console.log('Here Bounds', bounds);
-  svg.attr('viewBox', `${bounds.x} ${bounds.y} ${bounds.width} ${bounds.height}`);
+  console.log('Here Bounds', bounds, bounds2);
+  svg.attr(
+    'viewBox',
+    `${bounds2.x - 5} ${bounds2.y - 5} ${bounds2.width + 10} ${bounds2.height + 10}`
+  );
+  // svg.attr('viewBox', `${-200} ${-200} ${400} ${400}`);
 
   // Prepare data for construction based on diagObj.db
   // This must be a mutable object with `nodes` and `links` properties:
diff --git a/packages/mermaid/src/diagrams/block/layout.ts b/packages/mermaid/src/diagrams/block/layout.ts
index 2d6100229..b745ce1b9 100644
--- a/packages/mermaid/src/diagrams/block/layout.ts
+++ b/packages/mermaid/src/diagrams/block/layout.ts
@@ -66,17 +66,17 @@ let maxY = 0;
 function findBounds(block: Block) {
   if (block.size) {
     const { x, y, width, height } = block.size;
-    if (x - width < minX) {
-      minX = x - width;
+    if (x - width / 2 < minX) {
+      minX = x - width / 2;
     }
-    if (y - height < minY) {
-      minY = y - height;
+    if (y - height / 2 < minY) {
+      minY = y - height / 2;
     }
-    if (x > maxX) {
-      maxX = x;
+    if (x + width / 2 > maxX) {
+      maxX = x + width / 2;
     }
-    if (y > maxY) {
-      maxY = y;
+    if (y + height / 2 > maxY) {
+      maxY = y + height / 2;
     }
   }
   if (block.children) {
@@ -90,13 +90,14 @@ export function layout(db: BlockDB) {
   const blocks = db.getBlocks();
   const root = { id: 'root', type: 'composite', children: blocks } as Block;
   layoutBLock(root, db);
-  positionBlock(root, db);
+  // positionBlock(root, db);
 
   minX = 0;
   minY = 0;
   maxX = 0;
   maxY = 0;
   findBounds(root);
+  console.log('Here maxX', maxX);
   const height = maxY - minY;
   const width = maxX - minX;
   return { x: minX, y: minY, width, height };
diff --git a/packages/mermaid/src/diagrams/block/renderHelpers.ts b/packages/mermaid/src/diagrams/block/renderHelpers.ts
index 1b29b4536..cb7833050 100644
--- a/packages/mermaid/src/diagrams/block/renderHelpers.ts
+++ b/packages/mermaid/src/diagrams/block/renderHelpers.ts
@@ -1,5 +1,5 @@
 import { getStylesFromArray } from '../../utils.js';
-import { insertNode } from '../../dagre-wrapper/nodes.js';
+import { insertNode, positionNode } from '../../dagre-wrapper/nodes.js';
 import { getConfig } from '../../config.js';
 import { ContainerElement } from 'd3';
 import type { Block } from './blockTypes.js';
@@ -146,6 +146,7 @@ export async function insertBlockPositioned(elem: any, block: any, db: any) {
   // Add the element to the DOM to size it
   const obj = db.getBlock(node.id);
   const nodeEl = await insertNode(elem, node);
+  positionNode(node);
 }
 
 export async function performOperations(