mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-10-08 08:39:38 +02:00
fix: node label positioning in mindmap nodes
on-behalf-of: @Mermaid-Chart <hello@mermaidchart.com>
This commit is contained in:
@@ -8,6 +8,8 @@ import { handleUndefinedAttr } from '../../../utils.js';
|
||||
import type { Bounds, Point } from '../../../types.js';
|
||||
import rough from 'roughjs';
|
||||
|
||||
const ICON_SIZE = 30;
|
||||
const ICON_PADDING = 1;
|
||||
export async function bang<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
|
||||
const { labelStyles, nodeStyles } = styles2String(node);
|
||||
node.labelStyle = labelStyles;
|
||||
@@ -20,9 +22,6 @@ export async function bang<T extends SVGGraphicsElement>(parent: D3Selection<T>,
|
||||
let w = bbox.width + 10 * halfPadding;
|
||||
let h = bbox.height + 8 * halfPadding;
|
||||
|
||||
const ICON_SIZE = 30;
|
||||
const ICON_PADDING = 1;
|
||||
|
||||
if (node.icon) {
|
||||
const minWidthWithIcon = bbox.width + ICON_SIZE + ICON_PADDING * 2 + 10 * halfPadding;
|
||||
w = Math.max(w, minWidthWithIcon);
|
||||
@@ -42,10 +41,9 @@ export async function bang<T extends SVGGraphicsElement>(parent: D3Selection<T>,
|
||||
const iconSpace = ICON_SIZE + ICON_PADDING;
|
||||
const remainingWidth = effectiveWidth - iconSpace;
|
||||
labelXOffset = -effectiveWidth / 2 + iconSpace + (remainingWidth - bbox.width) / 2;
|
||||
label.attr('transform', `translate(${labelXOffset}, ${-bbox.height / 2})`);
|
||||
}
|
||||
|
||||
label.attr('transform', `translate(${labelXOffset}, ${-bbox.height / 2})`);
|
||||
|
||||
const r = 0.15 * effectiveWidth;
|
||||
let bangElem;
|
||||
const path = `M0 0
|
||||
|
@@ -6,6 +6,10 @@ import intersect from '../intersect/index.js';
|
||||
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
||||
import { getNodeClasses, labelHelper, updateNodeBounds } from './util.js';
|
||||
import rough from 'roughjs';
|
||||
|
||||
const ICON_SIZE = 30;
|
||||
const ICON_PADDING = 20;
|
||||
|
||||
export async function circle<T extends SVGGraphicsElement>(
|
||||
parent: D3Selection<T>,
|
||||
node: Node,
|
||||
@@ -21,27 +25,20 @@ export async function circle<T extends SVGGraphicsElement>(
|
||||
);
|
||||
|
||||
const padding = options?.padding ?? halfPadding;
|
||||
const ICON_SIZE = 30;
|
||||
const ICON_PADDING = 15;
|
||||
|
||||
let radius = bbox.width / 2 + padding;
|
||||
let labelXOffset = -bbox.width / 2;
|
||||
const labelYOffset = -bbox.height / 2;
|
||||
|
||||
if (node.icon) {
|
||||
const totalWidthNeeded = bbox.width + ICON_SIZE + ICON_PADDING * 2;
|
||||
const minRadiusWithIcon = totalWidthNeeded / 2 + padding;
|
||||
radius = Math.max(radius, minRadiusWithIcon);
|
||||
labelXOffset = -radius + ICON_SIZE + ICON_PADDING;
|
||||
label.attr('transform', `translate(${labelXOffset}, ${labelYOffset})`);
|
||||
}
|
||||
|
||||
node.width = radius * 2;
|
||||
node.height = radius * 2;
|
||||
|
||||
let labelXOffset = -bbox.width / 2;
|
||||
if (node.icon) {
|
||||
labelXOffset = -radius + ICON_SIZE + ICON_PADDING;
|
||||
}
|
||||
const labelYOffset = -bbox.height / 2;
|
||||
label.attr('transform', `translate(${labelXOffset}, ${labelYOffset})`);
|
||||
|
||||
let circleElem;
|
||||
|
||||
if (node.look === 'handDrawn') {
|
||||
|
@@ -6,6 +6,9 @@ import intersect from '../intersect/index.js';
|
||||
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
||||
import { getNodeClasses, labelHelper, updateNodeBounds } from './util.js';
|
||||
import rough from 'roughjs';
|
||||
|
||||
const ICON_SIZE = 30;
|
||||
const ICON_PADDING = 15;
|
||||
export async function cloud<T extends SVGGraphicsElement>(parent: D3Selection<T>, node: Node) {
|
||||
const { labelStyles, nodeStyles } = styles2String(node);
|
||||
node.labelStyle = labelStyles;
|
||||
@@ -16,13 +19,11 @@ export async function cloud<T extends SVGGraphicsElement>(parent: D3Selection<T>
|
||||
getNodeClasses(node)
|
||||
);
|
||||
|
||||
const ICON_SIZE = 30;
|
||||
const ICON_PADDING = 15;
|
||||
|
||||
let w = bbox.width + 2 * halfPadding;
|
||||
let h = bbox.height + 2 * halfPadding;
|
||||
|
||||
let labelXOffset = -bbox.width / 2;
|
||||
const labelYOffset = -bbox.height / 2;
|
||||
if (node.icon) {
|
||||
const minWidthWithIcon = bbox.width + ICON_SIZE + ICON_PADDING * 2 + 2 * halfPadding;
|
||||
w = Math.max(w, minWidthWithIcon);
|
||||
@@ -33,14 +34,12 @@ export async function cloud<T extends SVGGraphicsElement>(parent: D3Selection<T>
|
||||
|
||||
const availableTextSpace = w - ICON_SIZE - ICON_PADDING * 2;
|
||||
labelXOffset = -w / 2 + ICON_SIZE + ICON_PADDING + availableTextSpace / 2 - bbox.width / 2;
|
||||
label.attr('transform', `translate(${labelXOffset}, ${labelYOffset})`);
|
||||
} else {
|
||||
node.width = w;
|
||||
node.height = h;
|
||||
}
|
||||
|
||||
const labelYOffset = -bbox.height / 2;
|
||||
label.attr('transform', `translate(${labelXOffset}, ${labelYOffset})`);
|
||||
|
||||
// Cloud radii
|
||||
const r1 = 0.15 * w;
|
||||
const r2 = 0.25 * w;
|
||||
|
@@ -4,6 +4,9 @@ import intersect from '../intersect/index.js';
|
||||
import { styles2String } from './handDrawnShapeStyles.js';
|
||||
import { getNodeClasses, labelHelper, updateNodeBounds } from './util.js';
|
||||
|
||||
const ICON_SIZE = 30;
|
||||
const ICON_PADDING = 15;
|
||||
|
||||
export async function defaultMindmapNode<T extends SVGGraphicsElement>(
|
||||
parent: D3Selection<T>,
|
||||
node: Node
|
||||
@@ -20,9 +23,6 @@ export async function defaultMindmapNode<T extends SVGGraphicsElement>(
|
||||
let w = bbox.width + 8 * halfPadding;
|
||||
let h = bbox.height + 2 * halfPadding;
|
||||
|
||||
const ICON_SIZE = 30;
|
||||
const ICON_PADDING = 15;
|
||||
|
||||
if (node.icon) {
|
||||
const minWidthWithIcon = bbox.width + ICON_SIZE + ICON_PADDING * 2 + 8 * halfPadding;
|
||||
w = Math.max(w, minWidthWithIcon);
|
||||
|
@@ -8,6 +8,9 @@ import type { D3Selection } from '../../../types.js';
|
||||
import { handleUndefinedAttr } from '../../../utils.js';
|
||||
import type { Bounds, Point } from '../../../types.js';
|
||||
|
||||
const ICON_SIZE = 30;
|
||||
const ICON_PADDING = 10;
|
||||
|
||||
export async function drawRect<T extends SVGGraphicsElement>(
|
||||
parent: D3Selection<T>,
|
||||
node: Node,
|
||||
@@ -18,13 +21,11 @@ export async function drawRect<T extends SVGGraphicsElement>(
|
||||
|
||||
const { shapeSvg, bbox, label } = await labelHelper(parent, node, getNodeClasses(node));
|
||||
|
||||
const ICON_SIZE = 30;
|
||||
const ICON_PADDING = 10;
|
||||
|
||||
let totalWidth = Math.max(bbox.width + options.labelPaddingX * 2, node?.width || 0);
|
||||
let totalHeight = Math.max(bbox.height + options.labelPaddingY * 2, node?.height || 0);
|
||||
|
||||
let labelXOffset = -bbox.width / 2;
|
||||
const labelYOffset = -bbox.height / 2;
|
||||
|
||||
if (node.icon) {
|
||||
const minWidthWithIcon = bbox.width + ICON_SIZE + ICON_PADDING * 2 + options.labelPaddingX * 2;
|
||||
totalWidth = Math.max(totalWidth, minWidthWithIcon);
|
||||
@@ -36,12 +37,11 @@ export async function drawRect<T extends SVGGraphicsElement>(
|
||||
const availableTextSpace = totalWidth - ICON_SIZE - ICON_PADDING * 2;
|
||||
labelXOffset =
|
||||
-totalWidth / 2 + ICON_SIZE + ICON_PADDING + availableTextSpace / 2 - bbox.width / 2;
|
||||
label.attr('transform', `translate(${labelXOffset}, ${labelYOffset})`);
|
||||
} else {
|
||||
node.width = totalWidth;
|
||||
node.height = totalHeight;
|
||||
}
|
||||
const labelYOffset = -bbox.height / 2;
|
||||
label.attr('transform', `translate(${labelXOffset}, ${labelYOffset})`);
|
||||
const x = -totalWidth / 2;
|
||||
const y = -totalHeight / 2;
|
||||
|
||||
|
@@ -5,6 +5,9 @@ import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
||||
import type { D3Selection } from '../../../types.js';
|
||||
import rough from 'roughjs';
|
||||
|
||||
const ICON_SIZE = 30;
|
||||
const ICON_PADDING = 1;
|
||||
|
||||
export const createHexagonPathD = (
|
||||
x: number,
|
||||
y: number,
|
||||
@@ -28,12 +31,11 @@ export async function hexagon<T extends SVGGraphicsElement>(parent: D3Selection<
|
||||
node.labelStyle = labelStyles;
|
||||
const { shapeSvg, bbox, label } = await labelHelper(parent, node, getNodeClasses(node));
|
||||
|
||||
const ICON_SIZE = 30;
|
||||
const ICON_PADDING = 1;
|
||||
let h = bbox.height + (node.padding ?? 0);
|
||||
let w = bbox.width + (node.padding ?? 0) * 2.5;
|
||||
|
||||
let labelXOffset = -bbox.width / 2;
|
||||
const labelYOffset = -bbox.height / 2;
|
||||
if (node.icon) {
|
||||
const minWidthWithIcon = bbox.width + ICON_SIZE + ICON_PADDING * 2 + (node.padding ?? 0) * 2.5;
|
||||
w = Math.max(w, minWidthWithIcon);
|
||||
@@ -44,12 +46,11 @@ export async function hexagon<T extends SVGGraphicsElement>(parent: D3Selection<
|
||||
|
||||
const availableTextSpace = w - ICON_SIZE - ICON_PADDING * 2;
|
||||
labelXOffset = -w / 2 + ICON_SIZE + ICON_PADDING + availableTextSpace / 2 - bbox.width / 2;
|
||||
label.attr('transform', `translate(${labelXOffset}, ${labelYOffset})`);
|
||||
} else {
|
||||
node.width = w;
|
||||
node.height = h;
|
||||
}
|
||||
const labelYOffset = -bbox.height / 2;
|
||||
label.attr('transform', `translate(${labelXOffset}, ${labelYOffset})`);
|
||||
const { cssStyles } = node;
|
||||
// @ts-expect-error -- Passing a D3.Selection seems to work for some reason
|
||||
const rc = rough.svg(shapeSvg);
|
||||
|
@@ -85,6 +85,9 @@ export function generateArcPoints(
|
||||
return points;
|
||||
}
|
||||
|
||||
const ICON_SIZE = 30;
|
||||
const ICON_PADDING = 15;
|
||||
|
||||
export async function roundedRect<T extends SVGGraphicsElement>(
|
||||
parent: D3Selection<T>,
|
||||
node: Node
|
||||
@@ -99,9 +102,6 @@ export async function roundedRect<T extends SVGGraphicsElement>(
|
||||
let w = (node?.width ? node?.width : bbox.width) + labelPaddingX * 2;
|
||||
let h = (node?.height ? node?.height : bbox.height) + labelPaddingY * 2;
|
||||
|
||||
const ICON_SIZE = 30;
|
||||
const ICON_PADDING = 15;
|
||||
|
||||
let labelXOffset = -bbox.width / 2;
|
||||
|
||||
if (node.icon) {
|
||||
@@ -114,10 +114,9 @@ export async function roundedRect<T extends SVGGraphicsElement>(
|
||||
|
||||
const availableTextSpace = w - ICON_SIZE - ICON_PADDING * 2;
|
||||
labelXOffset = -w / 2 + ICON_SIZE + ICON_PADDING + availableTextSpace / 2 - bbox.width / 2;
|
||||
label.attr('transform', `translate(${labelXOffset}, ${-bbox.height / 2})`);
|
||||
}
|
||||
|
||||
label.attr('transform', `translate(${labelXOffset}, ${-bbox.height / 2})`);
|
||||
|
||||
const radius = node.radius || 5;
|
||||
const taper = node.taper || 5; // Taper width for the rounded corners
|
||||
const { cssStyles } = node;
|
||||
|
Reference in New Issue
Block a user