mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-09-19 15:30:03 +02:00
Added rounded icon shape
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
import { imgSnapshotTest } from '../../helpers/util';
|
import { imgSnapshotTest } from '../../helpers/util';
|
||||||
|
|
||||||
const looks = ['classic', 'handDrawn'] as const;
|
const looks = ['classic'] as const;
|
||||||
const directions = ['TB', 'BT', 'LR', 'RL'] as const;
|
const directions = ['TB'] as const;
|
||||||
const forms = [undefined, 'square', 'circle'] as const;
|
const forms = [undefined, 'square', 'circle'] as const;
|
||||||
const labelPos = [undefined, 't', 'b'] as const;
|
const labelPos = [undefined, 't', 'b'] as const;
|
||||||
|
|
||||||
|
@@ -62,32 +62,41 @@
|
|||||||
|
|
||||||
<body style="display: flex; gap: 2rem; flex-direction: row">
|
<body style="display: flex; gap: 2rem; flex-direction: row">
|
||||||
<pre id="diagram4" class="mermaid">
|
<pre id="diagram4" class="mermaid">
|
||||||
flowchart BT
|
flowchart TB
|
||||||
A --test2--> B2@{ icon: "fa:bell", form: "square", label: "B2 aiduaid uyawduad uaduabd uyduadb", pos: "b" }@
|
A --test2--> B2@{ icon: "fa:bell", form: "rounded", label: "B2 aiduaid uyawduad uaduabd uyduadb", pos: "b" }@
|
||||||
B2 --test--> C
|
B2 --test--> C
|
||||||
|
D --> B2 --> E
|
||||||
|
style B2 fill:#f9f,stroke:#333,stroke-width:4px
|
||||||
</pre
|
</pre
|
||||||
>
|
>
|
||||||
<pre id="diagram43" class="mermaid">
|
<pre id="diagram43" class="mermaid2">
|
||||||
flowchart BT
|
flowchart BT
|
||||||
A --test2--> B2@{ icon: "fa:bell", form: "square", label: "B2", pos: "t", h: 40, w: 30 }@
|
A --test2--> B2@{ icon: "fa:bell", form: "square", label: "B2", pos: "t", h: 40, w: 30 }@
|
||||||
B2 --test--> C
|
B2 --test--> C
|
||||||
|
D --> B2 --> E
|
||||||
</pre
|
</pre
|
||||||
>
|
>
|
||||||
<pre id="diagram4" class="mermaid">
|
<pre id="diagram4" class="mermaid2">
|
||||||
flowchart BT
|
flowchart BT
|
||||||
A --test2--> B2@{ icon: "fa:bell", label: "B2", pos: "b", h: 40, w: 30 }@
|
A --test2--> B2@{ icon: "fa:bell", label: "B2 awiugdawu uydgayuiwd wuydguy", pos: "b", h: 40, w: 30 }@
|
||||||
B2 --test--> C
|
B2 --test--> C
|
||||||
</pre
|
</pre
|
||||||
>
|
>
|
||||||
<pre id="diagram43" class="mermaid">
|
<pre id="diagram43" class="mermaid2">
|
||||||
flowchart BT
|
flowchart BT
|
||||||
A --test2--> B2@{ icon: "fa:bell", label: "B2", pos: "t", h: 40, w: 30 }@
|
A --test2--> B2@{ icon: "fa:bell", label: "B2 dawuygd ayuwgd uy", pos: "t", h: 40, w: 30 }@
|
||||||
B2 --test--> C
|
B2 --test--> C
|
||||||
</pre
|
</pre
|
||||||
>
|
>
|
||||||
<pre id="diagram6" class="mermaid2">
|
<pre id="diagram6" class="mermaid2">
|
||||||
flowchart
|
flowchart TB
|
||||||
A --> B2@{ icon: "fa:bell", label: "test augfuyfavf ydvaubfuac", pos: "t", w: 200, h: 100 }@ --> C
|
A --> B2@{ icon: "fa:bell", form: "circle", label: "test augfuyfavf ydvaubfuac", pos: "t", w: 200, h: 100 }@ --> C
|
||||||
|
</pre
|
||||||
|
>
|
||||||
|
<pre id="diagram6" class="mermaid2">
|
||||||
|
flowchart TB
|
||||||
|
A --> B2@{ icon: "fa:bell", form: "circle", label: "test augfuyfavf ydvaubfuac", pos: "b", w: 200, h: 100 }@ --> C
|
||||||
|
D --> B2 --> E
|
||||||
</pre
|
</pre
|
||||||
>
|
>
|
||||||
<script type="module">
|
<script type="module">
|
||||||
@@ -115,7 +124,7 @@
|
|||||||
mermaid.initialize({
|
mermaid.initialize({
|
||||||
// theme: 'base',
|
// theme: 'base',
|
||||||
// handdrawnSeed: 12,
|
// handdrawnSeed: 12,
|
||||||
// look: 'handDrawn',
|
look: 'classic',
|
||||||
// 'elk.nodePlacement.strategy': 'NETWORK_SIMPLEX',
|
// 'elk.nodePlacement.strategy': 'NETWORK_SIMPLEX',
|
||||||
// 'elk.nodePlacement.strategy': 'SIMPLE',
|
// 'elk.nodePlacement.strategy': 'SIMPLE',
|
||||||
// 'elk.nodePlacement.strategy': 'LAYERED',
|
// 'elk.nodePlacement.strategy': 'LAYERED',
|
||||||
@@ -124,7 +133,7 @@
|
|||||||
// layout: 'elk',
|
// layout: 'elk',
|
||||||
// layout: 'fixed',
|
// layout: 'fixed',
|
||||||
// htmlLabels: false,
|
// htmlLabels: false,
|
||||||
flowchart: { titleTopMargin: 10, padding: 50, htmlLables: false },
|
flowchart: { titleTopMargin: 10, htmlLables: true },
|
||||||
// fontFamily: 'Caveat',
|
// fontFamily: 'Caveat',
|
||||||
fontFamily: 'Kalam',
|
fontFamily: 'Kalam',
|
||||||
// fontFamily: 'courier',
|
// fontFamily: 'courier',
|
||||||
|
@@ -826,6 +826,9 @@ const getTypeFromVertex = (vertex: FlowVertex) => {
|
|||||||
if (vertex.form === 'square') {
|
if (vertex.form === 'square') {
|
||||||
return 'iconSquare';
|
return 'iconSquare';
|
||||||
}
|
}
|
||||||
|
if (vertex.form === 'rounded') {
|
||||||
|
return 'iconRounded';
|
||||||
|
}
|
||||||
return 'icon';
|
return 'icon';
|
||||||
}
|
}
|
||||||
if (vertex.type === 'square') {
|
if (vertex.type === 'square') {
|
||||||
|
@@ -55,6 +55,7 @@ import { iconSquare } from './shapes/iconSquare.js';
|
|||||||
import { iconCircle } from './shapes/iconCircle.js';
|
import { iconCircle } from './shapes/iconCircle.js';
|
||||||
import { icon } from './shapes/icon.js';
|
import { icon } from './shapes/icon.js';
|
||||||
import { imageSquare } from './shapes/imageSquare.js';
|
import { imageSquare } from './shapes/imageSquare.js';
|
||||||
|
import { iconRounded } from './shapes/iconRounded.js';
|
||||||
|
|
||||||
//Use these names as the left side to render shapes.
|
//Use these names as the left side to render shapes.
|
||||||
export const shapes = {
|
export const shapes = {
|
||||||
@@ -222,6 +223,7 @@ export const shapes = {
|
|||||||
iconSquare,
|
iconSquare,
|
||||||
iconCircle,
|
iconCircle,
|
||||||
icon,
|
icon,
|
||||||
|
iconRounded,
|
||||||
imageSquare,
|
imageSquare,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -10,7 +10,7 @@ import { getConfig } from '../../../diagram-api/diagramAPI.js';
|
|||||||
|
|
||||||
export const icon = async (parent: SVG, node: Node, dir: string) => {
|
export const icon = async (parent: SVG, node: Node, dir: string) => {
|
||||||
const translateHorizontal = dir === 'TB' || dir === 'BT' || dir === 'TD' || dir === 'DT';
|
const translateHorizontal = dir === 'TB' || dir === 'BT' || dir === 'TD' || dir === 'DT';
|
||||||
const { labelStyles, nodeStyles } = styles2String(node);
|
const { labelStyles } = styles2String(node);
|
||||||
node.labelStyle = labelStyles;
|
node.labelStyle = labelStyles;
|
||||||
const assetHeight = node.assetHeight ?? 48;
|
const assetHeight = node.assetHeight ?? 48;
|
||||||
const assetWidth = node.assetWidth ?? 48;
|
const assetWidth = node.assetWidth ?? 48;
|
||||||
@@ -18,7 +18,6 @@ export const icon = async (parent: SVG, node: Node, dir: string) => {
|
|||||||
const defaultWidth = getConfig()?.flowchart?.wrappingWidth;
|
const defaultWidth = getConfig()?.flowchart?.wrappingWidth;
|
||||||
node.width = Math.max(iconSize, defaultWidth ?? 0);
|
node.width = Math.max(iconSize, defaultWidth ?? 0);
|
||||||
const { shapeSvg, bbox, label } = await labelHelper(parent, node, 'icon-shape default');
|
const { shapeSvg, bbox, label } = await labelHelper(parent, node, 'icon-shape default');
|
||||||
const { cssStyles } = node;
|
|
||||||
|
|
||||||
const topLabel = node.pos === 't';
|
const topLabel = node.pos === 't';
|
||||||
|
|
||||||
@@ -64,14 +63,6 @@ export const icon = async (parent: SVG, node: Node, dir: string) => {
|
|||||||
iconShape.attr('transform', `translate(${0},${topLabel ? bbox.height / 2 : -bbox.height / 2})`);
|
iconShape.attr('transform', `translate(${0},${topLabel ? bbox.height / 2 : -bbox.height / 2})`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cssStyles && node.look !== 'handDrawn') {
|
|
||||||
iconShape.selectAll('path').attr('style', cssStyles);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nodeStyles && node.look !== 'handDrawn') {
|
|
||||||
iconShape.selectAll('path').attr('style', nodeStyles);
|
|
||||||
}
|
|
||||||
|
|
||||||
updateNodeBounds(node, shapeSvg);
|
updateNodeBounds(node, shapeSvg);
|
||||||
|
|
||||||
node.intersect = function (point) {
|
node.intersect = function (point) {
|
||||||
|
@@ -0,0 +1,92 @@
|
|||||||
|
import { log } from '../../../logger.js';
|
||||||
|
import { labelHelper, updateNodeBounds } from './util.js';
|
||||||
|
import type { Node } from '../../types.js';
|
||||||
|
import type { SVG } from '../../../diagram-api/types.js';
|
||||||
|
import { compileStyles, styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
||||||
|
import rough from 'roughjs';
|
||||||
|
import intersect from '../intersect/index.js';
|
||||||
|
import { getIconSVG } from '../../icons.js';
|
||||||
|
import { getConfig } from '../../../diagram-api/diagramAPI.js';
|
||||||
|
import { createRoundedRectPathD } from './roundedRectPath.js';
|
||||||
|
|
||||||
|
export const iconRounded = async (parent: SVG, node: Node, dir: string) => {
|
||||||
|
const translateHorizontal = dir === 'TB' || dir === 'BT' || dir === 'TD' || dir === 'DT';
|
||||||
|
const { labelStyles, nodeStyles } = styles2String(node);
|
||||||
|
node.labelStyle = labelStyles;
|
||||||
|
const assetHeight = node.assetHeight ?? 48;
|
||||||
|
const assetWidth = node.assetWidth ?? 48;
|
||||||
|
const iconSize = Math.max(assetHeight, assetWidth);
|
||||||
|
const defaultWidth = getConfig()?.flowchart?.wrappingWidth;
|
||||||
|
node.width = Math.max(iconSize, defaultWidth ?? 0);
|
||||||
|
const { shapeSvg, bbox, halfPadding, label } = await labelHelper(
|
||||||
|
parent,
|
||||||
|
node,
|
||||||
|
'icon-shape default'
|
||||||
|
);
|
||||||
|
const { cssStyles } = node;
|
||||||
|
|
||||||
|
const topLabel = node.pos === 't';
|
||||||
|
|
||||||
|
const height = iconSize + halfPadding * 2;
|
||||||
|
const width = iconSize + halfPadding * 2;
|
||||||
|
const { themeVariables } = getConfig();
|
||||||
|
const { mainBkg } = themeVariables;
|
||||||
|
const { stylesMap } = compileStyles(node);
|
||||||
|
|
||||||
|
const x = -width / 2;
|
||||||
|
const y = -height / 2;
|
||||||
|
|
||||||
|
// @ts-ignore - rough is not typed
|
||||||
|
const rc = rough.svg(shapeSvg);
|
||||||
|
const options = userNodeOverrides(node, { stroke: stylesMap.get('fill') || mainBkg });
|
||||||
|
|
||||||
|
if (node.look !== 'handDrawn') {
|
||||||
|
options.roughness = 0;
|
||||||
|
options.fillStyle = 'solid';
|
||||||
|
}
|
||||||
|
|
||||||
|
const iconNode = rc.path(createRoundedRectPathD(x, y, width, height, 5), options);
|
||||||
|
|
||||||
|
const iconShape = shapeSvg.insert(() => iconNode, ':first-child');
|
||||||
|
|
||||||
|
if (node.icon) {
|
||||||
|
const iconElem = shapeSvg.append('g');
|
||||||
|
iconElem.html(
|
||||||
|
`<g>${await getIconSVG(node.icon, { height: iconSize, fallbackPrefix: '' })}</g>`
|
||||||
|
);
|
||||||
|
const iconBBox = iconElem.node().getBBox();
|
||||||
|
const iconWidth = iconBBox.width;
|
||||||
|
const iconHeight = iconBBox.height;
|
||||||
|
iconElem.attr(
|
||||||
|
'transform',
|
||||||
|
`translate(${-iconWidth / 2},${topLabel ? height / 2 - iconHeight - halfPadding + (translateHorizontal ? bbox.height / 2 : 0) : -height / 2 + halfPadding - (translateHorizontal ? bbox.height / 2 : 0)})`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
label.attr(
|
||||||
|
'transform',
|
||||||
|
`translate(${-width / 2 + width / 2 - bbox.width / 2},${topLabel ? -height / 2 - 2.5 - (translateHorizontal ? bbox.height / 2 : bbox.height) : height / 2 + 5 - (translateHorizontal ? bbox.height / 2 : 0)})`
|
||||||
|
);
|
||||||
|
|
||||||
|
if (translateHorizontal) {
|
||||||
|
iconShape.attr('transform', `translate(${0},${topLabel ? bbox.height / 2 : -bbox.height / 2})`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cssStyles && node.look !== 'handDrawn') {
|
||||||
|
iconShape.selectAll('path').attr('style', cssStyles);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nodeStyles && node.look !== 'handDrawn') {
|
||||||
|
iconShape.selectAll('path').attr('style', nodeStyles);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateNodeBounds(node, shapeSvg);
|
||||||
|
|
||||||
|
node.intersect = function (point) {
|
||||||
|
log.info('iconSquare intersect', node, point);
|
||||||
|
const pos = intersect.rect(node, point);
|
||||||
|
return pos;
|
||||||
|
};
|
||||||
|
|
||||||
|
return shapeSvg;
|
||||||
|
};
|
Reference in New Issue
Block a user