mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-10-11 01:59:41 +02:00
Compare commits
12 Commits
fix/html-l
...
6623-add-i
Author | SHA1 | Date | |
---|---|---|---|
![]() |
4c40dd406d | ||
![]() |
994f7df29a | ||
![]() |
dc11b8645c | ||
![]() |
8dcddaf314 | ||
![]() |
bd19523f5d | ||
![]() |
6b64b92b6e | ||
![]() |
41e3d2449a | ||
![]() |
0386ed6b32 | ||
![]() |
97481b4d11 | ||
![]() |
b8b120939e | ||
![]() |
71e4d62153 | ||
![]() |
b867370f1b |
5
.changeset/bumpy-shrimps-stay.md
Normal file
5
.changeset/bumpy-shrimps-stay.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'mermaid': minor
|
||||
---
|
||||
|
||||
feat: Add custom images and icons support for sequence diagram actors
|
@@ -122,46 +122,6 @@ describe('Flowchart v2', () => {
|
||||
expect(svg).to.not.have.attr('style');
|
||||
});
|
||||
});
|
||||
it('renders only pure SVG labels (no <foreignObject>) when flowchart.htmlLabels=false', () => {
|
||||
renderGraph(
|
||||
`---
|
||||
config:
|
||||
flowchart:
|
||||
htmlLabels: false
|
||||
---
|
||||
flowchart LR
|
||||
subgraph \`**One**\`
|
||||
a["\`**The cat**
|
||||
in the hat\`"] -- "\`**edge label**\`" --> b{{"\`**The dog** in the hog\`"}}
|
||||
end
|
||||
subgraph \`**Two**\`
|
||||
c["\`**The cat**
|
||||
in the hat\`"] -- "\`**Bold edge label**\`" --> d["\`The dog in the hog\`"]
|
||||
end
|
||||
`
|
||||
);
|
||||
cy.get('svg').find('foreignObject').should('not.exist');
|
||||
});
|
||||
|
||||
it('renders only pure SVG labels (no <foreignObject>) when global htmlLabels=false', () => {
|
||||
renderGraph(
|
||||
`---
|
||||
config:
|
||||
htmlLabels: false
|
||||
---
|
||||
flowchart LR
|
||||
subgraph \`**One**\`
|
||||
a["\`**The cat**
|
||||
in the hat\`"] -- "\`**edge label**\`" --> b{{"\`**The dog** in the hog\`"}}
|
||||
end
|
||||
subgraph \`**Two**\`
|
||||
c["\`**The cat**
|
||||
in the hat\`"] -- "\`**Bold edge label**\`" --> d["\`The dog in the hog\`"]
|
||||
end
|
||||
`
|
||||
);
|
||||
cy.get('svg').find('foreignObject').should('not.exist');
|
||||
});
|
||||
|
||||
it('V2 - 16: Render Stadium shape', () => {
|
||||
imgSnapshotTest(
|
||||
|
118
cypress/integration/rendering/sequenceDiagram-icon.spec.ts
Normal file
118
cypress/integration/rendering/sequenceDiagram-icon.spec.ts
Normal file
@@ -0,0 +1,118 @@
|
||||
import { imgSnapshotTest } from '../../helpers/util';
|
||||
|
||||
const looks = ['classic'] as const;
|
||||
|
||||
looks.forEach((look) => {
|
||||
describe(`SequenceDiagram icon participants in ${look} look`, () => {
|
||||
it(`single participant with icon`, () => {
|
||||
const diagram = `
|
||||
sequenceDiagram
|
||||
participant Bob@{ type: "icon", icon: "fa:bell" }
|
||||
Note over Bob: Icon participant`;
|
||||
imgSnapshotTest(diagram, { look });
|
||||
});
|
||||
|
||||
it(`two participants, one icon and one normal`, () => {
|
||||
const diagram = `
|
||||
sequenceDiagram
|
||||
participant Bob@{ type: "icon", icon: "fa:bell" }
|
||||
participant Alice
|
||||
Bob->>Alice: Hello`;
|
||||
imgSnapshotTest(diagram, { look });
|
||||
});
|
||||
|
||||
it(`two icon participants`, () => {
|
||||
const diagram = `
|
||||
sequenceDiagram
|
||||
participant Bob@{ type: "icon", icon: "fa:bell" }
|
||||
participant Alice@{ type: "icon", icon: "fa:user" }
|
||||
Bob->>Alice: Hello
|
||||
Alice-->>Bob: Hi`;
|
||||
imgSnapshotTest(diagram, { look });
|
||||
});
|
||||
|
||||
it(`with markdown htmlLabels:true content`, () => {
|
||||
// html/markdown in messages/notes (participants themselves don't support label/form/w/h)
|
||||
const diagram = `
|
||||
sequenceDiagram
|
||||
participant Bob@{ type: "icon", icon: "fa:bell" }
|
||||
participant Alice
|
||||
Bob->>Alice: This is **bold** </br>and <strong>strong</strong>
|
||||
Note over Bob,Alice: Mixed <em>HTML</em> and **markdown**`;
|
||||
imgSnapshotTest(diagram, { look });
|
||||
});
|
||||
|
||||
it(`with markdown htmlLabels:false content`, () => {
|
||||
const diagram = `
|
||||
sequenceDiagram
|
||||
participant Bob@{ type: "icon", icon: "fa:bell" }
|
||||
participant Alice
|
||||
Bob->>Alice: This is **bold** </br>and <strong>strong</strong>`;
|
||||
imgSnapshotTest(diagram, {
|
||||
look,
|
||||
htmlLabels: false,
|
||||
flowchart: { htmlLabels: false },
|
||||
});
|
||||
});
|
||||
|
||||
it(`with styles applied to participant`, () => {
|
||||
// style by participant id
|
||||
const diagram = `
|
||||
sequenceDiagram
|
||||
participant Bob@{ type: "icon", icon: "fa:bell" }
|
||||
participant Alice
|
||||
Bob->>Alice: Styled participant
|
||||
`;
|
||||
imgSnapshotTest(diagram, { look });
|
||||
});
|
||||
|
||||
it(`with classDef and class application`, () => {
|
||||
const diagram = `
|
||||
sequenceDiagram
|
||||
participant Bob@{ type: "icon", icon: "fa:bell" }
|
||||
participant Alice
|
||||
Bob->>Alice: Classed participant
|
||||
`;
|
||||
imgSnapshotTest(diagram, { look });
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Colored emoji icon tests (analogous to the flowchart colored icon tests), no direction line.
|
||||
describe('SequenceDiagram colored icon participant', () => {
|
||||
it('colored emoji icon without styles', () => {
|
||||
const icon = 'fluent-emoji:tropical-fish';
|
||||
const diagram = `
|
||||
sequenceDiagram
|
||||
participant Bob@{ type: "icon", icon: "${icon}" }
|
||||
Note over Bob: colored emoji icon
|
||||
`;
|
||||
imgSnapshotTest(diagram);
|
||||
});
|
||||
|
||||
it('colored emoji icon with styles', () => {
|
||||
const icon = 'fluent-emoji:tropical-fish';
|
||||
const diagram = `
|
||||
sequenceDiagram
|
||||
participant Bob@{ type: "icon", icon: "${icon}" }
|
||||
`;
|
||||
imgSnapshotTest(diagram);
|
||||
});
|
||||
});
|
||||
|
||||
// Mixed scenario: multiple interactions, still no direction line.
|
||||
describe('SequenceDiagram icon participant with multiple interactions', () => {
|
||||
const icon = 'fa:bell-slash';
|
||||
it('icon participant interacts with two normal participants', () => {
|
||||
const diagram = `
|
||||
sequenceDiagram
|
||||
participant Bob@{ type: "icon", icon: "${icon}" }
|
||||
participant Alice
|
||||
participant Carol
|
||||
Bob->>Alice: Ping
|
||||
Alice-->>Bob: Pong
|
||||
Bob->>Carol: Notify
|
||||
Note right of Bob: Icon side note`;
|
||||
imgSnapshotTest(diagram);
|
||||
});
|
||||
});
|
94
cypress/integration/rendering/sequenceDiagram-image.spec.ts
Normal file
94
cypress/integration/rendering/sequenceDiagram-image.spec.ts
Normal file
@@ -0,0 +1,94 @@
|
||||
import { imgSnapshotTest } from '../../helpers/util';
|
||||
|
||||
const looks = ['classic'] as const;
|
||||
|
||||
looks.forEach((look) => {
|
||||
describe(`SequenceDiagram image participants in ${look} look`, () => {
|
||||
it(`single participant with image`, () => {
|
||||
const diagram = `
|
||||
sequenceDiagram
|
||||
participant Bob@{ type: "image", "image": "https://cdn.pixabay.com/photo/2020/02/22/18/49/paper-4871356_1280.jpg" }
|
||||
Note over Bob: Image participant`;
|
||||
imgSnapshotTest(diagram, { look });
|
||||
});
|
||||
|
||||
it(`two participants, one image and one normal`, () => {
|
||||
const diagram = `
|
||||
sequenceDiagram
|
||||
participant Bob@{ type: "image", "image": "https://cdn.pixabay.com/photo/2020/02/22/18/49/paper-4871356_1280.jpg" }
|
||||
participant Alice
|
||||
Bob->>Alice: Hello`;
|
||||
imgSnapshotTest(diagram, { look });
|
||||
});
|
||||
|
||||
it(`two image participants`, () => {
|
||||
const diagram = `
|
||||
sequenceDiagram
|
||||
participant Bob@{ type: "image", "image": "https://cdn.pixabay.com/photo/2020/02/22/18/49/paper-4871356_1280.jpg" }
|
||||
participant Alice@{ type: "image", "image": "https://cdn.pixabay.com/photo/2020/02/22/18/49/paper-4871356_1280.jpg" }
|
||||
Bob->>Alice: Hello
|
||||
Alice-->>Bob: Hi`;
|
||||
imgSnapshotTest(diagram, { look });
|
||||
});
|
||||
|
||||
it(`with markdown htmlLabels:true content`, () => {
|
||||
const diagram = `
|
||||
sequenceDiagram
|
||||
participant Bob@{ type: "image", "image": "https://cdn.pixabay.com/photo/2020/02/22/18/49/paper-4871356_1280.jpg" }
|
||||
participant Alice
|
||||
Bob->>Alice: This is **bold** </br>and <strong>strong</strong>
|
||||
Note over Bob,Alice: Mixed <em>HTML</em> and **markdown**`;
|
||||
imgSnapshotTest(diagram, { look });
|
||||
});
|
||||
|
||||
it(`with markdown htmlLabels:false content`, () => {
|
||||
const diagram = `
|
||||
sequenceDiagram
|
||||
participant Bob@{ type: "image", "image": "https://cdn.pixabay.com/photo/2020/02/22/18/49/paper-4871356_1280.jpg" }
|
||||
participant Alice
|
||||
Bob->>Alice: This is **bold** </br>and <strong>strong</strong>`;
|
||||
imgSnapshotTest(diagram, {
|
||||
look,
|
||||
htmlLabels: false,
|
||||
flowchart: { htmlLabels: false },
|
||||
});
|
||||
});
|
||||
|
||||
it(`with styles applied to participant`, () => {
|
||||
const diagram = `
|
||||
sequenceDiagram
|
||||
participant Bob@{ type: "image", "image": "https://cdn.pixabay.com/photo/2020/02/22/18/49/paper-4871356_1280.jpg" }
|
||||
participant Alice
|
||||
Bob->>Alice: Styled participant
|
||||
`;
|
||||
imgSnapshotTest(diagram, { look });
|
||||
});
|
||||
|
||||
it(`with classDef and class application`, () => {
|
||||
const diagram = `
|
||||
sequenceDiagram
|
||||
participant Bob@{ type: "image", "image": "https://cdn.pixabay.com/photo/2020/02/22/18/49/paper-4871356_1280.jpg" }
|
||||
participant Alice
|
||||
Bob->>Alice: Classed participant
|
||||
`;
|
||||
imgSnapshotTest(diagram, { look });
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Mixed scenario: multiple interactions, still no direction line.
|
||||
describe('SequenceDiagram image participant with multiple interactions', () => {
|
||||
const imageUrl = 'https://cdn.pixabay.com/photo/2020/02/22/18/49/paper-4871356_1280.jpg';
|
||||
it('image participant interacts with two normal participants', () => {
|
||||
const diagram = `
|
||||
sequenceDiagram
|
||||
participant Bob@{ type: "image", "image": "${imageUrl}" }
|
||||
participant Alice
|
||||
participant Carol
|
||||
Bob->>Alice: Ping
|
||||
Alice-->>Bob: Pong
|
||||
Bob->>Carol: Notify
|
||||
Note right of Bob: Image side note`;
|
||||
imgSnapshotTest(diagram);
|
||||
});
|
||||
});
|
@@ -10,7 +10,7 @@
|
||||
|
||||
# Interface: DetailedError
|
||||
|
||||
Defined in: [packages/mermaid/src/utils.ts:784](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/utils.ts#L784)
|
||||
Defined in: [packages/mermaid/src/utils.ts:783](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/utils.ts#L783)
|
||||
|
||||
## Properties
|
||||
|
||||
@@ -18,7 +18,7 @@ Defined in: [packages/mermaid/src/utils.ts:784](https://github.com/mermaid-js/me
|
||||
|
||||
> `optional` **error**: `any`
|
||||
|
||||
Defined in: [packages/mermaid/src/utils.ts:789](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/utils.ts#L789)
|
||||
Defined in: [packages/mermaid/src/utils.ts:788](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/utils.ts#L788)
|
||||
|
||||
---
|
||||
|
||||
@@ -26,7 +26,7 @@ Defined in: [packages/mermaid/src/utils.ts:789](https://github.com/mermaid-js/me
|
||||
|
||||
> **hash**: `any`
|
||||
|
||||
Defined in: [packages/mermaid/src/utils.ts:787](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/utils.ts#L787)
|
||||
Defined in: [packages/mermaid/src/utils.ts:786](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/utils.ts#L786)
|
||||
|
||||
---
|
||||
|
||||
@@ -34,7 +34,7 @@ Defined in: [packages/mermaid/src/utils.ts:787](https://github.com/mermaid-js/me
|
||||
|
||||
> `optional` **message**: `string`
|
||||
|
||||
Defined in: [packages/mermaid/src/utils.ts:790](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/utils.ts#L790)
|
||||
Defined in: [packages/mermaid/src/utils.ts:789](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/utils.ts#L789)
|
||||
|
||||
---
|
||||
|
||||
@@ -42,4 +42,4 @@ Defined in: [packages/mermaid/src/utils.ts:790](https://github.com/mermaid-js/me
|
||||
|
||||
> **str**: `string`
|
||||
|
||||
Defined in: [packages/mermaid/src/utils.ts:785](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/utils.ts#L785)
|
||||
Defined in: [packages/mermaid/src/utils.ts:784](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/utils.ts#L784)
|
||||
|
@@ -10,7 +10,7 @@
|
||||
|
||||
# Interface: ParseOptions
|
||||
|
||||
Defined in: [packages/mermaid/src/types.ts:88](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L88)
|
||||
Defined in: [packages/mermaid/src/types.ts:76](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L76)
|
||||
|
||||
## Properties
|
||||
|
||||
@@ -18,7 +18,7 @@ Defined in: [packages/mermaid/src/types.ts:88](https://github.com/mermaid-js/mer
|
||||
|
||||
> `optional` **suppressErrors**: `boolean`
|
||||
|
||||
Defined in: [packages/mermaid/src/types.ts:93](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L93)
|
||||
Defined in: [packages/mermaid/src/types.ts:81](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L81)
|
||||
|
||||
If `true`, parse will return `false` instead of throwing error when the diagram is invalid.
|
||||
The `parseError` function will not be called.
|
||||
|
@@ -10,7 +10,7 @@
|
||||
|
||||
# Interface: ParseResult
|
||||
|
||||
Defined in: [packages/mermaid/src/types.ts:96](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L96)
|
||||
Defined in: [packages/mermaid/src/types.ts:84](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L84)
|
||||
|
||||
## Properties
|
||||
|
||||
@@ -18,7 +18,7 @@ Defined in: [packages/mermaid/src/types.ts:96](https://github.com/mermaid-js/mer
|
||||
|
||||
> **config**: [`MermaidConfig`](MermaidConfig.md)
|
||||
|
||||
Defined in: [packages/mermaid/src/types.ts:104](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L104)
|
||||
Defined in: [packages/mermaid/src/types.ts:92](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L92)
|
||||
|
||||
The config passed as YAML frontmatter or directives
|
||||
|
||||
@@ -28,6 +28,6 @@ The config passed as YAML frontmatter or directives
|
||||
|
||||
> **diagramType**: `string`
|
||||
|
||||
Defined in: [packages/mermaid/src/types.ts:100](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L100)
|
||||
Defined in: [packages/mermaid/src/types.ts:88](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L88)
|
||||
|
||||
The diagram type, e.g. 'flowchart', 'sequence', etc.
|
||||
|
@@ -10,7 +10,7 @@
|
||||
|
||||
# Interface: RenderResult
|
||||
|
||||
Defined in: [packages/mermaid/src/types.ts:114](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L114)
|
||||
Defined in: [packages/mermaid/src/types.ts:102](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L102)
|
||||
|
||||
## Properties
|
||||
|
||||
@@ -18,7 +18,7 @@ Defined in: [packages/mermaid/src/types.ts:114](https://github.com/mermaid-js/me
|
||||
|
||||
> `optional` **bindFunctions**: (`element`) => `void`
|
||||
|
||||
Defined in: [packages/mermaid/src/types.ts:132](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L132)
|
||||
Defined in: [packages/mermaid/src/types.ts:120](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L120)
|
||||
|
||||
Bind function to be called after the svg has been inserted into the DOM.
|
||||
This is necessary for adding event listeners to the elements in the svg.
|
||||
@@ -45,7 +45,7 @@ bindFunctions?.(div); // To call bindFunctions only if it's present.
|
||||
|
||||
> **diagramType**: `string`
|
||||
|
||||
Defined in: [packages/mermaid/src/types.ts:122](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L122)
|
||||
Defined in: [packages/mermaid/src/types.ts:110](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L110)
|
||||
|
||||
The diagram type, e.g. 'flowchart', 'sequence', etc.
|
||||
|
||||
@@ -55,6 +55,6 @@ The diagram type, e.g. 'flowchart', 'sequence', etc.
|
||||
|
||||
> **svg**: `string`
|
||||
|
||||
Defined in: [packages/mermaid/src/types.ts:118](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L118)
|
||||
Defined in: [packages/mermaid/src/types.ts:106](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L106)
|
||||
|
||||
The svg code for the rendered graph.
|
||||
|
@@ -194,6 +194,46 @@ sequenceDiagram
|
||||
Bob->>Alice: Queue response
|
||||
```
|
||||
|
||||
### Icon
|
||||
|
||||
If you want to use a custom icon for a participant, use the JSON configuration syntax as shown below. The `icon` value can be a FontAwesome icon name, emoji, or other supported icon identifier.
|
||||
|
||||
```mermaid-example
|
||||
sequenceDiagram
|
||||
participant Alice@{ "type" : "icon", "icon": "fa:bell" }
|
||||
participant Bob
|
||||
Alice->>Bob: Icon participant
|
||||
Bob->>Alice: Response to icon
|
||||
```
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Alice@{ "type" : "icon", "icon": "fa:bell" }
|
||||
participant Bob
|
||||
Alice->>Bob: Icon participant
|
||||
Bob->>Alice: Response to icon
|
||||
```
|
||||
|
||||
### Image
|
||||
|
||||
If you want to use a custom image for a participant, use the JSON configuration syntax as shown below. The `image` value should be a valid image URL.
|
||||
|
||||
```mermaid-example
|
||||
sequenceDiagram
|
||||
participant Alice@{ "type" : "image", "image": "https://cdn.pixabay.com/photo/2020/02/22/18/49/paper-4871356_1280.jpg" }
|
||||
participant Bob
|
||||
Alice->>Bob: Image participant
|
||||
Bob->>Alice: Response to image
|
||||
```
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Alice@{ "type" : "image", "image": "https://cdn.pixabay.com/photo/2020/02/22/18/49/paper-4871356_1280.jpg" }
|
||||
participant Bob
|
||||
Alice->>Bob: Image participant
|
||||
Bob->>Alice: Response to image
|
||||
```
|
||||
|
||||
### Aliases
|
||||
|
||||
The actor can have a convenient identifier and a descriptive label.
|
||||
|
@@ -3,6 +3,7 @@
|
||||
"version": "1.0.0",
|
||||
"description": "Mermaid examples package",
|
||||
"author": "Sidharth Vinod",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"module": "./dist/mermaid-examples.core.mjs",
|
||||
"types": "./dist/mermaid.d.ts",
|
||||
|
@@ -33,7 +33,10 @@ const getStyles = (options: FlowChartStyleOptions) =>
|
||||
background-color: ${fade(options.tertiaryColor, 0.5)};
|
||||
}
|
||||
|
||||
|
||||
.edgeLabel .label {
|
||||
fill: ${options.nodeBorder};
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.label {
|
||||
font-family: ${options.fontFamily};
|
||||
@@ -65,14 +68,6 @@ const getStyles = (options: FlowChartStyleOptions) =>
|
||||
stroke: ${options.lineColor} !important;
|
||||
stroke-width: 1;
|
||||
}
|
||||
.background {
|
||||
fill: ${options.tertiaryColor};
|
||||
opacity: 0.7;
|
||||
background-color: ${options.tertiaryColor};
|
||||
rect {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export default getStyles;
|
||||
|
@@ -2,7 +2,6 @@ import { getConfig } from '../../diagram-api/diagramAPI.js';
|
||||
import type { DiagramDB } from '../../diagram-api/types.js';
|
||||
import { log } from '../../logger.js';
|
||||
import type { Node, Edge } from '../../rendering-util/types.js';
|
||||
import { shouldUseHtmlLabels } from '../../utils.js';
|
||||
|
||||
import {
|
||||
setAccTitle,
|
||||
@@ -318,17 +317,11 @@ export class RequirementDB implements DiagramDB {
|
||||
for (const relation of this.relations) {
|
||||
let counter = 0;
|
||||
const isContains = relation.type === this.Relationships.CONTAINS;
|
||||
|
||||
let relationLabel = `<<${relation.type}>>`;
|
||||
if (!shouldUseHtmlLabels()) {
|
||||
relationLabel = relationLabel.replace(/</g, '<').replace(/>/g, '>');
|
||||
}
|
||||
|
||||
const edge: Edge = {
|
||||
id: `${relation.src}-${relation.dst}-${counter}`,
|
||||
start: this.requirements.get(relation.src)?.name ?? this.elements.get(relation.src)?.name,
|
||||
end: this.requirements.get(relation.dst)?.name ?? this.elements.get(relation.dst)?.name,
|
||||
label: relationLabel,
|
||||
label: `<<${relation.type}>>`,
|
||||
classes: 'relationshipLine',
|
||||
style: ['fill:none', isContains ? '' : 'stroke-dasharray: 10,7'],
|
||||
labelpos: 'c',
|
||||
|
@@ -55,11 +55,6 @@ const getStyles = (options) => `
|
||||
.labelBkg {
|
||||
background-color: ${options.edgeLabelBackground};
|
||||
}
|
||||
.background {
|
||||
fill: ${options.edgeLabelBackground};
|
||||
stroke: none;
|
||||
}
|
||||
|
||||
|
||||
`;
|
||||
// fill', conf.rect_fill)
|
||||
|
@@ -13,8 +13,7 @@ import {
|
||||
setAccTitle,
|
||||
setDiagramTitle,
|
||||
} from '../common/commonDb.js';
|
||||
import type { Actor, AddMessageParams, Box, Message, Note } from './types.js';
|
||||
import type { ParticipantMetaData } from '../../types.js';
|
||||
import type { Actor, AddMessageParams, Box, Message, Note, ParticipantMetaData } from './types.js';
|
||||
|
||||
interface SequenceState {
|
||||
prevActor?: string;
|
||||
@@ -86,6 +85,8 @@ export const PARTICIPANT_TYPE = {
|
||||
ENTITY: 'entity',
|
||||
PARTICIPANT: 'participant',
|
||||
QUEUE: 'queue',
|
||||
ICON: 'icon',
|
||||
IMAGE: 'image',
|
||||
} as const;
|
||||
|
||||
export class SequenceDB implements DiagramDB {
|
||||
@@ -186,6 +187,7 @@ export class SequenceDB implements DiagramDB {
|
||||
actorCnt: null,
|
||||
rectData: null,
|
||||
type: type ?? 'participant',
|
||||
doc: doc,
|
||||
});
|
||||
if (this.state.records.prevActor) {
|
||||
const prevActorInRecords = this.state.records.actors.get(this.state.records.prevActor);
|
||||
|
@@ -2326,4 +2326,73 @@ Bob->>Alice:Got it!
|
||||
expect(actors.get('E').description).toBe('E');
|
||||
});
|
||||
});
|
||||
|
||||
describe('image and icon participant parsing', () => {
|
||||
it('should parse image participant with image URL', async () => {
|
||||
const diagram = await Diagram.fromText(`
|
||||
sequenceDiagram
|
||||
participant Bob@{ "type": "image", "image": "https://cdn.pixabay.com/photo/2020/02/22/18/49/paper-4871356_1280.jpg" }
|
||||
Bob->>Bob: test
|
||||
`);
|
||||
const actors = diagram.db.getActors();
|
||||
expect(actors.get('Bob').type).toBe('image');
|
||||
expect(actors.get('Bob').doc.image).toBe(
|
||||
'https://cdn.pixabay.com/photo/2020/02/22/18/49/paper-4871356_1280.jpg'
|
||||
);
|
||||
});
|
||||
|
||||
it('should parse icon participant with icon name', async () => {
|
||||
const diagram = await Diagram.fromText(`
|
||||
sequenceDiagram
|
||||
participant Alice@{ "type": "icon", "icon": "fa:bell" }
|
||||
Alice->>Alice: test
|
||||
`);
|
||||
const actors = diagram.db.getActors();
|
||||
expect(actors.get('Alice').type).toBe('icon');
|
||||
expect(actors.get('Alice').doc.icon).toBe('fa:bell');
|
||||
});
|
||||
|
||||
it('should parse two image participants', async () => {
|
||||
const diagram = await Diagram.fromText(`
|
||||
sequenceDiagram
|
||||
participant Bob@{ "type": "image", "image": "https://cdn.pixabay.com/photo/2020/02/22/18/49/paper-4871356_1280.jpg" }
|
||||
participant Alice@{ "type": "image", "image": "https://cdn.pixabay.com/photo/2016/11/29/09/32/animal-1867121_1280.jpg" }
|
||||
Bob->>Alice: Hello
|
||||
Alice-->>Bob: Hi
|
||||
`);
|
||||
const actors = diagram.db.getActors();
|
||||
expect(actors.get('Bob').type).toBe('image');
|
||||
expect(actors.get('Bob').doc.image).toBe(
|
||||
'https://cdn.pixabay.com/photo/2020/02/22/18/49/paper-4871356_1280.jpg'
|
||||
);
|
||||
expect(actors.get('Alice').type).toBe('image');
|
||||
expect(actors.get('Alice').doc.image).toBe(
|
||||
'https://cdn.pixabay.com/photo/2016/11/29/09/32/animal-1867121_1280.jpg'
|
||||
);
|
||||
});
|
||||
|
||||
it('should parse image participant with normal participant', async () => {
|
||||
const diagram = await Diagram.fromText(`
|
||||
sequenceDiagram
|
||||
participant Bob@{ "type": "image", "image": "https://cdn.pixabay.com/photo/2020/02/22/18/49/paper-4871356_1280.jpg" }
|
||||
participant Alice
|
||||
Bob->>Alice: Hello
|
||||
`);
|
||||
const actors = diagram.db.getActors();
|
||||
expect(actors.get('Bob').type).toBe('image');
|
||||
expect(actors.get('Alice').type).toBe('participant');
|
||||
});
|
||||
|
||||
it('should parse icon participant with normal participant', async () => {
|
||||
const diagram = await Diagram.fromText(`
|
||||
sequenceDiagram
|
||||
participant Bob@{ "type": "icon", "icon": "fa:bell" }
|
||||
participant Alice
|
||||
Bob->>Alice: Hello
|
||||
`);
|
||||
const actors = diagram.db.getActors();
|
||||
expect(actors.get('Bob').type).toBe('icon');
|
||||
expect(actors.get('Alice').type).toBe('participant');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -752,6 +752,8 @@ function adjustCreatedDestroyedData(
|
||||
PARTICIPANT_TYPE.CONTROL,
|
||||
PARTICIPANT_TYPE.ENTITY,
|
||||
PARTICIPANT_TYPE.DATABASE,
|
||||
PARTICIPANT_TYPE.ICON,
|
||||
PARTICIPANT_TYPE.IMAGE,
|
||||
];
|
||||
|
||||
// if it is a create message
|
||||
|
@@ -1,5 +1,6 @@
|
||||
import { sanitizeUrl } from '@braintree/sanitize-url';
|
||||
import * as configApi from '../../config.js';
|
||||
import { getIconSVG } from '../../rendering-util/icons.js';
|
||||
import { ZERO_WIDTH_SPACE, parseFontSize } from '../../utils.js';
|
||||
import common, {
|
||||
calculateMathMLDimensions,
|
||||
@@ -322,6 +323,89 @@ export const fixLifeLineHeights = (diagram, actors, actorKeys, conf) => {
|
||||
});
|
||||
};
|
||||
|
||||
const drawActorTypeIcon = async function (elem, actor, conf, isFooter) {
|
||||
const actorY = isFooter ? actor.stopy : actor.starty;
|
||||
const center = actor.x + actor.width / 2;
|
||||
const centerY = actorY + actor.height / 2;
|
||||
|
||||
const line = elem.append('g').lower();
|
||||
if (!isFooter) {
|
||||
actorCnt++;
|
||||
line
|
||||
.append('line')
|
||||
.attr('id', 'actor' + actorCnt)
|
||||
.attr('x1', center)
|
||||
.attr('y1', centerY + 25)
|
||||
.attr('x2', center)
|
||||
.attr('y2', 2000)
|
||||
.attr('class', 'actor-line')
|
||||
.attr('stroke-width', '0.5px')
|
||||
.attr('stroke', '#999')
|
||||
.attr('name', actor.name);
|
||||
actor.actorCnt = actorCnt;
|
||||
}
|
||||
|
||||
const actElem = elem.append('g');
|
||||
let cssClass = 'actor-icon';
|
||||
if (isFooter) {
|
||||
cssClass += ` ${BOTTOM_ACTOR_CLASS}`;
|
||||
} else {
|
||||
cssClass += ` ${TOP_ACTOR_CLASS}`;
|
||||
}
|
||||
|
||||
actElem.attr('class', cssClass);
|
||||
actElem.attr('name', actor.name);
|
||||
|
||||
// Define the size of the square and icon
|
||||
const iconSize = actor.width / 5;
|
||||
const squareX = center - iconSize / 2;
|
||||
const squareY = !isFooter ? actorY + 10 : actorY;
|
||||
|
||||
// Draw a square rectangle for the actor icon background
|
||||
|
||||
actElem
|
||||
.append('rect')
|
||||
.attr('x', squareX)
|
||||
.attr('y', squareY)
|
||||
.attr('width', iconSize)
|
||||
.attr('height', iconSize)
|
||||
.attr('rx', 3) // rounded corners, optional
|
||||
.attr('ry', 3)
|
||||
.attr('fill', 'none'); // light gray background or customize as needed
|
||||
|
||||
// Render icon SVG inside the rectangle
|
||||
const iconGroup = actElem.append('g').attr('transform', `translate(${squareX}, ${squareY})`);
|
||||
|
||||
iconGroup
|
||||
.append('svg')
|
||||
.attr('width', iconSize)
|
||||
.attr('height', iconSize)
|
||||
.html(
|
||||
`<g>${await getIconSVG(actor.doc.icon, {
|
||||
height: iconSize,
|
||||
width: iconSize,
|
||||
fallbackPrefix: '',
|
||||
})}</g>`
|
||||
);
|
||||
|
||||
// Add text label below icon
|
||||
_drawTextCandidateFunc(conf, hasKatex(actor.description))(
|
||||
actor.description,
|
||||
actElem,
|
||||
actor.x,
|
||||
actorY + (!isFooter ? 40 : 30), // positioning below the square icon
|
||||
actor.width,
|
||||
20,
|
||||
{ class: 'actor-icon-text' },
|
||||
conf
|
||||
);
|
||||
|
||||
const bounds = actElem.node().getBBox();
|
||||
actor.height = bounds.height + (conf.sequence?.labelBoxHeight ?? 0);
|
||||
|
||||
return actor.height;
|
||||
};
|
||||
|
||||
/**
|
||||
* Draws an actor in the diagram with the attached line
|
||||
*
|
||||
@@ -414,6 +498,174 @@ const drawActorTypeParticipant = function (elem, actor, conf, isFooter) {
|
||||
|
||||
return height;
|
||||
};
|
||||
const drawActorTypeImage = async function (elem, actor, conf, isFooter) {
|
||||
const img = new Image();
|
||||
img.src = actor.doc.image ?? '';
|
||||
await img.decode();
|
||||
|
||||
const imageNaturalWidth = Number(img.naturalWidth.toString().replace('px', ''));
|
||||
const imageNaturalHeight = Number(img.naturalHeight.toString().replace('px', ''));
|
||||
|
||||
actor.doc.imageAspectRatio = imageNaturalWidth / imageNaturalHeight;
|
||||
|
||||
// Calculate image dimensions with proper sizing logic
|
||||
let imageWidth, imageHeight;
|
||||
|
||||
// Check if custom dimensions are provided and valid
|
||||
const hasValidCustomDimensions =
|
||||
actor.doc.height && actor.doc.height > 10 && actor.doc.width && actor.doc.width > 10;
|
||||
|
||||
if (hasValidCustomDimensions) {
|
||||
if (actor.doc.constraint === 'on') {
|
||||
// Maintain aspect ratio with constraint
|
||||
const customAspectRatio = imageNaturalWidth / imageNaturalHeight;
|
||||
|
||||
if (customAspectRatio > actor.doc.imageAspectRatio) {
|
||||
// Width is the limiting factor
|
||||
imageHeight = actor.doc.height;
|
||||
imageWidth = actor.doc.height * actor.doc.imageAspectRatio;
|
||||
} else {
|
||||
// Height is the limiting factor
|
||||
imageWidth = actor.doc.width;
|
||||
imageHeight = actor.doc.width / actor.doc.imageAspectRatio;
|
||||
}
|
||||
} else {
|
||||
// Use custom dimensions without maintaining aspect ratio
|
||||
imageWidth = actor.doc.width;
|
||||
imageHeight = actor.doc.height;
|
||||
}
|
||||
} else {
|
||||
// Use default sizing based on actor width
|
||||
const defaultImageSize = actor.width / 3.5;
|
||||
|
||||
// Ensure minimum and maximum sizes
|
||||
const minSize = 30;
|
||||
const maxSize = actor.width * 0.8;
|
||||
|
||||
if (actor.doc.imageAspectRatio >= 1) {
|
||||
// Landscape or square image
|
||||
imageWidth = Math.min(Math.max(defaultImageSize, minSize), maxSize);
|
||||
imageHeight = imageWidth / actor.doc.imageAspectRatio;
|
||||
} else {
|
||||
// Portrait image
|
||||
imageHeight = Math.min(Math.max(defaultImageSize, minSize), maxSize);
|
||||
imageWidth = imageHeight * actor.doc.imageAspectRatio;
|
||||
}
|
||||
|
||||
// Ensure the image doesn't exceed actor bounds
|
||||
if (imageWidth > actor.width * 0.9) {
|
||||
imageWidth = actor.width * 0.9;
|
||||
imageHeight = imageWidth / actor.doc.imageAspectRatio;
|
||||
}
|
||||
}
|
||||
|
||||
const actorY = isFooter ? actor.stopy : actor.starty;
|
||||
const center = actor.x + actor.width / 2;
|
||||
const centerY = actorY + imageHeight;
|
||||
|
||||
// Calculate positioning
|
||||
const squareX = center - imageWidth / 2;
|
||||
let squareY;
|
||||
|
||||
if (isFooter) {
|
||||
squareY = actorY + (imageHeight - imageHeight * 1);
|
||||
} else {
|
||||
squareY = actorY + 5;
|
||||
}
|
||||
|
||||
// Calculate text position based on image position and size
|
||||
const textY = !isFooter ? squareY + imageHeight : actorY + imageHeight; // Place text below image for header
|
||||
|
||||
// Draw actor line for non-footer elements
|
||||
const x = center;
|
||||
const y = centerY + (isFooter ? 0 : imageHeight / 2); // Adjust line start based on image height
|
||||
const line = elem.append('g').lower();
|
||||
if (!isFooter) {
|
||||
actorCnt++;
|
||||
line
|
||||
.append('line')
|
||||
.attr('id', 'actor' + actorCnt)
|
||||
.attr('x1', x)
|
||||
.attr('y1', y) // Adjust line start based on image height
|
||||
.attr('x2', center)
|
||||
.attr('y2', 2000)
|
||||
.attr('class', 'actor-line')
|
||||
.attr('stroke-width', '0.5px')
|
||||
.attr('stroke', '#999')
|
||||
.attr('name', actor.name);
|
||||
actor.actorCnt = actorCnt;
|
||||
}
|
||||
|
||||
const actElem = elem.append('g');
|
||||
let cssClass = 'actor-image';
|
||||
if (isFooter) {
|
||||
cssClass += ` ${BOTTOM_ACTOR_CLASS}`;
|
||||
} else {
|
||||
cssClass += ` ${TOP_ACTOR_CLASS}`;
|
||||
}
|
||||
|
||||
actElem.attr('class', cssClass);
|
||||
actElem.attr('name', actor.name);
|
||||
|
||||
// Draw background rectangle for the actor image
|
||||
actElem
|
||||
.append('rect')
|
||||
.attr('x', squareX)
|
||||
.attr('y', squareY)
|
||||
.attr('width', imageWidth)
|
||||
.attr('height', imageHeight)
|
||||
.attr('rx', 3)
|
||||
.attr('ry', 3)
|
||||
.attr('fill', 'white')
|
||||
.attr('stroke', '#ddd')
|
||||
.attr('stroke-width', '1px');
|
||||
|
||||
// Create clipping path for the image
|
||||
const clipId = `clip-actor-${actorCnt || 'footer'}-${Math.random().toString(36).substr(2, 9)}`;
|
||||
actElem
|
||||
.append('defs')
|
||||
.append('clipPath')
|
||||
.attr('id', clipId)
|
||||
.append('rect')
|
||||
.attr('x', squareX)
|
||||
.attr('y', squareY)
|
||||
.attr('width', imageWidth)
|
||||
.attr('height', imageHeight)
|
||||
.attr('rx', 3)
|
||||
.attr('ry', 3);
|
||||
|
||||
// Render image inside the rectangle
|
||||
const imageGroup = actElem.append('g');
|
||||
|
||||
if (actor.doc.image) {
|
||||
imageGroup
|
||||
.append('image')
|
||||
.attr('x', squareX)
|
||||
.attr('y', squareY)
|
||||
.attr('width', imageWidth)
|
||||
.attr('height', imageHeight)
|
||||
.attr('href', img.src)
|
||||
.attr('preserveAspectRatio', actor.doc.constraint === 'on' ? 'xMidYMid meet' : 'none');
|
||||
}
|
||||
|
||||
// Add text label
|
||||
_drawTextCandidateFunc(conf, hasKatex(actor.description))(
|
||||
actor.description,
|
||||
actElem,
|
||||
actor.x,
|
||||
textY,
|
||||
actor.width,
|
||||
20,
|
||||
{ class: 'actor-image-text' },
|
||||
conf
|
||||
);
|
||||
|
||||
// Calculate final bounds and update actor height
|
||||
const bounds = actElem.node().getBBox();
|
||||
actor.height = bounds.height + (conf.sequence?.labelBoxHeight ?? 0);
|
||||
|
||||
return actor.height;
|
||||
};
|
||||
|
||||
/**
|
||||
* Draws an actor in the diagram with the attached line
|
||||
@@ -1122,6 +1374,10 @@ export const drawActor = async function (elem, actor, conf, isFooter) {
|
||||
return await drawActorTypeCollections(elem, actor, conf, isFooter);
|
||||
case 'queue':
|
||||
return await drawActorTypeQueue(elem, actor, conf, isFooter);
|
||||
case 'icon':
|
||||
return await drawActorTypeIcon(elem, actor, conf, isFooter);
|
||||
case 'image':
|
||||
return await drawActorTypeImage(elem, actor, conf, isFooter);
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -17,6 +17,9 @@ export interface Actor {
|
||||
actorCnt: number | null;
|
||||
rectData: unknown;
|
||||
type: string;
|
||||
doc?: ParticipantMetaData; // For documentation
|
||||
iconName?: string; // For icon type
|
||||
imgSrc?: string; // For img type
|
||||
}
|
||||
|
||||
export interface Message {
|
||||
@@ -90,3 +93,20 @@ export interface Note {
|
||||
message: string;
|
||||
wrap: boolean;
|
||||
}
|
||||
|
||||
export interface ParticipantMetaData {
|
||||
type?:
|
||||
| 'actor'
|
||||
| 'participant'
|
||||
| 'boundary'
|
||||
| 'control'
|
||||
| 'entity'
|
||||
| 'database'
|
||||
| 'collections'
|
||||
| 'queue'
|
||||
| 'icon'
|
||||
| 'img';
|
||||
icon?: string;
|
||||
img?: string;
|
||||
form?: string;
|
||||
}
|
||||
|
@@ -118,6 +118,30 @@ sequenceDiagram
|
||||
Bob->>Alice: Queue response
|
||||
```
|
||||
|
||||
### Icon
|
||||
|
||||
If you want to use a custom icon for a participant, use the JSON configuration syntax as shown below. The `icon` value can be a FontAwesome icon name, emoji, or other supported icon identifier.
|
||||
|
||||
```mermaid-example
|
||||
sequenceDiagram
|
||||
participant Alice@{ "type" : "icon", "icon": "fa:bell" }
|
||||
participant Bob
|
||||
Alice->>Bob: Icon participant
|
||||
Bob->>Alice: Response to icon
|
||||
```
|
||||
|
||||
### Image
|
||||
|
||||
If you want to use a custom image for a participant, use the JSON configuration syntax as shown below. The `image` value should be a valid image URL.
|
||||
|
||||
```mermaid-example
|
||||
sequenceDiagram
|
||||
participant Alice@{ "type" : "image", "image": "https://cdn.pixabay.com/photo/2020/02/22/18/49/paper-4871356_1280.jpg" }
|
||||
participant Bob
|
||||
Alice->>Bob: Image participant
|
||||
Bob->>Alice: Response to image
|
||||
```
|
||||
|
||||
### Aliases
|
||||
|
||||
The actor can have a convenient identifier and a descriptive label.
|
||||
|
@@ -176,9 +176,8 @@ function updateTextContentAndStyles(tspan: any, wrappedLine: MarkdownWord[]) {
|
||||
if (index === 0) {
|
||||
innerTspan.text(word.content);
|
||||
} else {
|
||||
const prev = wrappedLine[index - 1].content;
|
||||
const insertSpace = !prev.endsWith('<') && !word.content.startsWith('>');
|
||||
innerTspan.text((insertSpace ? ' ' : '') + word.content);
|
||||
// TODO: check what joiner to use.
|
||||
innerTspan.text(' ' + word.content);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@@ -9,7 +9,6 @@ import intersectRect from '../rendering-elements/intersect/intersect-rect.js';
|
||||
import createLabel from './createLabel.js';
|
||||
import { createRoundedRectPathD } from './shapes/roundedRectPath.ts';
|
||||
import { styles2String, userNodeOverrides } from './shapes/handDrawnShapeStyles.js';
|
||||
import { shouldUseHtmlLabels } from '../../utils.js';
|
||||
|
||||
const rect = async (parent, node) => {
|
||||
log.info('Creating subgraph rect for ', node.id, node);
|
||||
@@ -26,7 +25,8 @@ const rect = async (parent, node) => {
|
||||
.attr('id', node.id)
|
||||
.attr('data-look', node.look);
|
||||
|
||||
const useHtmlLabels = shouldUseHtmlLabels();
|
||||
const useHtmlLabels = evaluate(siteConfig.flowchart.htmlLabels);
|
||||
|
||||
// Create the label and insert it after the rect
|
||||
const labelEl = shapeSvg.insert('g').attr('class', 'cluster-label ');
|
||||
|
||||
|
@@ -1,12 +1,13 @@
|
||||
import { select } from 'd3';
|
||||
import { getConfig } from '../../diagram-api/diagramAPI.js';
|
||||
import common, {
|
||||
evaluate,
|
||||
hasKatex,
|
||||
renderKatexSanitized,
|
||||
sanitizeText,
|
||||
} from '../../diagrams/common/common.js';
|
||||
import { log } from '../../logger.js';
|
||||
import { decodeEntities, shouldUseHtmlLabels } from '../../utils.js';
|
||||
import { decodeEntities } from '../../utils.js';
|
||||
|
||||
/**
|
||||
* @param dom
|
||||
@@ -62,7 +63,8 @@ const createLabel = async (_vertexText, style, isTitle, isNode) => {
|
||||
if (typeof vertexText === 'object') {
|
||||
vertexText = vertexText[0];
|
||||
}
|
||||
if (shouldUseHtmlLabels()) {
|
||||
|
||||
if (evaluate(getConfig().flowchart.htmlLabels)) {
|
||||
// TODO: addHtmlLabel accepts a labelStyle. Do we possibly have that?
|
||||
vertexText = vertexText.replace(/\\n|\n/g, '<br />');
|
||||
log.info('vertexText' + vertexText);
|
||||
|
@@ -1,7 +1,8 @@
|
||||
import { getConfig } from '../../diagram-api/diagramAPI.js';
|
||||
import { evaluate } from '../../diagrams/common/common.js';
|
||||
import { log } from '../../logger.js';
|
||||
import { createText } from '../createText.js';
|
||||
import utils, { shouldUseHtmlLabels } from '../../utils.js';
|
||||
import utils from '../../utils.js';
|
||||
import {
|
||||
getLineFunctionsWithOffset,
|
||||
markerOffsets,
|
||||
@@ -44,13 +45,10 @@ export const getLabelStyles = (styleArray) => {
|
||||
};
|
||||
|
||||
export const insertEdgeLabel = async (elem, edge) => {
|
||||
const useHtmlLabels = shouldUseHtmlLabels();
|
||||
let useHtmlLabels = evaluate(getConfig().flowchart.htmlLabels);
|
||||
|
||||
const { labelStyles } = styles2String(edge);
|
||||
edge.labelStyle = labelStyles;
|
||||
// if (useHtmlLabels === false) {
|
||||
// edge.label = edge.label.replaceAll('>', '>').replaceAll('<', '<');
|
||||
// }
|
||||
const labelElement = await createText(elem, edge.label, {
|
||||
style: edge.labelStyle,
|
||||
useHtmlLabels,
|
||||
|
@@ -4,12 +4,7 @@ import { getConfig } from '../../../diagram-api/diagramAPI.js';
|
||||
import { select } from 'd3';
|
||||
import defaultConfig from '../../../defaultConfig.js';
|
||||
import { evaluate, sanitizeText } from '../../../diagrams/common/common.js';
|
||||
import {
|
||||
decodeEntities,
|
||||
handleUndefinedAttr,
|
||||
parseFontSize,
|
||||
shouldUseHtmlLabels,
|
||||
} from '../../../utils.js';
|
||||
import { decodeEntities, handleUndefinedAttr, parseFontSize } from '../../../utils.js';
|
||||
import type { D3Selection, Point } from '../../../types.js';
|
||||
|
||||
export const labelHelper = async <T extends SVGGraphicsElement>(
|
||||
@@ -18,7 +13,7 @@ export const labelHelper = async <T extends SVGGraphicsElement>(
|
||||
_classes?: string
|
||||
) => {
|
||||
let cssClasses;
|
||||
const useHtmlLabels = shouldUseHtmlLabels();
|
||||
const useHtmlLabels = node.useHtmlLabels || evaluate(getConfig()?.htmlLabels);
|
||||
if (!_classes) {
|
||||
cssClasses = 'node default';
|
||||
} else {
|
||||
|
@@ -13,18 +13,6 @@ export interface NodeMetaData {
|
||||
ticket?: string;
|
||||
}
|
||||
|
||||
export interface ParticipantMetaData {
|
||||
type?:
|
||||
| 'actor'
|
||||
| 'participant'
|
||||
| 'boundary'
|
||||
| 'control'
|
||||
| 'entity'
|
||||
| 'database'
|
||||
| 'collections'
|
||||
| 'queue';
|
||||
}
|
||||
|
||||
export interface EdgeMetaData {
|
||||
animation?: 'fast' | 'slow';
|
||||
animate?: boolean;
|
||||
|
@@ -7,12 +7,12 @@ import {
|
||||
curveBumpX,
|
||||
curveBumpY,
|
||||
curveBundle,
|
||||
curveCardinal,
|
||||
curveCardinalClosed,
|
||||
curveCardinalOpen,
|
||||
curveCatmullRom,
|
||||
curveCardinal,
|
||||
curveCatmullRomClosed,
|
||||
curveCatmullRomOpen,
|
||||
curveCatmullRom,
|
||||
curveLinear,
|
||||
curveLinearClosed,
|
||||
curveMonotoneX,
|
||||
@@ -23,17 +23,16 @@ import {
|
||||
curveStepBefore,
|
||||
select,
|
||||
} from 'd3';
|
||||
import common from './diagrams/common/common.js';
|
||||
import { sanitizeDirective } from './utils/sanitizeDirective.js';
|
||||
import { log } from './logger.js';
|
||||
import { detectType } from './diagram-api/detectType.js';
|
||||
import assignWithDepth from './assignWithDepth.js';
|
||||
import type { MermaidConfig } from './config.type.js';
|
||||
import memoize from 'lodash-es/memoize.js';
|
||||
import merge from 'lodash-es/merge.js';
|
||||
import assignWithDepth from './assignWithDepth.js';
|
||||
import { getUserDefinedConfig } from './config.js';
|
||||
import type { MermaidConfig } from './config.type.js';
|
||||
import { detectType } from './diagram-api/detectType.js';
|
||||
import { directiveRegex } from './diagram-api/regexes.js';
|
||||
import common, { evaluate } from './diagrams/common/common.js';
|
||||
import { log } from './logger.js';
|
||||
import type { D3Element, Point, TextDimensionConfig, TextDimensions } from './types.js';
|
||||
import { sanitizeDirective } from './utils/sanitizeDirective.js';
|
||||
|
||||
export const ZERO_WIDTH_SPACE = '\u200b';
|
||||
|
||||
@@ -982,14 +981,3 @@ export function isLabelCoordinateInPath(point: Point, dAttr: string) {
|
||||
|
||||
return sanitizedD.includes(roundedX.toString()) || sanitizedD.includes(roundedY.toString());
|
||||
}
|
||||
|
||||
export const shouldUseHtmlLabels = () => {
|
||||
const siteConfig = getUserDefinedConfig();
|
||||
let useHtmlLabels;
|
||||
if (siteConfig.flowchart?.htmlLabels !== undefined) {
|
||||
useHtmlLabels = evaluate(siteConfig.flowchart.htmlLabels);
|
||||
} else {
|
||||
useHtmlLabels = evaluate(siteConfig.htmlLabels);
|
||||
}
|
||||
return useHtmlLabels;
|
||||
};
|
||||
|
Reference in New Issue
Block a user