mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-09-26 02:39:41 +02:00
Compare commits
5 Commits
6638-seque
...
deprecate-
Author | SHA1 | Date | |
---|---|---|---|
![]() |
e82e464595 | ||
![]() |
3b5bbb0e29 | ||
![]() |
8f8c5c8d01 | ||
![]() |
0c659d486d | ||
![]() |
1672edbd49 |
@@ -1,5 +0,0 @@
|
||||
---
|
||||
'mermaid': minor
|
||||
---
|
||||
|
||||
feat: Add half-arrowheads (solid & stick) and central connection support
|
5
.changeset/seven-towns-obey.md
Normal file
5
.changeset/seven-towns-obey.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'mermaid': minor
|
||||
---
|
||||
|
||||
feat: Deprecate flowchart.htmlLabels in favor of root-level htmlLabels
|
@@ -655,126 +655,5 @@ describe('Sequence Diagram Special Cases', () => {
|
||||
expect(svg).to.not.have.attr('style');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Central Connection Rendering Tests', () => {
|
||||
it('should render central connection circles on actor vertical lines', () => {
|
||||
imgSnapshotTest(
|
||||
`sequenceDiagram
|
||||
participant Alice
|
||||
participant Bob
|
||||
participant Charlie
|
||||
Alice ()->>() Bob: Central connection
|
||||
Bob ()-->> Charlie: Reverse central connection
|
||||
Charlie ()<<-->>() Alice: Dual central connection`,
|
||||
{ look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
|
||||
);
|
||||
});
|
||||
|
||||
it('should render central connections with different arrow types', () => {
|
||||
imgSnapshotTest(
|
||||
`sequenceDiagram
|
||||
participant Alice
|
||||
participant Bob
|
||||
Alice ()->>() Bob: Solid open arrow
|
||||
Alice ()-->>() Bob: Dotted open arrow
|
||||
Alice ()-x() Bob: Solid cross
|
||||
Alice ()--x() Bob: Dotted cross
|
||||
Alice ()->() Bob: Solid arrow`,
|
||||
{ look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
|
||||
);
|
||||
});
|
||||
|
||||
it('should render central connections with bidirectional arrows', () => {
|
||||
imgSnapshotTest(
|
||||
`sequenceDiagram
|
||||
participant Alice
|
||||
participant Bob
|
||||
Alice ()<<->>() Bob: Bidirectional solid
|
||||
Alice ()<<-->>() Bob: Bidirectional dotted`,
|
||||
{ look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
|
||||
);
|
||||
});
|
||||
|
||||
it('should render central connections with activations', () => {
|
||||
imgSnapshotTest(
|
||||
`sequenceDiagram
|
||||
participant Alice
|
||||
participant Bob
|
||||
participant Charlie
|
||||
Alice ()->>() Bob: Activate Bob
|
||||
activate Bob
|
||||
Bob ()-->> Charlie: Message to Charlie
|
||||
Bob ()->>() Alice: Response to Alice
|
||||
deactivate Bob`,
|
||||
{ look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
|
||||
);
|
||||
});
|
||||
|
||||
it('should render central connections mixed with normal messages', () => {
|
||||
imgSnapshotTest(
|
||||
`sequenceDiagram
|
||||
participant Alice
|
||||
participant Bob
|
||||
participant Charlie
|
||||
Alice ->> Bob: Normal message
|
||||
Bob ()->>() Charlie: Central connection
|
||||
Charlie -->> Alice: Normal dotted message
|
||||
Alice ()<<-->>() Bob: Dual central connection
|
||||
Bob -x Charlie: Normal cross message`,
|
||||
{ look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
|
||||
);
|
||||
});
|
||||
|
||||
it('should render central connections with notes', () => {
|
||||
imgSnapshotTest(
|
||||
`sequenceDiagram
|
||||
participant Alice
|
||||
participant Bob
|
||||
participant Charlie
|
||||
Alice ()->>() Bob: Central connection
|
||||
Note over Alice,Bob: Central connection note
|
||||
Bob ()-->> Charlie: Reverse central connection
|
||||
Note right of Charlie: Response note
|
||||
Charlie ()<<-->>() Alice: Dual central connection`,
|
||||
{ look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
|
||||
);
|
||||
});
|
||||
|
||||
it('should render central connections with loops and alternatives', () => {
|
||||
imgSnapshotTest(
|
||||
`sequenceDiagram
|
||||
participant Alice
|
||||
participant Bob
|
||||
participant Charlie
|
||||
loop Every minute
|
||||
Alice ()->>() Bob: Central heartbeat
|
||||
Bob ()-->> Charlie: Forward heartbeat
|
||||
end
|
||||
alt Success
|
||||
Charlie ()<<-->>() Alice: Success response
|
||||
else Failure
|
||||
Charlie ()-x() Alice: Failure response
|
||||
end`,
|
||||
{ look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
|
||||
);
|
||||
});
|
||||
|
||||
it('should render central connections with different participant types', () => {
|
||||
imgSnapshotTest(
|
||||
`sequenceDiagram
|
||||
participant Alice
|
||||
actor Bob
|
||||
participant Charlie@{"type":"boundary"}
|
||||
participant David@{"type":"control"}
|
||||
participant Eve@{"type":"entity"}
|
||||
Alice ()->>() Bob: To actor
|
||||
Bob ()-->> Charlie: To boundary
|
||||
Charlie ()->>() David: To control
|
||||
David ()<<-->>() Eve: To entity
|
||||
Eve ()-x() Alice: Back to participant`,
|
||||
{ look: 'classic', sequence: { diagramMarginX: 50, diagramMarginY: 10 } }
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -1053,167 +1053,4 @@ describe('Sequence diagram', () => {
|
||||
]);
|
||||
});
|
||||
});
|
||||
describe('render new arrow type', () => {
|
||||
it('should render Solid half arrow top', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
Alice -|\\ John: Hello John, how are you?
|
||||
Alice-|\\ John: Hi Alice, I can hear you!
|
||||
Alice -|\\ John: Test
|
||||
`
|
||||
);
|
||||
});
|
||||
it('should render Solid half arrow bottom', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
Alice-|/John: Hello John, how are you?
|
||||
Alice-|/John: Hi Alice, I can hear you!
|
||||
Alice-|/John: Test
|
||||
`
|
||||
);
|
||||
});
|
||||
|
||||
it('should render Stick half arrow top ', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
Alice-\\\\John: Hello John, how are you?
|
||||
Alice-\\\\John: Hi Alice, I can hear you!
|
||||
Alice-\\\\John: Test
|
||||
`
|
||||
);
|
||||
});
|
||||
it('should render Stick half arrow bottom ', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
Alice-//John: Hello John, how are you?
|
||||
Alice-//John: Hi Alice, I can hear you!
|
||||
Alice-//John: Test
|
||||
`
|
||||
);
|
||||
});
|
||||
it('should render Solid half arrow top reverse ', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
Alice/|-John: Hello Alice, how are you?
|
||||
Alice/|-John: Hi Alice, I can hear you!
|
||||
Alice/|-John: Test
|
||||
|
||||
`
|
||||
);
|
||||
});
|
||||
|
||||
it('should render Solid half arrow bottom reverse ', () => {
|
||||
imgSnapshotTest(
|
||||
`sequenceDiagram
|
||||
Alice \\|- John: Hello Alice, how are you?
|
||||
Alice \\|- John: Hi Alice, I can hear you!
|
||||
Alice \\|- John: Test`
|
||||
);
|
||||
});
|
||||
|
||||
it('should render Stick half arrow top reverse ', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
Alice //-John: Hello Alice, how are you?
|
||||
Alice //-John: Hi Alice, I can hear you!
|
||||
Alice //-John: Test`
|
||||
);
|
||||
});
|
||||
|
||||
it('should render Stick half arrow bottom reverse ', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
Alice \\\\-John: Hello Alice, how are you?
|
||||
Alice \\\\-John: Hi Alice, I can hear you!
|
||||
Alice \\\\-John: Test`
|
||||
);
|
||||
});
|
||||
|
||||
it('should render Solid half arrow top dotted', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
Alice --|\\John: Hello John, how are you?
|
||||
Alice --|\\John: Hi Alice, I can hear you!
|
||||
Alice --|\\John: Test`
|
||||
);
|
||||
});
|
||||
|
||||
it('should render Solid half arrow bottom dotted', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
Alice --|/John: Hello John, how are you?
|
||||
Alice --|/John: Hi Alice, I can hear you!
|
||||
Alice --|/John: Test`
|
||||
);
|
||||
});
|
||||
|
||||
it('should render Stick half arrow top dotted', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
Alice--\\\\John: Hello John, how are you?
|
||||
Alice--\\\\John: Hi Alice, I can hear you!
|
||||
Alice--\\\\John: Test`
|
||||
);
|
||||
});
|
||||
|
||||
it('should render Stick half arrow bottom dotted', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
Alice--//John: Hello John, how are you?
|
||||
Alice--//John: Hi Alice, I can hear you!
|
||||
Alice--//John: Test`
|
||||
);
|
||||
});
|
||||
|
||||
it('should render Solid half arrow top reverse dotted', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
Alice/|--John: Hello Alice, how are you?
|
||||
Alice/|--John: Hi Alice, I can hear you!
|
||||
Alice/|--John: Test`
|
||||
);
|
||||
});
|
||||
|
||||
it('should render Solid half arrow bottom reverse dotted', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
Alice\\|--John: Hello Alice, how are you?
|
||||
Alice\\|--John: Hi Alice, I can hear you!
|
||||
Alice\\|--John: Test`
|
||||
);
|
||||
});
|
||||
|
||||
it('should render Stick half arrow top reverse dotted ', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
Alice//--John: Hello Alice, how are you?
|
||||
Alice//--John: Hi Alice, I can hear you!
|
||||
Alice//--John: Test`
|
||||
);
|
||||
});
|
||||
|
||||
it('should render Stick half arrow bottom reverse dotted ', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
sequenceDiagram
|
||||
Alice\\\\--John: Hello Alice, how are you?
|
||||
Alice\\\\--John: Hi Alice, I can hear you!
|
||||
Alice\\\\--John: Test`
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -236,22 +236,27 @@ A --> C[End]
|
||||
|
||||
Some common flowchart configurations are:
|
||||
|
||||
- _htmlLabels_: true/false
|
||||
- _curve_: linear/curve
|
||||
- _diagramPadding_: number
|
||||
- _useMaxWidth_: number
|
||||
|
||||
**Deprecated configurations:**
|
||||
|
||||
- ~~_htmlLabels_~~: Use global `htmlLabels` instead
|
||||
|
||||
For a complete list of flowchart configurations, see [defaultConfig.ts](https://github.com/mermaid-js/mermaid/blob/develop/packages/mermaid/src/defaultConfig.ts) in the source code.
|
||||
_Soon we plan to publish a complete list of all diagram-specific configurations updated in the docs._
|
||||
|
||||
The following code snippet changes flowchart config:
|
||||
|
||||
`%%{init: { "flowchart": { "htmlLabels": true, "curve": "linear" } } }%%`
|
||||
```
|
||||
%%{init: { "htmlLabels": true, "flowchart": { "curve": "linear" } } }%%
|
||||
```
|
||||
|
||||
Here we are overriding only the flowchart config, and not the general config, setting `htmlLabels` to `true` and `curve` to `linear`.
|
||||
**Note:** `flowchart.htmlLabels` has been deprecated. Use the global `htmlLabels` configuration instead.
|
||||
|
||||
```mermaid-example
|
||||
%%{init: { "flowchart": { "htmlLabels": true, "curve": "linear" } } }%%
|
||||
%%{init: { "htmlLabels": true, "flowchart": { "curve": "linear" } } }%%
|
||||
graph TD
|
||||
A(Forest) --> B[/Another/]
|
||||
A --> C[End]
|
||||
@@ -262,7 +267,7 @@ A --> C[End]
|
||||
```
|
||||
|
||||
```mermaid
|
||||
%%{init: { "flowchart": { "htmlLabels": true, "curve": "linear" } } }%%
|
||||
%%{init: { "htmlLabels": true, "flowchart": { "curve": "linear" } } }%%
|
||||
graph TD
|
||||
A(Forest) --> B[/Another/]
|
||||
A --> C[End]
|
||||
|
@@ -18,6 +18,7 @@
|
||||
|
||||
- [addDirective](functions/addDirective.md)
|
||||
- [getConfig](functions/getConfig.md)
|
||||
- [getEffectiveHtmlLabels](functions/getEffectiveHtmlLabels.md)
|
||||
- [getSiteConfig](functions/getSiteConfig.md)
|
||||
- [getUserDefinedConfig](functions/getUserDefinedConfig.md)
|
||||
- [reset](functions/reset.md)
|
||||
|
29
docs/config/setup/config/functions/getEffectiveHtmlLabels.md
Normal file
29
docs/config/setup/config/functions/getEffectiveHtmlLabels.md
Normal file
@@ -0,0 +1,29 @@
|
||||
> **Warning**
|
||||
>
|
||||
> ## THIS IS AN AUTOGENERATED FILE. DO NOT EDIT.
|
||||
>
|
||||
> ## Please edit the corresponding file in [/packages/mermaid/src/docs/config/setup/config/functions/getEffectiveHtmlLabels.md](../../../../../packages/mermaid/src/docs/config/setup/config/functions/getEffectiveHtmlLabels.md).
|
||||
|
||||
[**mermaid**](../../README.md)
|
||||
|
||||
---
|
||||
|
||||
# Function: getEffectiveHtmlLabels()
|
||||
|
||||
> **getEffectiveHtmlLabels**(`config`): `boolean`
|
||||
|
||||
Defined in: [packages/mermaid/src/config.ts:272](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.ts#L272)
|
||||
|
||||
Helper function to handle deprecated flowchart.htmlLabels
|
||||
|
||||
## Parameters
|
||||
|
||||
### config
|
||||
|
||||
[`MermaidConfig`](../../mermaid/interfaces/MermaidConfig.md)
|
||||
|
||||
The configuration object
|
||||
|
||||
## Returns
|
||||
|
||||
`boolean`
|
@@ -12,7 +12,7 @@
|
||||
|
||||
> **getUserDefinedConfig**(): [`MermaidConfig`](../../mermaid/interfaces/MermaidConfig.md)
|
||||
|
||||
Defined in: [packages/mermaid/src/config.ts:252](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.ts#L252)
|
||||
Defined in: [packages/mermaid/src/config.ts:254](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.ts#L254)
|
||||
|
||||
## Returns
|
||||
|
||||
|
@@ -372,7 +372,7 @@ The list of configuration objects are described [in the mermaidAPI documentation
|
||||
```html
|
||||
<script type="module">
|
||||
import mermaid from './mermaid.esm.mjs';
|
||||
let config = { startOnLoad: true, flowchart: { useMaxWidth: false, htmlLabels: true } };
|
||||
let config = { startOnLoad: true, htmlLabels: true, flowchart: { useMaxWidth: false } };
|
||||
mermaid.initialize(config);
|
||||
</script>
|
||||
```
|
||||
|
@@ -329,11 +329,7 @@ Messages can be of two displayed either solid or with a dotted line.
|
||||
[Actor][Arrow][Actor]:Message text
|
||||
```
|
||||
|
||||
Lines can be solid or dotted, and can end with various types of arrowheads, crosses, or open arrows.
|
||||
|
||||
#### Supported Arrow Types
|
||||
|
||||
**Standard Arrow Types**
|
||||
There are ten types of arrows currently supported:
|
||||
|
||||
| Type | Description |
|
||||
| -------- | ---------------------------------------------------- |
|
||||
@@ -348,58 +344,6 @@ Lines can be solid or dotted, and can end with various types of arrowheads, cros
|
||||
| `-)` | Solid line with an open arrow at the end (async) |
|
||||
| `--)` | Dotted line with a open arrow at the end (async) |
|
||||
|
||||
**Half-Arrows (v\<MERMAID_RELEASE_VERSION>+)**
|
||||
|
||||
The following half-arrow types are supported for more expressive sequence diagrams. Both solid and dotted variants are available by increasing the number of dashes (`-` → `--`).
|
||||
|
||||
---
|
||||
|
||||
| Type | Description |
|
||||
| ------- | ---------------------------------------------------- |
|
||||
| `-\|\` | Solid line with top half arrowhead |
|
||||
| `--\|\` | Dotted line with top half arrowhead |
|
||||
| `-\|/` | Solid line with bottom half arrowhead |
|
||||
| `--\|/` | Dotted line with bottom half arrowhead |
|
||||
| `/\|-` | Solid line with reverse top half arrowhead |
|
||||
| `/\|--` | Dotted line with reverse top half arrowhead |
|
||||
| `\\-` | Solid line with reverse bottom half arrowhead |
|
||||
| `\\--` | Dotted line with reverse bottom half arrowhead |
|
||||
| `-\\` | Solid line with top stick half arrowhead |
|
||||
| `--\\` | Dotted line with top stick half arrowhead |
|
||||
| `-//` | Solid line with bottom stick half arrowhead |
|
||||
| `--//` | Dotted line with bottom stick half arrowhead |
|
||||
| `//-` | Solid line with reverse top stick half arrowhead |
|
||||
| `//--` | Dotted line with reverse top stick half arrowhead |
|
||||
| `\\-` | Solid line with reverse bottom stick half arrowhead |
|
||||
| `\\--` | Dotted line with reverse bottom stick half arrowhead |
|
||||
|
||||
## Central Connections (v\<MERMAID_RELEASE_VERSION>+)
|
||||
|
||||
Mermaid sequence diagrams support **central lifeline connections** using a `()`.
|
||||
This is useful to represent messages or signals that connect to a central point, rather than from one actor directly to another.
|
||||
|
||||
To indicate a central connection, append `()` to the arrow syntax.
|
||||
|
||||
#### Basic Syntax
|
||||
|
||||
```mermaid-example
|
||||
sequenceDiagram
|
||||
participant Alice
|
||||
participant John
|
||||
Alice->>()John: Hello John
|
||||
Alice()->>John: How are you?
|
||||
John()->>()Alice: Great!
|
||||
```
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Alice
|
||||
participant John
|
||||
Alice->>()John: Hello John
|
||||
Alice()->>John: How are you?
|
||||
John()->>()Alice: Great!
|
||||
```
|
||||
|
||||
## Activations
|
||||
|
||||
It is possible to activate and deactivate an actor. (de)activation can be dedicated declarations:
|
||||
|
@@ -227,6 +227,8 @@ export const reset = (config = siteConfig): void => {
|
||||
const ConfigWarning = {
|
||||
LAZY_LOAD_DEPRECATED:
|
||||
'The configuration options lazyLoadedDiagrams and loadExternalDiagramsAtStartup are deprecated. Please use registerExternalDiagrams instead.',
|
||||
FLOWCHART_HTML_LABELS_DEPRECATED:
|
||||
'flowchart.htmlLabels is deprecated. Please use global htmlLabels instead.',
|
||||
} as const;
|
||||
|
||||
type ConfigWarningStrings = keyof typeof ConfigWarning;
|
||||
@@ -262,3 +264,15 @@ export const getUserDefinedConfig = (): MermaidConfig => {
|
||||
|
||||
return userConfig;
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper function to handle deprecated flowchart.htmlLabels
|
||||
* @param config - The configuration object
|
||||
*/
|
||||
export const getEffectiveHtmlLabels = (config: MermaidConfig): boolean => {
|
||||
if (config.flowchart?.htmlLabels !== undefined) {
|
||||
issueWarning('FLOWCHART_HTML_LABELS_DEPRECATED');
|
||||
}
|
||||
|
||||
return config.htmlLabels ?? config.flowchart?.htmlLabels ?? true;
|
||||
};
|
||||
|
@@ -248,7 +248,12 @@ export interface FlowchartDiagramConfig extends BaseDiagramConfig {
|
||||
*/
|
||||
diagramPadding?: number;
|
||||
/**
|
||||
* Flag for setting whether or not a html tag should be used for rendering labels on the edges.
|
||||
* @deprecated
|
||||
* **DEPRECATED: Use global `htmlLabels` instead.**
|
||||
*
|
||||
* Flag for setting whether or not a html tag should be used for rendering labels on nodes and edges.
|
||||
* This property is deprecated.
|
||||
* Please use the global `htmlLabels` configuration instead.
|
||||
*
|
||||
*/
|
||||
htmlLabels?: boolean;
|
||||
|
@@ -4,7 +4,8 @@ import createLabel from './createLabel.js';
|
||||
import { createText } from '../rendering-util/createText.js';
|
||||
import { select } from 'd3';
|
||||
import { getConfig } from '../diagram-api/diagramAPI.js';
|
||||
import { evaluate } from '../diagrams/common/common.js';
|
||||
import { getEffectiveHtmlLabels } from '../config.js';
|
||||
|
||||
import { getSubGraphTitleMargins } from '../utils/subGraphTitleMargins.js';
|
||||
|
||||
const rect = async (parent, node) => {
|
||||
@@ -20,7 +21,7 @@ const rect = async (parent, node) => {
|
||||
// add the rect
|
||||
const rect = shapeSvg.insert('rect', ':first-child');
|
||||
|
||||
const useHtmlLabels = evaluate(siteConfig.flowchart.htmlLabels);
|
||||
const useHtmlLabels = getEffectiveHtmlLabels(siteConfig);
|
||||
|
||||
// Create the label and insert it after the rect
|
||||
const label = shapeSvg.insert('g').attr('class', 'cluster-label');
|
||||
@@ -38,7 +39,7 @@ const rect = async (parent, node) => {
|
||||
// Get the size of the label
|
||||
let bbox = text.getBBox();
|
||||
|
||||
if (evaluate(siteConfig.flowchart.htmlLabels)) {
|
||||
if (getEffectiveHtmlLabels(siteConfig)) {
|
||||
const div = text.children[0];
|
||||
const dv = select(text);
|
||||
bbox = div.getBoundingClientRect();
|
||||
@@ -150,7 +151,7 @@ const roundedWithTitle = async (parent, node) => {
|
||||
|
||||
// Get the size of the label
|
||||
let bbox = text.getBBox();
|
||||
if (evaluate(siteConfig.flowchart.htmlLabels)) {
|
||||
if (getEffectiveHtmlLabels(siteConfig)) {
|
||||
const div = text.children[0];
|
||||
const dv = select(text);
|
||||
bbox = div.getBoundingClientRect();
|
||||
@@ -190,7 +191,7 @@ const roundedWithTitle = async (parent, node) => {
|
||||
node.y -
|
||||
node.height / 2 -
|
||||
node.padding / 3 +
|
||||
(evaluate(siteConfig.flowchart.htmlLabels) ? 5 : 3) +
|
||||
(getEffectiveHtmlLabels(siteConfig) ? 5 : 3) +
|
||||
subGraphTitleTopMargin
|
||||
})`
|
||||
);
|
||||
|
@@ -1,6 +1,7 @@
|
||||
import { select } from 'd3';
|
||||
import { getConfig } from '../diagram-api/diagramAPI.js';
|
||||
import { evaluate, sanitizeText } from '../diagrams/common/common.js';
|
||||
import { getEffectiveHtmlLabels } from '../config.js';
|
||||
import { sanitizeText } from '../diagrams/common/common.js';
|
||||
import { log } from '../logger.js';
|
||||
import { replaceIconSubstring } from '../rendering-util/createText.js';
|
||||
import { decodeEntities } from '../utils.js';
|
||||
@@ -50,7 +51,7 @@ const createLabel = async (_vertexText, style, isTitle, isNode) => {
|
||||
vertexText = vertexText[0];
|
||||
}
|
||||
const config = getConfig();
|
||||
if (evaluate(config.flowchart.htmlLabels)) {
|
||||
if (getEffectiveHtmlLabels(config)) {
|
||||
// TODO: addHtmlLabel accepts a labelStyle. Do we possibly have that?
|
||||
vertexText = vertexText.replace(/\\n|\n/g, '<br />');
|
||||
log.debug('vertexText' + vertexText);
|
||||
|
@@ -3,8 +3,9 @@ import createLabel from './createLabel.js';
|
||||
import { createText } from '../rendering-util/createText.js';
|
||||
import { line, curveBasis, select } from 'd3';
|
||||
import { getConfig } from '../diagram-api/diagramAPI.js';
|
||||
import { getEffectiveHtmlLabels } from '../config.js';
|
||||
import utils from '../utils.js';
|
||||
import { evaluate, getUrl } from '../diagrams/common/common.js';
|
||||
import { getUrl } from '../diagrams/common/common.js';
|
||||
import { getLineFunctionsWithOffset } from '../utils/lineWithOffset.js';
|
||||
import { getSubGraphTitleMargins } from '../utils/subGraphTitleMargins.js';
|
||||
import { addEdgeMarkers } from './edgeMarker.js';
|
||||
@@ -19,7 +20,7 @@ export const clear = () => {
|
||||
|
||||
export const insertEdgeLabel = async (elem, edge) => {
|
||||
const config = getConfig();
|
||||
const useHtmlLabels = evaluate(config.flowchart.htmlLabels);
|
||||
const useHtmlLabels = getEffectiveHtmlLabels(config);
|
||||
// Create the actual text element
|
||||
const labelElement =
|
||||
edge.labelType === 'markdown'
|
||||
@@ -133,7 +134,7 @@ export const insertEdgeLabel = async (elem, edge) => {
|
||||
* @param {any} value
|
||||
*/
|
||||
function setTerminalWidth(fo, value) {
|
||||
if (getConfig().flowchart.htmlLabels && fo) {
|
||||
if (getEffectiveHtmlLabels(getConfig()) && fo) {
|
||||
fo.style.width = value.length * 9 + 'px';
|
||||
fo.style.height = '12px';
|
||||
}
|
||||
|
@@ -1,6 +1,7 @@
|
||||
import { select } from 'd3';
|
||||
import { getConfig } from '../diagram-api/diagramAPI.js';
|
||||
import { evaluate } from '../diagrams/common/common.js';
|
||||
import { getEffectiveHtmlLabels } from '../config.js';
|
||||
|
||||
import { log } from '../logger.js';
|
||||
import { getArrowPoints } from './blockArrowHelper.js';
|
||||
import createLabel from './createLabel.js';
|
||||
@@ -588,7 +589,7 @@ const rectWithTitle = async (parent, node) => {
|
||||
|
||||
const text = label.node().appendChild(await createLabel(title, node.labelStyle, true, true));
|
||||
let bbox = { width: 0, height: 0 };
|
||||
if (evaluate(getConfig().flowchart.htmlLabels)) {
|
||||
if (getEffectiveHtmlLabels(getConfig())) {
|
||||
const div = text.children[0];
|
||||
const dv = select(text);
|
||||
bbox = div.getBoundingClientRect();
|
||||
@@ -609,7 +610,7 @@ const rectWithTitle = async (parent, node) => {
|
||||
)
|
||||
);
|
||||
|
||||
if (evaluate(getConfig().flowchart.htmlLabels)) {
|
||||
if (getEffectiveHtmlLabels(getConfig())) {
|
||||
const div = descr.children[0];
|
||||
const dv = select(descr);
|
||||
bbox = div.getBoundingClientRect();
|
||||
@@ -917,7 +918,7 @@ const class_box = async (parent, node) => {
|
||||
.node()
|
||||
.appendChild(await createLabel(interfaceLabelText, node.labelStyle, true, true));
|
||||
let interfaceBBox = interfaceLabel.getBBox();
|
||||
if (evaluate(getConfig().flowchart.htmlLabels)) {
|
||||
if (getEffectiveHtmlLabels(getConfig())) {
|
||||
const div = interfaceLabel.children[0];
|
||||
const dv = select(interfaceLabel);
|
||||
interfaceBBox = div.getBoundingClientRect();
|
||||
@@ -932,7 +933,7 @@ const class_box = async (parent, node) => {
|
||||
let classTitleString = node.classData.label;
|
||||
|
||||
if (node.classData.type !== undefined && node.classData.type !== '') {
|
||||
if (getConfig().flowchart.htmlLabels) {
|
||||
if (getEffectiveHtmlLabels(getConfig())) {
|
||||
classTitleString += '<' + node.classData.type + '>';
|
||||
} else {
|
||||
classTitleString += '<' + node.classData.type + '>';
|
||||
@@ -943,7 +944,7 @@ const class_box = async (parent, node) => {
|
||||
.appendChild(await createLabel(classTitleString, node.labelStyle, true, true));
|
||||
select(classTitleLabel).attr('class', 'classTitle');
|
||||
let classTitleBBox = classTitleLabel.getBBox();
|
||||
if (evaluate(getConfig().flowchart.htmlLabels)) {
|
||||
if (getEffectiveHtmlLabels(getConfig())) {
|
||||
const div = classTitleLabel.children[0];
|
||||
const dv = select(classTitleLabel);
|
||||
classTitleBBox = div.getBoundingClientRect();
|
||||
@@ -958,7 +959,7 @@ const class_box = async (parent, node) => {
|
||||
node.classData.members.forEach(async (member) => {
|
||||
const parsedInfo = member.getDisplayDetails();
|
||||
let parsedText = parsedInfo.displayText;
|
||||
if (getConfig().flowchart.htmlLabels) {
|
||||
if (getEffectiveHtmlLabels(getConfig())) {
|
||||
parsedText = parsedText.replace(/</g, '<').replace(/>/g, '>');
|
||||
}
|
||||
const lbl = labelContainer
|
||||
@@ -972,7 +973,7 @@ const class_box = async (parent, node) => {
|
||||
)
|
||||
);
|
||||
let bbox = lbl.getBBox();
|
||||
if (evaluate(getConfig().flowchart.htmlLabels)) {
|
||||
if (getEffectiveHtmlLabels(getConfig())) {
|
||||
const div = lbl.children[0];
|
||||
const dv = select(lbl);
|
||||
bbox = div.getBoundingClientRect();
|
||||
@@ -992,7 +993,7 @@ const class_box = async (parent, node) => {
|
||||
node.classData.methods.forEach(async (member) => {
|
||||
const parsedInfo = member.getDisplayDetails();
|
||||
let displayText = parsedInfo.displayText;
|
||||
if (getConfig().flowchart.htmlLabels) {
|
||||
if (getEffectiveHtmlLabels(getConfig())) {
|
||||
displayText = displayText.replace(/</g, '<').replace(/>/g, '>');
|
||||
}
|
||||
const lbl = labelContainer
|
||||
@@ -1006,7 +1007,7 @@ const class_box = async (parent, node) => {
|
||||
)
|
||||
);
|
||||
let bbox = lbl.getBBox();
|
||||
if (evaluate(getConfig().flowchart.htmlLabels)) {
|
||||
if (getEffectiveHtmlLabels(getConfig())) {
|
||||
const div = lbl.children[0];
|
||||
const dv = select(lbl);
|
||||
bbox = div.getBoundingClientRect();
|
||||
|
@@ -1,10 +1,11 @@
|
||||
import { updateNodeBounds, labelHelper } from './util.js';
|
||||
import { log } from '../../logger.js';
|
||||
import { getConfig } from '../../diagram-api/diagramAPI.js';
|
||||
import { getEffectiveHtmlLabels } from '../../config.js';
|
||||
import intersect from '../intersect/index.js';
|
||||
|
||||
const note = async (parent, node) => {
|
||||
const useHtmlLabels = node.useHtmlLabels || getConfig().flowchart.htmlLabels;
|
||||
const useHtmlLabels = getEffectiveHtmlLabels(getConfig()) || node.useHtmlLabels;
|
||||
if (!useHtmlLabels) {
|
||||
node.centerLabel = true;
|
||||
}
|
||||
|
@@ -1,14 +1,15 @@
|
||||
import createLabel from '../createLabel.js';
|
||||
import { createText } from '../../rendering-util/createText.js';
|
||||
import { getConfig } from '../../diagram-api/diagramAPI.js';
|
||||
import { getEffectiveHtmlLabels } from '../../config.js';
|
||||
import { select } from 'd3';
|
||||
import { evaluate, sanitizeText } from '../../diagrams/common/common.js';
|
||||
import { sanitizeText } from '../../diagrams/common/common.js';
|
||||
import { decodeEntities } from '../../utils.js';
|
||||
|
||||
export const labelHelper = async (parent, node, _classes, isNode) => {
|
||||
const config = getConfig();
|
||||
let classes;
|
||||
const useHtmlLabels = node.useHtmlLabels || evaluate(config.flowchart.htmlLabels);
|
||||
const useHtmlLabels = node.useHtmlLabels || getEffectiveHtmlLabels(config);
|
||||
if (!_classes) {
|
||||
classes = 'node default';
|
||||
} else {
|
||||
@@ -60,7 +61,7 @@ export const labelHelper = async (parent, node, _classes, isNode) => {
|
||||
let bbox = text.getBBox();
|
||||
const halfPadding = node.padding / 2;
|
||||
|
||||
if (evaluate(config.flowchart.htmlLabels)) {
|
||||
if (getEffectiveHtmlLabels(config)) {
|
||||
const div = text.children[0];
|
||||
const dv = select(text);
|
||||
|
||||
|
@@ -3,6 +3,7 @@ import { select, curveLinear } from 'd3';
|
||||
import * as graphlib from 'dagre-d3-es/src/graphlib/index.js';
|
||||
import { log } from '../../logger.js';
|
||||
import { getConfig } from '../../diagram-api/diagramAPI.js';
|
||||
import { getEffectiveHtmlLabels } from '../../config.js';
|
||||
import { render } from '../../dagre-wrapper/index.js';
|
||||
import utils, { getEdgeId } from '../../utils.js';
|
||||
import { interpolateToCurve, getStylesFromArray } from '../../utils.js';
|
||||
@@ -260,7 +261,7 @@ export const addRelations = function (relations: ClassRelation[], g: graphlib.Gr
|
||||
edgeData.labelpos = 'c';
|
||||
|
||||
// TODO V10: Flowchart ? Keeping flowchart for backwards compatibility. Remove in next major release
|
||||
if (getConfig().flowchart?.htmlLabels ?? getConfig().htmlLabels) {
|
||||
if (getEffectiveHtmlLabels(getConfig())) {
|
||||
edgeData.labelType = 'html';
|
||||
edgeData.label = '<span class="edgeLabel">' + edge.text + '</span>';
|
||||
} else {
|
||||
|
@@ -1,4 +1,5 @@
|
||||
import DOMPurify from 'dompurify';
|
||||
import { getEffectiveHtmlLabels } from '../../config.js';
|
||||
import type { MermaidConfig } from '../../config.type.js';
|
||||
|
||||
// Remove and ignore br:s
|
||||
@@ -64,7 +65,7 @@ export const removeScript = (txt: string): string => {
|
||||
};
|
||||
|
||||
const sanitizeMore = (text: string, config: MermaidConfig) => {
|
||||
if (config.flowchart?.htmlLabels !== false) {
|
||||
if (getEffectiveHtmlLabels(config)) {
|
||||
const level = config.securityLevel;
|
||||
if (level === 'antiscript' || level === 'strict') {
|
||||
text = removeScript(text);
|
||||
|
@@ -321,7 +321,7 @@ export class RequirementDB implements DiagramDB {
|
||||
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: `<<${relation.type}>>`,
|
||||
label: `«${relation.type}»`,
|
||||
classes: 'relationshipLine',
|
||||
style: ['fill:none', isContains ? '' : 'stroke-dasharray: 10,7'],
|
||||
labelpos: 'c',
|
||||
|
@@ -40,6 +40,15 @@ const getStyles = (options) => `
|
||||
.relationshipLabel {
|
||||
fill: ${options.relationLabelColor};
|
||||
}
|
||||
.edgeLabel {
|
||||
background-color: ${options.edgeLabelBackground};
|
||||
}
|
||||
.edgeLabel .label rect {
|
||||
fill: ${options.edgeLabelBackground};
|
||||
}
|
||||
.edgeLabel .label text {
|
||||
fill: ${options.relationLabelColor};
|
||||
}
|
||||
.divider {
|
||||
stroke: ${options.nodeBorder};
|
||||
stroke-width: 1;
|
||||
|
@@ -78,7 +78,7 @@ accDescr\s*"{"\s* { this.begin("acc_descr_multili
|
||||
"off" return 'off';
|
||||
"," return ',';
|
||||
";" return 'NEWLINE';
|
||||
[^\/\\\+\()\+<\->\->:\n,;]+((?!(\-x|\-\-x|\-\)|\-\-\)|\-\|\\|\-\\|\-\/|\-\/\/|\-\|\/|\/\|\-|\\\|\-|\/\/\-|\\\\\-|\/\|\-|\-\-\|\\|\-\-|\(\)))[\-]*[^\+<\->\->:\n,;]+)* { yytext = yytext.trim(); return 'ACTOR'; } //final_4.11
|
||||
[^+<\->\->:\n,;]+((?!(\-x|\-\-x|\-\)|\-\-\)))[\-]*[^\+<\->\->:\n,;]+)* { yytext = yytext.trim(); return 'ACTOR'; }
|
||||
"->>" return 'SOLID_ARROW';
|
||||
"<<->>" return 'BIDIRECTIONAL_SOLID_ARROW';
|
||||
"-->>" return 'DOTTED_ARROW';
|
||||
@@ -89,36 +89,10 @@ accDescr\s*"{"\s* { this.begin("acc_descr_multili
|
||||
\-\-[x] return 'DOTTED_CROSS';
|
||||
\-[\)] return 'SOLID_POINT';
|
||||
\-\-[\)] return 'DOTTED_POINT';
|
||||
|
||||
//normal-dotted
|
||||
\-\-\|\\ return 'SOLID_ARROW_TOP_DOTTED';
|
||||
\-\-\|\/ return 'SOLID_ARROW_BOTTOM_DOTTED';
|
||||
\-\-\\\\ return 'STICK_ARROW_TOP_DOTTED';
|
||||
\-\-\/\/ return 'STICK_ARROW_BOTTOM_DOTTED';
|
||||
|
||||
//reverse-dotted
|
||||
\/\|\-\- return 'SOLID_ARROW_TOP_REVERSE_DOTTED';
|
||||
\\\|\-\- return 'SOLID_ARROW_BOTTOM_REVERSE_DOTTED';
|
||||
\/\/\-\- return 'STICK_ARROW_TOP_REVERSE_DOTTED';
|
||||
\\\\\-\- return 'STICK_ARROW_BOTTOM_REVERSE_DOTTED';
|
||||
|
||||
//normal
|
||||
\-\|\\ return 'SOLID_ARROW_TOP';
|
||||
\-\|\/ return 'SOLID_ARROW_BOTTOM';
|
||||
\-\\\\ return 'STICK_ARROW_TOP';
|
||||
\-\/\/ return 'STICK_ARROW_BOTTOM';
|
||||
|
||||
//reverse
|
||||
\/\|\- return 'SOLID_ARROW_TOP_REVERSE';
|
||||
\\\|\- return 'SOLID_ARROW_BOTTOM_REVERSE';
|
||||
\/\/\- return 'STICK_ARROW_TOP_REVERSE';
|
||||
\\\\\- return 'STICK_ARROW_BOTTOM_REVERSE';
|
||||
|
||||
":"(?:(?:no)?wrap:)?[^#\n;]* return 'TXT';
|
||||
":" return 'TXT';
|
||||
"+" return '+';
|
||||
"-" return '-';
|
||||
"()" return '()';
|
||||
<<EOF>> return 'NEWLINE';
|
||||
. return 'INVALID';
|
||||
|
||||
@@ -330,20 +304,6 @@ signal
|
||||
{ $$ = [$1,$4,{type: 'addMessage', from:$1.actor, to:$4.actor, signalType:$2, msg:$5},
|
||||
{type: 'activeEnd', signalType: yy.LINETYPE.ACTIVE_END, actor: $1.actor}
|
||||
]}
|
||||
| actor signaltype '()' actor text2
|
||||
{ $$ = [$1,$4,{type: 'addMessage', from:$1.actor, to:$4.actor, signalType:$2, msg:$5, activate: true, centralConnection: yy.LINETYPE.CENTRAL_CONNECTION},
|
||||
{type: 'centralConnection', signalType: yy.LINETYPE.CENTRAL_CONNECTION, actor: $4.actor, }
|
||||
]}
|
||||
|
||||
| actor '()' signaltype actor text2
|
||||
{ $$ = [$1,$4,{type: 'addMessage', from:$1.actor, to:$4.actor, signalType:$3, msg:$5, activate: false, centralConnection: yy.LINETYPE.CENTRAL_CONNECTION_REVERSE},
|
||||
{type: 'centralConnectionReverse', signalType: yy.LINETYPE.CENTRAL_CONNECTION_REVERSE, actor: $1.actor}
|
||||
]}
|
||||
| actor '()' signaltype '()' actor text2
|
||||
{ $$ = [$1,$5,{type: 'addMessage', from:$1.actor, to:$5.actor, signalType:$3, msg:$6, activate: true, centralConnection: yy.LINETYPE.CENTRAL_CONNECTION_DUAL},
|
||||
{type: 'centralConnection', signalType: yy.LINETYPE.CENTRAL_CONNECTION, actor: $5.actor, },
|
||||
{type: 'centralConnectionReverse', signalType: yy.LINETYPE.CENTRAL_CONNECTION_REVERSE, actor: $1.actor}
|
||||
]}
|
||||
| actor signaltype actor text2
|
||||
{ $$ = [$1,$3,{type: 'addMessage', from:$1.actor, to:$3.actor, signalType:$2, msg:$4}]}
|
||||
;
|
||||
@@ -377,28 +337,7 @@ signaltype
|
||||
: SOLID_OPEN_ARROW { $$ = yy.LINETYPE.SOLID_OPEN; }
|
||||
| DOTTED_OPEN_ARROW { $$ = yy.LINETYPE.DOTTED_OPEN; }
|
||||
| SOLID_ARROW { $$ = yy.LINETYPE.SOLID; }
|
||||
|
||||
| SOLID_ARROW_TOP { $$ = yy.LINETYPE.SOLID_TOP; }
|
||||
| SOLID_ARROW_BOTTOM { $$ = yy.LINETYPE.SOLID_BOTTOM; }
|
||||
| STICK_ARROW_TOP { $$ = yy.LINETYPE.STICK_TOP; }
|
||||
| STICK_ARROW_BOTTOM { $$ = yy.LINETYPE.STICK_BOTTOM; }
|
||||
|
||||
| SOLID_ARROW_TOP_DOTTED { $$ = yy.LINETYPE.SOLID_TOP_DOTTED; }
|
||||
| SOLID_ARROW_BOTTOM_DOTTED { $$ = yy.LINETYPE.SOLID_BOTTOM_DOTTED; }
|
||||
| STICK_ARROW_TOP_DOTTED { $$ = yy.LINETYPE.STICK_TOP_DOTTED; }
|
||||
| STICK_ARROW_BOTTOM_DOTTED { $$ = yy.LINETYPE.STICK_BOTTOM_DOTTED; }
|
||||
|
||||
| SOLID_ARROW_TOP_REVERSE { $$ = yy.LINETYPE.SOLID_ARROW_TOP_REVERSE; }
|
||||
| SOLID_ARROW_BOTTOM_REVERSE { $$ = yy.LINETYPE.SOLID_ARROW_BOTTOM_REVERSE; }
|
||||
| STICK_ARROW_TOP_REVERSE { $$ = yy.LINETYPE.STICK_ARROW_TOP_REVERSE; }
|
||||
| STICK_ARROW_BOTTOM_REVERSE { $$ = yy.LINETYPE.STICK_ARROW_BOTTOM_REVERSE; }
|
||||
|
||||
| SOLID_ARROW_TOP_REVERSE_DOTTED { $$ = yy.LINETYPE.SOLID_ARROW_TOP_REVERSE_DOTTED; }
|
||||
| SOLID_ARROW_BOTTOM_REVERSE_DOTTED { $$ = yy.LINETYPE.SOLID_ARROW_BOTTOM_REVERSE_DOTTED; }
|
||||
| STICK_ARROW_TOP_REVERSE_DOTTED { $$ = yy.LINETYPE.STICK_ARROW_TOP_REVERSE_DOTTED; }
|
||||
| STICK_ARROW_BOTTOM_REVERSE_DOTTED { $$ = yy.LINETYPE.STICK_ARROW_BOTTOM_REVERSE_DOTTED; }
|
||||
|
||||
| BIDIRECTIONAL_SOLID_ARROW { $$ = yy.LINETYPE.BIDIRECTIONAL_SOLID; }
|
||||
| BIDIRECTIONAL_SOLID_ARROW { $$ = yy.LINETYPE.BIDIRECTIONAL_SOLID; }
|
||||
| DOTTED_ARROW { $$ = yy.LINETYPE.DOTTED; }
|
||||
| BIDIRECTIONAL_DOTTED_ARROW { $$ = yy.LINETYPE.BIDIRECTIONAL_DOTTED; }
|
||||
| SOLID_CROSS { $$ = yy.LINETYPE.SOLID_CROSS; }
|
||||
|
@@ -64,30 +64,6 @@ const LINETYPE = {
|
||||
PAR_OVER_START: 32,
|
||||
BIDIRECTIONAL_SOLID: 33,
|
||||
BIDIRECTIONAL_DOTTED: 34,
|
||||
|
||||
SOLID_TOP: 41,
|
||||
SOLID_BOTTOM: 42,
|
||||
STICK_TOP: 43,
|
||||
STICK_BOTTOM: 44,
|
||||
|
||||
SOLID_ARROW_TOP_REVERSE: 45,
|
||||
SOLID_ARROW_BOTTOM_REVERSE: 46,
|
||||
STICK_ARROW_TOP_REVERSE: 47,
|
||||
STICK_ARROW_BOTTOM_REVERSE: 48,
|
||||
|
||||
SOLID_TOP_DOTTED: 51,
|
||||
SOLID_BOTTOM_DOTTED: 52,
|
||||
STICK_TOP_DOTTED: 53,
|
||||
STICK_BOTTOM_DOTTED: 54,
|
||||
|
||||
SOLID_ARROW_TOP_REVERSE_DOTTED: 55,
|
||||
SOLID_ARROW_BOTTOM_REVERSE_DOTTED: 56,
|
||||
STICK_ARROW_TOP_REVERSE_DOTTED: 57,
|
||||
STICK_ARROW_BOTTOM_REVERSE_DOTTED: 58,
|
||||
|
||||
CENTRAL_CONNECTION: 59,
|
||||
CENTRAL_CONNECTION_REVERSE: 60,
|
||||
CENTRAL_CONNECTION_DUAL: 61,
|
||||
} as const;
|
||||
|
||||
const ARROWTYPE = {
|
||||
@@ -268,8 +244,7 @@ export class SequenceDB implements DiagramDB {
|
||||
idTo?: Message['to'],
|
||||
message?: { text: string; wrap: boolean },
|
||||
messageType?: number,
|
||||
activate = false,
|
||||
centralConnection?: number
|
||||
activate = false
|
||||
) {
|
||||
if (messageType === this.LINETYPE.ACTIVE_END) {
|
||||
const cnt = this.activationCount(idFrom ?? '');
|
||||
@@ -296,7 +271,6 @@ export class SequenceDB implements DiagramDB {
|
||||
wrap: message?.wrap ?? this.autoWrap(),
|
||||
type: messageType,
|
||||
activate,
|
||||
centralConnection: centralConnection ?? 0,
|
||||
});
|
||||
return true;
|
||||
}
|
||||
@@ -589,12 +563,6 @@ export class SequenceDB implements DiagramDB {
|
||||
case 'activeStart':
|
||||
this.addSignal(param.actor, undefined, undefined, param.signalType);
|
||||
break;
|
||||
case 'centralConnection':
|
||||
this.addSignal(param.actor, undefined, undefined, param.signalType);
|
||||
break;
|
||||
case 'centralConnectionReverse':
|
||||
this.addSignal(param.actor, undefined, undefined, param.signalType);
|
||||
break;
|
||||
case 'activeEnd':
|
||||
this.addSignal(param.actor, undefined, undefined, param.signalType);
|
||||
break;
|
||||
@@ -638,14 +606,7 @@ export class SequenceDB implements DiagramDB {
|
||||
this.state.records.lastDestroyed = undefined;
|
||||
}
|
||||
}
|
||||
this.addSignal(
|
||||
param.from,
|
||||
param.to,
|
||||
param.msg,
|
||||
param.signalType,
|
||||
param.activate,
|
||||
param.centralConnection
|
||||
);
|
||||
this.addSignal(param.from, param.to, param.msg, param.signalType, param.activate);
|
||||
break;
|
||||
case 'boxStart':
|
||||
this.addBox(param.boxData);
|
||||
|
@@ -104,7 +104,6 @@ describe('more than one sequence diagram', () => {
|
||||
[
|
||||
{
|
||||
"activate": false,
|
||||
"centralConnection": 0,
|
||||
"from": "Alice",
|
||||
"id": "0",
|
||||
"message": "Hello Bob, how are you?",
|
||||
@@ -114,7 +113,6 @@ describe('more than one sequence diagram', () => {
|
||||
},
|
||||
{
|
||||
"activate": false,
|
||||
"centralConnection": 0,
|
||||
"from": "Bob",
|
||||
"id": "1",
|
||||
"message": "I am good thanks!",
|
||||
@@ -133,7 +131,6 @@ describe('more than one sequence diagram', () => {
|
||||
[
|
||||
{
|
||||
"activate": false,
|
||||
"centralConnection": 0,
|
||||
"from": "Alice",
|
||||
"id": "0",
|
||||
"message": "Hello Bob, how are you?",
|
||||
@@ -143,7 +140,6 @@ describe('more than one sequence diagram', () => {
|
||||
},
|
||||
{
|
||||
"activate": false,
|
||||
"centralConnection": 0,
|
||||
"from": "Bob",
|
||||
"id": "1",
|
||||
"message": "I am good thanks!",
|
||||
@@ -164,7 +160,6 @@ describe('more than one sequence diagram', () => {
|
||||
[
|
||||
{
|
||||
"activate": false,
|
||||
"centralConnection": 0,
|
||||
"from": "Alice",
|
||||
"id": "0",
|
||||
"message": "Hello John, how are you?",
|
||||
@@ -174,7 +169,6 @@ describe('more than one sequence diagram', () => {
|
||||
},
|
||||
{
|
||||
"activate": false,
|
||||
"centralConnection": 0,
|
||||
"from": "John",
|
||||
"id": "1",
|
||||
"message": "I am good thanks!",
|
||||
@@ -187,254 +181,6 @@ describe('more than one sequence diagram', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Central Connection Parsing', () => {
|
||||
describe('when parsing central connection syntax', () => {
|
||||
it('should parse actor ()->>() actor syntax as CENTRAL_CONNECTION_DUAL', async () => {
|
||||
const diagram = await Diagram.fromText(`
|
||||
sequenceDiagram
|
||||
participant Alice
|
||||
participant Bob
|
||||
Alice ()->>() Bob: Hello Bob, how are you?
|
||||
`);
|
||||
|
||||
const messages = diagram.db.getMessages();
|
||||
expect(messages).toHaveLength(3); // addMessage + centralConnection + centralConnectionReverse
|
||||
|
||||
// Find the actual message (type: 'addMessage')
|
||||
const actualMessage = messages.find((msg) => msg.type !== undefined && msg.from && msg.to);
|
||||
expect(actualMessage).toMatchObject({
|
||||
from: 'Alice',
|
||||
to: 'Bob',
|
||||
message: 'Hello Bob, how are you?',
|
||||
centralConnection: 61, // CENTRAL_CONNECTION_DUAL
|
||||
activate: true,
|
||||
type: 0, // SOLID (based on test output)
|
||||
});
|
||||
});
|
||||
|
||||
it('should parse actor ()-->>() actor syntax as CENTRAL_CONNECTION_DUAL', async () => {
|
||||
const diagram = await Diagram.fromText(`
|
||||
sequenceDiagram
|
||||
participant Alice
|
||||
participant Bob
|
||||
Alice ()-->>() Bob: Hello Bob, how are you?
|
||||
`);
|
||||
|
||||
const messages = diagram.db.getMessages();
|
||||
expect(messages).toHaveLength(3); // addMessage + centralConnection + centralConnectionReverse
|
||||
|
||||
const actualMessage = messages.find((msg) => msg.type !== undefined && msg.from && msg.to);
|
||||
expect(actualMessage).toMatchObject({
|
||||
from: 'Alice',
|
||||
to: 'Bob',
|
||||
message: 'Hello Bob, how are you?',
|
||||
centralConnection: 61, // CENTRAL_CONNECTION_DUAL
|
||||
activate: true,
|
||||
type: 1, // DOTTED (based on test output)
|
||||
});
|
||||
});
|
||||
|
||||
it('should parse actor ->>() actor syntax as CENTRAL_CONNECTION', async () => {
|
||||
const diagram = await Diagram.fromText(`
|
||||
sequenceDiagram
|
||||
participant Alice
|
||||
participant Bob
|
||||
Alice ->>() Bob: Hello Bob, how are you?
|
||||
`);
|
||||
|
||||
const messages = diagram.db.getMessages();
|
||||
expect(messages).toHaveLength(2); // addMessage + centralConnection (no activation for this pattern)
|
||||
|
||||
const actualMessage = messages.find((msg) => msg.type !== undefined && msg.from && msg.to);
|
||||
expect(actualMessage).toMatchObject({
|
||||
from: 'Alice',
|
||||
to: 'Bob',
|
||||
message: 'Hello Bob, how are you?',
|
||||
centralConnection: 59, // CENTRAL_CONNECTION
|
||||
activate: true,
|
||||
type: 0, // SOLID (based on actual parsing)
|
||||
});
|
||||
});
|
||||
|
||||
it('should parse actor ()-->> actor syntax as CENTRAL_CONNECTION_REVERSE', async () => {
|
||||
const diagram = await Diagram.fromText(`
|
||||
sequenceDiagram
|
||||
participant Alice
|
||||
participant Bob
|
||||
Alice ()-->> Bob: Hello Bob, how are you?
|
||||
`);
|
||||
|
||||
const messages = diagram.db.getMessages();
|
||||
expect(messages).toHaveLength(2); // addMessage + centralConnectionReverse
|
||||
|
||||
const actualMessage = messages.find((msg) => msg.type !== undefined && msg.from && msg.to);
|
||||
expect(actualMessage).toMatchObject({
|
||||
from: 'Alice',
|
||||
to: 'Bob',
|
||||
message: 'Hello Bob, how are you?',
|
||||
centralConnection: 60, // CENTRAL_CONNECTION_REVERSE
|
||||
activate: false,
|
||||
type: 1, // DOTTED (based on test output)
|
||||
});
|
||||
});
|
||||
|
||||
it('should parse actor ()->> actor syntax as CENTRAL_CONNECTION_REVERSE', async () => {
|
||||
const diagram = await Diagram.fromText(`
|
||||
sequenceDiagram
|
||||
participant Alice
|
||||
participant Bob
|
||||
Alice ()->> Bob: Hello Bob, how are you?
|
||||
`);
|
||||
|
||||
const messages = diagram.db.getMessages();
|
||||
expect(messages).toHaveLength(2); // addMessage + centralConnectionReverse
|
||||
|
||||
const actualMessage = messages.find((msg) => msg.type !== undefined && msg.from && msg.to);
|
||||
expect(actualMessage).toMatchObject({
|
||||
from: 'Alice',
|
||||
to: 'Bob',
|
||||
message: 'Hello Bob, how are you?',
|
||||
centralConnection: 60, // CENTRAL_CONNECTION_REVERSE
|
||||
activate: false,
|
||||
type: 0, // SOLID (based on test output)
|
||||
});
|
||||
});
|
||||
|
||||
it('should parse actor ()<<-->>() actor syntax as CENTRAL_CONNECTION_DUAL', async () => {
|
||||
const diagram = await Diagram.fromText(`
|
||||
sequenceDiagram
|
||||
participant Alice
|
||||
participant Bob
|
||||
Alice ()<<-->>() Bob: Hello Bob, how are you?
|
||||
`);
|
||||
|
||||
const messages = diagram.db.getMessages();
|
||||
expect(messages).toHaveLength(3); // addMessage + centralConnection + centralConnectionReverse
|
||||
|
||||
const actualMessage = messages.find((msg) => msg.type !== undefined && msg.from && msg.to);
|
||||
expect(actualMessage).toMatchObject({
|
||||
from: 'Alice',
|
||||
to: 'Bob',
|
||||
message: 'Hello Bob, how are you?',
|
||||
centralConnection: 61, // CENTRAL_CONNECTION_DUAL
|
||||
activate: true,
|
||||
type: 34, // BIDIRECTIONAL_DOTTED
|
||||
});
|
||||
});
|
||||
|
||||
it('should parse actor ()<<->>() actor syntax as CENTRAL_CONNECTION_DUAL', async () => {
|
||||
const diagram = await Diagram.fromText(`
|
||||
sequenceDiagram
|
||||
participant Alice
|
||||
participant Bob
|
||||
Alice ()<<->>() Bob: Hello Bob, how are you?
|
||||
`);
|
||||
|
||||
const messages = diagram.db.getMessages();
|
||||
expect(messages).toHaveLength(3); // addMessage + centralConnection + centralConnectionReverse
|
||||
|
||||
const actualMessage = messages.find((msg) => msg.type !== undefined && msg.from && msg.to);
|
||||
expect(actualMessage).toMatchObject({
|
||||
from: 'Alice',
|
||||
to: 'Bob',
|
||||
message: 'Hello Bob, how are you?',
|
||||
centralConnection: 61, // CENTRAL_CONNECTION_DUAL
|
||||
activate: true,
|
||||
type: 33, // BIDIRECTIONAL_SOLID
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle multiple central connection types in one diagram', async () => {
|
||||
const diagram = await Diagram.fromText(`
|
||||
sequenceDiagram
|
||||
participant Alice
|
||||
participant Bob
|
||||
participant Charlie
|
||||
Alice ()->>() Bob: Message 1
|
||||
Bob ()-->> Charlie: Message 2
|
||||
Charlie ()<<-->>() Alice: Message 3
|
||||
`);
|
||||
|
||||
const messages = diagram.db.getMessages();
|
||||
expect(messages).toHaveLength(8); // 3 addMessages + 5 central connection markers
|
||||
|
||||
// Filter to get only the actual messages
|
||||
const actualMessages = messages.filter((msg) => msg.type !== undefined && msg.from && msg.to);
|
||||
expect(actualMessages).toHaveLength(3);
|
||||
|
||||
expect(actualMessages[0]).toMatchObject({
|
||||
from: 'Alice',
|
||||
to: 'Bob',
|
||||
centralConnection: 61, // CENTRAL_CONNECTION_DUAL (()->>())
|
||||
});
|
||||
|
||||
expect(actualMessages[1]).toMatchObject({
|
||||
from: 'Bob',
|
||||
to: 'Charlie',
|
||||
centralConnection: 60, // CENTRAL_CONNECTION_REVERSE (()-->>)
|
||||
});
|
||||
|
||||
expect(actualMessages[2]).toMatchObject({
|
||||
from: 'Charlie',
|
||||
to: 'Alice',
|
||||
centralConnection: 61, // CENTRAL_CONNECTION_DUAL (()<<-->>())
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle central connections with different arrow types', async () => {
|
||||
const diagram = await Diagram.fromText(`
|
||||
sequenceDiagram
|
||||
participant Alice
|
||||
participant Bob
|
||||
Alice ()-x() Bob: Cross message
|
||||
Alice ()--x() Bob: Dotted cross message
|
||||
`);
|
||||
|
||||
const messages = diagram.db.getMessages();
|
||||
expect(messages).toHaveLength(6); // 2 addMessages + 4 central connection markers
|
||||
|
||||
const actualMessages = messages.filter((msg) => msg.type !== undefined && msg.from && msg.to);
|
||||
expect(actualMessages).toHaveLength(2);
|
||||
|
||||
expect(actualMessages[0]).toMatchObject({
|
||||
from: 'Alice',
|
||||
to: 'Bob',
|
||||
centralConnection: 61, // CENTRAL_CONNECTION_DUAL (()-x())
|
||||
type: 3, // SOLID_CROSS
|
||||
});
|
||||
|
||||
expect(actualMessages[1]).toMatchObject({
|
||||
from: 'Alice',
|
||||
to: 'Bob',
|
||||
centralConnection: 61, // CENTRAL_CONNECTION_DUAL (()--x())
|
||||
type: 4, // DOTTED_CROSS
|
||||
});
|
||||
});
|
||||
|
||||
it('should not break existing parsing without central connections', async () => {
|
||||
const diagram = await Diagram.fromText(`
|
||||
sequenceDiagram
|
||||
participant Alice
|
||||
participant Bob
|
||||
Alice ->> Bob: Normal message
|
||||
Bob -->> Alice: Normal dotted message
|
||||
Alice -x Bob: Normal cross message
|
||||
`);
|
||||
|
||||
const messages = diagram.db.getMessages();
|
||||
expect(messages).toHaveLength(3);
|
||||
|
||||
messages.forEach((msg) => {
|
||||
expect(msg.centralConnection).toBe(0); // No central connection
|
||||
});
|
||||
|
||||
expect(messages[0].type).toBe(0); // SOLID (based on actual parsing)
|
||||
expect(messages[1].type).toBe(1); // DOTTED (based on actual parsing)
|
||||
expect(messages[2].type).toBe(3); // SOLID_CROSS
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when parsing a sequenceDiagram', function () {
|
||||
let diagram;
|
||||
beforeEach(async function () {
|
||||
@@ -2312,36 +2058,6 @@ Bob->>Alice:Got it!
|
||||
expect(messages[0].from).toBe('Alice');
|
||||
expect(messages[0].to).toBe('Bob');
|
||||
});
|
||||
|
||||
it('1 should parse ', async () => {
|
||||
const diagram = await Diagram.fromText(`
|
||||
sequenceDiagram
|
||||
actor Bob
|
||||
actor Alice
|
||||
Bob -|\\ Alice: Hello Alice, how are you?
|
||||
Bob -|/ Alice: Hello Alice, how are you?
|
||||
Bob -// Alice: Hello Alice, how are you?
|
||||
Bob -\\\\ Alice: Hello Alice, how are you?
|
||||
|
||||
Bob \\|- Alice: Hello Alice, how are you?
|
||||
Bob /|- Alice: Hello Alice, how are you?
|
||||
Bob //- Alice: Hello Alice, how are you?
|
||||
Bob \\\\- Alice: Hello Alice, how are you?
|
||||
`);
|
||||
|
||||
const messages = diagram.db.getMessages();
|
||||
});
|
||||
|
||||
it('2 should parse ', async () => {
|
||||
const diagram = await Diagram.fromText(`
|
||||
sequenceDiagram
|
||||
actor Bob
|
||||
actor Alice
|
||||
Alice ()<<->>() Bob: hey?
|
||||
`);
|
||||
|
||||
const messages = diagram.db.getMessages();
|
||||
});
|
||||
describe('when parsing extended participant syntax', () => {
|
||||
it('should parse participants with different quote styles and whitespace', async () => {
|
||||
const diagram = await Diagram.fromText(`
|
||||
|
@@ -282,49 +282,6 @@ const drawNote = async function (elem: any, noteModel: NoteModel) {
|
||||
bounds.models.addNote(noteModel);
|
||||
};
|
||||
|
||||
const drawCentralConnection = function (
|
||||
elem: any,
|
||||
msg: any,
|
||||
msgModel: any,
|
||||
diagObj: Diagram,
|
||||
startx: number,
|
||||
stopx: number,
|
||||
lineStartY: number
|
||||
) {
|
||||
const actors = diagObj.db.getActors();
|
||||
const fromActor = actors.get(msg.from);
|
||||
const toActor = actors.get(msg.to);
|
||||
const fromCenter = fromActor.x + fromActor.width / 2;
|
||||
const toCenter = toActor.x + toActor.width / 2;
|
||||
|
||||
const g = elem.append('g');
|
||||
|
||||
const drawCircle = (cx: number) => {
|
||||
g.append('circle')
|
||||
.attr('cx', cx)
|
||||
.attr('cy', lineStartY)
|
||||
.attr('r', 5)
|
||||
.attr('width', 10)
|
||||
.attr('height', 10);
|
||||
};
|
||||
|
||||
const { CENTRAL_CONNECTION, CENTRAL_CONNECTION_REVERSE, CENTRAL_CONNECTION_DUAL } =
|
||||
diagObj.db.LINETYPE;
|
||||
|
||||
switch (msg.centralConnection) {
|
||||
case CENTRAL_CONNECTION:
|
||||
drawCircle(toCenter);
|
||||
break;
|
||||
case CENTRAL_CONNECTION_REVERSE:
|
||||
drawCircle(fromCenter);
|
||||
break;
|
||||
case CENTRAL_CONNECTION_DUAL:
|
||||
drawCircle(fromCenter);
|
||||
drawCircle(toCenter);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
const messageFont = (cnf) => {
|
||||
return {
|
||||
fontFamily: cnf.messageFontFamily,
|
||||
@@ -410,7 +367,7 @@ async function boundMessage(_diagram, msgModel): Promise<number> {
|
||||
* @param lineStartY - The Y coordinate at which the message line starts
|
||||
* @param diagObj - The diagram object.
|
||||
*/
|
||||
const drawMessage = async function (diagram, msgModel, lineStartY: number, diagObj: Diagram, msg) {
|
||||
const drawMessage = async function (diagram, msgModel, lineStartY: number, diagObj: Diagram) {
|
||||
const { startx, stopx, starty, message, type, sequenceIndex, sequenceVisible } = msgModel;
|
||||
const textDims = utils.calculateTextDimensions(message, messageFont(conf));
|
||||
const textObj = svgDrawCommon.getTextObj();
|
||||
@@ -476,9 +433,6 @@ const drawMessage = async function (diagram, msgModel, lineStartY: number, diagO
|
||||
line.attr('y1', lineStartY);
|
||||
line.attr('x2', stopx);
|
||||
line.attr('y2', lineStartY);
|
||||
if (hasCentralConnection(msg, diagObj)) {
|
||||
drawCentralConnection(diagram, msg, msgModel, diagObj, startx, stopx, lineStartY);
|
||||
}
|
||||
}
|
||||
// Make an SVG Container
|
||||
// Draw the line
|
||||
@@ -487,15 +441,7 @@ const drawMessage = async function (diagram, msgModel, lineStartY: number, diagO
|
||||
type === diagObj.db.LINETYPE.DOTTED_CROSS ||
|
||||
type === diagObj.db.LINETYPE.DOTTED_POINT ||
|
||||
type === diagObj.db.LINETYPE.DOTTED_OPEN ||
|
||||
type === diagObj.db.LINETYPE.BIDIRECTIONAL_DOTTED ||
|
||||
type === diagObj.db.LINETYPE.SOLID_TOP_DOTTED ||
|
||||
type === diagObj.db.LINETYPE.SOLID_BOTTOM_DOTTED ||
|
||||
type === diagObj.db.LINETYPE.STICK_TOP_DOTTED ||
|
||||
type === diagObj.db.LINETYPE.STICK_BOTTOM_DOTTED ||
|
||||
type === diagObj.db.LINETYPE.SOLID_ARROW_TOP_REVERSE_DOTTED ||
|
||||
type === diagObj.db.LINETYPE.SOLID_ARROW_BOTTOM_REVERSE_DOTTED ||
|
||||
type === diagObj.db.LINETYPE.STICK_ARROW_TOP_REVERSE_DOTTED ||
|
||||
type === diagObj.db.LINETYPE.STICK_ARROW_BOTTOM_REVERSE_DOTTED
|
||||
type === diagObj.db.LINETYPE.BIDIRECTIONAL_DOTTED
|
||||
) {
|
||||
line.style('stroke-dasharray', '3, 3');
|
||||
line.attr('class', 'messageLine1');
|
||||
@@ -511,51 +457,6 @@ const drawMessage = async function (diagram, msgModel, lineStartY: number, diagO
|
||||
line.attr('stroke-width', 2);
|
||||
line.attr('stroke', 'none'); // handled by theme/css anyway
|
||||
line.style('fill', 'none'); // remove any fill colour
|
||||
|
||||
if (type === diagObj.db.LINETYPE.SOLID_TOP || type === diagObj.db.LINETYPE.SOLID_TOP_DOTTED) {
|
||||
line.attr('marker-end', 'url(' + url + '#solidTopArrowHead)');
|
||||
}
|
||||
if (
|
||||
type === diagObj.db.LINETYPE.SOLID_BOTTOM ||
|
||||
type === diagObj.db.LINETYPE.SOLID_BOTTOM_DOTTED
|
||||
) {
|
||||
line.attr('marker-end', 'url(' + url + '#solidBottomArrowHead)');
|
||||
}
|
||||
if (type === diagObj.db.LINETYPE.STICK_TOP || type === diagObj.db.LINETYPE.STICK_TOP_DOTTED) {
|
||||
line.attr('marker-end', 'url(' + url + '#stickTopArrowHead)');
|
||||
}
|
||||
if (
|
||||
type === diagObj.db.LINETYPE.STICK_BOTTOM ||
|
||||
type === diagObj.db.LINETYPE.STICK_BOTTOM_DOTTED
|
||||
) {
|
||||
line.attr('marker-end', 'url(' + url + '#stickBottomArrowHead)');
|
||||
}
|
||||
|
||||
if (
|
||||
type === diagObj.db.LINETYPE.SOLID_ARROW_TOP_REVERSE ||
|
||||
type === diagObj.db.LINETYPE.SOLID_ARROW_TOP_REVERSE_DOTTED
|
||||
) {
|
||||
line.attr('marker-start', 'url(' + url + '#solidBottomArrowHead)');
|
||||
}
|
||||
if (
|
||||
type === diagObj.db.LINETYPE.SOLID_ARROW_BOTTOM_REVERSE ||
|
||||
type === diagObj.db.LINETYPE.SOLID_ARROW_BOTTOM_REVERSE_DOTTED
|
||||
) {
|
||||
line.attr('marker-start', 'url(' + url + '#solidTopArrowHead)');
|
||||
}
|
||||
if (
|
||||
type === diagObj.db.LINETYPE.STICK_ARROW_TOP_REVERSE ||
|
||||
type === diagObj.db.LINETYPE.STICK_ARROW_TOP_REVERSE_DOTTED
|
||||
) {
|
||||
line.attr('marker-start', 'url(' + url + '#stickBottomArrowHead)');
|
||||
}
|
||||
if (
|
||||
type === diagObj.db.LINETYPE.STICK_ARROW_BOTTOM_REVERSE ||
|
||||
type === diagObj.db.LINETYPE.STICK_ARROW_BOTTOM_REVERSE_DOTTED
|
||||
) {
|
||||
line.attr('marker-start', 'url(' + url + '#stickTopArrowHead)');
|
||||
}
|
||||
|
||||
if (type === diagObj.db.LINETYPE.SOLID || type === diagObj.db.LINETYPE.DOTTED) {
|
||||
line.attr('marker-end', 'url(' + url + '#arrowhead)');
|
||||
}
|
||||
@@ -580,18 +481,7 @@ const drawMessage = async function (diagram, msgModel, lineStartY: number, diagO
|
||||
type === diagObj.db.LINETYPE.BIDIRECTIONAL_SOLID ||
|
||||
type === diagObj.db.LINETYPE.BIDIRECTIONAL_DOTTED;
|
||||
|
||||
const isReverseArrowType =
|
||||
type === diagObj.db.LINETYPE.SOLID_ARROW_TOP_REVERSE ||
|
||||
type === diagObj.db.LINETYPE.SOLID_ARROW_TOP_REVERSE_DOTTED ||
|
||||
type === diagObj.db.LINETYPE.SOLID_ARROW_BOTTOM_REVERSE ||
|
||||
type === diagObj.db.LINETYPE.SOLID_ARROW_BOTTOM_REVERSE_DOTTED ||
|
||||
type === diagObj.db.LINETYPE.STICK_ARROW_TOP_REVERSE ||
|
||||
type === diagObj.db.LINETYPE.STICK_ARROW_TOP_REVERSE_DOTTED ||
|
||||
type === diagObj.db.LINETYPE.STICK_ARROW_BOTTOM_REVERSE ||
|
||||
type === diagObj.db.LINETYPE.STICK_ARROW_BOTTOM_REVERSE_DOTTED;
|
||||
|
||||
let x = 0;
|
||||
if (isBidirectional || isReverseArrowType) {
|
||||
if (isBidirectional) {
|
||||
const SEQUENCE_NUMBER_RADIUS = 6;
|
||||
|
||||
if (startx < stopx) {
|
||||
@@ -599,7 +489,6 @@ const drawMessage = async function (diagram, msgModel, lineStartY: number, diagO
|
||||
} else {
|
||||
line.attr('x1', startx + SEQUENCE_NUMBER_RADIUS);
|
||||
}
|
||||
x = 3.5;
|
||||
}
|
||||
|
||||
diagram
|
||||
@@ -609,8 +498,7 @@ const drawMessage = async function (diagram, msgModel, lineStartY: number, diagO
|
||||
.attr('x2', startx)
|
||||
.attr('y2', lineStartY)
|
||||
.attr('stroke-width', 0)
|
||||
.attr('marker-start', 'url(' + url + '#sequencenumber)')
|
||||
.attr('transform', `translate(-${x}, 0)`);
|
||||
.attr('marker-start', 'url(' + url + '#sequencenumber)');
|
||||
|
||||
diagram
|
||||
.append('text')
|
||||
@@ -620,8 +508,7 @@ const drawMessage = async function (diagram, msgModel, lineStartY: number, diagO
|
||||
.attr('font-size', '12px')
|
||||
.attr('text-anchor', 'middle')
|
||||
.attr('class', 'sequenceNumber')
|
||||
.text(sequenceIndex)
|
||||
.attr('transform', `translate(-${x}, 0)`);
|
||||
.text(sequenceIndex);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -970,10 +857,6 @@ export const draw = async function (_text: string, id: string, _version: string,
|
||||
svgDraw.insertArrowCrossHead(diagram);
|
||||
svgDraw.insertArrowFilledHead(diagram);
|
||||
svgDraw.insertSequenceNumber(diagram);
|
||||
svgDraw.insertSolidTopArrowHead(diagram);
|
||||
svgDraw.insertSolidBottomArrowHead(diagram);
|
||||
svgDraw.insertStickTopArrowHead(diagram);
|
||||
svgDraw.insertStickBottomArrowHead(diagram);
|
||||
|
||||
/**
|
||||
* @param msg - The message to draw.
|
||||
@@ -1014,12 +897,6 @@ export const draw = async function (_text: string, id: string, _version: string,
|
||||
case diagObj.db.LINETYPE.ACTIVE_START:
|
||||
bounds.newActivation(msg, diagram, actors);
|
||||
break;
|
||||
case diagObj.db.LINETYPE.CENTRAL_CONNECTION:
|
||||
bounds.newActivation(msg, diagram, actors);
|
||||
break;
|
||||
case diagObj.db.LINETYPE.CENTRAL_CONNECTION_REVERSE:
|
||||
bounds.newActivation(msg, diagram, actors);
|
||||
break;
|
||||
case diagObj.db.LINETYPE.ACTIVE_END:
|
||||
activeEnd(msg, bounds.getVerticalPos());
|
||||
break;
|
||||
@@ -1178,7 +1055,7 @@ export const draw = async function (_text: string, id: string, _version: string,
|
||||
createdActors,
|
||||
destroyedActors
|
||||
);
|
||||
messagesToDraw.push({ messageModel: msgModel, lineStartY: lineStartY, msg });
|
||||
messagesToDraw.push({ messageModel: msgModel, lineStartY: lineStartY });
|
||||
bounds.models.addMessage(msgModel);
|
||||
} catch (e) {
|
||||
log.error('error while drawing message', e);
|
||||
@@ -1191,27 +1068,6 @@ export const draw = async function (_text: string, id: string, _version: string,
|
||||
diagObj.db.LINETYPE.SOLID_OPEN,
|
||||
diagObj.db.LINETYPE.DOTTED_OPEN,
|
||||
diagObj.db.LINETYPE.SOLID,
|
||||
|
||||
diagObj.db.LINETYPE.SOLID_TOP,
|
||||
diagObj.db.LINETYPE.SOLID_BOTTOM,
|
||||
diagObj.db.LINETYPE.STICK_TOP,
|
||||
diagObj.db.LINETYPE.STICK_BOTTOM,
|
||||
|
||||
diagObj.db.LINETYPE.SOLID_TOP_DOTTED,
|
||||
diagObj.db.LINETYPE.SOLID_BOTTOM_DOTTED,
|
||||
diagObj.db.LINETYPE.STICK_TOP_DOTTED,
|
||||
diagObj.db.LINETYPE.STICK_BOTTOM_DOTTED,
|
||||
|
||||
diagObj.db.LINETYPE.SOLID_ARROW_TOP_REVERSE,
|
||||
diagObj.db.LINETYPE.SOLID_ARROW_BOTTOM_REVERSE,
|
||||
diagObj.db.LINETYPE.STICK_ARROW_TOP_REVERSE,
|
||||
diagObj.db.LINETYPE.STICK_ARROW_BOTTOM_REVERSE,
|
||||
|
||||
diagObj.db.LINETYPE.SOLID_ARROW_TOP_REVERSE_DOTTED,
|
||||
diagObj.db.LINETYPE.SOLID_ARROW_BOTTOM_REVERSE_DOTTED,
|
||||
diagObj.db.LINETYPE.STICK_ARROW_TOP_REVERSE_DOTTED,
|
||||
diagObj.db.LINETYPE.STICK_ARROW_BOTTOM_REVERSE_DOTTED,
|
||||
|
||||
diagObj.db.LINETYPE.DOTTED,
|
||||
diagObj.db.LINETYPE.SOLID_CROSS,
|
||||
diagObj.db.LINETYPE.DOTTED_CROSS,
|
||||
@@ -1231,7 +1087,7 @@ export const draw = async function (_text: string, id: string, _version: string,
|
||||
await drawActors(diagram, actors, actorKeys, false);
|
||||
|
||||
for (const e of messagesToDraw) {
|
||||
await drawMessage(diagram, e.messageModel, e.lineStartY, diagObj, e.msg);
|
||||
await drawMessage(diagram, e.messageModel, e.lineStartY, diagObj);
|
||||
}
|
||||
if (conf.mirrorActors) {
|
||||
await drawActors(diagram, actors, actorKeys, true);
|
||||
@@ -1605,85 +1461,12 @@ const buildNoteModel = async function (msg, actors, diagObj) {
|
||||
return noteModel;
|
||||
};
|
||||
|
||||
// Central connection positioning constants
|
||||
const CENTRAL_CONNECTION_BASE_OFFSET = 4;
|
||||
const CENTRAL_CONNECTION_BIDIRECTIONAL_OFFSET = 6;
|
||||
|
||||
/**
|
||||
* Check if a message has central connection
|
||||
* @param msg - The message object
|
||||
* @param diagObj - The diagram object containing LINETYPE constants
|
||||
* @returns True if the message has any type of central connection
|
||||
*/
|
||||
const hasCentralConnection = function (msg, diagObj) {
|
||||
const { CENTRAL_CONNECTION, CENTRAL_CONNECTION_REVERSE, CENTRAL_CONNECTION_DUAL } =
|
||||
diagObj.db.LINETYPE;
|
||||
return [CENTRAL_CONNECTION, CENTRAL_CONNECTION_REVERSE, CENTRAL_CONNECTION_DUAL].includes(
|
||||
msg.centralConnection
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculate the positioning offset for central connection arrows
|
||||
* @param msg - The message object
|
||||
* @param diagObj - The diagram object containing LINETYPE constants
|
||||
* @param isArrowToRight - Whether the arrow is pointing to the right
|
||||
* @returns The offset to apply to startx position
|
||||
*/
|
||||
const calculateCentralConnectionOffset = function (msg, diagObj, isArrowToRight) {
|
||||
const {
|
||||
CENTRAL_CONNECTION_REVERSE,
|
||||
CENTRAL_CONNECTION_DUAL,
|
||||
BIDIRECTIONAL_SOLID,
|
||||
BIDIRECTIONAL_DOTTED,
|
||||
} = diagObj.db.LINETYPE;
|
||||
|
||||
let offset = 0;
|
||||
|
||||
if (
|
||||
msg.centralConnection === CENTRAL_CONNECTION_REVERSE ||
|
||||
msg.centralConnection === CENTRAL_CONNECTION_DUAL
|
||||
) {
|
||||
offset += CENTRAL_CONNECTION_BASE_OFFSET;
|
||||
}
|
||||
|
||||
if (
|
||||
msg.centralConnection === CENTRAL_CONNECTION_DUAL &&
|
||||
(msg.type === BIDIRECTIONAL_SOLID || msg.type === BIDIRECTIONAL_DOTTED)
|
||||
) {
|
||||
offset += isArrowToRight ? 0 : -CENTRAL_CONNECTION_BIDIRECTIONAL_OFFSET;
|
||||
}
|
||||
|
||||
return offset;
|
||||
};
|
||||
|
||||
const buildMessageModel = function (msg, actors, diagObj) {
|
||||
if (
|
||||
![
|
||||
diagObj.db.LINETYPE.SOLID_OPEN,
|
||||
diagObj.db.LINETYPE.DOTTED_OPEN,
|
||||
diagObj.db.LINETYPE.SOLID,
|
||||
|
||||
diagObj.db.LINETYPE.SOLID_TOP,
|
||||
diagObj.db.LINETYPE.SOLID_BOTTOM,
|
||||
diagObj.db.LINETYPE.STICK_TOP,
|
||||
diagObj.db.LINETYPE.STICK_BOTTOM,
|
||||
|
||||
diagObj.db.LINETYPE.SOLID_TOP_DOTTED,
|
||||
diagObj.db.LINETYPE.SOLID_BOTTOM_DOTTED,
|
||||
diagObj.db.LINETYPE.STICK_TOP_DOTTED,
|
||||
diagObj.db.LINETYPE.STICK_BOTTOM_DOTTED,
|
||||
|
||||
diagObj.db.LINETYPE.SOLID_ARROW_TOP_REVERSE,
|
||||
diagObj.db.LINETYPE.SOLID_ARROW_BOTTOM_REVERSE,
|
||||
diagObj.db.LINETYPE.STICK_ARROW_TOP_REVERSE,
|
||||
diagObj.db.LINETYPE.STICK_ARROW_BOTTOM_REVERSE,
|
||||
|
||||
diagObj.db.LINETYPE.SOLID_ARROW_TOP_REVERSE_DOTTED,
|
||||
diagObj.db.LINETYPE.SOLID_ARROW_BOTTOM_REVERSE_DOTTED,
|
||||
diagObj.db.LINETYPE.STICK_ARROW_TOP_REVERSE_DOTTED,
|
||||
diagObj.db.LINETYPE.STICK_ARROW_BOTTOM_REVERSE_DOTTED,
|
||||
|
||||
diagObj.db.LINETYPE.DOTTED,
|
||||
diagObj.db.LINETYPE.SOLID_CROSS,
|
||||
diagObj.db.LINETYPE.DOTTED_CROSS,
|
||||
@@ -1701,8 +1484,6 @@ const buildMessageModel = function (msg, actors, diagObj) {
|
||||
let startx = isArrowToRight ? fromRight : fromLeft;
|
||||
let stopx = isArrowToRight ? toLeft : toRight;
|
||||
|
||||
// Apply central connection positioning adjustments
|
||||
startx += calculateCentralConnectionOffset(msg, diagObj, isArrowToRight);
|
||||
// As the line width is considered, the left and right values will be off by 2.
|
||||
const isArrowToActivation = Math.abs(toLeft - toRight) > 2;
|
||||
|
||||
@@ -1736,30 +1517,7 @@ const buildMessageModel = function (msg, actors, diagObj) {
|
||||
* Shorten the length of arrow at the end and move the marker forward (using refX) to have a clean arrowhead
|
||||
* This is not required for open arrows that don't have arrowheads
|
||||
*/
|
||||
if (
|
||||
![
|
||||
diagObj.db.LINETYPE.SOLID_OPEN,
|
||||
diagObj.db.LINETYPE.DOTTED_OPEN,
|
||||
|
||||
diagObj.db.LINETYPE.STICK_TOP,
|
||||
diagObj.db.LINETYPE.STICK_BOTTOM,
|
||||
|
||||
diagObj.db.LINETYPE.STICK_TOP_DOTTED,
|
||||
diagObj.db.LINETYPE.STICK_BOTTOM_DOTTED,
|
||||
|
||||
diagObj.db.LINETYPE.SOLID_ARROW_TOP_REVERSE_DOTTED,
|
||||
diagObj.db.LINETYPE.SOLID_ARROW_BOTTOM_REVERSE_DOTTED,
|
||||
|
||||
diagObj.db.LINETYPE.STICK_ARROW_TOP_REVERSE,
|
||||
diagObj.db.LINETYPE.STICK_ARROW_BOTTOM_REVERSE,
|
||||
|
||||
diagObj.db.LINETYPE.STICK_ARROW_TOP_REVERSE_DOTTED,
|
||||
diagObj.db.LINETYPE.STICK_ARROW_BOTTOM_REVERSE_DOTTED,
|
||||
|
||||
diagObj.db.LINETYPE.SOLID_ARROW_TOP_REVERSE,
|
||||
diagObj.db.LINETYPE.SOLID_ARROW_BOTTOM_REVERSE,
|
||||
].includes(msg.type)
|
||||
) {
|
||||
if (![diagObj.db.LINETYPE.SOLID_OPEN, diagObj.db.LINETYPE.DOTTED_OPEN].includes(msg.type)) {
|
||||
stopx += adjustValue(3);
|
||||
}
|
||||
|
||||
@@ -1767,14 +1525,9 @@ const buildMessageModel = function (msg, actors, diagObj) {
|
||||
* Shorten start position of bidirectional arrow to accommodate for second arrowhead
|
||||
*/
|
||||
if (
|
||||
[
|
||||
diagObj.db.LINETYPE.BIDIRECTIONAL_SOLID,
|
||||
diagObj.db.LINETYPE.BIDIRECTIONAL_DOTTED,
|
||||
diagObj.db.LINETYPE.SOLID_ARROW_TOP_REVERSE_DOTTED,
|
||||
diagObj.db.LINETYPE.SOLID_ARROW_BOTTOM_REVERSE_DOTTED,
|
||||
diagObj.db.LINETYPE.SOLID_ARROW_TOP_REVERSE,
|
||||
diagObj.db.LINETYPE.SOLID_ARROW_BOTTOM_REVERSE,
|
||||
].includes(msg.type)
|
||||
[diagObj.db.LINETYPE.BIDIRECTIONAL_SOLID, diagObj.db.LINETYPE.BIDIRECTIONAL_DOTTED].includes(
|
||||
msg.type
|
||||
)
|
||||
) {
|
||||
startx -= adjustValue(3);
|
||||
}
|
||||
|
@@ -1709,77 +1709,6 @@ const _drawMenuItemTextCandidateFunc = (function () {
|
||||
};
|
||||
})();
|
||||
|
||||
/**
|
||||
* Setup arrow head and define the marker. The result is appended to the svg.
|
||||
*
|
||||
* @param elem
|
||||
*/
|
||||
export const insertSolidTopArrowHead = function (elem) {
|
||||
elem
|
||||
.append('defs')
|
||||
.append('marker')
|
||||
.attr('id', 'solidTopArrowHead')
|
||||
.attr('refX', 7.9)
|
||||
.attr('refY', 7.25)
|
||||
.attr('markerUnits', 'userSpaceOnUse')
|
||||
.attr('markerWidth', 12)
|
||||
.attr('markerHeight', 12)
|
||||
.attr('orient', 'auto-start-reverse')
|
||||
.append('path')
|
||||
.attr('d', 'M 0 0 L 10 8 L 0 8 z'); // this is actual shape for arrowhead
|
||||
};
|
||||
|
||||
export const insertSolidBottomArrowHead = function (elem) {
|
||||
elem
|
||||
.append('defs')
|
||||
.append('marker')
|
||||
.attr('id', 'solidBottomArrowHead')
|
||||
.attr('refX', 7.9)
|
||||
.attr('refY', 0.75)
|
||||
.attr('markerUnits', 'userSpaceOnUse')
|
||||
.attr('markerWidth', 12)
|
||||
.attr('markerHeight', 12)
|
||||
.attr('orient', 'auto-start-reverse')
|
||||
.append('path')
|
||||
.attr('d', 'M 0 0 L 10 0 L 0 8 z');
|
||||
};
|
||||
|
||||
export const insertStickTopArrowHead = function (elem) {
|
||||
elem
|
||||
.append('defs')
|
||||
.append('marker')
|
||||
.attr('id', 'stickTopArrowHead')
|
||||
.attr('refX', 7.5)
|
||||
.attr('refY', 7)
|
||||
.attr('markerUnits', 'userSpaceOnUse')
|
||||
.attr('markerWidth', 12)
|
||||
.attr('markerHeight', 12)
|
||||
.attr('orient', 'auto-start-reverse')
|
||||
.append('path')
|
||||
.attr('d', 'M 0 0 L 7 7')
|
||||
.attr('stroke', 'black')
|
||||
.attr('stroke-width', 1.5)
|
||||
.attr('fill', 'none');
|
||||
};
|
||||
|
||||
export const insertStickBottomArrowHead = function (elem) {
|
||||
elem
|
||||
.append('defs')
|
||||
.append('marker')
|
||||
.attr('id', 'stickBottomArrowHead')
|
||||
.attr('refX', 7.5)
|
||||
.attr('refY', 0)
|
||||
.attr('markerUnits', 'userSpaceOnUse')
|
||||
.attr('markerWidth', 12)
|
||||
.attr('markerHeight', 12)
|
||||
.attr('orient', 'auto-start-reverse')
|
||||
.append('path')
|
||||
.attr('d', 'M 0 7 L 7 0')
|
||||
.attr('stroke', 'black')
|
||||
.attr('stroke-width', 1.5)
|
||||
.attr('fill', 'none');
|
||||
};
|
||||
|
||||
export default {
|
||||
drawRect,
|
||||
drawText,
|
||||
@@ -1802,8 +1731,4 @@ export default {
|
||||
getNoteRect,
|
||||
fixLifeLineHeights,
|
||||
sanitizeUrl,
|
||||
insertSolidTopArrowHead,
|
||||
insertSolidBottomArrowHead,
|
||||
insertStickTopArrowHead,
|
||||
insertStickBottomArrowHead,
|
||||
};
|
||||
|
@@ -35,7 +35,6 @@ export interface Message {
|
||||
type?: number;
|
||||
activate?: boolean;
|
||||
placement?: string;
|
||||
centralConnection?: number;
|
||||
}
|
||||
|
||||
export interface AddMessageParams {
|
||||
@@ -51,8 +50,6 @@ export interface AddMessageParams {
|
||||
| 'destroyParticipant'
|
||||
| 'activeStart'
|
||||
| 'activeEnd'
|
||||
| 'centralConnection'
|
||||
| 'centralConnectionReverse'
|
||||
| 'addNote'
|
||||
| 'addLinks'
|
||||
| 'addALink'
|
||||
|
@@ -185,22 +185,27 @@ A --> C[End]
|
||||
|
||||
Some common flowchart configurations are:
|
||||
|
||||
- _htmlLabels_: true/false
|
||||
- _curve_: linear/curve
|
||||
- _diagramPadding_: number
|
||||
- _useMaxWidth_: number
|
||||
|
||||
**Deprecated configurations:**
|
||||
|
||||
- ~~_htmlLabels_~~: Use global `htmlLabels` instead
|
||||
|
||||
For a complete list of flowchart configurations, see [defaultConfig.ts](https://github.com/mermaid-js/mermaid/blob/develop/packages/mermaid/src/defaultConfig.ts) in the source code.
|
||||
_Soon we plan to publish a complete list of all diagram-specific configurations updated in the docs._
|
||||
|
||||
The following code snippet changes flowchart config:
|
||||
|
||||
`%%{init: { "flowchart": { "htmlLabels": true, "curve": "linear" } } }%%`
|
||||
```
|
||||
%%{init: { "htmlLabels": true, "flowchart": { "curve": "linear" } } }%%
|
||||
```
|
||||
|
||||
Here we are overriding only the flowchart config, and not the general config, setting `htmlLabels` to `true` and `curve` to `linear`.
|
||||
**Note:** `flowchart.htmlLabels` has been deprecated. Use the global `htmlLabels` configuration instead.
|
||||
|
||||
```mermaid-example
|
||||
%%{init: { "flowchart": { "htmlLabels": true, "curve": "linear" } } }%%
|
||||
%%{init: { "htmlLabels": true, "flowchart": { "curve": "linear" } } }%%
|
||||
graph TD
|
||||
A(Forest) --> B[/Another/]
|
||||
A --> C[End]
|
||||
|
@@ -368,7 +368,7 @@ The list of configuration objects are described [in the mermaidAPI documentation
|
||||
```html
|
||||
<script type="module">
|
||||
import mermaid from './mermaid.esm.mjs';
|
||||
let config = { startOnLoad: true, flowchart: { useMaxWidth: false, htmlLabels: true } };
|
||||
let config = { startOnLoad: true, htmlLabels: true, flowchart: { useMaxWidth: false } };
|
||||
mermaid.initialize(config);
|
||||
</script>
|
||||
```
|
||||
|
@@ -216,11 +216,7 @@ Messages can be of two displayed either solid or with a dotted line.
|
||||
[Actor][Arrow][Actor]:Message text
|
||||
```
|
||||
|
||||
Lines can be solid or dotted, and can end with various types of arrowheads, crosses, or open arrows.
|
||||
|
||||
#### Supported Arrow Types
|
||||
|
||||
**Standard Arrow Types**
|
||||
There are ten types of arrows currently supported:
|
||||
|
||||
| Type | Description |
|
||||
| -------- | ---------------------------------------------------- |
|
||||
@@ -235,49 +231,6 @@ Lines can be solid or dotted, and can end with various types of arrowheads, cros
|
||||
| `-)` | Solid line with an open arrow at the end (async) |
|
||||
| `--)` | Dotted line with a open arrow at the end (async) |
|
||||
|
||||
**Half-Arrows (v<MERMAID_RELEASE_VERSION>+)**
|
||||
|
||||
The following half-arrow types are supported for more expressive sequence diagrams. Both solid and dotted variants are available by increasing the number of dashes (`-` → `--`).
|
||||
|
||||
---
|
||||
|
||||
| Type | Description |
|
||||
| ------- | ---------------------------------------------------- |
|
||||
| `-\|\` | Solid line with top half arrowhead |
|
||||
| `--\|\` | Dotted line with top half arrowhead |
|
||||
| `-\|/` | Solid line with bottom half arrowhead |
|
||||
| `--\|/` | Dotted line with bottom half arrowhead |
|
||||
| `/\|-` | Solid line with reverse top half arrowhead |
|
||||
| `/\|--` | Dotted line with reverse top half arrowhead |
|
||||
| `\\-` | Solid line with reverse bottom half arrowhead |
|
||||
| `\\--` | Dotted line with reverse bottom half arrowhead |
|
||||
| `-\\` | Solid line with top stick half arrowhead |
|
||||
| `--\\` | Dotted line with top stick half arrowhead |
|
||||
| `-//` | Solid line with bottom stick half arrowhead |
|
||||
| `--//` | Dotted line with bottom stick half arrowhead |
|
||||
| `//-` | Solid line with reverse top stick half arrowhead |
|
||||
| `//--` | Dotted line with reverse top stick half arrowhead |
|
||||
| `\\-` | Solid line with reverse bottom stick half arrowhead |
|
||||
| `\\--` | Dotted line with reverse bottom stick half arrowhead |
|
||||
|
||||
## Central Connections (v<MERMAID_RELEASE_VERSION>+)
|
||||
|
||||
Mermaid sequence diagrams support **central lifeline connections** using a `()`.
|
||||
This is useful to represent messages or signals that connect to a central point, rather than from one actor directly to another.
|
||||
|
||||
To indicate a central connection, append `()` to the arrow syntax.
|
||||
|
||||
#### Basic Syntax
|
||||
|
||||
```mermaid-example
|
||||
sequenceDiagram
|
||||
participant Alice
|
||||
participant John
|
||||
Alice->>()John: Hello John
|
||||
Alice()->>John: How are you?
|
||||
John()->>()Alice: Great!
|
||||
```
|
||||
|
||||
## Activations
|
||||
|
||||
It is possible to activate and deactivate an actor. (de)activation can be dedicated declarations:
|
||||
|
@@ -207,7 +207,7 @@ describe('when using mermaid and ', () => {
|
||||
[Error: Parse error on line 2:
|
||||
...equenceDiagramAlice:->Bob: Hello Bob, h...
|
||||
----------------------^
|
||||
Expecting '()', 'SOLID_OPEN_ARROW', 'DOTTED_OPEN_ARROW', 'SOLID_ARROW', 'SOLID_ARROW_TOP', 'SOLID_ARROW_BOTTOM', 'STICK_ARROW_TOP', 'STICK_ARROW_BOTTOM', 'SOLID_ARROW_TOP_DOTTED', 'SOLID_ARROW_BOTTOM_DOTTED', 'STICK_ARROW_TOP_DOTTED', 'STICK_ARROW_BOTTOM_DOTTED', 'SOLID_ARROW_TOP_REVERSE', 'SOLID_ARROW_BOTTOM_REVERSE', 'STICK_ARROW_TOP_REVERSE', 'STICK_ARROW_BOTTOM_REVERSE', 'SOLID_ARROW_TOP_REVERSE_DOTTED', 'SOLID_ARROW_BOTTOM_REVERSE_DOTTED', 'STICK_ARROW_TOP_REVERSE_DOTTED', 'STICK_ARROW_BOTTOM_REVERSE_DOTTED', 'BIDIRECTIONAL_SOLID_ARROW', 'DOTTED_ARROW', 'BIDIRECTIONAL_DOTTED_ARROW', 'SOLID_CROSS', 'DOTTED_CROSS', 'SOLID_POINT', 'DOTTED_POINT', got 'TXT']
|
||||
Expecting 'SOLID_OPEN_ARROW', 'DOTTED_OPEN_ARROW', 'SOLID_ARROW', 'BIDIRECTIONAL_SOLID_ARROW', 'DOTTED_ARROW', 'BIDIRECTIONAL_DOTTED_ARROW', 'SOLID_CROSS', 'DOTTED_CROSS', 'SOLID_POINT', 'DOTTED_POINT', got 'TXT']
|
||||
`);
|
||||
});
|
||||
|
||||
|
@@ -2,6 +2,7 @@ import { assert, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import assignWithDepth from './assignWithDepth.js';
|
||||
import type { MermaidConfig } from './config.type.js';
|
||||
import { getEffectiveHtmlLabels } from './config.js';
|
||||
import mermaid from './mermaid.js';
|
||||
import mermaidAPI, {
|
||||
appendDivSvgG,
|
||||
@@ -358,10 +359,11 @@ describe('mermaidAPI', () => {
|
||||
});
|
||||
|
||||
describe('no htmlLabels in the configuration', () => {
|
||||
const mocked_config_no_htmlLabels = {
|
||||
const mocked_config_no_htmlLabels: MermaidConfig = {
|
||||
themeCSS: 'default',
|
||||
fontFamily: 'serif',
|
||||
altFontFamily: 'sans-serif',
|
||||
htmlLabels: false, // Explicitly set to false
|
||||
};
|
||||
|
||||
describe('creates styles for shape elements "rect", "polygon", "ellipse", and "circle"', () => {
|
||||
@@ -1148,4 +1150,63 @@ flowchart TD
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
describe('flowchart.htmlLabels deprecation behavior', () => {
|
||||
beforeEach(() => {
|
||||
mermaidAPI.globalReset();
|
||||
});
|
||||
|
||||
it('should use root-level htmlLabels when only root-level is set', () => {
|
||||
const config: MermaidConfig = { htmlLabels: true };
|
||||
expect(config.htmlLabels).toBe(true);
|
||||
|
||||
const config2: MermaidConfig = { htmlLabels: false };
|
||||
expect(config2.htmlLabels).toBe(false);
|
||||
});
|
||||
|
||||
it('should check config.htmlLabels value directly when set', () => {
|
||||
const config1: MermaidConfig = { htmlLabels: true };
|
||||
expect(config1.htmlLabels).toBe(true);
|
||||
|
||||
const config2: MermaidConfig = { htmlLabels: false };
|
||||
expect(config2.htmlLabels).toBe(false);
|
||||
|
||||
const config3: MermaidConfig = { htmlLabels: undefined };
|
||||
expect(config3.htmlLabels).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should use getEffectiveHtmlLabels only when fallback logic is needed', () => {
|
||||
// Only call getEffectiveHtmlLabels when we need the fallback behavior
|
||||
const configWithDeprecated: MermaidConfig = { flowchart: { htmlLabels: true } };
|
||||
expect(getEffectiveHtmlLabels(configWithDeprecated)).toBe(true);
|
||||
|
||||
const configWithBoth: MermaidConfig = {
|
||||
htmlLabels: false,
|
||||
flowchart: { htmlLabels: true },
|
||||
};
|
||||
expect(getEffectiveHtmlLabels(configWithBoth)).toBe(false); // Root takes precedence
|
||||
|
||||
const configEmpty: MermaidConfig = {};
|
||||
expect(getEffectiveHtmlLabels(configEmpty)).toBe(true); // Default to true
|
||||
});
|
||||
|
||||
it('should verify the precedence logic: config.htmlLabels ?? config.flowchart?.htmlLabels ?? true', () => {
|
||||
// Test the exact precedence chain
|
||||
const config1: MermaidConfig = { htmlLabels: true };
|
||||
const result1 = config1.htmlLabels ?? config1.flowchart?.htmlLabels ?? true;
|
||||
expect(result1).toBe(true);
|
||||
|
||||
const config2: MermaidConfig = { htmlLabels: false };
|
||||
const result2 = config2.htmlLabels ?? config2.flowchart?.htmlLabels ?? true;
|
||||
expect(result2).toBe(false);
|
||||
|
||||
const config3: MermaidConfig = { flowchart: { htmlLabels: true } };
|
||||
const result3 = config3.htmlLabels ?? config3.flowchart?.htmlLabels ?? true;
|
||||
expect(result3).toBe(true);
|
||||
|
||||
const config4: MermaidConfig = {};
|
||||
const result4 = config4.htmlLabels ?? config4.flowchart?.htmlLabels ?? true;
|
||||
expect(result4).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -11,6 +11,7 @@ import packageJson from '../package.json' assert { type: 'json' };
|
||||
import { addSVGa11yTitleDescription, setA11yDiagramInfo } from './accessibility.js';
|
||||
import assignWithDepth from './assignWithDepth.js';
|
||||
import * as configApi from './config.js';
|
||||
import { getEffectiveHtmlLabels } from './config.js';
|
||||
import type { MermaidConfig } from './config.type.js';
|
||||
import { addDiagrams } from './diagram-api/diagram-orchestration.js';
|
||||
import type { DiagramMetadata, DiagramStyleClassDef } from './diagram-api/types.js';
|
||||
@@ -128,7 +129,7 @@ export const createCssStyles = (
|
||||
|
||||
// classDefs defined in the diagram text
|
||||
if (classDefs instanceof Map) {
|
||||
const htmlLabels = config.htmlLabels ?? config.flowchart?.htmlLabels; // TODO why specifically check the Flowchart diagram config?
|
||||
const htmlLabels = getEffectiveHtmlLabels(config);
|
||||
|
||||
const cssHtmlElements = ['> *', 'span']; // TODO make a constant
|
||||
const cssShapeElements = ['rect', 'polygon', 'ellipse', 'circle', 'path']; // TODO make a constant
|
||||
|
@@ -1,5 +1,6 @@
|
||||
import { getConfig } from '../../diagram-api/diagramAPI.js';
|
||||
import { evaluate } from '../../diagrams/common/common.js';
|
||||
import { getEffectiveHtmlLabels } from '../../config.js';
|
||||
|
||||
import { log } from '../../logger.js';
|
||||
import { getSubGraphTitleMargins } from '../../utils/subGraphTitleMargins.js';
|
||||
import { select } from 'd3';
|
||||
@@ -25,7 +26,7 @@ const rect = async (parent, node) => {
|
||||
.attr('id', node.id)
|
||||
.attr('data-look', node.look);
|
||||
|
||||
const useHtmlLabels = evaluate(siteConfig.flowchart.htmlLabels);
|
||||
const useHtmlLabels = getEffectiveHtmlLabels(siteConfig);
|
||||
|
||||
// Create the label and insert it after the rect
|
||||
const labelEl = shapeSvg.insert('g').attr('class', 'cluster-label ');
|
||||
@@ -39,7 +40,7 @@ const rect = async (parent, node) => {
|
||||
// Get the size of the label
|
||||
let bbox = text.getBBox();
|
||||
|
||||
if (evaluate(siteConfig.flowchart.htmlLabels)) {
|
||||
if (getEffectiveHtmlLabels(siteConfig)) {
|
||||
const div = text.children[0];
|
||||
const dv = select(text);
|
||||
bbox = div.getBoundingClientRect();
|
||||
@@ -188,7 +189,7 @@ const roundedWithTitle = async (parent, node) => {
|
||||
// Get the size of the label
|
||||
let bbox = text.getBBox();
|
||||
|
||||
if (evaluate(siteConfig.flowchart.htmlLabels)) {
|
||||
if (getEffectiveHtmlLabels(siteConfig)) {
|
||||
const div = text.children[0];
|
||||
const dv = select(text);
|
||||
bbox = div.getBoundingClientRect();
|
||||
@@ -264,7 +265,7 @@ const roundedWithTitle = async (parent, node) => {
|
||||
|
||||
label.attr(
|
||||
'transform',
|
||||
`translate(${node.x - bbox.width / 2}, ${y + 1 - (evaluate(siteConfig.flowchart.htmlLabels) ? 0 : 3)})`
|
||||
`translate(${node.x - bbox.width / 2}, ${y + 1 - (getEffectiveHtmlLabels(siteConfig) ? 0 : 3)})`
|
||||
);
|
||||
|
||||
const rectBox = rect.node().getBBox();
|
||||
@@ -295,7 +296,7 @@ const kanbanSection = async (parent, node) => {
|
||||
.attr('id', node.id)
|
||||
.attr('data-look', node.look);
|
||||
|
||||
const useHtmlLabels = evaluate(siteConfig.flowchart.htmlLabels);
|
||||
const useHtmlLabels = getEffectiveHtmlLabels(siteConfig);
|
||||
|
||||
// Create the label and insert it after the rect
|
||||
const labelEl = shapeSvg.insert('g').attr('class', 'cluster-label ');
|
||||
@@ -310,7 +311,7 @@ const kanbanSection = async (parent, node) => {
|
||||
// Get the size of the label
|
||||
let bbox = text.getBBox();
|
||||
|
||||
if (evaluate(siteConfig.flowchart.htmlLabels)) {
|
||||
if (getEffectiveHtmlLabels(siteConfig)) {
|
||||
const div = text.children[0];
|
||||
const dv = select(text);
|
||||
bbox = div.getBoundingClientRect();
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { select } from 'd3';
|
||||
import { getConfig } from '../../diagram-api/diagramAPI.js';
|
||||
import { getEffectiveHtmlLabels } from '../../config.js';
|
||||
import common, {
|
||||
evaluate,
|
||||
hasKatex,
|
||||
renderKatexSanitized,
|
||||
sanitizeText,
|
||||
@@ -64,7 +64,7 @@ const createLabel = async (_vertexText, style, isTitle, isNode) => {
|
||||
vertexText = vertexText[0];
|
||||
}
|
||||
|
||||
if (evaluate(getConfig().flowchart.htmlLabels)) {
|
||||
if (getEffectiveHtmlLabels(getConfig())) {
|
||||
// TODO: addHtmlLabel accepts a labelStyle. Do we possibly have that?
|
||||
vertexText = vertexText.replace(/\\n|\n/g, '<br />');
|
||||
log.info('vertexText' + vertexText);
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { getConfig } from '../../diagram-api/diagramAPI.js';
|
||||
import { evaluate } from '../../diagrams/common/common.js';
|
||||
import { getEffectiveHtmlLabels } from '../../config.js';
|
||||
import { log } from '../../logger.js';
|
||||
import { createText } from '../createText.js';
|
||||
import utils from '../../utils.js';
|
||||
@@ -45,7 +45,7 @@ export const getLabelStyles = (styleArray) => {
|
||||
};
|
||||
|
||||
export const insertEdgeLabel = async (elem, edge) => {
|
||||
let useHtmlLabels = evaluate(getConfig().flowchart.htmlLabels);
|
||||
let useHtmlLabels = getEffectiveHtmlLabels(getConfig());
|
||||
|
||||
const { labelStyles } = styles2String(edge);
|
||||
edge.labelStyle = labelStyles;
|
||||
@@ -161,7 +161,7 @@ export const insertEdgeLabel = async (elem, edge) => {
|
||||
* @param {any} value
|
||||
*/
|
||||
function setTerminalWidth(fo, value) {
|
||||
if (getConfig().flowchart.htmlLabels && fo) {
|
||||
if (getEffectiveHtmlLabels(getConfig()) && fo) {
|
||||
fo.style.width = value.length * 9 + 'px';
|
||||
fo.style.height = '12px';
|
||||
}
|
||||
|
@@ -5,6 +5,7 @@ import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
||||
import { getNodeClasses, labelHelper, updateNodeBounds } from './util.js';
|
||||
import type { D3Selection } from '../../../types.js';
|
||||
import { getConfig } from '../../../config.js';
|
||||
import { getEffectiveHtmlLabels } from '../../../config.js';
|
||||
|
||||
export async function note<T extends SVGGraphicsElement>(
|
||||
parent: D3Selection<T>,
|
||||
@@ -13,7 +14,7 @@ export async function note<T extends SVGGraphicsElement>(
|
||||
) {
|
||||
const { labelStyles, nodeStyles } = styles2String(node);
|
||||
node.labelStyle = labelStyles;
|
||||
const useHtmlLabels = node.useHtmlLabels || getConfig().flowchart?.htmlLabels !== false;
|
||||
const useHtmlLabels = getEffectiveHtmlLabels(getConfig()) || node.useHtmlLabels;
|
||||
if (!useHtmlLabels) {
|
||||
node.centerLabel = true;
|
||||
}
|
||||
|
@@ -1,6 +1,7 @@
|
||||
import { createText } from '../../createText.js';
|
||||
import type { Node } from '../../types.js';
|
||||
import { getConfig } from '../../../diagram-api/diagramAPI.js';
|
||||
import { getEffectiveHtmlLabels } from '../../../config.js';
|
||||
import { select } from 'd3';
|
||||
import defaultConfig from '../../../defaultConfig.js';
|
||||
import { evaluate, sanitizeText } from '../../../diagrams/common/common.js';
|
||||
@@ -130,7 +131,7 @@ export const insertLabel = async <T extends SVGGraphicsElement>(
|
||||
addSvgBackground?: boolean | undefined;
|
||||
}
|
||||
) => {
|
||||
const useHtmlLabels = options.useHtmlLabels || evaluate(getConfig()?.flowchart?.htmlLabels);
|
||||
const useHtmlLabels = getEffectiveHtmlLabels(getConfig()) || options.useHtmlLabels;
|
||||
|
||||
// Create the label and insert it after the rect
|
||||
const labelEl = parent
|
||||
@@ -148,7 +149,7 @@ export const insertLabel = async <T extends SVGGraphicsElement>(
|
||||
let bbox = text.getBBox();
|
||||
const halfPadding = options.padding / 2;
|
||||
|
||||
if (evaluate(getConfig()?.flowchart?.htmlLabels)) {
|
||||
if (getEffectiveHtmlLabels(getConfig())) {
|
||||
const div = text.children[0];
|
||||
const dv = select(text);
|
||||
|
||||
|
@@ -153,6 +153,8 @@ properties:
|
||||
default: false
|
||||
htmlLabels:
|
||||
type: boolean # maybe unused, seems to be copied in each diagram config
|
||||
default: true
|
||||
|
||||
fontFamily:
|
||||
description: |
|
||||
Specifies the font to be used in the rendered diagrams.
|
||||
@@ -2052,7 +2054,6 @@ $defs: # JSON Schema definition (maybe we should move these to a separate file)
|
||||
- titleTopMargin
|
||||
- subGraphTitleMargin
|
||||
- diagramPadding
|
||||
- htmlLabels
|
||||
- nodeSpacing
|
||||
- rankSpacing
|
||||
- curve
|
||||
@@ -2084,9 +2085,13 @@ $defs: # JSON Schema definition (maybe we should move these to a separate file)
|
||||
default: 8
|
||||
htmlLabels:
|
||||
description: |
|
||||
Flag for setting whether or not a html tag should be used for rendering labels on the edges.
|
||||
**DEPRECATED: Use global `htmlLabels` instead.**
|
||||
|
||||
Flag for setting whether or not a html tag should be used for rendering labels on nodes and edges.
|
||||
This property is deprecated.
|
||||
Please use the global `htmlLabels` configuration instead.
|
||||
type: boolean
|
||||
default: true
|
||||
deprecated: true
|
||||
nodeSpacing:
|
||||
description: |
|
||||
Defines the spacing between nodes on the same level
|
||||
|
Reference in New Issue
Block a user