mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-09-27 19:29:38 +02:00
Compare commits
55 Commits
gh-readonl
...
fixElkTest
Author | SHA1 | Date | |
---|---|---|---|
![]() |
212b368ffd | ||
![]() |
773abbe7e2 | ||
![]() |
bcd03151e8 | ||
![]() |
c212490248 | ||
![]() |
abcf2a2eab | ||
![]() |
ebaabbf19a | ||
![]() |
fd7406b94a | ||
![]() |
e5e44dbd39 | ||
![]() |
7cc76505a8 | ||
![]() |
c38478f6c3 | ||
![]() |
3cf7649682 | ||
![]() |
12d4386fd3 | ||
![]() |
4f0abab91f | ||
![]() |
ce7783414b | ||
![]() |
1503306651 | ||
![]() |
88d1885cdc | ||
![]() |
4ab47a2ce7 | ||
![]() |
8f3bcf401d | ||
![]() |
3959e076cf | ||
![]() |
bc770c48c7 | ||
![]() |
82404dd0f6 | ||
![]() |
f707dafcb4 | ||
![]() |
a91679db30 | ||
![]() |
bdaf58a322 | ||
![]() |
49446940f5 | ||
![]() |
650d712bd8 | ||
![]() |
d61f9fbe62 | ||
![]() |
be3829232c | ||
![]() |
20fd6d35f0 | ||
![]() |
5b724b180f | ||
![]() |
784e235ff9 | ||
![]() |
02a0596e3c | ||
![]() |
498f75eece | ||
![]() |
a61887f5a2 | ||
![]() |
44a6a6758e | ||
![]() |
a12864d9e4 | ||
![]() |
bbbae7d59f | ||
![]() |
e84ee32408 | ||
![]() |
cca9662365 | ||
![]() |
f30a23f41e | ||
![]() |
58cb827839 | ||
![]() |
7de1abbcc2 | ||
![]() |
26e32665a4 | ||
![]() |
c3df18fc5b | ||
![]() |
eca0cea339 | ||
![]() |
efa6cb3434 | ||
![]() |
4efac6721d | ||
![]() |
6aa20ed64b | ||
![]() |
75737544c8 | ||
![]() |
8f340094d9 | ||
![]() |
264f7920f0 | ||
![]() |
d2ed52461e | ||
![]() |
9a5cae9c63 | ||
![]() |
0b8dce4b82 | ||
![]() |
37c18eb4c0 |
@@ -1,6 +1,6 @@
|
||||
import { imgSnapshotTest, renderGraph } from '../../helpers/util.ts';
|
||||
|
||||
describe.skip('Flowchart ELK', () => {
|
||||
describe('Flowchart ELK', () => {
|
||||
it('1-elk: should render a simple flowchart', () => {
|
||||
imgSnapshotTest(
|
||||
`flowchart-elk TD
|
||||
|
@@ -330,6 +330,48 @@ describe('Gantt diagram', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('should render a gantt diagram with tick is 2 milliseconds', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
gantt
|
||||
title A Gantt Diagram
|
||||
dateFormat SSS
|
||||
axisFormat %Lms
|
||||
tickInterval 2millisecond
|
||||
excludes weekends
|
||||
|
||||
section Section
|
||||
A task : a1, 000, 6ms
|
||||
Another task : after a1, 6ms
|
||||
section Another
|
||||
Task in sec : a2, 006, 3ms
|
||||
another task : 3ms
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it('should render a gantt diagram with tick is 2 seconds', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
gantt
|
||||
title A Gantt Diagram
|
||||
dateFormat ss
|
||||
axisFormat %Ss
|
||||
tickInterval 2second
|
||||
excludes weekends
|
||||
|
||||
section Section
|
||||
A task : a1, 00, 6s
|
||||
Another task : after a1, 6s
|
||||
section Another
|
||||
Task in sec : 06, 3s
|
||||
another task : 3s
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
|
||||
it('should render a gantt diagram with tick is 15 minutes', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
|
@@ -125,6 +125,21 @@
|
||||
</pre>
|
||||
<hr />
|
||||
|
||||
<pre class="mermaid">
|
||||
erDiagram
|
||||
_customer_order {
|
||||
bigint id PK
|
||||
bigint customer_id FK
|
||||
text shipping_address
|
||||
text delivery_method
|
||||
timestamp_with_time_zone ordered_at
|
||||
numeric total_tax_amount
|
||||
numeric total_price
|
||||
text payment_method
|
||||
}
|
||||
</pre>
|
||||
<hr />
|
||||
|
||||
<script type="module">
|
||||
import mermaid from './mermaid.esm.mjs';
|
||||
mermaid.initialize({
|
||||
|
@@ -62,10 +62,10 @@ from IPython.display import Image, display
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
def mm(graph):
|
||||
graphbytes = graph.encode("ascii")
|
||||
base64_bytes = base64.b64encode(graphbytes)
|
||||
base64_string = base64_bytes.decode("ascii")
|
||||
display(Image(url="https://mermaid.ink/img/" + base64_string))
|
||||
graphbytes = graph.encode("utf8")
|
||||
base64_bytes = base64.b64encode(graphbytes)
|
||||
base64_string = base64_bytes.decode("ascii")
|
||||
display(Image(url="https://mermaid.ink/img/" + base64_string))
|
||||
|
||||
mm("""
|
||||
graph LR;
|
||||
|
@@ -49,6 +49,7 @@ They also serve as proof of concept, for the variety of things that can be built
|
||||
- [Mermaid plugin for GitBook](https://github.com/wwformat/gitbook-plugin-mermaid-pdf)
|
||||
- [LiveBook](https://livebook.dev) (**Native support**)
|
||||
- [Atlassian Products](https://www.atlassian.com)
|
||||
- [Mermaid Live Editor for Confluence Cloud](https://marketplace.atlassian.com/apps/1231571/mermaid-live-editor-for-confluence?hosting=cloud&tab=overview)
|
||||
- [Mermaid Plugin for Confluence](https://marketplace.atlassian.com/apps/1214124/mermaid-plugin-for-confluence?hosting=server&tab=overview)
|
||||
- [CloudScript.io Addon](https://marketplace.atlassian.com/apps/1219878/cloudscript-io-mermaid-addon?hosting=cloud&tab=overview)
|
||||
- [Auto convert diagrams in Jira](https://github.com/coddingtonbear/jirafs-mermaid)
|
||||
|
@@ -90,7 +90,7 @@ Mermaid syntax for ER diagrams is compatible with PlantUML, with an extension to
|
||||
|
||||
Where:
|
||||
|
||||
- `first-entity` is the name of an entity. Names must begin with an alphabetic character and may also contain digits, hyphens, and underscores.
|
||||
- `first-entity` is the name of an entity. Names must begin with an alphabetic character or an underscore (from v\<MERMAID_RELEASE_VERSION>+), and may also contain digits and hyphens.
|
||||
- `relationship` describes the way that both entities inter-relate. See below.
|
||||
- `second-entity` is the name of the other entity.
|
||||
- `relationship-label` describes the relationship from the perspective of the first entity.
|
||||
|
@@ -241,7 +241,7 @@ The following formatting strings are supported:
|
||||
|
||||
More info in: <https://github.com/d3/d3-time-format/tree/v4.0.0#locale_format>
|
||||
|
||||
### Axis ticks
|
||||
### Axis ticks (v10.3.0+)
|
||||
|
||||
The default output ticks are auto. You can custom your `tickInterval`, like `1day` or `1week`.
|
||||
|
||||
@@ -252,7 +252,7 @@ tickInterval 1day
|
||||
The pattern is:
|
||||
|
||||
```javascript
|
||||
/^([1-9][0-9]*)(minute|hour|day|week|month)$/;
|
||||
/^([1-9][0-9]*)(millisecond|second|minute|hour|day|week|month)$/;
|
||||
```
|
||||
|
||||
More info in: <https://github.com/d3/d3-time#interval_every>
|
||||
@@ -271,7 +271,7 @@ gantt
|
||||
weekday monday
|
||||
```
|
||||
|
||||
Support: v10.3.0+
|
||||
> **Warning** > `millisecond` and `second` support was added in vMERMAID_RELEASE_VERSION
|
||||
|
||||
## Output in compact mode
|
||||
|
||||
|
@@ -1,47 +0,0 @@
|
||||
import { sanitizeText as _sanitizeText } from './diagrams/common/common.js';
|
||||
import { getConfig } from './config.js';
|
||||
let title = '';
|
||||
let diagramTitle = '';
|
||||
let description = '';
|
||||
|
||||
const sanitizeText = (txt: string): string => _sanitizeText(txt, getConfig());
|
||||
|
||||
export const clear = function (): void {
|
||||
title = '';
|
||||
description = '';
|
||||
diagramTitle = '';
|
||||
};
|
||||
|
||||
export const setAccTitle = function (txt: string): void {
|
||||
title = sanitizeText(txt).replace(/^\s+/g, '');
|
||||
};
|
||||
|
||||
export const getAccTitle = function (): string {
|
||||
return title || diagramTitle;
|
||||
};
|
||||
|
||||
export const setAccDescription = function (txt: string): void {
|
||||
description = sanitizeText(txt).replace(/\n\s+/g, '\n');
|
||||
};
|
||||
|
||||
export const getAccDescription = function (): string {
|
||||
return description;
|
||||
};
|
||||
|
||||
export const setDiagramTitle = function (txt: string): void {
|
||||
diagramTitle = sanitizeText(txt);
|
||||
};
|
||||
|
||||
export const getDiagramTitle = function (): string {
|
||||
return diagramTitle;
|
||||
};
|
||||
|
||||
export default {
|
||||
getAccTitle,
|
||||
setAccTitle,
|
||||
getDiagramTitle,
|
||||
setDiagramTitle,
|
||||
getAccDescription,
|
||||
setAccDescription,
|
||||
clear,
|
||||
};
|
@@ -1048,7 +1048,7 @@ export interface GanttDiagramConfig extends BaseDiagramConfig {
|
||||
* Pattern is:
|
||||
*
|
||||
* ```javascript
|
||||
* /^([1-9][0-9]*)(minute|hour|day|week|month)$/
|
||||
* /^([1-9][0-9]*)(millisecond|second|minute|hour|day|week|month)$/
|
||||
* ```
|
||||
*
|
||||
*/
|
||||
|
@@ -368,7 +368,20 @@ const cutPathAtIntersect = (_points, boundryNode) => {
|
||||
return points;
|
||||
};
|
||||
|
||||
//(edgePaths, e, edge, clusterDb, diagramtype, graph)
|
||||
/**
|
||||
* Calculate the deltas and angle between two points
|
||||
* @param {{x: number, y:number}} point1
|
||||
* @param {{x: number, y:number}} point2
|
||||
* @returns {{angle: number, deltaX: number, deltaY: number}}
|
||||
*/
|
||||
function calculateDeltaAndAngle(point1, point2) {
|
||||
const [x1, y1] = [point1.x, point1.y];
|
||||
const [x2, y2] = [point2.x, point2.y];
|
||||
const deltaX = x2 - x1;
|
||||
const deltaY = y2 - y1;
|
||||
return { angle: Math.atan(deltaY / deltaX), deltaX, deltaY };
|
||||
}
|
||||
|
||||
export const insertEdge = function (elem, e, edge, clusterDb, diagramType, graph) {
|
||||
let points = edge.points;
|
||||
let pointsHasChanged = false;
|
||||
@@ -435,22 +448,62 @@ export const insertEdge = function (elem, e, edge, clusterDb, diagramType, graph
|
||||
const lineData = points.filter((p) => !Number.isNaN(p.y));
|
||||
|
||||
// This is the accessor function we talked about above
|
||||
let curve;
|
||||
let curve = curveBasis;
|
||||
// Currently only flowcharts get the curve from the settings, perhaps this should
|
||||
// be expanded to a common setting? Restricting it for now in order not to cause side-effects that
|
||||
// have not been thought through
|
||||
if (diagramType === 'graph' || diagramType === 'flowchart') {
|
||||
curve = edge.curve || curveBasis;
|
||||
} else {
|
||||
curve = curveBasis;
|
||||
if (edge.curve && (diagramType === 'graph' || diagramType === 'flowchart')) {
|
||||
curve = edge.curve;
|
||||
}
|
||||
// curve = curveLinear;
|
||||
|
||||
// We need to draw the lines a bit shorter to avoid drawing
|
||||
// under any transparent markers.
|
||||
// The offsets are calculated from the markers' dimensions.
|
||||
const markerOffsets = {
|
||||
aggregation: 18,
|
||||
extension: 18,
|
||||
composition: 18,
|
||||
dependency: 6,
|
||||
lollipop: 13.5,
|
||||
arrow_point: 5.3,
|
||||
};
|
||||
|
||||
const lineFunction = line()
|
||||
.x(function (d) {
|
||||
return d.x;
|
||||
.x(function (d, i, data) {
|
||||
let offset = 0;
|
||||
if (i === 0 && Object.hasOwn(markerOffsets, edge.arrowTypeStart)) {
|
||||
// Handle first point
|
||||
// Calculate the angle and delta between the first two points
|
||||
const { angle, deltaX } = calculateDeltaAndAngle(data[0], data[1]);
|
||||
// Calculate the offset based on the angle and the marker's dimensions
|
||||
offset = markerOffsets[edge.arrowTypeStart] * Math.cos(angle) * (deltaX >= 0 ? 1 : -1) || 0;
|
||||
} else if (i === data.length - 1 && Object.hasOwn(markerOffsets, edge.arrowTypeEnd)) {
|
||||
// Handle last point
|
||||
// Calculate the angle and delta between the last two points
|
||||
const { angle, deltaX } = calculateDeltaAndAngle(
|
||||
data[data.length - 1],
|
||||
data[data.length - 2]
|
||||
);
|
||||
offset = markerOffsets[edge.arrowTypeEnd] * Math.cos(angle) * (deltaX >= 0 ? 1 : -1) || 0;
|
||||
}
|
||||
return d.x + offset;
|
||||
})
|
||||
.y(function (d) {
|
||||
return d.y;
|
||||
.y(function (d, i, data) {
|
||||
// Same handling as X above
|
||||
let offset = 0;
|
||||
if (i === 0 && Object.hasOwn(markerOffsets, edge.arrowTypeStart)) {
|
||||
const { angle, deltaY } = calculateDeltaAndAngle(data[0], data[1]);
|
||||
offset =
|
||||
markerOffsets[edge.arrowTypeStart] * Math.abs(Math.sin(angle)) * (deltaY >= 0 ? 1 : -1);
|
||||
} else if (i === data.length - 1 && Object.hasOwn(markerOffsets, edge.arrowTypeEnd)) {
|
||||
const { angle, deltaY } = calculateDeltaAndAngle(
|
||||
data[data.length - 1],
|
||||
data[data.length - 2]
|
||||
);
|
||||
offset =
|
||||
markerOffsets[edge.arrowTypeEnd] * Math.abs(Math.sin(angle)) * (deltaY >= 0 ? 1 : -1);
|
||||
}
|
||||
return d.y + offset;
|
||||
})
|
||||
.curve(curve);
|
||||
|
||||
|
@@ -155,9 +155,9 @@ export const render = async (elem, graph, markers, diagramtype, id) => {
|
||||
clearClusters();
|
||||
clearGraphlib();
|
||||
|
||||
log.warn('Graph at first:', graphlibJson.write(graph));
|
||||
log.warn('Graph at first:', JSON.stringify(graphlibJson.write(graph)));
|
||||
adjustClustersAndEdges(graph);
|
||||
log.warn('Graph after:', graphlibJson.write(graph));
|
||||
log.warn('Graph after:', JSON.stringify(graphlibJson.write(graph)));
|
||||
// log.warn('Graph ever after:', graphlibJson.write(graph.node('A').graph));
|
||||
await recursiveRender(elem, graph, diagramtype);
|
||||
};
|
||||
|
@@ -16,7 +16,7 @@ const extension = (elem, type, id) => {
|
||||
.append('marker')
|
||||
.attr('id', type + '-extensionStart')
|
||||
.attr('class', 'marker extension ' + type)
|
||||
.attr('refX', 0)
|
||||
.attr('refX', 18)
|
||||
.attr('refY', 7)
|
||||
.attr('markerWidth', 190)
|
||||
.attr('markerHeight', 240)
|
||||
@@ -29,7 +29,7 @@ const extension = (elem, type, id) => {
|
||||
.append('marker')
|
||||
.attr('id', type + '-extensionEnd')
|
||||
.attr('class', 'marker extension ' + type)
|
||||
.attr('refX', 19)
|
||||
.attr('refX', 1)
|
||||
.attr('refY', 7)
|
||||
.attr('markerWidth', 20)
|
||||
.attr('markerHeight', 28)
|
||||
@@ -44,7 +44,7 @@ const composition = (elem, type) => {
|
||||
.append('marker')
|
||||
.attr('id', type + '-compositionStart')
|
||||
.attr('class', 'marker composition ' + type)
|
||||
.attr('refX', 0)
|
||||
.attr('refX', 18)
|
||||
.attr('refY', 7)
|
||||
.attr('markerWidth', 190)
|
||||
.attr('markerHeight', 240)
|
||||
@@ -57,7 +57,7 @@ const composition = (elem, type) => {
|
||||
.append('marker')
|
||||
.attr('id', type + '-compositionEnd')
|
||||
.attr('class', 'marker composition ' + type)
|
||||
.attr('refX', 19)
|
||||
.attr('refX', 1)
|
||||
.attr('refY', 7)
|
||||
.attr('markerWidth', 20)
|
||||
.attr('markerHeight', 28)
|
||||
@@ -71,7 +71,7 @@ const aggregation = (elem, type) => {
|
||||
.append('marker')
|
||||
.attr('id', type + '-aggregationStart')
|
||||
.attr('class', 'marker aggregation ' + type)
|
||||
.attr('refX', 0)
|
||||
.attr('refX', 18)
|
||||
.attr('refY', 7)
|
||||
.attr('markerWidth', 190)
|
||||
.attr('markerHeight', 240)
|
||||
@@ -84,7 +84,7 @@ const aggregation = (elem, type) => {
|
||||
.append('marker')
|
||||
.attr('id', type + '-aggregationEnd')
|
||||
.attr('class', 'marker aggregation ' + type)
|
||||
.attr('refX', 19)
|
||||
.attr('refX', 1)
|
||||
.attr('refY', 7)
|
||||
.attr('markerWidth', 20)
|
||||
.attr('markerHeight', 28)
|
||||
@@ -98,7 +98,7 @@ const dependency = (elem, type) => {
|
||||
.append('marker')
|
||||
.attr('id', type + '-dependencyStart')
|
||||
.attr('class', 'marker dependency ' + type)
|
||||
.attr('refX', 0)
|
||||
.attr('refX', 6)
|
||||
.attr('refY', 7)
|
||||
.attr('markerWidth', 190)
|
||||
.attr('markerHeight', 240)
|
||||
@@ -111,7 +111,7 @@ const dependency = (elem, type) => {
|
||||
.append('marker')
|
||||
.attr('id', type + '-dependencyEnd')
|
||||
.attr('class', 'marker dependency ' + type)
|
||||
.attr('refX', 19)
|
||||
.attr('refX', 13)
|
||||
.attr('refY', 7)
|
||||
.attr('markerWidth', 20)
|
||||
.attr('markerHeight', 28)
|
||||
@@ -125,15 +125,32 @@ const lollipop = (elem, type) => {
|
||||
.append('marker')
|
||||
.attr('id', type + '-lollipopStart')
|
||||
.attr('class', 'marker lollipop ' + type)
|
||||
.attr('refX', 0)
|
||||
.attr('refX', 13)
|
||||
.attr('refY', 7)
|
||||
.attr('markerWidth', 190)
|
||||
.attr('markerHeight', 240)
|
||||
.attr('orient', 'auto')
|
||||
.append('circle')
|
||||
.attr('stroke', 'black')
|
||||
.attr('fill', 'white')
|
||||
.attr('cx', 6)
|
||||
.attr('fill', 'transparent')
|
||||
.attr('cx', 7)
|
||||
.attr('cy', 7)
|
||||
.attr('r', 6);
|
||||
|
||||
elem
|
||||
.append('defs')
|
||||
.append('marker')
|
||||
.attr('id', type + '-lollipopEnd')
|
||||
.attr('class', 'marker lollipop ' + type)
|
||||
.attr('refX', 1)
|
||||
.attr('refY', 7)
|
||||
.attr('markerWidth', 190)
|
||||
.attr('markerHeight', 240)
|
||||
.attr('orient', 'auto')
|
||||
.append('circle')
|
||||
.attr('stroke', 'black')
|
||||
.attr('fill', 'transparent')
|
||||
.attr('cx', 7)
|
||||
.attr('cy', 7)
|
||||
.attr('r', 6);
|
||||
};
|
||||
@@ -143,7 +160,7 @@ const point = (elem, type) => {
|
||||
.attr('id', type + '-pointEnd')
|
||||
.attr('class', 'marker ' + type)
|
||||
.attr('viewBox', '0 0 10 10')
|
||||
.attr('refX', 10)
|
||||
.attr('refX', 6)
|
||||
.attr('refY', 5)
|
||||
.attr('markerUnits', 'userSpaceOnUse')
|
||||
.attr('markerWidth', 12)
|
||||
|
@@ -291,8 +291,8 @@ export const adjustClustersAndEdges = (graph, depth) => {
|
||||
shape: 'labelRect',
|
||||
style: '',
|
||||
});
|
||||
const edge1 = JSON.parse(JSON.stringify(edge));
|
||||
const edge2 = JSON.parse(JSON.stringify(edge));
|
||||
const edge1 = structuredClone(edge);
|
||||
const edge2 = structuredClone(edge);
|
||||
edge1.label = '';
|
||||
edge1.arrowTypeEnd = 'none';
|
||||
edge2.label = '';
|
||||
|
@@ -5,7 +5,7 @@ import { sanitizeText as _sanitizeText } from '../diagrams/common/common.js';
|
||||
import { setupGraphViewbox as _setupGraphViewbox } from '../setupGraphViewbox.js';
|
||||
import { addStylesForDiagram } from '../styles.js';
|
||||
import type { DiagramDefinition, DiagramDetector } from './types.js';
|
||||
import * as _commonDb from '../commonDb.js';
|
||||
import * as _commonDb from '../diagrams/common/commonDb.js';
|
||||
import { parseDirective as _parseDirective } from '../directiveUtils.js';
|
||||
|
||||
/*
|
||||
|
@@ -1,7 +1,12 @@
|
||||
import mermaidAPI from '../../mermaidAPI.js';
|
||||
import * as configApi from '../../config.js';
|
||||
import { sanitizeText } from '../common/common.js';
|
||||
import { setAccTitle, getAccTitle, getAccDescription, setAccDescription } from '../../commonDb.js';
|
||||
import {
|
||||
setAccTitle,
|
||||
getAccTitle,
|
||||
getAccDescription,
|
||||
setAccDescription,
|
||||
} from '../common/commonDb.js';
|
||||
|
||||
let c4ShapeArray = [];
|
||||
let boundaryParseStack = [''];
|
||||
|
@@ -1,4 +1,3 @@
|
||||
// @ts-nocheck - don't check until handle it
|
||||
import type { Selection } from 'd3';
|
||||
import { select } from 'd3';
|
||||
import { log } from '../../logger.js';
|
||||
@@ -14,7 +13,7 @@ import {
|
||||
clear as commonClear,
|
||||
setDiagramTitle,
|
||||
getDiagramTitle,
|
||||
} from '../../commonDb.js';
|
||||
} from '../common/commonDb.js';
|
||||
import { ClassMember } from './classTypes.js';
|
||||
import type {
|
||||
ClassRelation,
|
||||
@@ -72,21 +71,21 @@ export const setClassLabel = function (id: string, label: string) {
|
||||
* @public
|
||||
*/
|
||||
export const addClass = function (id: string) {
|
||||
const classId = splitClassNameAndType(id);
|
||||
const { className, type } = splitClassNameAndType(id);
|
||||
// Only add class if not exists
|
||||
if (classes[classId.className] !== undefined) {
|
||||
if (Object.hasOwn(classes, className)) {
|
||||
return;
|
||||
}
|
||||
|
||||
classes[classId.className] = {
|
||||
id: classId.className,
|
||||
type: classId.type,
|
||||
label: classId.className,
|
||||
classes[className] = {
|
||||
id: className,
|
||||
type: type,
|
||||
label: className,
|
||||
cssClasses: [],
|
||||
methods: [],
|
||||
members: [],
|
||||
annotations: [],
|
||||
domId: MERMAID_DOM_ID_PREFIX + classId.className + '-' + classCounter,
|
||||
domId: MERMAID_DOM_ID_PREFIX + className + '-' + classCounter,
|
||||
} as ClassNode;
|
||||
|
||||
classCounter++;
|
||||
@@ -176,6 +175,8 @@ export const addAnnotation = function (className: string, annotation: string) {
|
||||
* @public
|
||||
*/
|
||||
export const addMember = function (className: string, member: string) {
|
||||
addClass(className);
|
||||
|
||||
const validatedClassName = splitClassNameAndType(className).className;
|
||||
const theClass = classes[validatedClassName];
|
||||
|
||||
@@ -370,6 +371,7 @@ export const relationType = {
|
||||
const setupToolTips = function (element: Element) {
|
||||
let tooltipElem: Selection<HTMLDivElement, unknown, HTMLElement, unknown> =
|
||||
select('.mermaidTooltip');
|
||||
// @ts-expect-error - Incorrect types
|
||||
if ((tooltipElem._groups || tooltipElem)[0][0] === null) {
|
||||
tooltipElem = select('body').append('div').attr('class', 'mermaidTooltip').style('opacity', 0);
|
||||
}
|
||||
@@ -379,7 +381,6 @@ const setupToolTips = function (element: Element) {
|
||||
const nodes = svg.selectAll('g.node');
|
||||
nodes
|
||||
.on('mouseover', function () {
|
||||
// @ts-expect-error - select is not part of the d3 type definition
|
||||
const el = select(this);
|
||||
const title = el.attr('title');
|
||||
// Don't try to draw a tooltip if no data is provided
|
||||
@@ -389,6 +390,7 @@ const setupToolTips = function (element: Element) {
|
||||
// @ts-ignore - getBoundingClientRect is not part of the d3 type definition
|
||||
const rect = this.getBoundingClientRect();
|
||||
|
||||
// @ts-expect-error - Incorrect types
|
||||
tooltipElem.transition().duration(200).style('opacity', '.9');
|
||||
tooltipElem
|
||||
.text(el.attr('title'))
|
||||
@@ -398,8 +400,8 @@ const setupToolTips = function (element: Element) {
|
||||
el.classed('hover', true);
|
||||
})
|
||||
.on('mouseout', function () {
|
||||
// @ts-expect-error - Incorrect types
|
||||
tooltipElem.transition().duration(500).style('opacity', 0);
|
||||
// @ts-expect-error - select is not part of the d3 type definition
|
||||
const el = select(this);
|
||||
el.classed('hover', false);
|
||||
});
|
||||
|
@@ -813,6 +813,20 @@ describe('given a class diagram with members and methods ', function () {
|
||||
parser.parse(str);
|
||||
});
|
||||
|
||||
it('should handle direct member declaration', function () {
|
||||
parser.parse('classDiagram\n' + 'Car : wheels');
|
||||
const car = classDb.getClass('Car');
|
||||
expect(car.members.length).toBe(1);
|
||||
expect(car.members[0].id).toBe('wheels');
|
||||
});
|
||||
|
||||
it('should handle direct member declaration with type', function () {
|
||||
parser.parse('classDiagram\n' + 'Car : int wheels');
|
||||
const car = classDb.getClass('Car');
|
||||
expect(car.members.length).toBe(1);
|
||||
expect(car.members[0].id).toBe('int wheels');
|
||||
});
|
||||
|
||||
it('should handle simple member declaration with type', function () {
|
||||
const str = 'classDiagram\n' + 'class Car\n' + 'Car : int wheels';
|
||||
|
||||
|
@@ -109,25 +109,25 @@ g.classGroup line {
|
||||
}
|
||||
|
||||
#extensionStart, .extension {
|
||||
fill: ${options.mainBkg} !important;
|
||||
fill: transparent !important;
|
||||
stroke: ${options.lineColor} !important;
|
||||
stroke-width: 1;
|
||||
}
|
||||
|
||||
#extensionEnd, .extension {
|
||||
fill: ${options.mainBkg} !important;
|
||||
fill: transparent !important;
|
||||
stroke: ${options.lineColor} !important;
|
||||
stroke-width: 1;
|
||||
}
|
||||
|
||||
#aggregationStart, .aggregation {
|
||||
fill: ${options.mainBkg} !important;
|
||||
fill: transparent !important;
|
||||
stroke: ${options.lineColor} !important;
|
||||
stroke-width: 1;
|
||||
}
|
||||
|
||||
#aggregationEnd, .aggregation {
|
||||
fill: ${options.mainBkg} !important;
|
||||
fill: transparent !important;
|
||||
stroke: ${options.lineColor} !important;
|
||||
stroke-width: 1;
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { sanitizeText, removeScript, parseGenericTypes } from './common.js';
|
||||
import { sanitizeText, removeScript, parseGenericTypes, countOccurrence } from './common.js';
|
||||
|
||||
describe('when securityLevel is antiscript, all script must be removed', () => {
|
||||
/**
|
||||
@@ -59,15 +59,29 @@ describe('Sanitize text', () => {
|
||||
});
|
||||
|
||||
describe('generic parser', () => {
|
||||
it('should parse generic types', () => {
|
||||
expect(parseGenericTypes('test~T~')).toEqual('test<T>');
|
||||
expect(parseGenericTypes('test~Array~Array~string~~~')).toEqual('test<Array<Array<string>>>');
|
||||
expect(parseGenericTypes('test~Array~Array~string[]~~~')).toEqual(
|
||||
'test<Array<Array<string[]>>>'
|
||||
);
|
||||
expect(parseGenericTypes('test ~Array~Array~string[]~~~')).toEqual(
|
||||
'test <Array<Array<string[]>>>'
|
||||
);
|
||||
expect(parseGenericTypes('~test')).toEqual('~test');
|
||||
it.each([
|
||||
['test~T~', 'test<T>'],
|
||||
['test~Array~Array~string~~~', 'test<Array<Array<string>>>'],
|
||||
['test~Array~Array~string[]~~~', 'test<Array<Array<string[]>>>'],
|
||||
['test ~Array~Array~string[]~~~', 'test <Array<Array<string[]>>>'],
|
||||
['~test', '~test'],
|
||||
['~test~T~', '~test<T>'],
|
||||
])('should parse generic types: %s to %s', (input: string, expected: string) => {
|
||||
expect(parseGenericTypes(input)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
it.each([
|
||||
['', '', 0],
|
||||
['', 'x', 0],
|
||||
['test', 'x', 0],
|
||||
['test', 't', 2],
|
||||
['test', 'te', 1],
|
||||
['test~T~', '~', 2],
|
||||
['test~Array~Array~string~~~', '~', 6],
|
||||
])(
|
||||
'should count `%s` to contain occurrences of `%s` to be `%i`',
|
||||
(str: string, substring: string, count: number) => {
|
||||
expect(countOccurrence(str, substring)).toEqual(count);
|
||||
}
|
||||
);
|
||||
|
@@ -208,21 +208,33 @@ export const parseGenericTypes = function (input: string): string {
|
||||
return output.join('');
|
||||
};
|
||||
|
||||
export const countOccurrence = (string: string, substring: string): number => {
|
||||
return Math.max(0, string.split(substring).length - 1);
|
||||
};
|
||||
|
||||
const shouldCombineSets = (previousSet: string, nextSet: string): boolean => {
|
||||
const prevCount = [...previousSet].reduce((count, char) => (char === '~' ? count + 1 : count), 0);
|
||||
const nextCount = [...nextSet].reduce((count, char) => (char === '~' ? count + 1 : count), 0);
|
||||
const prevCount = countOccurrence(previousSet, '~');
|
||||
const nextCount = countOccurrence(nextSet, '~');
|
||||
|
||||
return prevCount === 1 && nextCount === 1;
|
||||
};
|
||||
|
||||
const processSet = (input: string): string => {
|
||||
const chars = [...input];
|
||||
const tildeCount = chars.reduce((count, char) => (char === '~' ? count + 1 : count), 0);
|
||||
const tildeCount = countOccurrence(input, '~');
|
||||
let hasStartingTilde = false;
|
||||
|
||||
if (tildeCount <= 1) {
|
||||
return input;
|
||||
}
|
||||
|
||||
// If there is an odd number of tildes, and the input starts with a tilde, we need to remove it and add it back in later
|
||||
if (tildeCount % 2 !== 0 && input.startsWith('~')) {
|
||||
input = input.substring(1);
|
||||
hasStartingTilde = true;
|
||||
}
|
||||
|
||||
const chars = [...input];
|
||||
|
||||
let first = chars.indexOf('~');
|
||||
let last = chars.lastIndexOf('~');
|
||||
|
||||
@@ -234,6 +246,11 @@ const processSet = (input: string): string => {
|
||||
last = chars.lastIndexOf('~');
|
||||
}
|
||||
|
||||
// Add the starting tilde back in if we removed it
|
||||
if (hasStartingTilde) {
|
||||
chars.unshift('~');
|
||||
}
|
||||
|
||||
return chars.join('');
|
||||
};
|
||||
|
||||
|
32
packages/mermaid/src/diagrams/common/commonDb.ts
Normal file
32
packages/mermaid/src/diagrams/common/commonDb.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { sanitizeText as _sanitizeText } from './common.js';
|
||||
import { getConfig } from '../../config.js';
|
||||
|
||||
let accTitle = '';
|
||||
let diagramTitle = '';
|
||||
let accDescription = '';
|
||||
|
||||
const sanitizeText = (txt: string): string => _sanitizeText(txt, getConfig());
|
||||
|
||||
export const clear = (): void => {
|
||||
accTitle = '';
|
||||
accDescription = '';
|
||||
diagramTitle = '';
|
||||
};
|
||||
|
||||
export const setAccTitle = (txt: string): void => {
|
||||
accTitle = sanitizeText(txt).replace(/^\s+/g, '');
|
||||
};
|
||||
|
||||
export const getAccTitle = (): string => accTitle;
|
||||
|
||||
export const setAccDescription = (txt: string): void => {
|
||||
accDescription = sanitizeText(txt).replace(/\n\s+/g, '\n');
|
||||
};
|
||||
|
||||
export const getAccDescription = (): string => accDescription;
|
||||
|
||||
export const setDiagramTitle = (txt: string): void => {
|
||||
diagramTitle = sanitizeText(txt);
|
||||
};
|
||||
|
||||
export const getDiagramTitle = (): string => diagramTitle;
|
@@ -10,7 +10,7 @@ import {
|
||||
clear as commonClear,
|
||||
setDiagramTitle,
|
||||
getDiagramTitle,
|
||||
} from '../../commonDb.js';
|
||||
} from '../common/commonDb.js';
|
||||
|
||||
let entities = {};
|
||||
let relationships = [];
|
||||
|
@@ -66,7 +66,7 @@ o\{ return 'ZERO_OR_MORE';
|
||||
"optionally to" return 'NON_IDENTIFYING';
|
||||
\.\- return 'NON_IDENTIFYING';
|
||||
\-\. return 'NON_IDENTIFYING';
|
||||
[A-Za-z][A-Za-z0-9\-_]* return 'ALPHANUM';
|
||||
[A-Za-z_][A-Za-z0-9\-_]* return 'ALPHANUM';
|
||||
. return yytext[0];
|
||||
<<EOF>> return 'EOF';
|
||||
|
||||
|
@@ -33,7 +33,7 @@ describe('when parsing ER diagram it...', function () {
|
||||
describe('has non A-Za-z0-9_- chars', function () {
|
||||
// these were entered using the Mac keyboard utility.
|
||||
const chars =
|
||||
"~ ` ! @ # $ ^ & * ( ) - _ = + [ ] { } | / ; : ' . ? ¡ ⁄ ™ € £ ‹ ¢ › ∞ fi § ‡ • ° ª · º ‚ ≠ ± œ Œ ∑ „ ® † ˇ ¥ Á ¨ ˆ ˆ Ø π ∏ “ « » å Å ß Í ∂ Î ƒ Ï © ˙ Ó ∆ Ô ˚ ¬ Ò … Ú æ Æ Ω ¸ ≈ π ˛ ç Ç √ ◊ ∫ ı ˜ µ  ≤ ¯ ≥ ˘ ÷ ¿";
|
||||
"~ ` ! @ # $ ^ & * ( ) - = + [ ] { } | / ; : ' . ? ¡ ⁄ ™ € £ ‹ ¢ › ∞ fi § ‡ • ° ª · º ‚ ≠ ± œ Œ ∑ „ ® † ˇ ¥ Á ¨ ˆ ˆ Ø π ∏ “ « » å Å ß Í ∂ Î ƒ Ï © ˙ Ó ∆ Ô ˚ ¬ Ò … Ú æ Æ Ω ¸ ≈ π ˛ ç Ç √ ◊ ∫ ı ˜ µ  ≤ ¯ ≥ ˘ ÷ ¿";
|
||||
const allowed = chars.split(' ');
|
||||
|
||||
allowed.forEach((allowedChar) => {
|
||||
@@ -170,6 +170,13 @@ describe('when parsing ER diagram it...', function () {
|
||||
expect(entities[firstEntity].alias).toBe(alias);
|
||||
expect(entities[secondEntity].alias).toBeUndefined();
|
||||
});
|
||||
|
||||
it('can start with an underscore', function () {
|
||||
const entity = '_foo';
|
||||
erDiagram.parser.parse(`erDiagram\n${entity}\n`);
|
||||
const entities = erDb.getEntities();
|
||||
expect(entities.hasOwnProperty(entity)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('attribute name', () => {
|
||||
|
@@ -12,7 +12,7 @@ import {
|
||||
clear as commonClear,
|
||||
setDiagramTitle,
|
||||
getDiagramTitle,
|
||||
} from '../../commonDb.js';
|
||||
} from '../common/commonDb.js';
|
||||
|
||||
const MERMAID_DOM_ID_PREFIX = 'flowchart-';
|
||||
let vertexCounter = 0;
|
||||
|
@@ -16,7 +16,7 @@ import {
|
||||
clear as commonClear,
|
||||
setDiagramTitle,
|
||||
getDiagramTitle,
|
||||
} from '../../commonDb.js';
|
||||
} from '../common/commonDb.js';
|
||||
|
||||
dayjs.extend(dayjsIsoWeek);
|
||||
dayjs.extend(dayjsCustomParseFormat);
|
||||
|
@@ -10,6 +10,8 @@ import {
|
||||
axisBottom,
|
||||
axisTop,
|
||||
timeFormat,
|
||||
timeMillisecond,
|
||||
timeSecond,
|
||||
timeMinute,
|
||||
timeHour,
|
||||
timeDay,
|
||||
@@ -573,7 +575,7 @@ export const draw = function (text, id, version, diagObj) {
|
||||
.tickSize(-h + theTopPad + conf.gridLineStartPadding)
|
||||
.tickFormat(timeFormat(diagObj.db.getAxisFormat() || conf.axisFormat || '%Y-%m-%d'));
|
||||
|
||||
const reTickInterval = /^([1-9]\d*)(minute|hour|day|week|month)$/;
|
||||
const reTickInterval = /^([1-9]\d*)(millisecond|second|minute|hour|day|week|month)$/;
|
||||
const resultTickInterval = reTickInterval.exec(
|
||||
diagObj.db.getTickInterval() || conf.tickInterval
|
||||
);
|
||||
@@ -584,6 +586,12 @@ export const draw = function (text, id, version, diagObj) {
|
||||
const weekday = diagObj.db.getWeekday() || conf.weekday;
|
||||
|
||||
switch (interval) {
|
||||
case 'millisecond':
|
||||
bottomXAxis.ticks(timeMillisecond.every(every));
|
||||
break;
|
||||
case 'second':
|
||||
bottomXAxis.ticks(timeSecond.every(every));
|
||||
break;
|
||||
case 'minute':
|
||||
bottomXAxis.ticks(timeMinute.every(every));
|
||||
break;
|
||||
@@ -625,6 +633,12 @@ export const draw = function (text, id, version, diagObj) {
|
||||
const weekday = diagObj.db.getWeekday() || conf.weekday;
|
||||
|
||||
switch (interval) {
|
||||
case 'millisecond':
|
||||
topXAxis.ticks(timeMillisecond.every(every));
|
||||
break;
|
||||
case 'second':
|
||||
topXAxis.ticks(timeSecond.every(every));
|
||||
break;
|
||||
case 'minute':
|
||||
topXAxis.ticks(timeMinute.every(every));
|
||||
break;
|
||||
|
@@ -12,7 +12,7 @@ import {
|
||||
clear as commonClear,
|
||||
setDiagramTitle,
|
||||
getDiagramTitle,
|
||||
} from '../../commonDb.js';
|
||||
} from '../common/commonDb.js';
|
||||
|
||||
let mainBranchName = getConfig().gitGraph.mainBranchName;
|
||||
let mainBranchOrder = getConfig().gitGraph.mainBranchOrder;
|
||||
|
@@ -10,7 +10,7 @@ import {
|
||||
getAccDescription,
|
||||
setAccDescription,
|
||||
clear as commonClear,
|
||||
} from '../../commonDb.js';
|
||||
} from '../common/commonDb.js';
|
||||
import type { ParseDirectiveDefinition } from '../../diagram-api/types.js';
|
||||
import type { PieFields, PieDB, Sections } from './pieTypes.js';
|
||||
import type { RequiredDeep } from 'type-fest';
|
||||
|
@@ -10,7 +10,7 @@ import {
|
||||
getAccDescription,
|
||||
setAccDescription,
|
||||
clear as commonClear,
|
||||
} from '../../commonDb.js';
|
||||
} from '../common/commonDb.js';
|
||||
import { QuadrantBuilder } from './quadrantBuilder.js';
|
||||
|
||||
const config = configApi.getConfig();
|
||||
|
@@ -8,7 +8,7 @@ import {
|
||||
getAccDescription,
|
||||
setAccDescription,
|
||||
clear as commonClear,
|
||||
} from '../../commonDb.js';
|
||||
} from '../common/commonDb.js';
|
||||
|
||||
let relations = [];
|
||||
let latestRequirement = {};
|
||||
|
@@ -8,7 +8,7 @@ import {
|
||||
setDiagramTitle,
|
||||
getDiagramTitle,
|
||||
clear as commonClear,
|
||||
} from '../../commonDb.js';
|
||||
} from '../common/commonDb.js';
|
||||
|
||||
// Sankey diagram represented by nodes and links between those nodes
|
||||
let links: SankeyLink[] = [];
|
||||
|
@@ -301,7 +301,7 @@ placement
|
||||
|
||||
signal
|
||||
: actor signaltype '+' actor text2
|
||||
{ $$ = [$1,$4,{type: 'addMessage', from:$1.actor, to:$4.actor, signalType:$2, msg:$5},
|
||||
{ $$ = [$1,$4,{type: 'addMessage', from:$1.actor, to:$4.actor, signalType:$2, msg:$5, activate: true},
|
||||
{type: 'activeStart', signalType: yy.LINETYPE.ACTIVE_START, actor: $4}
|
||||
]}
|
||||
| actor signaltype '-' actor text2
|
||||
|
@@ -10,7 +10,7 @@ import {
|
||||
getAccDescription,
|
||||
setAccDescription,
|
||||
clear as commonClear,
|
||||
} from '../../commonDb.js';
|
||||
} from '../common/commonDb.js';
|
||||
|
||||
let prevActor = undefined;
|
||||
let actors = {};
|
||||
@@ -124,7 +124,8 @@ export const addSignal = function (
|
||||
idFrom,
|
||||
idTo,
|
||||
message = { text: undefined, wrap: undefined },
|
||||
messageType
|
||||
messageType,
|
||||
activate = false
|
||||
) {
|
||||
if (messageType === LINETYPE.ACTIVE_END) {
|
||||
const cnt = activationCount(idFrom.actor);
|
||||
@@ -147,6 +148,7 @@ export const addSignal = function (
|
||||
message: message.text,
|
||||
wrap: (message.wrap === undefined && autoWrap()) || !!message.wrap,
|
||||
type: messageType,
|
||||
activate,
|
||||
});
|
||||
return true;
|
||||
};
|
||||
@@ -450,6 +452,19 @@ export const getActorProperty = function (actor, key) {
|
||||
return undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
* @typedef {object} AddMessageParams A message from one actor to another.
|
||||
* @property {string} from - The id of the actor sending the message.
|
||||
* @property {string} to - The id of the actor receiving the message.
|
||||
* @property {string} msg - The message text.
|
||||
* @property {number} signalType - The type of signal.
|
||||
* @property {"addMessage"} type - Set to `"addMessage"` if this is an `AddMessageParams`.
|
||||
* @property {boolean} [activate] - If `true`, this signal starts an activation.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {object | object[] | AddMessageParams} param - Object of parameters.
|
||||
*/
|
||||
export const apply = function (param) {
|
||||
if (Array.isArray(param)) {
|
||||
param.forEach(function (item) {
|
||||
@@ -530,7 +545,7 @@ export const apply = function (param) {
|
||||
lastDestroyed = undefined;
|
||||
}
|
||||
}
|
||||
addSignal(param.from, param.to, param.msg, param.signalType);
|
||||
addSignal(param.from, param.to, param.msg, param.signalType, param.activate);
|
||||
break;
|
||||
case 'boxStart':
|
||||
addBox(param.boxData);
|
||||
|
@@ -104,6 +104,7 @@ describe('more than one sequence diagram', () => {
|
||||
expect(diagram1.db.getMessages()).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"activate": false,
|
||||
"from": "Alice",
|
||||
"message": "Hello Bob, how are you?",
|
||||
"to": "Bob",
|
||||
@@ -111,6 +112,7 @@ describe('more than one sequence diagram', () => {
|
||||
"wrap": false,
|
||||
},
|
||||
{
|
||||
"activate": false,
|
||||
"from": "Bob",
|
||||
"message": "I am good thanks!",
|
||||
"to": "Alice",
|
||||
@@ -127,6 +129,7 @@ describe('more than one sequence diagram', () => {
|
||||
expect(diagram2.db.getMessages()).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"activate": false,
|
||||
"from": "Alice",
|
||||
"message": "Hello Bob, how are you?",
|
||||
"to": "Bob",
|
||||
@@ -134,6 +137,7 @@ describe('more than one sequence diagram', () => {
|
||||
"wrap": false,
|
||||
},
|
||||
{
|
||||
"activate": false,
|
||||
"from": "Bob",
|
||||
"message": "I am good thanks!",
|
||||
"to": "Alice",
|
||||
@@ -152,6 +156,7 @@ describe('more than one sequence diagram', () => {
|
||||
expect(diagram3.db.getMessages()).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"activate": false,
|
||||
"from": "Alice",
|
||||
"message": "Hello John, how are you?",
|
||||
"to": "John",
|
||||
@@ -159,6 +164,7 @@ describe('more than one sequence diagram', () => {
|
||||
"wrap": false,
|
||||
},
|
||||
{
|
||||
"activate": false,
|
||||
"from": "John",
|
||||
"message": "I am good thanks!",
|
||||
"to": "Alice",
|
||||
@@ -548,6 +554,7 @@ deactivate Bob`;
|
||||
|
||||
expect(messages.length).toBe(4);
|
||||
expect(messages[0].type).toBe(diagram.db.LINETYPE.DOTTED);
|
||||
expect(messages[0].activate).toBeTruthy();
|
||||
expect(messages[1].type).toBe(diagram.db.LINETYPE.ACTIVE_START);
|
||||
expect(messages[1].from.actor).toBe('Bob');
|
||||
expect(messages[2].type).toBe(diagram.db.LINETYPE.DOTTED);
|
||||
|
@@ -1,5 +1,5 @@
|
||||
// @ts-nocheck TODO: fix file
|
||||
import { select, selectAll } from 'd3';
|
||||
import { select } from 'd3';
|
||||
import svgDraw, { ACTOR_TYPE_WIDTH, drawText, fixLifeLineHeights } from './svgDraw.js';
|
||||
import { log } from '../../logger.js';
|
||||
import common from '../common/common.js';
|
||||
@@ -622,10 +622,10 @@ const activationBounds = function (actor, actors) {
|
||||
|
||||
const left = activations.reduce(function (acc, activation) {
|
||||
return common.getMin(acc, activation.startx);
|
||||
}, actorObj.x + actorObj.width / 2);
|
||||
}, actorObj.x + actorObj.width / 2 - 1);
|
||||
const right = activations.reduce(function (acc, activation) {
|
||||
return common.getMax(acc, activation.stopx);
|
||||
}, actorObj.x + actorObj.width / 2);
|
||||
}, actorObj.x + actorObj.width / 2 + 1);
|
||||
return [left, right];
|
||||
};
|
||||
|
||||
@@ -1389,9 +1389,8 @@ const buildNoteModel = function (msg, actors, diagObj) {
|
||||
};
|
||||
|
||||
const buildMessageModel = function (msg, actors, diagObj) {
|
||||
let process = false;
|
||||
if (
|
||||
[
|
||||
![
|
||||
diagObj.db.LINETYPE.SOLID_OPEN,
|
||||
diagObj.db.LINETYPE.DOTTED_OPEN,
|
||||
diagObj.db.LINETYPE.SOLID,
|
||||
@@ -1402,17 +1401,47 @@ const buildMessageModel = function (msg, actors, diagObj) {
|
||||
diagObj.db.LINETYPE.DOTTED_POINT,
|
||||
].includes(msg.type)
|
||||
) {
|
||||
process = true;
|
||||
}
|
||||
if (!process) {
|
||||
return {};
|
||||
}
|
||||
const fromBounds = activationBounds(msg.from, actors);
|
||||
const toBounds = activationBounds(msg.to, actors);
|
||||
const fromIdx = fromBounds[0] <= toBounds[0] ? 1 : 0;
|
||||
const toIdx = fromBounds[0] < toBounds[0] ? 0 : 1;
|
||||
const allBounds = [...fromBounds, ...toBounds];
|
||||
const boundedWidth = Math.abs(toBounds[toIdx] - fromBounds[fromIdx]);
|
||||
const [fromLeft, fromRight] = activationBounds(msg.from, actors);
|
||||
const [toLeft, toRight] = activationBounds(msg.to, actors);
|
||||
const isArrowToRight = fromLeft <= toLeft;
|
||||
const startx = isArrowToRight ? fromRight : fromLeft;
|
||||
let stopx = isArrowToRight ? toLeft : toRight;
|
||||
|
||||
// As the line width is considered, the left and right values will be off by 2.
|
||||
const isArrowToActivation = Math.abs(toLeft - toRight) > 2;
|
||||
|
||||
/**
|
||||
* Adjust the value based on the arrow direction
|
||||
* @param value - The value to adjust
|
||||
* @returns The adjustment with correct sign to be added to the actual value.
|
||||
*/
|
||||
const adjustValue = (value: number) => {
|
||||
return isArrowToRight ? -value : value;
|
||||
};
|
||||
|
||||
/**
|
||||
* This is an edge case for the first activation.
|
||||
* Proper fix would require significant changes.
|
||||
* So, we set an activate flag in the message, and cross check that with isToActivation
|
||||
* In cases where the message is to an activation that was properly detected, we don't want to move the arrow head
|
||||
* The activation will not be detected on the first message, so we need to move the arrow head
|
||||
*/
|
||||
if (msg.activate && !isArrowToActivation) {
|
||||
stopx += adjustValue(conf.activationWidth / 2 - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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].includes(msg.type)) {
|
||||
stopx += adjustValue(3);
|
||||
}
|
||||
|
||||
const allBounds = [fromLeft, fromRight, toLeft, toRight];
|
||||
const boundedWidth = Math.abs(startx - stopx);
|
||||
if (msg.wrap && msg.message) {
|
||||
msg.message = utils.wrapLabel(
|
||||
msg.message,
|
||||
@@ -1429,8 +1458,8 @@ const buildMessageModel = function (msg, actors, diagObj) {
|
||||
conf.width
|
||||
),
|
||||
height: 0,
|
||||
startx: fromBounds[fromIdx],
|
||||
stopx: toBounds[toIdx],
|
||||
startx,
|
||||
stopx,
|
||||
starty: 0,
|
||||
stopy: 0,
|
||||
message: msg.message,
|
||||
|
@@ -703,7 +703,7 @@ export const insertArrowHead = function (elem) {
|
||||
.append('defs')
|
||||
.append('marker')
|
||||
.attr('id', 'arrowhead')
|
||||
.attr('refX', 9)
|
||||
.attr('refX', 7.9)
|
||||
.attr('refY', 5)
|
||||
.attr('markerUnits', 'userSpaceOnUse')
|
||||
.attr('markerWidth', 12)
|
||||
@@ -723,7 +723,7 @@ export const insertArrowFilledHead = function (elem) {
|
||||
.append('defs')
|
||||
.append('marker')
|
||||
.attr('id', 'filled-head')
|
||||
.attr('refX', 18)
|
||||
.attr('refX', 15.5)
|
||||
.attr('refY', 7)
|
||||
.attr('markerWidth', 20)
|
||||
.attr('markerHeight', 28)
|
||||
@@ -768,7 +768,7 @@ export const insertArrowCrossHead = function (elem) {
|
||||
.attr('markerHeight', 8)
|
||||
.attr('orient', 'auto')
|
||||
.attr('refX', 4)
|
||||
.attr('refY', 5);
|
||||
.attr('refY', 4.5);
|
||||
// The cross
|
||||
marker
|
||||
.append('path')
|
||||
|
@@ -11,7 +11,7 @@ import {
|
||||
clear as commonClear,
|
||||
setDiagramTitle,
|
||||
getDiagramTitle,
|
||||
} from '../../commonDb.js';
|
||||
} from '../common/commonDb.js';
|
||||
|
||||
import {
|
||||
DEFAULT_DIAGRAM_DIRECTION,
|
||||
|
@@ -1,7 +1,6 @@
|
||||
import { parser as timeline } from './parser/timeline.jison';
|
||||
import * as timelineDB from './timelineDb.js';
|
||||
// import { injectUtils } from './mermaidUtils.js';
|
||||
import * as _commonDb from '../../commonDb.js';
|
||||
import { parseDirective as _parseDirective } from '../../directiveUtils.js';
|
||||
|
||||
import {
|
||||
@@ -18,7 +17,6 @@ import {
|
||||
// getConfig,
|
||||
// sanitizeText,
|
||||
// setupGraphViewBox,
|
||||
// _commonDb,
|
||||
// _parseDirective
|
||||
// );
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { parseDirective as _parseDirective } from '../../directiveUtils.js';
|
||||
import * as commonDb from '../../commonDb.js';
|
||||
import * as commonDb from '../common/commonDb.js';
|
||||
let currentSection = '';
|
||||
let currentTaskId = 0;
|
||||
|
||||
|
@@ -8,7 +8,7 @@ import {
|
||||
getAccDescription,
|
||||
setAccDescription,
|
||||
clear as commonClear,
|
||||
} from '../../commonDb.js';
|
||||
} from '../common/commonDb.js';
|
||||
|
||||
let currentSection = '';
|
||||
|
||||
|
@@ -56,10 +56,10 @@ from IPython.display import Image, display
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
def mm(graph):
|
||||
graphbytes = graph.encode("ascii")
|
||||
base64_bytes = base64.b64encode(graphbytes)
|
||||
base64_string = base64_bytes.decode("ascii")
|
||||
display(Image(url="https://mermaid.ink/img/" + base64_string))
|
||||
graphbytes = graph.encode("utf8")
|
||||
base64_bytes = base64.b64encode(graphbytes)
|
||||
base64_string = base64_bytes.decode("ascii")
|
||||
display(Image(url="https://mermaid.ink/img/" + base64_string))
|
||||
|
||||
mm("""
|
||||
graph LR;
|
||||
|
@@ -43,6 +43,7 @@ They also serve as proof of concept, for the variety of things that can be built
|
||||
- [Mermaid plugin for GitBook](https://github.com/wwformat/gitbook-plugin-mermaid-pdf)
|
||||
- [LiveBook](https://livebook.dev) (**Native support**)
|
||||
- [Atlassian Products](https://www.atlassian.com)
|
||||
- [Mermaid Live Editor for Confluence Cloud](https://marketplace.atlassian.com/apps/1231571/mermaid-live-editor-for-confluence?hosting=cloud&tab=overview)
|
||||
- [Mermaid Plugin for Confluence](https://marketplace.atlassian.com/apps/1214124/mermaid-plugin-for-confluence?hosting=server&tab=overview)
|
||||
- [CloudScript.io Addon](https://marketplace.atlassian.com/apps/1219878/cloudscript-io-mermaid-addon?hosting=cloud&tab=overview)
|
||||
- [Auto convert diagrams in Jira](https://github.com/coddingtonbear/jirafs-mermaid)
|
||||
|
@@ -56,7 +56,7 @@ Mermaid syntax for ER diagrams is compatible with PlantUML, with an extension to
|
||||
|
||||
Where:
|
||||
|
||||
- `first-entity` is the name of an entity. Names must begin with an alphabetic character and may also contain digits, hyphens, and underscores.
|
||||
- `first-entity` is the name of an entity. Names must begin with an alphabetic character or an underscore (from v<MERMAID_RELEASE_VERSION>+), and may also contain digits and hyphens.
|
||||
- `relationship` describes the way that both entities inter-relate. See below.
|
||||
- `second-entity` is the name of the other entity.
|
||||
- `relationship-label` describes the relationship from the perspective of the first entity.
|
||||
|
@@ -173,7 +173,7 @@ The following formatting strings are supported:
|
||||
|
||||
More info in: [https://github.com/d3/d3-time-format/tree/v4.0.0#locale_format](https://github.com/d3/d3-time-format/tree/v4.0.0#locale_format)
|
||||
|
||||
### Axis ticks
|
||||
### Axis ticks (v10.3.0+)
|
||||
|
||||
The default output ticks are auto. You can custom your `tickInterval`, like `1day` or `1week`.
|
||||
|
||||
@@ -184,7 +184,7 @@ tickInterval 1day
|
||||
The pattern is:
|
||||
|
||||
```javascript
|
||||
/^([1-9][0-9]*)(minute|hour|day|week|month)$/;
|
||||
/^([1-9][0-9]*)(millisecond|second|minute|hour|day|week|month)$/;
|
||||
```
|
||||
|
||||
More info in: [https://github.com/d3/d3-time#interval_every](https://github.com/d3/d3-time#interval_every)
|
||||
@@ -197,7 +197,9 @@ gantt
|
||||
weekday monday
|
||||
```
|
||||
|
||||
Support: v10.3.0+
|
||||
```warning
|
||||
`millisecond` and `second` support was added in vMERMAID_RELEASE_VERSION
|
||||
```
|
||||
|
||||
## Output in compact mode
|
||||
|
||||
|
@@ -1524,10 +1524,10 @@ $defs: # JSON Schema definition (maybe we should move these to a seperate file)
|
||||
Pattern is:
|
||||
|
||||
```javascript
|
||||
/^([1-9][0-9]*)(minute|hour|day|week|month)$/
|
||||
/^([1-9][0-9]*)(millisecond|second|minute|hour|day|week|month)$/
|
||||
```
|
||||
type: string
|
||||
pattern: ^([1-9][0-9]*)(minute|hour|day|week|month)$
|
||||
pattern: ^([1-9][0-9]*)(millisecond|second|minute|hour|day|week|month)$
|
||||
topAxis:
|
||||
description: |
|
||||
When this flag is set, date labels will be added to the top of the chart
|
||||
|
Reference in New Issue
Block a user