mirror of
				https://github.com/mermaid-js/mermaid.git
				synced 2025-11-03 20:34:20 +01:00 
			
		
		
		
	#6097 Next shapes, learn-right and card
This commit is contained in:
		
							
								
								
									
										102
									
								
								cypress/platform/shape-tester.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								cypress/platform/shape-tester.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,102 @@
 | 
			
		||||
<html>
 | 
			
		||||
  <head>
 | 
			
		||||
    <link href="https://fonts.googleapis.com/css?family=Montserrat&display=swap" rel="stylesheet" />
 | 
			
		||||
    <link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
 | 
			
		||||
    <link
 | 
			
		||||
      rel="stylesheet"
 | 
			
		||||
      href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
 | 
			
		||||
    />
 | 
			
		||||
    <link
 | 
			
		||||
      href="https://cdn.jsdelivr.net/npm/@mdi/font@6.9.96/css/materialdesignicons.min.css"
 | 
			
		||||
      rel="stylesheet"
 | 
			
		||||
    />
 | 
			
		||||
    <link
 | 
			
		||||
      href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
 | 
			
		||||
      rel="stylesheet"
 | 
			
		||||
    />
 | 
			
		||||
    <link rel="preconnect" href="https://fonts.googleapis.com" />
 | 
			
		||||
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
 | 
			
		||||
    <link
 | 
			
		||||
      href="https://fonts.googleapis.com/css2?family=Kalam:wght@300;400;700&display=swap"
 | 
			
		||||
      rel="stylesheet"
 | 
			
		||||
    />
 | 
			
		||||
    <link
 | 
			
		||||
      href="https://fonts.googleapis.com/css2?family=Caveat:wght@400..700&family=Kalam:wght@300;400;700&family=Rubik+Mono+One&display=swap"
 | 
			
		||||
      rel="stylesheet"
 | 
			
		||||
    />
 | 
			
		||||
    <link
 | 
			
		||||
      href="https://fonts.googleapis.com/css2?family=Kalam:wght@300;400;700&family=Rubik+Mono+One&display=swap"
 | 
			
		||||
      rel="stylesheet"
 | 
			
		||||
    />
 | 
			
		||||
 | 
			
		||||
    <style>
 | 
			
		||||
      body {
 | 
			
		||||
        font-family: 'Arial';
 | 
			
		||||
        background-color: #333;
 | 
			
		||||
      }
 | 
			
		||||
    </style>
 | 
			
		||||
  </head>
 | 
			
		||||
 | 
			
		||||
  <body>
 | 
			
		||||
    <div id="diagram"></div>
 | 
			
		||||
    <script type="module">
 | 
			
		||||
      import mermaid from './mermaid.esm.mjs';
 | 
			
		||||
      import layouts from './mermaid-layout-elk.esm.mjs';
 | 
			
		||||
      mermaid.registerLayoutLoaders(layouts);
 | 
			
		||||
      mermaid.parseError = function (err, hash) {
 | 
			
		||||
        console.error('Mermaid error: ', err);
 | 
			
		||||
      };
 | 
			
		||||
      mermaid.initialize({
 | 
			
		||||
        startOnLoad: false,
 | 
			
		||||
        //look: 'handdrawn',
 | 
			
		||||
        // layout: 'fixed',
 | 
			
		||||
        theme: 'dark',
 | 
			
		||||
        //layout: 'elk',
 | 
			
		||||
        fontFamily: 'Kalam',
 | 
			
		||||
        logLevel: 1,
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      let shape = 'card';
 | 
			
		||||
      // let simplified = true;
 | 
			
		||||
      let simplified = false;
 | 
			
		||||
      let algorithm = 'elk';
 | 
			
		||||
      // let algorithm = 'dagre';
 | 
			
		||||
      let code = `---
 | 
			
		||||
config:
 | 
			
		||||
  layout: ${algorithm}
 | 
			
		||||
---
 | 
			
		||||
flowchart TD
 | 
			
		||||
A["Abrakadabra"] --> C["C"] & D["I am a circle"] & n4["Untitled Node"]
 | 
			
		||||
D@{ shape: diamond}
 | 
			
		||||
    B["Bombrakadombra"] --> D & C & D
 | 
			
		||||
    C --> E["E"] & B
 | 
			
		||||
    D --> E & A
 | 
			
		||||
    n4 --> C
 | 
			
		||||
    A@{ shape: ${shape}}
 | 
			
		||||
    B@{ shape: ${shape}}
 | 
			
		||||
    C@{ shape: ${shape}}
 | 
			
		||||
    D@{ shape: ${shape}}
 | 
			
		||||
    E@{ shape: ${shape}}
 | 
			
		||||
    n4@{ shape: ${shape}}
 | 
			
		||||
 | 
			
		||||
          `;
 | 
			
		||||
      if (simplified) {
 | 
			
		||||
        code = `---
 | 
			
		||||
config:
 | 
			
		||||
  layout: ${algorithm}
 | 
			
		||||
---
 | 
			
		||||
flowchart LR
 | 
			
		||||
A["Abrakadabra"] --> C["C"] & C & C & C & C
 | 
			
		||||
%% A["Abrakadabra"] --> C
 | 
			
		||||
    A@{ shape: ${shape}}
 | 
			
		||||
    C@{ shape: ${shape}}
 | 
			
		||||
 | 
			
		||||
          `;
 | 
			
		||||
      }
 | 
			
		||||
      console.log(code);
 | 
			
		||||
      const { svg } = await mermaid.render('the-id-of-the-svg', code, undefined, undefined);
 | 
			
		||||
      const elem = document.querySelector('#diagram');
 | 
			
		||||
      elem.innerHTML = svg;
 | 
			
		||||
    </script>
 | 
			
		||||
  </body>
 | 
			
		||||
</html>
 | 
			
		||||
@@ -592,9 +592,10 @@ export const render = async (
 | 
			
		||||
      setIncludeChildrenPolicy(target, ancestorId);
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  // const copy = JSON.parse(JSON.stringify({ ...elkGraph }));
 | 
			
		||||
  // console.log('APA13 layout before', copy);
 | 
			
		||||
  const g = await elk.layout(elkGraph);
 | 
			
		||||
 | 
			
		||||
  // console.log('APA13 layout', JSON.parse(JSON.stringify(g)));
 | 
			
		||||
  // debugger;
 | 
			
		||||
  await drawNodes(0, 0, g.children, svg, subGraphsEl, 0);
 | 
			
		||||
  g.edges?.map(
 | 
			
		||||
@@ -683,6 +684,18 @@ export const render = async (
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (startNode.calcIntersect) {
 | 
			
		||||
          // console.log(
 | 
			
		||||
          //   'APA13 calculating start intersection start node',
 | 
			
		||||
          //   startNode.id,
 | 
			
		||||
          //   startNode.x,
 | 
			
		||||
          //   startNode.y,
 | 
			
		||||
          //   'w:',
 | 
			
		||||
          //   startNode.width,
 | 
			
		||||
          //   'h:',
 | 
			
		||||
          //   startNode.height,
 | 
			
		||||
          //   '\nPos',
 | 
			
		||||
          //   edge.points[0]
 | 
			
		||||
          // );
 | 
			
		||||
          const intersection = startNode.calcIntersect(
 | 
			
		||||
            {
 | 
			
		||||
              x: startNode.offset.posX + startNode.width / 2,
 | 
			
		||||
@@ -707,9 +720,18 @@ export const render = async (
 | 
			
		||||
            },
 | 
			
		||||
            edge.points[edge.points.length - 1]
 | 
			
		||||
          );
 | 
			
		||||
          // if (edge.id === 'L_n4_C_10_0') {
 | 
			
		||||
          // console.log('APA14 lineData', edge.points, 'intersection:', intersection);
 | 
			
		||||
          // console.log(
 | 
			
		||||
          //   'APA14! calculating end intersection\ndistance:',
 | 
			
		||||
          //   distance(intersection, edge.points[edge.points.length - 1])
 | 
			
		||||
          // );
 | 
			
		||||
          // }
 | 
			
		||||
 | 
			
		||||
          if (distance(intersection, edge.points[edge.points.length - 1]) > epsilon) {
 | 
			
		||||
            // console.log('APA13! distance ok\nintersection:', intersection);
 | 
			
		||||
            edge.points.push(intersection);
 | 
			
		||||
            // console.log('APA13! distance ok\npoints:', edge.points);
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -5,7 +5,8 @@ import { createText } from '../createText.js';
 | 
			
		||||
import utils from '../../utils.js';
 | 
			
		||||
import { getLineFunctionsWithOffset } from '../../utils/lineWithOffset.js';
 | 
			
		||||
import { getSubGraphTitleMargins } from '../../utils/subGraphTitleMargins.js';
 | 
			
		||||
import { curveBasis, line, select } from 'd3';
 | 
			
		||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
 | 
			
		||||
import { curveBasis, curveLinear, line, select } from 'd3';
 | 
			
		||||
import rough from 'roughjs';
 | 
			
		||||
import createLabel from './createLabel.js';
 | 
			
		||||
import { addEdgeMarkers } from './edgeMarker.ts';
 | 
			
		||||
@@ -335,7 +336,7 @@ const cutPathAtIntersect = (_points, boundaryNode) => {
 | 
			
		||||
  return points;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const adjustForArrowHeads = function (lineData, size = 5) {
 | 
			
		||||
const adjustForArrowHeads = function (lineData, size = 5, shouldLog = false) {
 | 
			
		||||
  const newLineData = [...lineData];
 | 
			
		||||
  const lastPoint = lineData[lineData.length - 1];
 | 
			
		||||
  const secondLastPoint = lineData[lineData.length - 2];
 | 
			
		||||
@@ -344,6 +345,9 @@ const adjustForArrowHeads = function (lineData, size = 5) {
 | 
			
		||||
    (lastPoint.x - secondLastPoint.x) ** 2 + (lastPoint.y - secondLastPoint.y) ** 2
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  if (shouldLog) {
 | 
			
		||||
    log.debug('APA14 distanceBetweenLastPoints', distanceBetweenLastPoints);
 | 
			
		||||
  }
 | 
			
		||||
  if (distanceBetweenLastPoints < size) {
 | 
			
		||||
    // Calculate the direction vector from the last point to the second last point
 | 
			
		||||
    const directionX = secondLastPoint.x - lastPoint.x;
 | 
			
		||||
@@ -366,6 +370,195 @@ const adjustForArrowHeads = function (lineData, size = 5) {
 | 
			
		||||
 | 
			
		||||
  return newLineData;
 | 
			
		||||
};
 | 
			
		||||
function extractCornerPoints(points) {
 | 
			
		||||
  const cornerPoints = [];
 | 
			
		||||
  const cornerPointPositions = [];
 | 
			
		||||
  for (let i = 1; i < points.length - 1; i++) {
 | 
			
		||||
    const prev = points[i - 1];
 | 
			
		||||
    const curr = points[i];
 | 
			
		||||
    const next = points[i + 1];
 | 
			
		||||
    if (
 | 
			
		||||
      prev.x === curr.x &&
 | 
			
		||||
      curr.y === next.y &&
 | 
			
		||||
      Math.abs(curr.x - next.x) > 5 &&
 | 
			
		||||
      Math.abs(curr.y - prev.y) > 5
 | 
			
		||||
    ) {
 | 
			
		||||
      cornerPoints.push(curr);
 | 
			
		||||
      cornerPointPositions.push(i);
 | 
			
		||||
    } else if (
 | 
			
		||||
      prev.y === curr.y &&
 | 
			
		||||
      curr.x === next.x &&
 | 
			
		||||
      Math.abs(curr.x - prev.x) > 5 &&
 | 
			
		||||
      Math.abs(curr.y - next.y) > 5
 | 
			
		||||
    ) {
 | 
			
		||||
      cornerPoints.push(curr);
 | 
			
		||||
      cornerPointPositions.push(i);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return { cornerPoints, cornerPointPositions };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const findAdjacentPoint = function (pointA, pointB, distance) {
 | 
			
		||||
  const xDiff = pointB.x - pointA.x;
 | 
			
		||||
  const yDiff = pointB.y - pointA.y;
 | 
			
		||||
  const length = Math.sqrt(xDiff * xDiff + yDiff * yDiff);
 | 
			
		||||
  const ratio = distance / length;
 | 
			
		||||
  return { x: pointB.x - ratio * xDiff, y: pointB.y - ratio * yDiff };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const fixCorners = function (lineData) {
 | 
			
		||||
  const { cornerPointPositions } = extractCornerPoints(lineData);
 | 
			
		||||
  const newLineData = [];
 | 
			
		||||
  for (let i = 0; i < lineData.length; i++) {
 | 
			
		||||
    if (cornerPointPositions.includes(i)) {
 | 
			
		||||
      const prevPoint = lineData[i - 1];
 | 
			
		||||
      const nextPoint = lineData[i + 1];
 | 
			
		||||
      const cornerPoint = lineData[i];
 | 
			
		||||
 | 
			
		||||
      const newPrevPoint = findAdjacentPoint(prevPoint, cornerPoint, 5);
 | 
			
		||||
      const newNextPoint = findAdjacentPoint(nextPoint, cornerPoint, 5);
 | 
			
		||||
 | 
			
		||||
      const xDiff = newNextPoint.x - newPrevPoint.x;
 | 
			
		||||
      const yDiff = newNextPoint.y - newPrevPoint.y;
 | 
			
		||||
      newLineData.push(newPrevPoint);
 | 
			
		||||
 | 
			
		||||
      const a = Math.sqrt(2) * 2;
 | 
			
		||||
      let newCornerPoint = { x: cornerPoint.x, y: cornerPoint.y };
 | 
			
		||||
      if (Math.abs(nextPoint.x - prevPoint.x) > 10 && Math.abs(nextPoint.y - prevPoint.y) >= 10) {
 | 
			
		||||
        log.debug(
 | 
			
		||||
          'Corner point fixing',
 | 
			
		||||
          Math.abs(nextPoint.x - prevPoint.x),
 | 
			
		||||
          Math.abs(nextPoint.y - prevPoint.y)
 | 
			
		||||
        );
 | 
			
		||||
        const r = 5;
 | 
			
		||||
        if (cornerPoint.x === newPrevPoint.x) {
 | 
			
		||||
          newCornerPoint = {
 | 
			
		||||
            x: xDiff < 0 ? newPrevPoint.x - r + a : newPrevPoint.x + r - a,
 | 
			
		||||
            y: yDiff < 0 ? newPrevPoint.y - a : newPrevPoint.y + a,
 | 
			
		||||
          };
 | 
			
		||||
        } else {
 | 
			
		||||
          newCornerPoint = {
 | 
			
		||||
            x: xDiff < 0 ? newPrevPoint.x - a : newPrevPoint.x + a,
 | 
			
		||||
            y: yDiff < 0 ? newPrevPoint.y - r + a : newPrevPoint.y + r - a,
 | 
			
		||||
          };
 | 
			
		||||
        }
 | 
			
		||||
      } else {
 | 
			
		||||
        log.debug(
 | 
			
		||||
          'Corner point skipping fixing',
 | 
			
		||||
          Math.abs(nextPoint.x - prevPoint.x),
 | 
			
		||||
          Math.abs(nextPoint.y - prevPoint.y)
 | 
			
		||||
        );
 | 
			
		||||
      }
 | 
			
		||||
      newLineData.push(newCornerPoint, newNextPoint);
 | 
			
		||||
    } else {
 | 
			
		||||
      newLineData.push(lineData[i]);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return newLineData;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const generateRoundedPath = (points, radius, endPosition) => {
 | 
			
		||||
  if (points.length < 2) {
 | 
			
		||||
    return '';
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // console.trace('here', points);
 | 
			
		||||
  const path = [];
 | 
			
		||||
  const startPoint = points[0];
 | 
			
		||||
 | 
			
		||||
  path.push(`M ${startPoint.x},${startPoint.y}`);
 | 
			
		||||
 | 
			
		||||
  for (let i = 1; i < points.length - 1; i++) {
 | 
			
		||||
    const currPoint = points[i];
 | 
			
		||||
    const nextPoint = points[i + 1];
 | 
			
		||||
    const prevPoint = points[i - 1];
 | 
			
		||||
 | 
			
		||||
    // Calculate vectors
 | 
			
		||||
    const v1 = { x: currPoint.x - prevPoint.x, y: currPoint.y - prevPoint.y };
 | 
			
		||||
    const v2 = { x: nextPoint.x - currPoint.x, y: nextPoint.y - currPoint.y };
 | 
			
		||||
 | 
			
		||||
    // Normalize vectors
 | 
			
		||||
    const v1Length = Math.hypot(v1.x, v1.y);
 | 
			
		||||
    const v2Length = Math.hypot(v2.x, v2.y);
 | 
			
		||||
    const v1Normalized = { x: v1.x / v1Length, y: v1.y / v1Length };
 | 
			
		||||
    const v2Normalized = { x: v2.x / v2Length, y: v2.y / v2Length };
 | 
			
		||||
 | 
			
		||||
    // Calculate tangent points
 | 
			
		||||
    const tangentLength = Math.min(radius, v1Length / 2, v2Length / 2);
 | 
			
		||||
    const tangent1 = {
 | 
			
		||||
      x: currPoint.x - v1Normalized.x * tangentLength,
 | 
			
		||||
      y: currPoint.y - v1Normalized.y * tangentLength,
 | 
			
		||||
    };
 | 
			
		||||
    const tangent2 = {
 | 
			
		||||
      x: currPoint.x + v2Normalized.x * tangentLength,
 | 
			
		||||
      y: currPoint.y + v2Normalized.y * tangentLength,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    if (endPosition) {
 | 
			
		||||
      const { bottomY, leftX, rightX, topY } = endPosition;
 | 
			
		||||
      if (startPoint.pos === 'b' && tangent1.y > topY) {
 | 
			
		||||
        tangent1.y = topY;
 | 
			
		||||
        tangent2.y = topY;
 | 
			
		||||
        currPoint.y = topY;
 | 
			
		||||
      }
 | 
			
		||||
      if (startPoint.pos === 't' && tangent1.y < bottomY) {
 | 
			
		||||
        tangent1.y = bottomY;
 | 
			
		||||
        tangent2.y = bottomY;
 | 
			
		||||
        currPoint.y = bottomY;
 | 
			
		||||
      }
 | 
			
		||||
      if (startPoint.pos === 'l' && tangent1.x < rightX) {
 | 
			
		||||
        tangent1.x = rightX;
 | 
			
		||||
        tangent2.x = rightX;
 | 
			
		||||
        currPoint.x = rightX;
 | 
			
		||||
      }
 | 
			
		||||
      if (startPoint.pos === 'r' && tangent1.x > leftX) {
 | 
			
		||||
        tangent1.x = leftX;
 | 
			
		||||
        tangent2.x = leftX;
 | 
			
		||||
        currPoint.x = leftX;
 | 
			
		||||
      }
 | 
			
		||||
      if (tangent2.x && tangent2.y && tangent1.x && tangent1.y) {
 | 
			
		||||
        path.push(
 | 
			
		||||
          `L ${tangent1.x},${tangent1.y}`,
 | 
			
		||||
          `Q ${currPoint.x},${currPoint.y} ${tangent2.x},${tangent2.y}`
 | 
			
		||||
        );
 | 
			
		||||
      }
 | 
			
		||||
    } else {
 | 
			
		||||
      if (tangent2.x && tangent2.y && tangent1.x && tangent1.y) {
 | 
			
		||||
        path.push(
 | 
			
		||||
          `L ${tangent1.x},${tangent1.y}`,
 | 
			
		||||
          `Q ${currPoint.x},${currPoint.y} ${tangent2.x},${tangent2.y}`
 | 
			
		||||
        );
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  // Last point
 | 
			
		||||
  const lastPoint = points[points.length - 1];
 | 
			
		||||
  if (endPosition) {
 | 
			
		||||
    if (startPoint.pos === 'b') {
 | 
			
		||||
      if (endPosition?.topY && points[1].y > endPosition?.topY && points[2].y > endPosition?.topY) {
 | 
			
		||||
        points[1].y = endPosition?.topY;
 | 
			
		||||
        points[2].y = endPosition?.topY;
 | 
			
		||||
      }
 | 
			
		||||
      path.push(`L ${lastPoint.x},${endPosition.topY}`);
 | 
			
		||||
    }
 | 
			
		||||
    if (startPoint.pos === 't') {
 | 
			
		||||
      if (points[1].y < endPosition.bottomY) {
 | 
			
		||||
        points[1].y = endPosition.bottomY;
 | 
			
		||||
        points[2].y = endPosition.bottomY;
 | 
			
		||||
      }
 | 
			
		||||
      path.push(`L ${lastPoint.x},${endPosition.bottomY}`);
 | 
			
		||||
    }
 | 
			
		||||
    if (startPoint.pos === 'l') {
 | 
			
		||||
      path.push(`L ${endPosition.rightX},${lastPoint.y}`);
 | 
			
		||||
    }
 | 
			
		||||
    if (startPoint.pos === 'r') {
 | 
			
		||||
      path.push(`L ${endPosition.leftX},${lastPoint.y}`);
 | 
			
		||||
    }
 | 
			
		||||
  } else {
 | 
			
		||||
    path.push(`L ${lastPoint.x},${lastPoint.y}`);
 | 
			
		||||
  }
 | 
			
		||||
  return path.join(' ');
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const insertEdge = function (elem, edge, clusterDb, diagramType, startNode, endNode, id) {
 | 
			
		||||
  const { handDrawnSeed } = getConfig();
 | 
			
		||||
@@ -407,8 +600,12 @@ export const insertEdge = function (elem, edge, clusterDb, diagramType, startNod
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  let lineData = points.filter((p) => !Number.isNaN(p.y));
 | 
			
		||||
  lineData = adjustForArrowHeads(lineData);
 | 
			
		||||
  // lineData = fixCorners(lineData);
 | 
			
		||||
  lineData = adjustForArrowHeads(lineData, 4, edge.id === 'L_n4_C_10_0');
 | 
			
		||||
  lineData = fixCorners(lineData);
 | 
			
		||||
  // if (edge.id === 'L_n4_C_10_0') {
 | 
			
		||||
  //   console.log('APA14 lineData', lineData);
 | 
			
		||||
  // }
 | 
			
		||||
  // lineData = adjustForArrowHeads(lineData);
 | 
			
		||||
  let curve = curveBasis;
 | 
			
		||||
  // let curve = curveLinear;
 | 
			
		||||
  if (edge.curve) {
 | 
			
		||||
@@ -417,6 +614,7 @@ export const insertEdge = function (elem, edge, clusterDb, diagramType, startNod
 | 
			
		||||
 | 
			
		||||
  const { x, y } = getLineFunctionsWithOffset(edge);
 | 
			
		||||
  const lineFunction = line().x(x).y(y).curve(curve);
 | 
			
		||||
  // const lineFunction = line().curve(curve);
 | 
			
		||||
 | 
			
		||||
  let strokeClasses;
 | 
			
		||||
  switch (edge.thickness) {
 | 
			
		||||
@@ -447,6 +645,7 @@ export const insertEdge = function (elem, edge, clusterDb, diagramType, startNod
 | 
			
		||||
  }
 | 
			
		||||
  let svgPath;
 | 
			
		||||
  let linePath = lineFunction(lineData);
 | 
			
		||||
  // let linePath = generateRoundedPath(lineData, 5);
 | 
			
		||||
  const edgeStyles = Array.isArray(edge.style) ? edge.style : [edge.style];
 | 
			
		||||
  if (edge.look === 'handDrawn') {
 | 
			
		||||
    const rc = rough.svg(elem);
 | 
			
		||||
@@ -478,16 +677,7 @@ export const insertEdge = function (elem, edge, clusterDb, diagramType, startNod
 | 
			
		||||
 | 
			
		||||
  // DEBUG code, DO NOT REMOVE
 | 
			
		||||
  // adds a red circle at each edge coordinate
 | 
			
		||||
  // cornerPoints.forEach((point) => {
 | 
			
		||||
  //   elem
 | 
			
		||||
  //     .append('circle')
 | 
			
		||||
  //     .style('stroke', 'blue')
 | 
			
		||||
  //     .style('fill', 'blue')
 | 
			
		||||
  //     .attr('r', 3)
 | 
			
		||||
  //     .attr('cx', point.x)
 | 
			
		||||
  //     .attr('cy', point.y);
 | 
			
		||||
  // });
 | 
			
		||||
  // lineData.forEach((point) => {
 | 
			
		||||
  // points.forEach((point) => {
 | 
			
		||||
  //   elem
 | 
			
		||||
  //     .append('circle')
 | 
			
		||||
  //     .style('stroke', 'red')
 | 
			
		||||
 
 | 
			
		||||
@@ -57,7 +57,7 @@ function intersectLine(p1, p2, q1, q2) {
 | 
			
		||||
    num = a2 * c1 - a1 * c2;
 | 
			
		||||
    const y = num < 0 ? (num - offset) / denom : (num + offset) / denom;
 | 
			
		||||
    // console.log(
 | 
			
		||||
    //   'APA30 intersectLine intersection',
 | 
			
		||||
    //   'APA13 intersectLine intersection',
 | 
			
		||||
    //   '\np1: (',
 | 
			
		||||
    //   p1.x,
 | 
			
		||||
    //   p1.y,
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@ import intersectLine from './intersect-line.js';
 | 
			
		||||
function intersectPolygon(node, polyPoints, point) {
 | 
			
		||||
  let x1 = node.x;
 | 
			
		||||
  let y1 = node.y;
 | 
			
		||||
 | 
			
		||||
  // console.trace('APA14 intersectPolygon', x1, y1, polyPoints, point);
 | 
			
		||||
  let intersections = [];
 | 
			
		||||
 | 
			
		||||
  let minX = Number.POSITIVE_INFINITY;
 | 
			
		||||
@@ -24,7 +24,7 @@ function intersectPolygon(node, polyPoints, point) {
 | 
			
		||||
 | 
			
		||||
  let left = x1 - node.width / 2 - minX;
 | 
			
		||||
  let top = y1 - node.height / 2 - minY;
 | 
			
		||||
 | 
			
		||||
  // console.log('APA13 intersectPolygon2 ', left, y1);
 | 
			
		||||
  for (let i = 0; i < polyPoints.length; i++) {
 | 
			
		||||
    let p1 = polyPoints[i];
 | 
			
		||||
    let p2 = polyPoints[i < polyPoints.length - 1 ? i + 1 : 0];
 | 
			
		||||
@@ -34,7 +34,9 @@ function intersectPolygon(node, polyPoints, point) {
 | 
			
		||||
      { x: left + p1.x, y: top + p1.y },
 | 
			
		||||
      { x: left + p2.x, y: top + p2.y }
 | 
			
		||||
    );
 | 
			
		||||
    // console.log('APA13 intersectPolygon3 ', intersect);
 | 
			
		||||
    if (intersect) {
 | 
			
		||||
      // console.log('APA13 intersectPolygon4 ', intersect);
 | 
			
		||||
      intersections.push(intersect);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
@@ -42,6 +44,7 @@ function intersectPolygon(node, polyPoints, point) {
 | 
			
		||||
  if (!intersections.length) {
 | 
			
		||||
    return node;
 | 
			
		||||
  }
 | 
			
		||||
  // console.log('APA12 intersectPolygon5 ');
 | 
			
		||||
 | 
			
		||||
  if (intersections.length > 1) {
 | 
			
		||||
    // More intersections, find the one nearest to edge end point
 | 
			
		||||
@@ -54,6 +57,8 @@ function intersectPolygon(node, polyPoints, point) {
 | 
			
		||||
      let qdy = q.y - point.y;
 | 
			
		||||
      let distq = Math.sqrt(qdx * qdx + qdy * qdy);
 | 
			
		||||
 | 
			
		||||
      // console.log('APA12 intersectPolygon6 ');
 | 
			
		||||
 | 
			
		||||
      return distp < distq ? -1 : distp === distq ? 0 : 1;
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -66,7 +66,9 @@ export async function card<T extends SVGGraphicsElement>(parent: D3Selection<T>,
 | 
			
		||||
    const w = bounds.width;
 | 
			
		||||
 | 
			
		||||
    const points = getPoints(w, h, padding);
 | 
			
		||||
    return intersect.polygon(bounds, points, point);
 | 
			
		||||
 | 
			
		||||
    const res = intersect.polygon(bounds, points, point);
 | 
			
		||||
    return { x: res.x - 0.5, y: res.y - 0.5 };
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
 
 | 
			
		||||
@@ -61,9 +61,7 @@ export function forkJoin<T extends SVGGraphicsElement>(
 | 
			
		||||
    node.height += padding / 2 || 0;
 | 
			
		||||
  }
 | 
			
		||||
  node.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    // TODO: Implement intersect for this shape
 | 
			
		||||
    const radius = bounds.width / 2;
 | 
			
		||||
    return intersect.circle(bounds, radius, point);
 | 
			
		||||
    return intersect.rect(bounds, point);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
 
 | 
			
		||||
@@ -51,13 +51,58 @@ export async function lean_right<T extends SVGGraphicsElement>(parent: D3Selecti
 | 
			
		||||
  updateNodeBounds(node, polygon);
 | 
			
		||||
 | 
			
		||||
  node.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    // TODO: Implement intersect for this shape
 | 
			
		||||
    const radius = bounds.width / 2;
 | 
			
		||||
    return intersect.circle(bounds, radius, point);
 | 
			
		||||
    const w = bounds.width;
 | 
			
		||||
    const h = bounds.height;
 | 
			
		||||
    const dx = h / 2;
 | 
			
		||||
    const z = w - h;
 | 
			
		||||
    // (w = dx+z+dx)
 | 
			
		||||
    const points = [
 | 
			
		||||
      { x: -dx, y: 0 },
 | 
			
		||||
      { x: z, y: 0 },
 | 
			
		||||
      { x: z + dx, y: -h },
 | 
			
		||||
      { x: 0, y: -h },
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    const res = intersect.polygon(bounds, points, point);
 | 
			
		||||
    // if (node.id === 'C') {
 | 
			
		||||
    //   console.log(
 | 
			
		||||
    //     'APA14!',
 | 
			
		||||
    //     bounds.x,
 | 
			
		||||
    //     bounds.x,
 | 
			
		||||
    //     bounds.width,
 | 
			
		||||
    //     '\nw:',
 | 
			
		||||
    //     w,
 | 
			
		||||
    //     points,
 | 
			
		||||
    //     '\nExternal point: ',
 | 
			
		||||
    //     '(',
 | 
			
		||||
    //     point.x,
 | 
			
		||||
    //     point.y,
 | 
			
		||||
    //     ')\nIntersection:',
 | 
			
		||||
    //     res
 | 
			
		||||
    //   );
 | 
			
		||||
    // }
 | 
			
		||||
    return { x: res.x - 0.5, y: res.y - 0.5 };
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
    return intersect.polygon(node, points, point);
 | 
			
		||||
  node.intersect = function (point: Point) {
 | 
			
		||||
    const res = intersect.polygon(node, points, point);
 | 
			
		||||
    // if (node.id === 'C') {
 | 
			
		||||
    //   console.log(
 | 
			
		||||
    //     'APA14!!',
 | 
			
		||||
    //     node.x,
 | 
			
		||||
    //     node.y,
 | 
			
		||||
    //     '\nw:',
 | 
			
		||||
    //     node.width,
 | 
			
		||||
    //     points,
 | 
			
		||||
    //     '\nExternal point: ',
 | 
			
		||||
    //     '(',
 | 
			
		||||
    //     point.x,
 | 
			
		||||
    //     point.y,
 | 
			
		||||
    //     ')\nIntersection:',
 | 
			
		||||
    //     res
 | 
			
		||||
    //   );
 | 
			
		||||
    // }
 | 
			
		||||
    return res;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return shapeSvg;
 | 
			
		||||
 
 | 
			
		||||
@@ -12,6 +12,14 @@ import rough from 'roughjs';
 | 
			
		||||
import type { D3Selection } from '../../../types.js';
 | 
			
		||||
import type { Bounds, Point } from '../../../types.js';
 | 
			
		||||
 | 
			
		||||
function getPoints(w: number, finalH: number, waveAmplitude: number) {
 | 
			
		||||
  return [
 | 
			
		||||
    { x: -w / 2, y: finalH / 2 },
 | 
			
		||||
    ...generateFullSineWavePoints(-w / 2, finalH / 2, w / 2, finalH / 2, waveAmplitude, 1),
 | 
			
		||||
    { x: w / 2, y: -finalH / 2 },
 | 
			
		||||
    ...generateFullSineWavePoints(w / 2, -finalH / 2, -w / 2, -finalH / 2, waveAmplitude, -1),
 | 
			
		||||
  ];
 | 
			
		||||
}
 | 
			
		||||
export async function waveRectangle<T extends SVGGraphicsElement>(
 | 
			
		||||
  parent: D3Selection<T>,
 | 
			
		||||
  node: Node
 | 
			
		||||
@@ -53,12 +61,7 @@ export async function waveRectangle<T extends SVGGraphicsElement>(
 | 
			
		||||
    options.fillStyle = 'solid';
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const points = [
 | 
			
		||||
    { x: -w / 2, y: finalH / 2 },
 | 
			
		||||
    ...generateFullSineWavePoints(-w / 2, finalH / 2, w / 2, finalH / 2, waveAmplitude, 1),
 | 
			
		||||
    { x: w / 2, y: -finalH / 2 },
 | 
			
		||||
    ...generateFullSineWavePoints(w / 2, -finalH / 2, -w / 2, -finalH / 2, waveAmplitude, -1),
 | 
			
		||||
  ];
 | 
			
		||||
  const points = getPoints(w, finalH, waveAmplitude);
 | 
			
		||||
 | 
			
		||||
  const waveRectPath = createPathFromPoints(points);
 | 
			
		||||
  const waveRectNode = rc.path(waveRectPath, options);
 | 
			
		||||
@@ -78,9 +81,14 @@ export async function waveRectangle<T extends SVGGraphicsElement>(
 | 
			
		||||
  updateNodeBounds(node, waveRect);
 | 
			
		||||
 | 
			
		||||
  node.calcIntersect = function (bounds: Bounds, point: Point) {
 | 
			
		||||
    // TODO: Implement intersect for this shape
 | 
			
		||||
    const radius = bounds.width / 2;
 | 
			
		||||
    return intersect.circle(bounds, radius, point);
 | 
			
		||||
    const w = bounds.width;
 | 
			
		||||
    const h = bounds.height;
 | 
			
		||||
 | 
			
		||||
    const waveAmplitude = Math.min(h * 0.2, h / 4);
 | 
			
		||||
    const finalH = h + waveAmplitude * 2;
 | 
			
		||||
 | 
			
		||||
    const points = getPoints(w, finalH, waveAmplitude);
 | 
			
		||||
    return intersect.polygon(node, points, point);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  node.intersect = function (point) {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user