mermaid/packages/mermaid/src/dagre-wrapper/blockArrowHelper.ts

249 lines
7.0 KiB
TypeScript

import type { Direction } from '../../src/diagrams/block/blockTypes.js';
const expandAndDeduplicateDirections = (directions: Direction[]) => {
const uniqueDirections = new Set();
for (const direction of directions) {
switch (direction) {
case 'x':
uniqueDirections.add('right');
uniqueDirections.add('left');
break;
case 'y':
uniqueDirections.add('up');
uniqueDirections.add('down');
break;
default:
uniqueDirections.add(direction);
break;
}
}
return uniqueDirections;
};
export const getArrowPoints = (
duplicatedDirections: Direction[],
bbox: { width: number; height: number },
node: any
) => {
// Expand and deduplicate the provided directions.
// for instance: x, right => right, left
const directions = expandAndDeduplicateDirections(duplicatedDirections);
// Factor to divide height for some calculations.
const f = 2;
// Calculated height of the bounding box, accounting for node padding.
const height = bbox.height + 2 * node.padding;
// Midpoint calculation based on height.
const midpoint = height / f;
// Calculated width of the bounding box, accounting for additional width and node padding.
const width = bbox.width + 2 * midpoint + node.padding;
// Padding to use, half of the node padding.
const padding = node.padding / 2;
// Initialize an empty array to store points for the arrow.
const points = [];
if (
directions.has('right') &&
directions.has('left') &&
directions.has('up') &&
directions.has('down')
) {
// SQUARE
return [
// Bottom
{ x: 0, y: 0 },
{ x: midpoint, y: 0 },
{ x: width / 2, y: 2 * padding },
{ x: width - midpoint, y: 0 },
{ x: width, y: 0 },
// Right
{ x: width, y: -height / 3 },
{ x: width + 2 * padding, y: -height / 2 },
{ x: width, y: (-2 * height) / 3 },
{ x: width, y: -height },
// Top
{ x: width - midpoint, y: -height },
{ x: width / 2, y: -height - 2 * padding },
{ x: midpoint, y: -height },
// Left
{ x: 0, y: -height },
{ x: 0, y: (-2 * height) / 3 },
{ x: -2 * padding, y: -height / 2 },
{ x: 0, y: -height / 3 },
];
}
if (directions.has('right') && directions.has('left') && directions.has('up')) {
// RECTANGLE_VERTICAL (Top Open)
return [
{ x: midpoint, y: 0 },
{ x: width - midpoint, y: 0 },
{ x: width, y: -height / 2 },
{ x: width - midpoint, y: -height },
{ x: midpoint, y: -height },
{ x: 0, y: -height / 2 },
];
}
if (directions.has('right') && directions.has('left') && directions.has('down')) {
// RECTANGLE_VERTICAL (Bottom Open)
return [
{ x: 0, y: 0 },
{ x: midpoint, y: -height },
{ x: width - midpoint, y: -height },
{ x: width, y: 0 },
];
}
if (directions.has('right') && directions.has('up') && directions.has('down')) {
// RECTANGLE_HORIZONTAL (Right Open)
return [
{ x: 0, y: 0 },
{ x: width, y: -midpoint },
{ x: width, y: -height + midpoint },
{ x: 0, y: -height },
];
}
if (directions.has('left') && directions.has('up') && directions.has('down')) {
// RECTANGLE_HORIZONTAL (Left Open)
return [
{ x: width, y: 0 },
{ x: 0, y: -midpoint },
{ x: 0, y: -height + midpoint },
{ x: width, y: -height },
];
}
if (directions.has('right') && directions.has('left')) {
// HORIZONTAL_LINE
return [
{ x: midpoint, y: 0 },
{ x: midpoint, y: -padding },
{ x: width - midpoint, y: -padding },
{ x: width - midpoint, y: 0 },
{ x: width, y: -height / 2 },
{ x: width - midpoint, y: -height },
{ x: width - midpoint, y: -height + padding },
{ x: midpoint, y: -height + padding },
{ x: midpoint, y: -height },
{ x: 0, y: -height / 2 },
];
}
if (directions.has('up') && directions.has('down')) {
// VERTICAL_LINE
return [
// Bottom center
{ x: width / 2, y: 0 },
// Left pont of bottom arrow
{ x: 0, y: -padding },
{ x: midpoint, y: -padding },
// Left top over vertical section
{ x: midpoint, y: -height + padding },
{ x: 0, y: -height + padding },
// Top of arrow
{ x: width / 2, y: -height },
{ x: width, y: -height + padding },
// Top of right vertical bar
{ x: width - midpoint, y: -height + padding },
{ x: width - midpoint, y: -padding },
{ x: width, y: -padding },
];
}
if (directions.has('right') && directions.has('up')) {
// ANGLE_RT
return [
{ x: 0, y: 0 },
{ x: width, y: -midpoint },
{ x: 0, y: -height },
];
}
if (directions.has('right') && directions.has('down')) {
// ANGLE_RB
return [
{ x: 0, y: 0 },
{ x: width, y: 0 },
{ x: 0, y: -height },
];
}
if (directions.has('left') && directions.has('up')) {
// ANGLE_LT
return [
{ x: width, y: 0 },
{ x: 0, y: -midpoint },
{ x: width, y: -height },
];
}
if (directions.has('left') && directions.has('down')) {
// ANGLE_LB
return [
{ x: width, y: 0 },
{ x: 0, y: 0 },
{ x: width, y: -height },
];
}
if (directions.has('right')) {
// ARROW_RIGHT
return [
{ x: midpoint, y: -padding },
{ x: midpoint, y: -padding },
{ x: width - midpoint, y: -padding },
{ x: width - midpoint, y: 0 },
{ x: width, y: -height / 2 },
{ x: width - midpoint, y: -height },
{ x: width - midpoint, y: -height + padding },
// top left corner of arrow
{ x: midpoint, y: -height + padding },
{ x: midpoint, y: -height + padding },
];
}
if (directions.has('left')) {
// ARROW_LEFT
return [
{ x: midpoint, y: 0 },
{ x: midpoint, y: -padding },
// Two points, the right corners
{ x: width - midpoint, y: -padding },
{ x: width - midpoint, y: -height + padding },
{ x: midpoint, y: -height + padding },
{ x: midpoint, y: -height },
{ x: 0, y: -height / 2 },
];
}
if (directions.has('up')) {
// ARROW_TOP
return [
// Bottom center
{ x: midpoint, y: -padding },
// Left top over vertical section
{ x: midpoint, y: -height + padding },
{ x: 0, y: -height + padding },
// Top of arrow
{ x: width / 2, y: -height },
{ x: width, y: -height + padding },
// Top of right vertical bar
{ x: width - midpoint, y: -height + padding },
{ x: width - midpoint, y: -padding },
];
}
if (directions.has('down')) {
// ARROW_BOTTOM
return [
// Bottom center
{ x: width / 2, y: 0 },
// Left pont of bottom arrow
{ x: 0, y: -padding },
{ x: midpoint, y: -padding },
// Left top over vertical section
{ x: midpoint, y: -height + padding },
{ x: width - midpoint, y: -height + padding },
{ x: width - midpoint, y: -padding },
{ x: width, y: -padding },
];
}
// POINT
return [{ x: 0, y: 0 }];
};