mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-10-25 17:04:19 +02:00
Compare commits
50 Commits
update-blo
...
chore/fix_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3e57d35aee | ||
|
|
801bdea300 | ||
|
|
ef572bb859 | ||
|
|
77a16fc3fa | ||
|
|
a80171a7ce | ||
|
|
c5106a1d1f | ||
|
|
df636c6d0a | ||
|
|
64554a6c60 | ||
|
|
becadf0a7d | ||
|
|
54d485f173 | ||
|
|
b4f5b8ddaf | ||
|
|
cb5c1ae367 | ||
|
|
b29081d4e8 | ||
|
|
654097c438 | ||
|
|
1e672868c4 | ||
|
|
bff32827b5 | ||
|
|
65f9b29b86 | ||
|
|
9868f3a4c3 | ||
|
|
b4879d13b8 | ||
|
|
95964b5487 | ||
|
|
4e17da0a30 | ||
|
|
d8bf155f0e | ||
|
|
0b4f85230a | ||
|
|
0dff4ca438 | ||
|
|
cc29437ede | ||
|
|
dfaaf361f3 | ||
|
|
37538310d3 | ||
|
|
c7ae08abc3 | ||
|
|
69973eaa02 | ||
|
|
d3b2c7ea18 | ||
|
|
68f41f685d | ||
|
|
255279eb22 | ||
|
|
fe3cffbb67 | ||
|
|
2a91849a38 | ||
|
|
082de76eef | ||
|
|
570ae78b15 | ||
|
|
885ac6f947 | ||
|
|
8328f74751 | ||
|
|
01b5079562 | ||
|
|
6b23647bec | ||
|
|
193fdb225e | ||
|
|
c8ce416aba | ||
|
|
1388662132 | ||
|
|
757627427b | ||
|
|
7cbd80af33 | ||
|
|
16c448b89b | ||
|
|
c218e365bd | ||
|
|
cb0a4703bd | ||
|
|
8cb1c68166 | ||
|
|
d752240efc |
5
.changeset/angry-bags-brake.md
Normal file
5
.changeset/angry-bags-brake.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'mermaid': patch
|
||||
---
|
||||
|
||||
fix: architecture diagrams no longer grow to extreme heights due to conflicting alignments
|
||||
5
.changeset/lucky-points-wave.md
Normal file
5
.changeset/lucky-points-wave.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'mermaid': minor
|
||||
---
|
||||
|
||||
Rename internal fields for class diagrams to match documentation and usage
|
||||
@@ -1 +1 @@
|
||||
./packages/mermaid/src/docs/community/contributing.md
|
||||
./packages/mermaid/src/docs/community/contributing.md
|
||||
|
||||
@@ -171,6 +171,58 @@ describe.skip('architecture diagram', () => {
|
||||
`
|
||||
);
|
||||
});
|
||||
|
||||
it('should render an architecture diagram with a resonable height', () => {
|
||||
imgSnapshotTest(
|
||||
`architecture-beta
|
||||
group federated(cloud)[Federated Environment]
|
||||
service server1(server)[System] in federated
|
||||
service edge(server)[Edge Device] in federated
|
||||
server1:R -- L:edge
|
||||
|
||||
group on_prem(cloud)[Hub]
|
||||
service firewall(server)[Firewall Device] in on_prem
|
||||
service server(server)[Server] in on_prem
|
||||
firewall:R -- L:server
|
||||
|
||||
service db1(database)[db1] in on_prem
|
||||
service db2(database)[db2] in on_prem
|
||||
service db3(database)[db3] in on_prem
|
||||
service db4(database)[db4] in on_prem
|
||||
service db5(database)[db5] in on_prem
|
||||
service db6(database)[db6] in on_prem
|
||||
|
||||
junction mid in on_prem
|
||||
server:B -- T:mid
|
||||
|
||||
junction 1Leftofmid in on_prem
|
||||
1Leftofmid:R -- L:mid
|
||||
1Leftofmid:B -- T:db1
|
||||
|
||||
junction 2Leftofmid in on_prem
|
||||
2Leftofmid:R -- L:1Leftofmid
|
||||
2Leftofmid:B -- T:db2
|
||||
|
||||
junction 3Leftofmid in on_prem
|
||||
3Leftofmid:R -- L:2Leftofmid
|
||||
3Leftofmid:B -- T:db3
|
||||
|
||||
junction 1RightOfMid in on_prem
|
||||
mid:R -- L:1RightOfMid
|
||||
1RightOfMid:B -- T:db4
|
||||
|
||||
junction 2RightOfMid in on_prem
|
||||
1RightOfMid:R -- L:2RightOfMid
|
||||
2RightOfMid:B -- T:db5
|
||||
|
||||
junction 3RightOfMid in on_prem
|
||||
2RightOfMid:R -- L:3RightOfMid
|
||||
3RightOfMid:B -- T:db6
|
||||
|
||||
edge:R -- L:firewall
|
||||
`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
// Skipped as the layout is not deterministic, and causes issues in E2E tests.
|
||||
|
||||
@@ -650,12 +650,12 @@ class Class10
|
||||
{ logLevel: 1, htmlLabels: true, layout: 'elk' }
|
||||
);
|
||||
});
|
||||
it('ELK: should render a class with a text label, members and annotation', () => {
|
||||
it('ELK: should render a class with a text label, attribute and annotation', () => {
|
||||
imgSnapshotTest(
|
||||
`classDiagram
|
||||
class C1["Class 1 with text label"] {
|
||||
<<interface>>
|
||||
+member1
|
||||
+attribute1
|
||||
}
|
||||
C1 --> C2`,
|
||||
{ logLevel: 1, htmlLabels: true, layout: 'elk' }
|
||||
|
||||
@@ -650,12 +650,12 @@ class Class10
|
||||
{ logLevel: 1, htmlLabels: true, look: 'handDrawn' }
|
||||
);
|
||||
});
|
||||
it('HD: should render a class with a text label, members and annotation', () => {
|
||||
it('HD: should render a class with a text label, attribute and annotation', () => {
|
||||
imgSnapshotTest(
|
||||
`classDiagram
|
||||
class C1["Class 1 with text label"] {
|
||||
<<interface>>
|
||||
+member1
|
||||
+attribute1
|
||||
}
|
||||
C1 --> C2`,
|
||||
{ logLevel: 1, htmlLabels: true, look: 'handDrawn' }
|
||||
|
||||
@@ -500,12 +500,12 @@ class Class10
|
||||
C1 --> C2`
|
||||
);
|
||||
});
|
||||
it('should render a class with a text label, members and annotation', () => {
|
||||
it('should render a class with a text label, attribute and annotation', () => {
|
||||
imgSnapshotTest(
|
||||
`classDiagram
|
||||
class C1["Class 1 with text label"] {
|
||||
<<interface>>
|
||||
+member1
|
||||
+attribute1
|
||||
}
|
||||
C1 --> C2`
|
||||
);
|
||||
|
||||
@@ -647,12 +647,12 @@ class Class10
|
||||
C1 --> C2`
|
||||
);
|
||||
});
|
||||
it('should render a class with a text label, members and annotation', () => {
|
||||
it('should render a class with a text label, attribute and annotation', () => {
|
||||
imgSnapshotTest(
|
||||
`classDiagram
|
||||
class C1["Class 1 with text label"] {
|
||||
<<interface>>
|
||||
+member1
|
||||
+attribute1
|
||||
}
|
||||
C1 --> C2`
|
||||
);
|
||||
|
||||
@@ -430,7 +430,7 @@ describe('Class diagram', () => {
|
||||
class \`This\nTitle\nHas\nMany\nNewlines\` {
|
||||
+String Also
|
||||
-Stirng Many
|
||||
#int Members
|
||||
#int attribute
|
||||
+And()
|
||||
-Many()
|
||||
#Methods()
|
||||
@@ -444,7 +444,7 @@ describe('Class diagram', () => {
|
||||
class \`This\nTitle\nHas\nMany\nNewlines\` {
|
||||
+String Also
|
||||
-Stirng Many
|
||||
#int Members
|
||||
#int attribute
|
||||
+And()
|
||||
-Many()
|
||||
#Methods()
|
||||
@@ -460,7 +460,7 @@ describe('Class diagram', () => {
|
||||
class \`This\nTitle\nHas\nMany\nNewlines\` {
|
||||
+String Also
|
||||
-Stirng Many
|
||||
#int Members
|
||||
#int attribute
|
||||
+And()
|
||||
-Many()
|
||||
#Methods()
|
||||
|
||||
@@ -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
|
||||
@@ -857,6 +857,196 @@ flowchart LR
|
||||
D --> E
|
||||
A["A"]
|
||||
|
||||
`,
|
||||
{ flowchart: { titleTopMargin: 0 } }
|
||||
);
|
||||
});
|
||||
it('6080: should handle diamond shape intersections', () => {
|
||||
imgSnapshotTest(
|
||||
`---
|
||||
config:
|
||||
layout: elk
|
||||
---
|
||||
flowchart LR
|
||||
subgraph s1["Untitled subgraph"]
|
||||
n1["Evaluate"]
|
||||
n2["Option 1"]
|
||||
n3["Option 2"]
|
||||
n4["fa:fa-car Option 3"]
|
||||
end
|
||||
subgraph s2["Untitled subgraph"]
|
||||
n5["Evaluate"]
|
||||
n6["Option 1"]
|
||||
n7["Option 2"]
|
||||
n8["fa:fa-car Option 3"]
|
||||
end
|
||||
A["Start"] -- Some text --> B("Continue")
|
||||
B --> C{"Evaluate"}
|
||||
C -- One --> D["Option 1"]
|
||||
C -- Two --> E["Option 2"]
|
||||
C -- Three --> F["fa:fa-car Option 3"]
|
||||
n1 -- One --> n2
|
||||
n1 -- Two --> n3
|
||||
n1 -- Three --> n4
|
||||
n5 -- One --> n6
|
||||
n5 -- Two --> n7
|
||||
n5 -- Three --> n8
|
||||
n1@{ shape: diam}
|
||||
n2@{ shape: rect}
|
||||
n3@{ shape: rect}
|
||||
n4@{ shape: rect}
|
||||
n5@{ shape: diam}
|
||||
n6@{ shape: rect}
|
||||
n7@{ shape: rect}
|
||||
n8@{ shape: rect}
|
||||
|
||||
`,
|
||||
{ flowchart: { titleTopMargin: 0 } }
|
||||
);
|
||||
});
|
||||
|
||||
it('6088-1: should handle diamond shape intersections', () => {
|
||||
imgSnapshotTest(
|
||||
`---
|
||||
config:
|
||||
layout: elk
|
||||
---
|
||||
flowchart LR
|
||||
subgraph S2
|
||||
subgraph s1["APA"]
|
||||
D{"Use the editor"}
|
||||
end
|
||||
|
||||
|
||||
D -- Mermaid js --> I{"fa:fa-code Text"}
|
||||
D --> I
|
||||
D --> I
|
||||
|
||||
end
|
||||
`,
|
||||
{ flowchart: { titleTopMargin: 0 } }
|
||||
);
|
||||
});
|
||||
|
||||
it('6088-2: should handle diamond shape intersections', () => {
|
||||
imgSnapshotTest(
|
||||
`---
|
||||
config:
|
||||
layout: elk
|
||||
---
|
||||
flowchart LR
|
||||
a
|
||||
subgraph s0["APA"]
|
||||
subgraph s8["APA"]
|
||||
subgraph s1["APA"]
|
||||
D{"X"}
|
||||
E[Q]
|
||||
end
|
||||
subgraph s3["BAPA"]
|
||||
F[Q]
|
||||
I
|
||||
end
|
||||
D --> I
|
||||
D --> I
|
||||
D --> I
|
||||
|
||||
I{"X"}
|
||||
end
|
||||
end
|
||||
|
||||
`,
|
||||
{ flowchart: { titleTopMargin: 0 } }
|
||||
);
|
||||
});
|
||||
|
||||
it('6088-3: should handle diamond shape intersections', () => {
|
||||
imgSnapshotTest(
|
||||
`---
|
||||
config:
|
||||
layout: elk
|
||||
---
|
||||
flowchart LR
|
||||
a
|
||||
D{"Use the editor"}
|
||||
|
||||
D -- Mermaid js --> I{"fa:fa-code Text"}
|
||||
D-->I
|
||||
D-->I
|
||||
|
||||
`,
|
||||
{ flowchart: { titleTopMargin: 0 } }
|
||||
);
|
||||
});
|
||||
|
||||
it('6088-4: should handle diamond shape intersections', () => {
|
||||
imgSnapshotTest(
|
||||
`---
|
||||
config:
|
||||
layout: elk
|
||||
---
|
||||
flowchart LR
|
||||
subgraph s1["Untitled subgraph"]
|
||||
n1["Evaluate"]
|
||||
n2["Option 1"]
|
||||
n3["Option 2"]
|
||||
n4["fa:fa-car Option 3"]
|
||||
end
|
||||
subgraph s2["Untitled subgraph"]
|
||||
n5["Evaluate"]
|
||||
n6["Option 1"]
|
||||
n7["Option 2"]
|
||||
n8["fa:fa-car Option 3"]
|
||||
end
|
||||
A["Start"] -- Some text --> B("Continue")
|
||||
B --> C{"Evaluate"}
|
||||
C -- One --> D["Option 1"]
|
||||
C -- Two --> E["Option 2"]
|
||||
C -- Three --> F["fa:fa-car Option 3"]
|
||||
n1 -- One --> n2
|
||||
n1 -- Two --> n3
|
||||
n1 -- Three --> n4
|
||||
n5 -- One --> n6
|
||||
n5 -- Two --> n7
|
||||
n5 -- Three --> n8
|
||||
n1@{ shape: diam}
|
||||
n2@{ shape: rect}
|
||||
n3@{ shape: rect}
|
||||
n4@{ shape: rect}
|
||||
n5@{ shape: diam}
|
||||
n6@{ shape: rect}
|
||||
n7@{ shape: rect}
|
||||
n8@{ shape: rect}
|
||||
|
||||
`,
|
||||
{ flowchart: { titleTopMargin: 0 } }
|
||||
);
|
||||
});
|
||||
|
||||
it('6088-5: should handle diamond shape intersections', () => {
|
||||
imgSnapshotTest(
|
||||
`---
|
||||
config:
|
||||
layout: elk
|
||||
---
|
||||
flowchart LR
|
||||
A{A} --> B & C
|
||||
|
||||
`,
|
||||
{ flowchart: { titleTopMargin: 0 } }
|
||||
);
|
||||
});
|
||||
it('6088-6: should handle diamond shape intersections', () => {
|
||||
imgSnapshotTest(
|
||||
`---
|
||||
config:
|
||||
layout: elk
|
||||
---
|
||||
flowchart LR
|
||||
A{A} --> B & C
|
||||
subgraph "subbe"
|
||||
A
|
||||
end
|
||||
|
||||
`,
|
||||
{ flowchart: { titleTopMargin: 0 } }
|
||||
);
|
||||
|
||||
@@ -89,70 +89,239 @@
|
||||
|
||||
<body>
|
||||
<pre id="diagram4" class="mermaid">
|
||||
---
|
||||
config:
|
||||
layout: elk
|
||||
---
|
||||
flowchart LR
|
||||
subgraph S2
|
||||
subgraph s1["APA"]
|
||||
D{"Use the editor"}
|
||||
end
|
||||
|
||||
|
||||
D -- Mermaid js --> I{"fa:fa-code Text"}
|
||||
D --> I
|
||||
D --> I
|
||||
|
||||
end
|
||||
</pre>
|
||||
<pre id="diagram4" class="mermaid">
|
||||
---
|
||||
config:
|
||||
layout: elk
|
||||
---
|
||||
flowchart LR
|
||||
a
|
||||
subgraph s0["APA"]
|
||||
subgraph s8["APA"]
|
||||
subgraph s1["APA"]
|
||||
D{"X"}
|
||||
E[Q]
|
||||
end
|
||||
subgraph s3["BAPA"]
|
||||
F[Q]
|
||||
I
|
||||
end
|
||||
D --> I
|
||||
D --> I
|
||||
D --> I
|
||||
|
||||
I{"X"}
|
||||
end
|
||||
end
|
||||
</pre>
|
||||
<pre id="diagram4" class="mermaid">
|
||||
---
|
||||
config:
|
||||
layout: elk
|
||||
---
|
||||
flowchart LR
|
||||
a
|
||||
D{"Use the editor"}
|
||||
|
||||
D -- Mermaid js --> I{"fa:fa-code Text"}
|
||||
D-->I
|
||||
D-->I
|
||||
</pre>
|
||||
<pre id="diagram4" class="mermaid">
|
||||
---
|
||||
config:
|
||||
layout: elk
|
||||
---
|
||||
flowchart LR
|
||||
subgraph s1["Untitled subgraph"]
|
||||
n1["Evaluate"]
|
||||
n2["Option 1"]
|
||||
n3["Option 2"]
|
||||
n4["fa:fa-car Option 3"]
|
||||
end
|
||||
subgraph s2["Untitled subgraph"]
|
||||
n5["Evaluate"]
|
||||
n6["Option 1"]
|
||||
n7["Option 2"]
|
||||
n8["fa:fa-car Option 3"]
|
||||
end
|
||||
A["Start"] -- Some text --> B("Continue")
|
||||
B --> C{"Evaluate"}
|
||||
C -- One --> D["Option 1"]
|
||||
C -- Two --> E["Option 2"]
|
||||
C -- Three --> F["fa:fa-car Option 3"]
|
||||
n1 -- One --> n2
|
||||
n1 -- Two --> n3
|
||||
n1 -- Three --> n4
|
||||
n5 -- One --> n6
|
||||
n5 -- Two --> n7
|
||||
n5 -- Three --> n8
|
||||
n1@{ shape: diam}
|
||||
n2@{ shape: rect}
|
||||
n3@{ shape: rect}
|
||||
n4@{ shape: rect}
|
||||
n5@{ shape: diam}
|
||||
n6@{ shape: rect}
|
||||
n7@{ shape: rect}
|
||||
n8@{ shape: rect}
|
||||
|
||||
</pre>
|
||||
<pre id="diagram4" class="mermaid">
|
||||
---
|
||||
config:
|
||||
layout: elk
|
||||
---
|
||||
flowchart LR
|
||||
subgraph s1["Untitled subgraph"]
|
||||
n1["Evaluate"]
|
||||
n2["Option 1"]
|
||||
end
|
||||
n1 -- One --> n2
|
||||
|
||||
|
||||
|
||||
|
||||
</pre>
|
||||
<pre id="diagram4" class="mermaid">
|
||||
---
|
||||
config:
|
||||
layout: elk
|
||||
---
|
||||
flowchart LR
|
||||
A{A} --> B & C
|
||||
</pre
|
||||
>
|
||||
<pre id="diagram4" class="mermaid">
|
||||
---
|
||||
config:
|
||||
layout: elk
|
||||
---
|
||||
flowchart LR
|
||||
A{A} --> B & C
|
||||
subgraph "subbe"
|
||||
A
|
||||
end
|
||||
</pre
|
||||
>
|
||||
<pre id="diagram4" class="mermaid">
|
||||
---
|
||||
config:
|
||||
layout: elk
|
||||
---
|
||||
flowchart LR
|
||||
n2@{ shape: rect}
|
||||
n3@{ shape: rect}
|
||||
n4@{ shape: rect}
|
||||
A["Start"] -- Some text --> B("Continue")
|
||||
B --> C{"Evaluate"}
|
||||
C -- One --> D["Option 1"]
|
||||
C -- Two --> E["Option 2"]
|
||||
C -- Three --> F["fa:fa-car Option 3"]
|
||||
%% C@{ shape: hexagon}
|
||||
|
||||
|
||||
</pre>
|
||||
<pre id="diagram4" class="mermaid2">
|
||||
---
|
||||
config:
|
||||
kanban:
|
||||
ticketBaseUrl: 'https://github.com/your-repo/issues/#TICKET#'
|
||||
---
|
||||
kanban
|
||||
Backlog
|
||||
task1[📝 Define project requirements]@{ ticket: a101 }
|
||||
To Do
|
||||
task2[🔍 Research technologies]@{ ticket: a102 }
|
||||
Review
|
||||
task4[🔍 Code review for login feature]@{ ticket: a104 }
|
||||
Done
|
||||
task5[✅ Deploy initial version]@{ ticket: a105 }
|
||||
In Progress
|
||||
task3[💻 Develop login feature]@{ ticket: 103 }
|
||||
|
||||
</pre>
|
||||
<pre id="diagram4" class="mermaid2">
|
||||
flowchart LR
|
||||
nA[Default] --> A@{ icon: 'fa:bell', form: 'rounded' }
|
||||
|
||||
</pre>
|
||||
<pre id="diagram4" class="mermaid">
|
||||
<pre id="diagram4" class="mermaid2">
|
||||
flowchart LR
|
||||
nA[Style] --> A@{ icon: 'fa:bell', form: 'rounded' }
|
||||
style A fill:#f9f,stroke:#333,stroke-width:4px
|
||||
</pre>
|
||||
<pre id="diagram4" class="mermaid">
|
||||
<pre id="diagram4" class="mermaid2">
|
||||
flowchart LR
|
||||
nA[Class] --> A@{ icon: 'fa:bell', form: 'rounded' }
|
||||
A:::AClass
|
||||
classDef AClass fill:#f9f,stroke:#333,stroke-width:4px
|
||||
</pre>
|
||||
<pre id="diagram4" class="mermaid">
|
||||
<pre id="diagram4" class="mermaid2">
|
||||
flowchart LR
|
||||
nA[Class] --> A@{ icon: 'logos:aws', form: 'rounded' }
|
||||
|
||||
</pre>
|
||||
<pre id="diagram4" class="mermaid">
|
||||
<pre id="diagram4" class="mermaid2">
|
||||
flowchart LR
|
||||
nA[Default] --> A@{ icon: 'fa:bell', form: 'square' }
|
||||
|
||||
</pre>
|
||||
<pre id="diagram4" class="mermaid">
|
||||
<pre id="diagram4" class="mermaid2">
|
||||
flowchart LR
|
||||
nA[Style] --> A@{ icon: 'fa:bell', form: 'square' }
|
||||
style A fill:#f9f,stroke:#333,stroke-width:4px
|
||||
</pre>
|
||||
<pre id="diagram4" class="mermaid">
|
||||
<pre id="diagram4" class="mermaid2">
|
||||
flowchart LR
|
||||
nA[Class] --> A@{ icon: 'fa:bell', form: 'square' }
|
||||
A:::AClass
|
||||
classDef AClass fill:#f9f,stroke:#333,stroke-width:4px
|
||||
</pre>
|
||||
<pre id="diagram4" class="mermaid">
|
||||
<pre id="diagram4" class="mermaid2">
|
||||
flowchart LR
|
||||
nA[Class] --> A@{ icon: 'logos:aws', form: 'square' }
|
||||
|
||||
</pre>
|
||||
<pre id="diagram4" class="mermaid">
|
||||
<pre id="diagram4" class="mermaid2">
|
||||
flowchart LR
|
||||
nA[Default] --> A@{ icon: 'fa:bell', form: 'circle' }
|
||||
|
||||
</pre>
|
||||
<pre id="diagram4" class="mermaid">
|
||||
<pre id="diagram4" class="mermaid2">
|
||||
flowchart LR
|
||||
nA[Style] --> A@{ icon: 'fa:bell', form: 'circle' }
|
||||
style A fill:#f9f,stroke:#333,stroke-width:4px
|
||||
</pre>
|
||||
<pre id="diagram4" class="mermaid">
|
||||
<pre id="diagram4" class="mermaid2">
|
||||
flowchart LR
|
||||
nA[Class] --> A@{ icon: 'fa:bell', form: 'circle' }
|
||||
A:::AClass
|
||||
classDef AClass fill:#f9f,stroke:#333,stroke-width:4px
|
||||
</pre>
|
||||
<pre id="diagram4" class="mermaid">
|
||||
<pre id="diagram4" class="mermaid2">
|
||||
flowchart LR
|
||||
nA[Class] --> A@{ icon: 'logos:aws', form: 'circle' }
|
||||
A:::AClass
|
||||
classDef AClass fill:#f9f,stroke:#333,stroke-width:4px
|
||||
</pre>
|
||||
<pre id="diagram4" class="mermaid">
|
||||
<pre id="diagram4" class="mermaid2">
|
||||
flowchart LR
|
||||
nA[Style] --> A@{ icon: 'logos:aws', form: 'circle' }
|
||||
style A fill:#f9f,stroke:#333,stroke-width:4px
|
||||
|
||||
@@ -39,8 +39,8 @@ graph TB
|
||||
|
||||
<script type="module">
|
||||
import mermaid from '/mermaid.esm.mjs';
|
||||
import flowchartELK from '/mermaid-flowchart-elk.esm.mjs';
|
||||
await mermaid.registerExternalDiagrams([flowchartELK]);
|
||||
import layouts from '/mermaid-layout-elk.esm.mjs';
|
||||
mermaid.registerLayoutLoaders(layouts);
|
||||
async function render(str) {
|
||||
const { svg } = await mermaid.render('dynamic', str);
|
||||
document.getElementById('dynamicDiagram').innerHTML = svg;
|
||||
|
||||
@@ -185,8 +185,6 @@ Communication tools and platforms
|
||||
- [=Diagram block](https://github.com/zag/podlite/tree/main/packages/podlite-diagrams)
|
||||
- [Standard Notes](https://standardnotes.com/)
|
||||
- [Mermaid Extension](https://github.com/nienow/sn-mermaid)
|
||||
- [Sublime Text 3](https://sublimetext.com)
|
||||
- [Mermaid Package](https://packagecontrol.io/packages/Mermaid)
|
||||
- [VS Code](https://code.visualstudio.com/)
|
||||
- [Mermaid Editor](https://marketplace.visualstudio.com/items?itemName=tomoyukim.vscode-mermaid-editor)
|
||||
- [Mermaid Export](https://marketplace.visualstudio.com/items?itemName=Gruntfuggly.mermaid-export)
|
||||
|
||||
@@ -18,169 +18,169 @@ An entity relationship (ER) diagram acts like a blueprint for your database. Thi
|
||||
|
||||
October 24, 2024 · 4 mins
|
||||
|
||||
## [Expanding the Horizons of Mermaid Flowcharts: Introducing 30 New Shapes!](https://www.mermaidchart.com/blog/posts/expanding-the-horizons-of-mermaid-flowcharts-introducing-30-new-shapes)
|
||||
## [Expanding the Horizons of Mermaid Flowcharts: Introducing 30 New Shapes!](https://www.mermaidchart.com/blog/posts/new-mermaid-flowchart-shapes/)
|
||||
|
||||
24 September 2024 · 5 mins
|
||||
|
||||
Discover 30 new shapes in Mermaid flowcharts, offering enhanced clarity, customization, and versatility for more dynamic and expressive visualizations.
|
||||
|
||||
## [Introducing Architecture Diagrams in Mermaid](https://www.mermaidchart.com/blog/posts/introducing-architecture-diagrams-in-mermaid)
|
||||
## [Introducing Architecture Diagrams in Mermaid](https://www.mermaidchart.com/blog/posts/mermaid-supports-architecture-diagrams/)
|
||||
|
||||
2 September 2024 · 2 mins
|
||||
|
||||
Discover the fresh new and unique Neo and Hand-Drawn looks for Mermaid Diagrams, while still offering the classic look you love.
|
||||
|
||||
## [Mermaid v11 is out!](https://www.mermaidchart.com/blog/posts/mermaid-v11-is-out)
|
||||
## [Mermaid v11 is out!](https://www.mermaidchart.com/blog/posts/mermaid-v11/)
|
||||
|
||||
23 August 2024 · 2 mins
|
||||
|
||||
Mermaid v11 introduces advanced layout options, new diagram types, and enhanced customization features, thanks to the incredible contributions from our community.
|
||||
|
||||
## [Mermaid Innovation - Introducing New Looks for Mermaid Diagrams](https://www.mermaidchart.com/blog/posts/mermaid-innovation-introducing-new-looks-for-mermaid-diagrams)
|
||||
## [Mermaid Innovation - Introducing New Looks for Mermaid Diagrams](https://www.mermaidchart.com/blog/posts/mermaid-innovation-introducing-new-looks-for-mermaid-diagrams/)
|
||||
|
||||
6 August 2024 ·3 mins
|
||||
|
||||
Discover the fresh new and unique Neo and Hand-Drawn looks for Mermaid Diagrams, while still offering the classic look you love.
|
||||
|
||||
## [The Mermaid Chart Plugin for Jira: A How-To User Guide](https://www.mermaidchart.com/blog/posts/the-mermaid-chart-plugin-for-jira)
|
||||
## [The Mermaid Chart Plugin for Jira: A How-To User Guide](https://www.mermaidchart.com/blog/posts/the-mermaid-chart-plugin-for-jira-a-how-to-user-guide/)
|
||||
|
||||
31 July 2024 · 5 mins
|
||||
|
||||
The Mermaid Chart plugin for Jira has arrived!
|
||||
|
||||
## [Mermaid AI Is Here to Change the Game For Diagram Creation](https://www.mermaidchart.com/blog/posts/mermaid-ai-is-here-to-change-the-game-for-diagram-creation)
|
||||
## [Mermaid AI Is Here to Change the Game For Diagram Creation](https://www.mermaidchart.com/blog/posts/mermaid-ai-is-here-to-change-the-game-for-diagram-creation/)
|
||||
|
||||
22 July 2024 · 5 mins
|
||||
|
||||
The Mermaid AI chat interface
|
||||
|
||||
## [How to Make a Sequence Diagram with Mermaid Chart](https://www.mermaidchart.com/blog/posts/how-to-make-a-sequence-diagram-with-mermaid-chart)
|
||||
## [How to Make a Sequence Diagram with Mermaid Chart](https://www.mermaidchart.com/blog/posts/how-to-make-a-sequence-diagram-in-mermaid-chart-step-by-step-guide/)
|
||||
|
||||
8 July 2024 · 6 mins
|
||||
|
||||
Sequence diagrams are important for communicating complex systems in a clear and concise manner.
|
||||
|
||||
## [How to Use the New “Comments” Feature in Mermaid Chart](https://www.mermaidchart.com/blog/posts/how-to-use-the-new-comments-feature-in-mermaid-chart)
|
||||
## [How to Use the New “Comments” Feature in Mermaid Chart](https://www.mermaidchart.com/blog/posts/how-to-use-the-new-comments-feature-in-mermaid-chart/)
|
||||
|
||||
2 July 2024 · 3 mins
|
||||
|
||||
How to Use the New Comments Feature in Mermaid Chart
|
||||
|
||||
## [How to Use the official Mermaid Chart for Confluence app](https://www.mermaidchart.com/blog/posts/how-to-use-the-official-mermaid-chart-for-confluence-app)
|
||||
## [How to Use the official Mermaid Chart for Confluence app](https://www.mermaidchart.com/blog/posts/how-to-use-the-official-mermaid-chart-for-confluence-app/)
|
||||
|
||||
21 May 2024 · 4 mins
|
||||
|
||||
It doesn’t matter if you’re a data enthusiast, software engineer, or visual storyteller; our Confluence app can allow you to embed Mermaid Chart diagrams — and dynamically edit them — within your Confluence pages.
|
||||
|
||||
## [How to Choose the Right Documentation Software](https://www.mermaidchart.com/blog/posts/how-to-choose-the-right-documentation-software)
|
||||
## [How to Choose the Right Documentation Software](https://www.mermaidchart.com/blog/posts/how-to-choose-the-right-documentation-software/)
|
||||
|
||||
7 May 2024 · 5 mins
|
||||
|
||||
How to Choose the Right Documentation Software. Reliable and efficient documentation software is crucial in the fast-paced world of software development.
|
||||
|
||||
## [AI in software diagramming: What trends will define the future?](https://www.mermaidchart.com/blog/posts/ai-in-software-diagramming)
|
||||
## [AI in software diagramming: What trends will define the future?](https://www.mermaidchart.com/blog/posts/ai-in-software-diagramming/)
|
||||
|
||||
24 April 2024 · 5 mins
|
||||
|
||||
Artificial intelligence (AI) tools are changing the way developers work.
|
||||
|
||||
## [Mermaid Chart Unveils Visual Editor for Sequence Diagrams](https://www.mermaidchart.com/blog/posts/mermaid-chart-unveils-visual-editor-for-sequence-diagrams)
|
||||
## [Mermaid Chart Unveils Visual Editor for Sequence Diagrams](https://www.mermaidchart.com/blog/posts/mermaid-chart-unveils-visual-editor-for-sequence-diagrams/)
|
||||
|
||||
8 April 2024 · 5 mins
|
||||
|
||||
Sequence diagrams are excellent tools for communication and documentation.
|
||||
|
||||
## [Modeling system states: It starts with a Turing machine](https://www.mermaidchart.com/blog/posts/modeling-system-states-it-starts-with-a-turing-machine)
|
||||
## [Modeling system states: It starts with a Turing machine](https://www.mermaidchart.com/blog/posts/modeling-system-states/)
|
||||
|
||||
27 March 2024 · 12 mins
|
||||
|
||||
In computer science, there are a few fundamental papers that, without exaggeration, changed everything.
|
||||
|
||||
## [Mermaid Chart Raises $7.5M to Reinvent Visual Collaboration for Enterprises](https://www.mermaidchart.com/blog/posts/mermaid-chart-raises-7-5m-to-reinvent-visual-collaboration-for-enterprises)
|
||||
## [Mermaid Chart Raises $7.5M to Reinvent Visual Collaboration for Enterprises](https://www.mermaidchart.com/blog/posts/mermaid-chart-raises-7.5m-to-reinvent-visual-collaoration-for-enterprises/)
|
||||
|
||||
20 March 2024 · 4 mins
|
||||
|
||||
Mermaid Chart, the company offering text-based diagramming and workflow management tools, today announced it has raised $7.5 million in Seed funding.
|
||||
|
||||
## [Mermaid Chart GPT Is Now Available In the GPT Store!](https://www.mermaidchart.com/blog/posts/mermaid-chart-gpt-is-now-available-in-the-gpt-store)
|
||||
## [Mermaid Chart GPT Is Now Available In the GPT Store!](https://www.mermaidchart.com/blog/posts/mermaid-chart-gpt-is-now-available-in-the-gpt-store/)
|
||||
|
||||
7 March 2024 · 3 mins
|
||||
|
||||
Mermaid Chart GPT is Now Available In the GPT Store!
|
||||
|
||||
## [How to Make a Flowchart with Mermaid Chart](https://www.mermaidchart.com/blog/posts/how-to-make-a-flowchart-with-mermaid-chart)
|
||||
## [How to Make a Flowchart with Mermaid Chart](https://www.mermaidchart.com/blog/posts/how-to-make-flowcharts-with-mermaid-chart/)
|
||||
|
||||
30 January 2024 · 6 mins
|
||||
|
||||
Learn how to make a flowchart with Mermaid Chart, the leading text-to-diagram platform for both developers and non-developers.
|
||||
|
||||
## [How one data scientist uses Mermaid Chart to quickly and easily build flowcharts](https://www.mermaidchart.com/blog/posts/how-one-data-scientist-uses-mermaid-chart-to-quickly-and-easily-build-flowcharts)
|
||||
## [How one data scientist uses Mermaid Chart to quickly and easily build flowcharts](https://www.mermaidchart.com/blog/posts/customer-spotlight-ari-tal/)
|
||||
|
||||
23 January 2024 · 4 mins
|
||||
|
||||
Read about how Ari Tal, a data scientist and founder of Leveling Up with XAI, utilizes Mermaid Chart for its easy-to-use flowchart creation capabilities to enhance his work in explainable AI (XAI).
|
||||
|
||||
## [Introducing Mermaid Chart’s JetBrains IDE Extension](https://www.mermaidchart.com/blog/posts/introducing-mermaid-charts-jetbrains-ide-extension)
|
||||
## [Introducing Mermaid Chart’s JetBrains IDE Extension](https://www.mermaidchart.com/blog/posts/introducing-mermaid-charts-jetbrains-ide-extension/)
|
||||
|
||||
20 December 2023 · 5 mins
|
||||
|
||||
Diagrams are essential for documenting your code.
|
||||
|
||||
## [Mermaid Chart Releases New Visual Editor For Flowcharts](https://www.mermaidchart.com/blog/posts/mermaid-chart-releases-new-visual-editor-for-flowcharts)
|
||||
## [Mermaid Chart Releases New Visual Editor For Flowcharts](https://www.mermaidchart.com/blog/posts/mermaid-chart-releases-new-visual-editor-for-flowcharts/)
|
||||
|
||||
14 December 2023 · 5 mins
|
||||
|
||||
Mermaid Chart introduces a new Visual Editor for flowcharts, enabling users of all skill levels to create diagrams easily and efficiently, with both GUI and code-based editing options.
|
||||
|
||||
## [7 best practices (+ examples) for good developer documentation](https://www.mermaidchart.com/blog/posts/7-best-practices-examples-for-good-developer-documentation)
|
||||
## [7 best practices (+ examples) for good developer documentation](https://www.mermaidchart.com/blog/posts/7-best-practices-for-good-documentation/)
|
||||
|
||||
4 December 2023 · 11 min
|
||||
|
||||
Essential strategies for crafting grate developer documentation, with practical examples and insights from leading tech companies.
|
||||
|
||||
## [5 Reasons You Should Be Using Mermaid Chart As Your Diagram Generator](https://www.mermaidchart.com/blog/posts/5-reasons-you-should-be-using-mermaid-chart-as-your-diagram-generator)
|
||||
## [5 Reasons You Should Be Using Mermaid Chart As Your Diagram Generator](https://www.mermaidchart.com/blog/posts/5-reasons-you-should-be-using-mermaid-chart-as-your-diagram-generator/)
|
||||
|
||||
14 November 2023 · 5 mins
|
||||
|
||||
Mermaid Chart, a user-friendly, code-based diagram generator with AI integrations, templates, collaborative tools, and plugins for developers, streamlines the process of creating and sharing diagrams, enhancing both creativity and collaboration.
|
||||
|
||||
## [How to Use Mermaid Chart as an AI Diagram Generator](https://www.mermaidchart.com/blog/posts/how-to-use-mermaid-chart-as-an-ai-diagram-generator)
|
||||
## [How to Use Mermaid Chart as an AI Diagram Generator](https://www.mermaidchart.com/blog/posts/how-to-use-mermaid-chart-as-an-ai-diagram-generator/)
|
||||
|
||||
1 November 2023 · 5 mins
|
||||
|
||||
Would an AI diagram generator make your life easier?
|
||||
|
||||
## [Diagrams, Made Even Easier: Introducing “Code Snippets” in the Mermaid Chart Editor](https://www.mermaidchart.com/blog/posts/diagrams-made-even-easier-introducing-code-snippets-in-the-mermaid-chart-editor)
|
||||
## [Diagrams, Made Even Easier: Introducing “Code Snippets” in the Mermaid Chart Editor](https://www.mermaidchart.com/blog/posts/easier-diagram-editing-with-code-snippets/)
|
||||
|
||||
12 October 2023 · 4 mins
|
||||
|
||||
Mermaid Chart introduces Code Snippets in its editor, streamlining the diagramming process for developers and professionals.
|
||||
|
||||
## [How to Make a Git Graph with Mermaid Chart](https://www.mermaidchart.com/blog/posts/how-to-make-a-git-graph-with-mermaid-chart)
|
||||
## [How to Make a Git Graph with Mermaid Chart](https://www.mermaidchart.com/blog/posts/how-to-make-a-git-graph-with-mermaid-chart/)
|
||||
|
||||
22 September 2023 · 7 mins
|
||||
|
||||
A git graph is one of the more useful forms of diagrams for developers and DevOps professionals.
|
||||
|
||||
## [Present flow data using Sankey diagrams in Mermaid, thanks to Nikolay Rozhkov](https://www.mermaidchart.com/blog/posts/present-flow-data-using-sankey-diagrams-in-mermaid-thanks-to-nikolay-rozhkov)
|
||||
## [Present flow data using Sankey diagrams in Mermaid, thanks to Nikolay Rozhkov](https://www.mermaidchart.com/blog/posts/present-flow-data-using-sankey-diagrams/)
|
||||
|
||||
8 September 2023 · 4 mins
|
||||
|
||||
Sankey diagrams are a powerful tool for visualizing flow data.
|
||||
|
||||
## [Special cases broke Microsoft Zune and can ruin your code base too](https://www.mermaidchart.com/blog/posts/special-cases-broke-microsoft-zune-and-can-ruin-your-code-base-too)
|
||||
## [Special cases broke Microsoft Zune and can ruin your code base too](https://www.mermaidchart.com/blog/posts/special-cases-broke-microsoft-zune-and-can-ruin-your-code-base-too/)
|
||||
|
||||
23 August 2023 · 15 mins
|
||||
|
||||
Read about the pitfalls of special cases in programming, illustrating how they can lead to complexity, diminish readability, and create maintenance challenges.
|
||||
|
||||
## [New AI chatbot now available on Mermaid Chart to simplify text-based diagram creation](https://www.mermaidchart.com/blog/posts/new-ai-chatbot-now-available-on-mermaid-chart-to-simplify-text-based-diagram-creation)
|
||||
## [New AI chatbot now available on Mermaid Chart to simplify text-based diagram creation](https://www.mermaidchart.com/blog/posts/ai-chatbot-now-available-on-mermaid-chart-to-simplify-text-based-diagram-creation/)
|
||||
|
||||
14 August 2023 · 4 mins
|
||||
|
||||
Introducing Mermaid Chart’s new AI chatbot, a diagramming assistant that simplifies text-based diagram creation for everyone, from developers to educators, offering features to start, edit, and fix diagrams, and embodying our vision to make diagramming accessible, user-friendly, and fun.
|
||||
|
||||
## [Believe It or Not, You Still Need an Online UML Diagram Tool](https://www.mermaidchart.com/blog/posts/believe-it-or-not-you-still-need-an-online-uml-diagram-tool)
|
||||
## [Believe It or Not, You Still Need an Online UML Diagram Tool](https://www.mermaidchart.com/blog/posts/uml-diagram-tool/)
|
||||
|
||||
14 August 2023 · 8 mins
|
||||
|
||||
@@ -192,25 +192,25 @@ A UML diagram tool helps developers and other professionals quickly create and s
|
||||
|
||||
Introducing the concept of mind mapping as a tool for organizing complex information, and highlights Mermaid as a user-friendly software that simplifies the creation and editing of mind maps for applications in IT solution design, business decision-making, and knowledge organization.
|
||||
|
||||
## [Mermaid Chart Announces Visual Studio Code Plugin to Simplify Development Workflows](https://www.mermaidchart.com/blog/posts/mermaid-chart-announces-visual-studio-code-plugin-to-simplify-development-workflows)
|
||||
## [Mermaid Chart Announces Visual Studio Code Plugin to Simplify Development Workflows](https://www.mermaidchart.com/blog/posts/mermaid-chart-announces-visual-studio-code-plugin)
|
||||
|
||||
17 July 2023 · 3 mins
|
||||
|
||||
New Integration Enhances Workflows By Enabling Developers To Reference And Edit Diagrams Within Visual Studio Code.
|
||||
|
||||
## [Mermaid Chart’s ChatGPT Plugin Combines Generative AI and Smart Diagramming For Users](https://www.mermaidchart.com/blog/posts/mermaid-charts-chatgpt-plugin-combines-generative-ai-and-smart-diagramming-for-users)
|
||||
## [Mermaid Chart’s ChatGPT Plugin Combines Generative AI and Smart Diagramming For Users](https://www.mermaidchart.com/blog/posts/mermaid-chart-chatgpt-plugin-combines-generative-ai-and-smart-diagramming)
|
||||
|
||||
29 June 2023 · 4 mins
|
||||
|
||||
Mermaid Chart’s new ChatGPT plugin integrates AI-powered text prompts with Mermaid’s intuitive diagramming editor, enabling users to generate, edit, and share complex diagrams with ease and efficiency.
|
||||
|
||||
## [Sequence diagrams, the only good thing UML brought to software development](https://www.mermaidchart.com/blog/posts/sequence-diagrams-the-only-good-thing-uml-brought-to-software-development)
|
||||
## [Sequence diagrams, the only good thing UML brought to software development](https://www.mermaidchart.com/blog/posts/sequence-diagrams-the-good-thing-uml-brought-to-software-development/)
|
||||
|
||||
15 June 2023 · 12 mins
|
||||
|
||||
Sequence diagrams really shine when you’re documenting different parts of a system and the various ways these parts interact with each other.
|
||||
|
||||
## [subhash-halder contributed quadrant charts so you can show your manager what to select - just like the strategy consultants at BCG do](https://www.mermaidchart.com/blog/posts/subhash-halder-contributed-quadrant-charts-so-you-can-show-your-manager-what-to-select-just-like-the-strategy-consultants-at-bcg-do)
|
||||
## [subhash-halder contributed quadrant charts so you can show your manager what to select - just like the strategy consultants at BCG do](https://www.mermaidchart.com/blog/posts/subhash-halder-contributed-quadrant-charts-so-you-can-show-your-manager-what-to-select-just-like-the-strategy-consultants-at-bcg-do/)
|
||||
|
||||
8 June 2023 · 7 mins
|
||||
|
||||
@@ -222,31 +222,31 @@ A quadrant chart is a useful diagram that helps users visualize data and identif
|
||||
|
||||
Documentation tends to be bad because companies and projects don’t fully realize the costs of bad documentation.
|
||||
|
||||
## [Automatic text wrapping in flowcharts is here!](https://www.mermaidchart.com/blog/posts/automatic-text-wrapping-in-flowcharts-is-here)
|
||||
## [Automatic text wrapping in flowcharts is here!](https://www.mermaidchart.com/blog/posts/automatic-text-wrapping-in-flowcharts-is-here/)
|
||||
|
||||
3 April 2023 · 3 mins
|
||||
|
||||
Markdown Strings reduce the hassle # Starting from v10.
|
||||
|
||||
## [Mermaid Chart officially launched with sharable diagram links and presentation mode](https://www.mermaidchart.com/blog/posts/mermaid-chart-officially-launched-with-sharable-diagram-links-and-presentation-mode)
|
||||
## [Mermaid Chart officially launched with sharable diagram links and presentation mode](https://www.mermaidchart.com/blog/posts/mermaid-chart-officially-launched-with-sharable-diagram-links-and-presentation-mode/)
|
||||
|
||||
27 March 2023 · 2 mins
|
||||
|
||||
Exciting news for all Mermaid OSS fans: Mermaid Chart has officially launched with Mermaid Chart!
|
||||
|
||||
## [If you're not excited about ChatGPT, then you're not being creative](https://www.mermaidchart.com/blog/posts/if-youre-not-excited-about-chatgpt-then-youre-not-being-creative)
|
||||
## [If you're not excited about ChatGPT, then you're not being creative](https://www.mermaidchart.com/blog/posts/if-youre-not-excited-about-chatgpt-then-youre-not-being-creative-enough/)
|
||||
|
||||
8 March 2023 · 9 mins
|
||||
|
||||
The hype around AI in general and ChatGPT, in particular, is so intense that it’s very understandable to assume the hype train is driving straight toward the trough of disillusionment.
|
||||
|
||||
## [Flow charts are O(n)2 complex, so don't go over 100 connections](https://www.mermaidchart.com/blog/posts/flow-charts-are-on2-complex-so-dont-go-over-100-connections)
|
||||
## [Flow charts are O(n)2 complex, so don't go over 100 connections](https://www.mermaidchart.com/blog/posts/flow-charts-are-on2-complex-so-dont-go-over-100-connections/)
|
||||
|
||||
1 March 2023 · 12 mins
|
||||
|
||||
Flowchart design is a game of balance: Read about the importance of dialling in the right level of detail and how to manage complexity in large flowcharts.
|
||||
|
||||
## [Busting the myth that developers can't write](https://www.mermaidchart.com/blog/posts/busting-the-myth-that-developers-cant-write)
|
||||
## [Busting the myth that developers can't write](https://www.mermaidchart.com/blog/posts/busting-the-myth-that-developers-cant-write/)
|
||||
|
||||
10 February 2023 · 10 mins
|
||||
|
||||
|
||||
@@ -500,7 +500,7 @@ mermaid.ganttConfig = {
|
||||
sectionFontSize: 24, // Font size for sections
|
||||
numberSectionStyles: 1, // The number of alternating section styles
|
||||
axisFormat: '%d/%m', // Date/time format of the axis
|
||||
tickInterval: '1 week', // Axis ticks
|
||||
tickInterval: '1week', // Axis ticks
|
||||
topAxis: true, // When this flag is set, date labels will be added to the top of the chart
|
||||
displayMode: 'compact', // Turns compact mode on
|
||||
weekday: 'sunday', // On which day a week-based interval should start
|
||||
|
||||
@@ -86,7 +86,7 @@ todo[Todo]
|
||||
|
||||
## Configuration Options
|
||||
|
||||
You can customize the Kanban diagram using a configuration block at the beginning of your markdown file. This is useful for setting global settings like a base URL for tickets. Currently there is one configuration option for kanban diagrams tacketBaseUrl. This can be set as in the the following example:
|
||||
You can customize the Kanban diagram using a configuration block at the beginning of your markdown file. This is useful for setting global settings like a base URL for tickets. Currently there is one configuration option for kanban diagrams `ticketBaseUrl`. This can be set as in the the following example:
|
||||
|
||||
```yaml
|
||||
---
|
||||
|
||||
@@ -1,5 +1,20 @@
|
||||
# @mermaid-js/layout-elk
|
||||
|
||||
## 0.1.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#6090](https://github.com/mermaid-js/mermaid/pull/6090) [`654097c`](https://github.com/mermaid-js/mermaid/commit/654097c43801b2d606bc3d2bef8c6fbc3301e9e4) Thanks [@knsv](https://github.com/knsv)! - fix: Updated offset calculations for diamond shape when handling intersections
|
||||
|
||||
## 0.1.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#6081](https://github.com/mermaid-js/mermaid/pull/6081) [`68f41f6`](https://github.com/mermaid-js/mermaid/commit/68f41f685d2afe7d12f63aabf3de0c3461898471) Thanks [@knsv](https://github.com/knsv)! - fix: Elk rendering of Diamond shape intersections
|
||||
|
||||
- Updated dependencies [[`01b5079`](https://github.com/mermaid-js/mermaid/commit/01b5079562ec8d34ce9964910f168873843c68f8), [`1388662`](https://github.com/mermaid-js/mermaid/commit/1388662132cc829f9820c2e9970ae04e2dd90588), [`fe3cffb`](https://github.com/mermaid-js/mermaid/commit/fe3cffbb673a25b81989aacb06e5d0eda35326db)]:
|
||||
- mermaid@11.4.1
|
||||
|
||||
## 0.1.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@mermaid-js/layout-elk",
|
||||
"version": "0.1.5",
|
||||
"version": "0.1.7",
|
||||
"description": "ELK layout engine for mermaid",
|
||||
"module": "dist/mermaid-layout-elk.core.mjs",
|
||||
"types": "dist/layouts.d.ts",
|
||||
|
||||
@@ -15,6 +15,7 @@ interface LabelData {
|
||||
interface NodeWithVertex extends Omit<Node, 'domId'> {
|
||||
children?: unknown[];
|
||||
labelData?: LabelData;
|
||||
|
||||
domId?: Node['domId'] | SVGGroup | d3.Selection<SVGAElement, unknown, Element | null, unknown>;
|
||||
}
|
||||
|
||||
@@ -484,6 +485,8 @@ export const render = async (
|
||||
const r3 = a1 * q1.x + b1 * q1.y + c1;
|
||||
const r4 = a1 * q2.x + b1 * q2.y + c1;
|
||||
|
||||
const epsilon = 1e-6;
|
||||
|
||||
// Check signs of r3 and r4. If both point 3 and point 4 lie on
|
||||
// same side of line 1, the line segments do not intersect.
|
||||
if (r3 !== 0 && r4 !== 0 && sameSign(r3, r4)) {
|
||||
@@ -502,7 +505,7 @@ export const render = async (
|
||||
// Check signs of r1 and r2. If both point 1 and point 2 lie
|
||||
// on same side of second line segment, the line segments do
|
||||
// not intersect.
|
||||
if (r1 !== 0 && r2 !== 0 && sameSign(r1, r2)) {
|
||||
if (Math.abs(r1) < epsilon && Math.abs(r2) < epsilon && sameSign(r1, r2)) {
|
||||
return /*DON'T_INTERSECT*/;
|
||||
}
|
||||
|
||||
@@ -547,11 +550,11 @@ export const render = async (
|
||||
{ x: x1 - w / 2, y: y1 },
|
||||
];
|
||||
log.debug(
|
||||
`UIO diamondIntersection calc abc89:
|
||||
`APA16 diamondIntersection calc abc89:
|
||||
outsidePoint: ${JSON.stringify(outsidePoint)}
|
||||
insidePoint : ${JSON.stringify(insidePoint)}
|
||||
node : x:${bounds.x} y:${bounds.y} w:${bounds.width} h:${bounds.height}`,
|
||||
polyPoints
|
||||
node-bounds : x:${bounds.x} y:${bounds.y} w:${bounds.width} h:${bounds.height}`,
|
||||
JSON.stringify(polyPoints)
|
||||
);
|
||||
|
||||
const intersections = [];
|
||||
@@ -564,8 +567,8 @@ export const render = async (
|
||||
minY = Math.min(minY, entry.y);
|
||||
});
|
||||
|
||||
// const left = x1 - w / 2;
|
||||
// const top = y1 + h / 2;
|
||||
const left = x1 - w / 2 - minX;
|
||||
const top = y1 - h / 2 - minY;
|
||||
|
||||
for (let i = 0; i < polyPoints.length; i++) {
|
||||
const p1 = polyPoints[i];
|
||||
@@ -573,8 +576,8 @@ export const render = async (
|
||||
const intersect = intersectLine(
|
||||
bounds,
|
||||
outsidePoint,
|
||||
{ x: p1.x, y: p1.y },
|
||||
{ x: p2.x, y: p2.y }
|
||||
{ x: left + p1.x, y: top + p1.y },
|
||||
{ x: left + p2.x, y: top + p2.y }
|
||||
);
|
||||
|
||||
if (intersect) {
|
||||
@@ -703,14 +706,11 @@ export const render = async (
|
||||
bounds: { x: any; y: any; width: any; height: any; padding: any },
|
||||
isDiamond: boolean
|
||||
) => {
|
||||
log.debug('UIO cutPathAtIntersect Points:', _points, 'node:', bounds, 'isDiamond', isDiamond);
|
||||
log.debug('APA18 cutPathAtIntersect Points:', _points, 'node:', bounds, 'isDiamond', isDiamond);
|
||||
const points: any[] = [];
|
||||
let lastPointOutside = _points[0];
|
||||
let isInside = false;
|
||||
_points.forEach((point: any) => {
|
||||
// const node = clusterDb[edge.toCluster].node;
|
||||
log.debug(' checking point', point, bounds);
|
||||
|
||||
// check if point is inside the boundary rect
|
||||
if (!outsideNode(bounds, point) && !isInside) {
|
||||
// First point inside the rect found
|
||||
@@ -753,7 +753,6 @@ export const render = async (
|
||||
}
|
||||
}
|
||||
});
|
||||
log.debug('returning points', points);
|
||||
return points;
|
||||
};
|
||||
|
||||
@@ -905,7 +904,7 @@ export const render = async (
|
||||
|
||||
const offset = calcOffset(sourceId, targetId, parentLookupDb);
|
||||
log.debug(
|
||||
'offset',
|
||||
'APA18 offset',
|
||||
offset,
|
||||
sourceId,
|
||||
' ==> ',
|
||||
@@ -968,48 +967,41 @@ export const render = async (
|
||||
startNode.innerHTML
|
||||
);
|
||||
}
|
||||
if (startNode.shape === 'diamond') {
|
||||
if (startNode.shape === 'diamond' || startNode.shape === 'diam') {
|
||||
edge.points.unshift({
|
||||
x: startNode.x + startNode.width / 2 + offset.x,
|
||||
y: startNode.y + startNode.height / 2 + offset.y,
|
||||
x: startNode.offset.posX + startNode.width / 2,
|
||||
y: startNode.offset.posY + startNode.height / 2,
|
||||
});
|
||||
}
|
||||
if (endNode.shape === 'diamond') {
|
||||
const x = endNode.x + endNode.width / 2 + offset.x;
|
||||
// Add a point at the center of the diamond
|
||||
if (
|
||||
Math.abs(edge.points[edge.points.length - 1].y - endNode.y - offset.y) > 0.001 ||
|
||||
Math.abs(edge.points[edge.points.length - 1].x - x) > 0.001
|
||||
) {
|
||||
edge.points.push({
|
||||
x: endNode.x + endNode.width / 2 + offset.x,
|
||||
y: endNode.y + endNode.height / 2 + offset.y,
|
||||
});
|
||||
}
|
||||
if (endNode.shape === 'diamond' || endNode.shape === 'diam') {
|
||||
edge.points.push({
|
||||
x: endNode.offset.posX + endNode.width / 2,
|
||||
y: endNode.offset.posY + endNode.height / 2,
|
||||
});
|
||||
}
|
||||
|
||||
edge.points = cutPathAtIntersect(
|
||||
edge.points.reverse(),
|
||||
{
|
||||
x: startNode.x + startNode.width / 2 + offset.x,
|
||||
y: startNode.y + startNode.height / 2 + offset.y,
|
||||
x: startNode.offset.posX + startNode.width / 2,
|
||||
y: startNode.offset.posY + startNode.height / 2,
|
||||
width: sw,
|
||||
height: startNode.height,
|
||||
padding: startNode.padding,
|
||||
},
|
||||
startNode.shape === 'diamond'
|
||||
startNode.shape === 'diamond' || startNode.shape === 'diam'
|
||||
).reverse();
|
||||
|
||||
edge.points = cutPathAtIntersect(
|
||||
edge.points,
|
||||
{
|
||||
x: endNode.x + ew / 2 + endNode.offset.x,
|
||||
y: endNode.y + endNode.height / 2 + endNode.offset.y,
|
||||
x: endNode.offset.posX + endNode.width / 2,
|
||||
y: endNode.offset.posY + endNode.height / 2,
|
||||
width: ew,
|
||||
height: endNode.height,
|
||||
padding: endNode.padding,
|
||||
},
|
||||
endNode.shape === 'diamond'
|
||||
endNode.shape === 'diamond' || endNode.shape === 'diam'
|
||||
);
|
||||
|
||||
const paths = insertEdge(
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
# mermaid
|
||||
|
||||
## 11.4.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#6059](https://github.com/mermaid-js/mermaid/pull/6059) [`01b5079`](https://github.com/mermaid-js/mermaid/commit/01b5079562ec8d34ce9964910f168873843c68f8) Thanks [@knsv](https://github.com/knsv)! - fix: Kanban diagrams will not render when adding a number as ticket id or assigned for a task
|
||||
|
||||
- [#6038](https://github.com/mermaid-js/mermaid/pull/6038) [`1388662`](https://github.com/mermaid-js/mermaid/commit/1388662132cc829f9820c2e9970ae04e2dd90588) Thanks [@knsv](https://github.com/knsv)! - fix: Intersection calculations for tilted cylinder/DAS when using handdrawn look. Some random seeds could cause the calculations to break.
|
||||
|
||||
- [#6079](https://github.com/mermaid-js/mermaid/pull/6079) [`fe3cffb`](https://github.com/mermaid-js/mermaid/commit/fe3cffbb673a25b81989aacb06e5d0eda35326db) Thanks [@aloisklink](https://github.com/aloisklink)! - Bump dompurify to `^3.2.1`. This removes the need for `@types/dompurify`.
|
||||
|
||||
## 11.4.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mermaid",
|
||||
"version": "11.4.0",
|
||||
"version": "11.4.1",
|
||||
"description": "Markdown-ish syntax for generating flowcharts, mindmaps, sequence diagrams, class diagrams, gantt charts, git graphs and more.",
|
||||
"type": "module",
|
||||
"module": "./dist/mermaid.core.mjs",
|
||||
@@ -71,7 +71,6 @@
|
||||
"@iconify/utils": "^2.1.32",
|
||||
"@mermaid-js/parser": "workspace:^",
|
||||
"@types/d3": "^7.4.3",
|
||||
"@types/dompurify": "^3.0.5",
|
||||
"cytoscape": "^3.29.2",
|
||||
"cytoscape-cose-bilkent": "^4.1.0",
|
||||
"cytoscape-fcose": "^2.2.0",
|
||||
@@ -79,7 +78,7 @@
|
||||
"d3-sankey": "^0.12.3",
|
||||
"dagre-d3-es": "7.0.11",
|
||||
"dayjs": "^1.11.10",
|
||||
"dompurify": "^3.0.11 <3.1.7",
|
||||
"dompurify": "^3.2.1",
|
||||
"katex": "^0.16.9",
|
||||
"khroma": "^2.1.0",
|
||||
"lodash-es": "^4.17.21",
|
||||
|
||||
@@ -950,8 +950,8 @@ const class_box = (parent, node) => {
|
||||
maxWidth = classTitleBBox.width;
|
||||
}
|
||||
const classAttributes = [];
|
||||
node.classData.members.forEach((member) => {
|
||||
const parsedInfo = member.getDisplayDetails();
|
||||
node.classData.attributes.forEach((attribute) => {
|
||||
const parsedInfo = attribute.getDisplayDetails();
|
||||
let parsedText = parsedInfo.displayText;
|
||||
if (getConfig().flowchart.htmlLabels) {
|
||||
parsedText = parsedText.replace(/</g, '<').replace(/>/g, '>');
|
||||
@@ -984,8 +984,8 @@ const class_box = (parent, node) => {
|
||||
maxHeight += lineHeight;
|
||||
|
||||
const classMethods = [];
|
||||
node.classData.methods.forEach((member) => {
|
||||
const parsedInfo = member.getDisplayDetails();
|
||||
node.classData.methods.forEach((method) => {
|
||||
const parsedInfo = method.getDisplayDetails();
|
||||
let displayText = parsedInfo.displayText;
|
||||
if (getConfig().flowchart.htmlLabels) {
|
||||
displayText = displayText.replace(/</g, '<').replace(/>/g, '>');
|
||||
@@ -1059,9 +1059,9 @@ const class_box = (parent, node) => {
|
||||
((-1 * maxHeight) / 2 + verticalPos + lineHeight / 2) +
|
||||
')'
|
||||
);
|
||||
//get the height of the bounding box of each member if exists
|
||||
const memberBBox = lbl?.getBBox();
|
||||
verticalPos += (memberBBox?.height ?? 0) + rowPadding;
|
||||
//get the height of the bounding box of each attribute if exists
|
||||
const fieldBBox = lbl?.getBBox();
|
||||
verticalPos += (fieldBBox?.height ?? 0) + rowPadding;
|
||||
});
|
||||
|
||||
verticalPos += lineHeight;
|
||||
@@ -1079,8 +1079,8 @@ const class_box = (parent, node) => {
|
||||
'transform',
|
||||
'translate( ' + -maxWidth / 2 + ', ' + ((-1 * maxHeight) / 2 + verticalPos) + ')'
|
||||
);
|
||||
const memberBBox = lbl?.getBBox();
|
||||
verticalPos += (memberBBox?.height ?? 0) + rowPadding;
|
||||
const methodBBox = lbl?.getBBox();
|
||||
verticalPos += (methodBBox?.height ?? 0) + rowPadding;
|
||||
});
|
||||
|
||||
rect
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
setDiagramTitle,
|
||||
} from '../common/commonDb.js';
|
||||
import type {
|
||||
ArchitectureAlignment,
|
||||
ArchitectureDB,
|
||||
ArchitectureDirectionPair,
|
||||
ArchitectureDirectionPairMap,
|
||||
@@ -25,6 +26,7 @@ import type {
|
||||
ArchitectureState,
|
||||
} from './architectureTypes.js';
|
||||
import {
|
||||
getArchitectureDirectionAlignment,
|
||||
getArchitectureDirectionPair,
|
||||
isArchitectureDirection,
|
||||
isArchitectureJunction,
|
||||
@@ -211,12 +213,18 @@ const addEdge = function ({
|
||||
const getEdges = (): ArchitectureEdge[] => state.records.edges;
|
||||
|
||||
/**
|
||||
* Returns the current diagram's adjacency list & spatial map.
|
||||
* Returns the current diagram's adjacency list, spatial map, & group alignments.
|
||||
* If they have not been created, run the algorithms to generate them.
|
||||
* @returns
|
||||
*/
|
||||
const getDataStructures = () => {
|
||||
if (state.records.dataStructures === undefined) {
|
||||
// Tracks how groups are aligned with one another. Generated while creating the adj list
|
||||
const groupAlignments: Record<
|
||||
string,
|
||||
Record<string, Exclude<ArchitectureAlignment, 'bend'>>
|
||||
> = {};
|
||||
|
||||
// Create an adjacency list of the diagram to perform BFS on
|
||||
// Outer reduce applied on all services
|
||||
// Inner reduce applied on the edges for a service
|
||||
@@ -224,6 +232,19 @@ const getDataStructures = () => {
|
||||
Record<string, ArchitectureDirectionPairMap>
|
||||
>((prevOuter, [id, service]) => {
|
||||
prevOuter[id] = service.edges.reduce<ArchitectureDirectionPairMap>((prevInner, edge) => {
|
||||
// track the direction groups connect to one another
|
||||
const lhsGroupId = getNode(edge.lhsId)?.in;
|
||||
const rhsGroupId = getNode(edge.rhsId)?.in;
|
||||
if (lhsGroupId && rhsGroupId && lhsGroupId !== rhsGroupId) {
|
||||
const alignment = getArchitectureDirectionAlignment(edge.lhsDir, edge.rhsDir);
|
||||
if (alignment !== 'bend') {
|
||||
groupAlignments[lhsGroupId] ??= {};
|
||||
groupAlignments[lhsGroupId][rhsGroupId] = alignment;
|
||||
groupAlignments[rhsGroupId] ??= {};
|
||||
groupAlignments[rhsGroupId][lhsGroupId] = alignment;
|
||||
}
|
||||
}
|
||||
|
||||
if (edge.lhsId === id) {
|
||||
// source is LHS
|
||||
const pair = getArchitectureDirectionPair(edge.lhsDir, edge.rhsDir);
|
||||
@@ -245,6 +266,7 @@ const getDataStructures = () => {
|
||||
// Configuration for the initial pass of BFS
|
||||
const firstId = Object.keys(adjList)[0];
|
||||
const visited = { [firstId]: 1 };
|
||||
// If a key is present in this object, it has not been visited
|
||||
const notVisited = Object.keys(adjList).reduce(
|
||||
(prev, id) => (id === firstId ? prev : { ...prev, [id]: 1 }),
|
||||
{} as Record<string, number>
|
||||
@@ -283,6 +305,7 @@ const getDataStructures = () => {
|
||||
state.records.dataStructures = {
|
||||
adjList,
|
||||
spatialMaps,
|
||||
groupAlignments,
|
||||
};
|
||||
}
|
||||
return state.records.dataStructures;
|
||||
|
||||
@@ -12,7 +12,9 @@ import { setupGraphViewbox } from '../../setupGraphViewbox.js';
|
||||
import { getConfigField } from './architectureDb.js';
|
||||
import { architectureIcons } from './architectureIcons.js';
|
||||
import type {
|
||||
ArchitectureAlignment,
|
||||
ArchitectureDataStructures,
|
||||
ArchitectureGroupAlignments,
|
||||
ArchitectureJunction,
|
||||
ArchitectureSpatialMap,
|
||||
EdgeSingular,
|
||||
@@ -149,25 +151,91 @@ function addEdges(edges: ArchitectureEdge[], cy: cytoscape.Core) {
|
||||
});
|
||||
}
|
||||
|
||||
function getAlignments(spatialMaps: ArchitectureSpatialMap[]): fcose.FcoseAlignmentConstraint {
|
||||
function getAlignments(
|
||||
db: ArchitectureDB,
|
||||
spatialMaps: ArchitectureSpatialMap[],
|
||||
groupAlignments: ArchitectureGroupAlignments
|
||||
): fcose.FcoseAlignmentConstraint {
|
||||
/**
|
||||
* Flattens the alignment object so nodes in different groups will be in the same alignment array IFF their groups don't connect in a conflicting alignment
|
||||
*
|
||||
* i.e., two groups which connect horizontally should not have nodes with vertical alignments to one another
|
||||
*
|
||||
* See: #5952
|
||||
*
|
||||
* @param alignmentObj - alignment object with the outer key being the row/col # and the inner key being the group name mapped to the nodes on that axis in the group
|
||||
* @param alignmentDir - alignment direction
|
||||
* @returns flattened alignment object with an arbitrary key mapping to nodes in the same row/col
|
||||
*/
|
||||
const flattenAlignments = (
|
||||
alignmentObj: Record<number, Record<string, string[]>>,
|
||||
alignmentDir: ArchitectureAlignment
|
||||
): Record<string, string[]> => {
|
||||
return Object.entries(alignmentObj).reduce(
|
||||
(prev, [dir, alignments]) => {
|
||||
// prev is the mapping of x/y coordinate to an array of the nodes in that row/column
|
||||
let cnt = 0;
|
||||
const arr = Object.entries(alignments); // [group name, array of nodes within the group on axis dir]
|
||||
if (arr.length === 1) {
|
||||
// If only one group exists in the row/column, we don't need to do anything else
|
||||
prev[dir] = arr[0][1];
|
||||
return prev;
|
||||
}
|
||||
for (let i = 0; i < arr.length - 1; i++) {
|
||||
for (let j = i + 1; j < arr.length; j++) {
|
||||
const [aGroupId, aNodeIds] = arr[i];
|
||||
const [bGroupId, bNodeIds] = arr[j];
|
||||
const alignment = groupAlignments[aGroupId]?.[bGroupId]; // Get how the two groups are intended to align (undefined if they aren't)
|
||||
|
||||
if (alignment === alignmentDir) {
|
||||
// If the intended alignment between the two groups is the same as the alignment we are parsing
|
||||
prev[dir] ??= [];
|
||||
prev[dir] = [...prev[dir], ...aNodeIds, ...bNodeIds]; // add the node ids of both groups to the axis array in prev
|
||||
} else if (aGroupId === 'default' || bGroupId === 'default') {
|
||||
// If either of the groups are in the default space (not in a group), use the same behavior as above
|
||||
prev[dir] ??= [];
|
||||
prev[dir] = [...prev[dir], ...aNodeIds, ...bNodeIds];
|
||||
} else {
|
||||
// Otherwise, the nodes in the two groups are not intended to align
|
||||
const keyA = `${dir}-${cnt++}`;
|
||||
prev[keyA] = aNodeIds;
|
||||
const keyB = `${dir}-${cnt++}`;
|
||||
prev[keyB] = bNodeIds;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return prev;
|
||||
},
|
||||
{} as Record<string, string[]>
|
||||
);
|
||||
};
|
||||
|
||||
const alignments = spatialMaps.map((spatialMap) => {
|
||||
const horizontalAlignments: Record<number, string[]> = {};
|
||||
const verticalAlignments: Record<number, string[]> = {};
|
||||
const horizontalAlignments: Record<number, Record<string, string[]>> = {};
|
||||
const verticalAlignments: Record<number, Record<string, string[]>> = {};
|
||||
|
||||
// Group service ids in an object with their x and y coordinate as the key
|
||||
Object.entries(spatialMap).forEach(([id, [x, y]]) => {
|
||||
if (!horizontalAlignments[y]) {
|
||||
horizontalAlignments[y] = [];
|
||||
}
|
||||
if (!verticalAlignments[x]) {
|
||||
verticalAlignments[x] = [];
|
||||
}
|
||||
horizontalAlignments[y].push(id);
|
||||
verticalAlignments[x].push(id);
|
||||
const nodeGroup = db.getNode(id)?.in ?? 'default';
|
||||
|
||||
horizontalAlignments[y] ??= {};
|
||||
horizontalAlignments[y][nodeGroup] ??= [];
|
||||
horizontalAlignments[y][nodeGroup].push(id);
|
||||
|
||||
verticalAlignments[x] ??= {};
|
||||
verticalAlignments[x][nodeGroup] ??= [];
|
||||
verticalAlignments[x][nodeGroup].push(id);
|
||||
});
|
||||
|
||||
// Merge the values of each object into a list if the inner list has at least 2 elements
|
||||
return {
|
||||
horiz: Object.values(horizontalAlignments).filter((arr) => arr.length > 1),
|
||||
vert: Object.values(verticalAlignments).filter((arr) => arr.length > 1),
|
||||
horiz: Object.values(flattenAlignments(horizontalAlignments, 'horizontal')).filter(
|
||||
(arr) => arr.length > 1
|
||||
),
|
||||
vert: Object.values(flattenAlignments(verticalAlignments, 'vertical')).filter(
|
||||
(arr) => arr.length > 1
|
||||
),
|
||||
};
|
||||
});
|
||||
|
||||
@@ -244,7 +312,8 @@ function layoutArchitecture(
|
||||
junctions: ArchitectureJunction[],
|
||||
groups: ArchitectureGroup[],
|
||||
edges: ArchitectureEdge[],
|
||||
{ spatialMaps }: ArchitectureDataStructures
|
||||
db: ArchitectureDB,
|
||||
{ spatialMaps, groupAlignments }: ArchitectureDataStructures
|
||||
): Promise<cytoscape.Core> {
|
||||
return new Promise((resolve) => {
|
||||
const renderEl = select('body').append('div').attr('id', 'cy').attr('style', 'display:none');
|
||||
@@ -318,9 +387,8 @@ function layoutArchitecture(
|
||||
addServices(services, cy);
|
||||
addJunctions(junctions, cy);
|
||||
addEdges(edges, cy);
|
||||
|
||||
// Use the spatial map to create alignment arrays for fcose
|
||||
const alignmentConstraint = getAlignments(spatialMaps);
|
||||
const alignmentConstraint = getAlignments(db, spatialMaps, groupAlignments);
|
||||
|
||||
// Create the relative constraints for fcose by using an inverse of the spatial map and performing BFS on it
|
||||
const relativePlacementConstraint = getRelativeConstraints(spatialMaps);
|
||||
@@ -454,7 +522,7 @@ export const draw: DrawDefinition = async (text, id, _version, diagObj: Diagram)
|
||||
await drawServices(db, servicesElem, services);
|
||||
drawJunctions(db, servicesElem, junctions);
|
||||
|
||||
const cy = await layoutArchitecture(services, junctions, groups, edges, ds);
|
||||
const cy = await layoutArchitecture(services, junctions, groups, edges, db, ds);
|
||||
|
||||
await drawEdges(edgesElem, cy);
|
||||
await drawGroups(groupElem, cy);
|
||||
|
||||
@@ -7,6 +7,8 @@ import type cytoscape from 'cytoscape';
|
||||
| Architecture Diagram Types |
|
||||
\*=======================================*/
|
||||
|
||||
export type ArchitectureAlignment = 'vertical' | 'horizontal' | 'bend';
|
||||
|
||||
export type ArchitectureDirection = 'L' | 'R' | 'T' | 'B';
|
||||
export type ArchitectureDirectionX = Extract<ArchitectureDirection, 'L' | 'R'>;
|
||||
export type ArchitectureDirectionY = Extract<ArchitectureDirection, 'T' | 'B'>;
|
||||
@@ -170,6 +172,18 @@ export const getArchitectureDirectionXYFactors = function (
|
||||
}
|
||||
};
|
||||
|
||||
export const getArchitectureDirectionAlignment = function (
|
||||
a: ArchitectureDirection,
|
||||
b: ArchitectureDirection
|
||||
): ArchitectureAlignment {
|
||||
if (isArchitectureDirectionXY(a, b)) {
|
||||
return 'bend';
|
||||
} else if (isArchitectureDirectionX(a)) {
|
||||
return 'horizontal';
|
||||
}
|
||||
return 'vertical';
|
||||
};
|
||||
|
||||
export interface ArchitectureStyleOptions {
|
||||
archEdgeColor: string;
|
||||
archEdgeArrowColor: string;
|
||||
@@ -249,9 +263,27 @@ export interface ArchitectureDB extends DiagramDB {
|
||||
|
||||
export type ArchitectureAdjacencyList = Record<string, ArchitectureDirectionPairMap>;
|
||||
export type ArchitectureSpatialMap = Record<string, number[]>;
|
||||
|
||||
/**
|
||||
* Maps the direction that groups connect from.
|
||||
*
|
||||
* **Outer key**: ID of group A
|
||||
*
|
||||
* **Inner key**: ID of group B
|
||||
*
|
||||
* **Value**: 'vertical' or 'horizontal'
|
||||
*
|
||||
* Note: tmp[groupA][groupB] == tmp[groupB][groupA]
|
||||
*/
|
||||
export type ArchitectureGroupAlignments = Record<
|
||||
string,
|
||||
Record<string, Exclude<ArchitectureAlignment, 'bend'>>
|
||||
>;
|
||||
|
||||
export interface ArchitectureDataStructures {
|
||||
adjList: ArchitectureAdjacencyList;
|
||||
spatialMaps: ArchitectureSpatialMap[];
|
||||
groupAlignments: ArchitectureGroupAlignments;
|
||||
}
|
||||
|
||||
export interface ArchitectureState extends Record<string, unknown> {
|
||||
|
||||
@@ -40,30 +40,18 @@ let functions: any[] = [];
|
||||
|
||||
const sanitizeText = (txt: string) => common.sanitizeText(txt, getConfig());
|
||||
|
||||
const splitClassNameAndType = function (_id: string) {
|
||||
const id = common.sanitizeText(_id, getConfig());
|
||||
const splitClassIdAndType = function (_id: string) {
|
||||
const id = sanitizeText(_id);
|
||||
let genericType = '';
|
||||
let className = id;
|
||||
let classId = id;
|
||||
|
||||
if (id.indexOf('~') > 0) {
|
||||
const split = id.split('~');
|
||||
className = sanitizeText(split[0]);
|
||||
classId = sanitizeText(split[0]);
|
||||
genericType = sanitizeText(split[1]);
|
||||
}
|
||||
|
||||
return { className: className, type: genericType };
|
||||
};
|
||||
|
||||
export const setClassLabel = function (_id: string, label: string) {
|
||||
const id = common.sanitizeText(_id, getConfig());
|
||||
if (label) {
|
||||
label = sanitizeText(label);
|
||||
}
|
||||
|
||||
const { className } = splitClassNameAndType(id);
|
||||
classes.get(className)!.label = label;
|
||||
classes.get(className)!.text =
|
||||
`${label}${classes.get(className)!.type ? `<${classes.get(className)!.type}>` : ''}`;
|
||||
return { classId, type: genericType };
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -72,28 +60,33 @@ export const setClassLabel = function (_id: string, label: string) {
|
||||
* @param id - Id of the class to add
|
||||
* @public
|
||||
*/
|
||||
export const addClass = function (_id: string) {
|
||||
const id = common.sanitizeText(_id, getConfig());
|
||||
const { className, type } = splitClassNameAndType(id);
|
||||
// Only add class if not exists
|
||||
if (classes.has(className)) {
|
||||
export const addClass = function (_id: string, label?: string) {
|
||||
const id = sanitizeText(_id);
|
||||
const { classId, type } = splitClassIdAndType(id);
|
||||
let newLabel = classId;
|
||||
|
||||
if (classes.has(classId)) {
|
||||
return;
|
||||
}
|
||||
// alert('Adding class: ' + className);
|
||||
const name = common.sanitizeText(className, getConfig());
|
||||
// alert('Adding class after: ' + name);
|
||||
classes.set(name, {
|
||||
id: name,
|
||||
|
||||
if (label) {
|
||||
newLabel = sanitizeText(label);
|
||||
}
|
||||
|
||||
const text = `${newLabel}${type ? `<${type}>` : ''}`;
|
||||
|
||||
classes.set(classId, {
|
||||
id: classId,
|
||||
type: type,
|
||||
label: name,
|
||||
text: `${name}${type ? `<${type}>` : ''}`,
|
||||
label: newLabel,
|
||||
text: text,
|
||||
shape: 'classBox',
|
||||
cssClasses: 'default',
|
||||
methods: [],
|
||||
members: [],
|
||||
attributes: [],
|
||||
annotations: [],
|
||||
styles: [],
|
||||
domId: MERMAID_DOM_ID_PREFIX + name + '-' + classCounter,
|
||||
domId: `${MERMAID_DOM_ID_PREFIX}${classId}-${classCounter}`,
|
||||
} as ClassNode);
|
||||
|
||||
classCounter++;
|
||||
@@ -116,7 +109,7 @@ const addInterface = function (label: string, classId: string) {
|
||||
* @public
|
||||
*/
|
||||
export const lookUpDomId = function (_id: string): string {
|
||||
const id = common.sanitizeText(_id, getConfig());
|
||||
const id = sanitizeText(_id);
|
||||
if (classes.has(id)) {
|
||||
return classes.get(id)!.domId;
|
||||
}
|
||||
@@ -182,18 +175,12 @@ export const addRelation = function (classRelation: ClassRelation) {
|
||||
addClass(classRelation.id2);
|
||||
}
|
||||
|
||||
classRelation.id1 = splitClassNameAndType(classRelation.id1).className;
|
||||
classRelation.id2 = splitClassNameAndType(classRelation.id2).className;
|
||||
classRelation.id1 = splitClassIdAndType(classRelation.id1).classId;
|
||||
classRelation.id2 = splitClassIdAndType(classRelation.id2).classId;
|
||||
|
||||
classRelation.relationTitle1 = common.sanitizeText(
|
||||
classRelation.relationTitle1.trim(),
|
||||
getConfig()
|
||||
);
|
||||
classRelation.relationTitle1 = sanitizeText(classRelation.relationTitle1.trim());
|
||||
|
||||
classRelation.relationTitle2 = common.sanitizeText(
|
||||
classRelation.relationTitle2.trim(),
|
||||
getConfig()
|
||||
);
|
||||
classRelation.relationTitle2 = sanitizeText(classRelation.relationTitle2.trim());
|
||||
|
||||
relations.push(classRelation);
|
||||
};
|
||||
@@ -202,29 +189,29 @@ export const addRelation = function (classRelation: ClassRelation) {
|
||||
* Adds an annotation to the specified class Annotations mark special properties of the given type
|
||||
* (like 'interface' or 'service')
|
||||
*
|
||||
* @param className - The class name
|
||||
* @param classId - The class name
|
||||
* @param annotation - The name of the annotation without any brackets
|
||||
* @public
|
||||
*/
|
||||
export const addAnnotation = function (className: string, annotation: string) {
|
||||
const validatedClassName = splitClassNameAndType(className).className;
|
||||
const validatedClassName = splitClassIdAndType(className).classId;
|
||||
classes.get(validatedClassName)!.annotations.push(annotation);
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds a member to the specified class
|
||||
*
|
||||
* @param className - The class name
|
||||
* @param classId - The class name
|
||||
* @param member - The full name of the member. If the member is enclosed in `<<brackets>>` it is
|
||||
* treated as an annotation If the member is ending with a closing bracket ) it is treated as a
|
||||
* method Otherwise the member will be treated as a normal property
|
||||
* @public
|
||||
*/
|
||||
export const addMember = function (className: string, member: string) {
|
||||
addClass(className);
|
||||
export const addMember = function (classId: string, member: string) {
|
||||
addClass(classId);
|
||||
|
||||
const validatedClassName = splitClassNameAndType(className).className;
|
||||
const theClass = classes.get(validatedClassName)!;
|
||||
const validatedClassId = splitClassIdAndType(classId).classId;
|
||||
const theClass = classes.get(validatedClassId)!;
|
||||
|
||||
if (typeof member === 'string') {
|
||||
// Member can contain white spaces, we trim them out
|
||||
@@ -237,7 +224,7 @@ export const addMember = function (className: string, member: string) {
|
||||
//its a method
|
||||
theClass.methods.push(new ClassMember(memberString, 'method'));
|
||||
} else if (memberString) {
|
||||
theClass.members.push(new ClassMember(memberString, 'attribute'));
|
||||
theClass.attributes.push(new ClassMember(memberString, 'attribute'));
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -377,7 +364,7 @@ export const setClickEvent = function (ids: string, functionName: string, functi
|
||||
};
|
||||
|
||||
const setClickFunc = function (_domId: string, functionName: string, functionArgs: string) {
|
||||
const domId = common.sanitizeText(_domId, getConfig());
|
||||
const domId = sanitizeText(_domId);
|
||||
const config = getConfig();
|
||||
if (config.securityLevel !== 'loose') {
|
||||
return;
|
||||
@@ -520,17 +507,15 @@ const getNamespaces = function (): NamespaceMap {
|
||||
* Function called by parser when a namespace definition has been found.
|
||||
*
|
||||
* @param id - Id of the namespace to add
|
||||
* @param classNames - Ids of the class to add
|
||||
* @param classIds - Ids of the class to add
|
||||
* @public
|
||||
*/
|
||||
export const addClassesToNamespace = function (id: string, classNames: string[]) {
|
||||
if (!namespaces.has(id)) {
|
||||
return;
|
||||
}
|
||||
for (const name of classNames) {
|
||||
const { className } = splitClassNameAndType(name);
|
||||
classes.get(className)!.parent = id;
|
||||
namespaces.get(id)!.classes.set(className, classes.get(className)!);
|
||||
export const addClassesToNamespace = function (_id: string, classIds: string[]) {
|
||||
addNamespace(_id);
|
||||
for (const id of classIds) {
|
||||
const { classId } = splitClassIdAndType(id);
|
||||
classes.get(classId)!.parent = _id;
|
||||
namespaces.get(_id)!.classes.set(classId, classes.get(classId)!);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -726,7 +711,6 @@ export default {
|
||||
lookUpDomId,
|
||||
setDiagramTitle,
|
||||
getDiagramTitle,
|
||||
setClassLabel,
|
||||
addNamespace,
|
||||
addClassesToNamespace,
|
||||
getNamespace,
|
||||
|
||||
@@ -212,29 +212,29 @@ describe('given a basic class diagram, ', function () {
|
||||
expect(c2.label).toBe('Class 2 with chars @?');
|
||||
});
|
||||
|
||||
it('should parse a class with a text label and member', () => {
|
||||
const str = 'classDiagram\n' + 'class C1["Class 1 with text label"]\n' + 'C1: member1';
|
||||
it('should parse a class with a text label and attribute', () => {
|
||||
const str = 'classDiagram\n' + 'class C1["Class 1 with text label"]\n' + 'C1: attribute1';
|
||||
|
||||
parser.parse(str);
|
||||
const c1 = classDb.getClass('C1');
|
||||
expect(c1.label).toBe('Class 1 with text label');
|
||||
expect(c1.members.length).toBe(1);
|
||||
expect(c1.members[0].getDisplayDetails().displayText).toBe('member1');
|
||||
expect(c1.attributes.length).toBe(1);
|
||||
expect(c1.attributes[0].getDisplayDetails().displayText).toBe('attribute1');
|
||||
});
|
||||
|
||||
it('should parse a class with a text label, member and annotation', () => {
|
||||
it('should parse a class with a text label, attribute and annotation', () => {
|
||||
const str =
|
||||
'classDiagram\n' +
|
||||
'class C1["Class 1 with text label"]\n' +
|
||||
'<<interface>> C1\n' +
|
||||
'C1 : int member1';
|
||||
'C1 : int attribute1';
|
||||
|
||||
parser.parse(str);
|
||||
|
||||
const c1 = classDb.getClass('C1');
|
||||
expect(c1.label).toBe('Class 1 with text label');
|
||||
expect(c1.members.length).toBe(1);
|
||||
expect(c1.members[0].getDisplayDetails().displayText).toBe('int member1');
|
||||
expect(c1.attributes.length).toBe(1);
|
||||
expect(c1.attributes[0].getDisplayDetails().displayText).toBe('int attribute1');
|
||||
expect(c1.annotations.length).toBe(1);
|
||||
expect(c1.annotations[0]).toBe('interface');
|
||||
});
|
||||
@@ -253,14 +253,14 @@ describe('given a basic class diagram, ', function () {
|
||||
const str =
|
||||
'classDiagram\n' +
|
||||
'class C1["Class 1 with text label"]\n' +
|
||||
'C1 : int member1\n' +
|
||||
'C1 : int attribute1\n' +
|
||||
'cssClass "C1" styleClass';
|
||||
|
||||
parser.parse(str);
|
||||
|
||||
const c1 = classDb.getClass('C1');
|
||||
expect(c1.label).toBe('Class 1 with text label');
|
||||
expect(c1.members[0].getDisplayDetails().displayText).toBe('int member1');
|
||||
expect(c1.attributes[0].getDisplayDetails().displayText).toBe('int attribute1');
|
||||
expect(c1.cssClasses).toBe('default styleClass');
|
||||
});
|
||||
|
||||
@@ -268,7 +268,7 @@ describe('given a basic class diagram, ', function () {
|
||||
const str =
|
||||
'classDiagram\n' +
|
||||
'class C1["Class 1 with text label"]\n' +
|
||||
'C1 : int member1\n' +
|
||||
'C1 : int attribute1\n' +
|
||||
'class C2["Long long long long long long long long long long label"]\n' +
|
||||
'cssClass "C1,C2" styleClass';
|
||||
|
||||
@@ -486,7 +486,7 @@ class C13["With Città foreign language"]
|
||||
expect(studentClass).toMatchObject({
|
||||
id: 'Student',
|
||||
label: 'Student',
|
||||
members: [
|
||||
attributes: [
|
||||
expect.objectContaining({
|
||||
id: 'idCard : IdCard',
|
||||
visibility: '-',
|
||||
@@ -500,11 +500,7 @@ class C13["With Città foreign language"]
|
||||
expect(classDb.getClasses().get('Student')).toMatchInlineSnapshot(`
|
||||
{
|
||||
"annotations": [],
|
||||
"cssClasses": "default",
|
||||
"domId": "classId-Student-141",
|
||||
"id": "Student",
|
||||
"label": "Student",
|
||||
"members": [
|
||||
"attributes": [
|
||||
ClassMember {
|
||||
"classifier": "",
|
||||
"id": "idCard : IdCard",
|
||||
@@ -513,6 +509,10 @@ class C13["With Città foreign language"]
|
||||
"visibility": "-",
|
||||
},
|
||||
],
|
||||
"cssClasses": "default",
|
||||
"domId": "classId-Student-141",
|
||||
"id": "Student",
|
||||
"label": "Student",
|
||||
"methods": [],
|
||||
"shape": "classBox",
|
||||
"styles": [],
|
||||
@@ -569,7 +569,7 @@ class C13["With Città foreign language"]
|
||||
parser.yy = classDb;
|
||||
});
|
||||
|
||||
it('should handle member definitions', function () {
|
||||
it('should handle attribute definitions', function () {
|
||||
const str = 'classDiagram\n' + 'class Car{\n' + '+int wheels\n' + '}';
|
||||
|
||||
parser.parse(str);
|
||||
@@ -588,7 +588,7 @@ class C13["With Città foreign language"]
|
||||
parser.parse(str);
|
||||
});
|
||||
|
||||
it('should handle member and method definitions', () => {
|
||||
it('should handle attribute and method definitions', () => {
|
||||
const str =
|
||||
'classDiagram\n' + 'class Dummy_Class {\n' + 'String data\n' + 'void methods()\n' + '}';
|
||||
|
||||
@@ -611,45 +611,46 @@ class C13["With Città foreign language"]
|
||||
const str =
|
||||
'classDiagram\n' +
|
||||
'class Class1 {\n' +
|
||||
'int testMember\n' +
|
||||
'int testAttribute\n' +
|
||||
'test()\n' +
|
||||
'string fooMember\n' +
|
||||
'string fooAttribute\n' +
|
||||
'foo()\n' +
|
||||
'}';
|
||||
parser.parse(str);
|
||||
|
||||
const actual = parser.yy.getClass('Class1');
|
||||
expect(actual.members.length).toBe(2);
|
||||
expect(actual.attributes.length).toBe(2);
|
||||
expect(actual.methods.length).toBe(2);
|
||||
expect(actual.members[0].getDisplayDetails().displayText).toBe('int testMember');
|
||||
expect(actual.members[1].getDisplayDetails().displayText).toBe('string fooMember');
|
||||
expect(actual.attributes[0].getDisplayDetails().displayText).toBe('int testAttribute');
|
||||
expect(actual.attributes[1].getDisplayDetails().displayText).toBe('string fooAttribute');
|
||||
expect(actual.methods[0].getDisplayDetails().displayText).toBe('test()');
|
||||
expect(actual.methods[1].getDisplayDetails().displayText).toBe('foo()');
|
||||
});
|
||||
|
||||
it('should parse a class with a text label and members', () => {
|
||||
const str = 'classDiagram\n' + 'class C1["Class 1 with text label"] {\n' + '+member1\n' + '}';
|
||||
it('should parse a class with a text label and attribute', () => {
|
||||
const str =
|
||||
'classDiagram\n' + 'class C1["Class 1 with text label"] {\n' + '+attributes1\n' + '}';
|
||||
|
||||
parser.parse(str);
|
||||
const c1 = classDb.getClass('C1');
|
||||
expect(c1.label).toBe('Class 1 with text label');
|
||||
expect(c1.members.length).toBe(1);
|
||||
expect(c1.members[0].getDisplayDetails().displayText).toBe('+member1');
|
||||
expect(c1.attributes.length).toBe(1);
|
||||
expect(c1.attributes[0].getDisplayDetails().displayText).toBe('+attributes1');
|
||||
});
|
||||
|
||||
it('should parse a class with a text label, members and annotation', () => {
|
||||
it('should parse a class with a text label, attribute and annotation', () => {
|
||||
const str =
|
||||
'classDiagram\n' +
|
||||
'class C1["Class 1 with text label"] {\n' +
|
||||
'<<interface>>\n' +
|
||||
'+member1\n' +
|
||||
'+attribute1\n' +
|
||||
'}';
|
||||
|
||||
parser.parse(str);
|
||||
const c1 = classDb.getClass('C1');
|
||||
expect(c1.label).toBe('Class 1 with text label');
|
||||
expect(c1.members.length).toBe(1);
|
||||
expect(c1.members[0].getDisplayDetails().displayText).toBe('+member1');
|
||||
expect(c1.attributes.length).toBe(1);
|
||||
expect(c1.attributes[0].getDisplayDetails().displayText).toBe('+attribute1');
|
||||
expect(c1.annotations.length).toBe(1);
|
||||
expect(c1.annotations[0]).toBe('interface');
|
||||
});
|
||||
@@ -868,12 +869,12 @@ foo()
|
||||
|
||||
const actual = parser.yy.getClass('Class1');
|
||||
expect(actual.annotations.length).toBe(1);
|
||||
expect(actual.members.length).toBe(0);
|
||||
expect(actual.methods.length).toBe(0);
|
||||
expect(actual.attributes.length).toBe(0);
|
||||
expect(actual.attributes.length).toBe(0);
|
||||
expect(actual.annotations[0]).toBe('interface');
|
||||
});
|
||||
|
||||
it('should handle class annotations with members and methods', function () {
|
||||
it('should handle class annotations with attributes and methods', function () {
|
||||
const str =
|
||||
'classDiagram\n' +
|
||||
'class Class1\n' +
|
||||
@@ -884,7 +885,7 @@ foo()
|
||||
|
||||
const actual = parser.yy.getClass('Class1');
|
||||
expect(actual.annotations.length).toBe(1);
|
||||
expect(actual.members.length).toBe(1);
|
||||
expect(actual.attributes.length).toBe(1);
|
||||
expect(actual.methods.length).toBe(1);
|
||||
expect(actual.annotations[0]).toBe('interface');
|
||||
});
|
||||
@@ -895,12 +896,12 @@ foo()
|
||||
|
||||
const actual = parser.yy.getClass('Class1');
|
||||
expect(actual.annotations.length).toBe(1);
|
||||
expect(actual.members.length).toBe(0);
|
||||
expect(actual.attributes.length).toBe(0);
|
||||
expect(actual.methods.length).toBe(0);
|
||||
expect(actual.annotations[0]).toBe('interface');
|
||||
});
|
||||
|
||||
it('should handle class annotations in brackets with members and methods', function () {
|
||||
it('should handle class annotations in brackets with attributes and methods', function () {
|
||||
const str =
|
||||
'classDiagram\n' +
|
||||
'class Class1 {\n' +
|
||||
@@ -912,41 +913,41 @@ foo()
|
||||
|
||||
const actual = parser.yy.getClass('Class1');
|
||||
expect(actual.annotations.length).toBe(1);
|
||||
expect(actual.members.length).toBe(1);
|
||||
expect(actual.attributes.length).toBe(1);
|
||||
expect(actual.methods.length).toBe(1);
|
||||
expect(actual.annotations[0]).toBe('interface');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('given a class diagram with members and methods ', function () {
|
||||
describe('when parsing members', function () {
|
||||
describe('given a class diagram with attributes and methods ', function () {
|
||||
describe('when parsing attributes', function () {
|
||||
beforeEach(function () {
|
||||
classDb.clear();
|
||||
parser.yy = classDb;
|
||||
});
|
||||
|
||||
it('should handle simple member declaration', function () {
|
||||
it('should handle simple attribute declaration', function () {
|
||||
const str = 'classDiagram\n' + 'class Car\n' + 'Car : wheels';
|
||||
|
||||
parser.parse(str);
|
||||
});
|
||||
|
||||
it('should handle direct member declaration', function () {
|
||||
it('should handle direct attribute 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');
|
||||
expect(car.attributes.length).toBe(1);
|
||||
expect(car.attributes[0].id).toBe('wheels');
|
||||
});
|
||||
|
||||
it('should handle direct member declaration with type', function () {
|
||||
it('should handle direct attribute 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');
|
||||
expect(car.attributes.length).toBe(1);
|
||||
expect(car.attributes[0].id).toBe('int wheels');
|
||||
});
|
||||
|
||||
it('should handle simple member declaration with type', function () {
|
||||
it('should handle simple attribute declaration with type', function () {
|
||||
const str = 'classDiagram\n' + 'class Car\n' + 'Car : int wheels';
|
||||
|
||||
parser.parse(str);
|
||||
@@ -956,20 +957,20 @@ describe('given a class diagram with members and methods ', function () {
|
||||
const str =
|
||||
'classDiagram\n' +
|
||||
'class actual\n' +
|
||||
'actual : -int privateMember\n' +
|
||||
'actual : +int publicMember\n' +
|
||||
'actual : #int protectedMember\n' +
|
||||
'actual : -int privateAttribute\n' +
|
||||
'actual : +int publicAttribute\n' +
|
||||
'actual : #int protectedAttribute\n' +
|
||||
'actual : ~int privatePackage';
|
||||
|
||||
parser.parse(str);
|
||||
|
||||
const actual = parser.yy.getClass('actual');
|
||||
expect(actual.members.length).toBe(4);
|
||||
expect(actual.attributes.length).toBe(4);
|
||||
expect(actual.methods.length).toBe(0);
|
||||
expect(actual.members[0].getDisplayDetails().displayText).toBe('-int privateMember');
|
||||
expect(actual.members[1].getDisplayDetails().displayText).toBe('+int publicMember');
|
||||
expect(actual.members[2].getDisplayDetails().displayText).toBe('#int protectedMember');
|
||||
expect(actual.members[3].getDisplayDetails().displayText).toBe('~int privatePackage');
|
||||
expect(actual.attributes[0].getDisplayDetails().displayText).toBe('-int privateAttribute');
|
||||
expect(actual.attributes[1].getDisplayDetails().displayText).toBe('+int publicAttribute');
|
||||
expect(actual.attributes[2].getDisplayDetails().displayText).toBe('#int protectedAttribute');
|
||||
expect(actual.attributes[3].getDisplayDetails().displayText).toBe('~int privatePackage');
|
||||
});
|
||||
|
||||
it('should handle generic types', function () {
|
||||
@@ -1020,7 +1021,7 @@ describe('given a class diagram with members and methods ', function () {
|
||||
|
||||
const actual = parser.yy.getClass('Class1');
|
||||
expect(actual.annotations.length).toBe(0);
|
||||
expect(actual.members.length).toBe(0);
|
||||
expect(actual.attributes.length).toBe(0);
|
||||
expect(actual.methods.length).toBe(1);
|
||||
const method = actual.methods[0];
|
||||
expect(method.getDisplayDetails().displayText).toBe('someMethod()');
|
||||
@@ -1033,7 +1034,7 @@ describe('given a class diagram with members and methods ', function () {
|
||||
|
||||
const actual = parser.yy.getClass('Class1');
|
||||
expect(actual.annotations.length).toBe(0);
|
||||
expect(actual.members.length).toBe(0);
|
||||
expect(actual.attributes.length).toBe(0);
|
||||
expect(actual.methods.length).toBe(1);
|
||||
const method = actual.methods[0];
|
||||
expect(method.getDisplayDetails().displayText).toBe('someMethod()');
|
||||
@@ -1051,7 +1052,7 @@ describe('given a class diagram with members and methods ', function () {
|
||||
parser.parse(str);
|
||||
});
|
||||
|
||||
it('should handle generic types in members in class with brackets', function () {
|
||||
it('should handle generic types in attributes in class with brackets', function () {
|
||||
const str =
|
||||
'classDiagram\n' +
|
||||
'class Car {\n' +
|
||||
@@ -1385,12 +1386,12 @@ describe('given a class diagram with relationships, ', function () {
|
||||
|
||||
const testClass = parser.yy.getClass('Class1');
|
||||
expect(testClass.annotations.length).toBe(1);
|
||||
expect(testClass.members.length).toBe(0);
|
||||
expect(testClass.attributes.length).toBe(0);
|
||||
expect(testClass.methods.length).toBe(0);
|
||||
expect(testClass.annotations[0]).toBe('interface');
|
||||
});
|
||||
|
||||
it('should handle class annotations with members and methods', function () {
|
||||
it('should handle class annotations with attributes and methods', function () {
|
||||
const str =
|
||||
'classDiagram\n' +
|
||||
'class Class1\n' +
|
||||
@@ -1401,7 +1402,7 @@ describe('given a class diagram with relationships, ', function () {
|
||||
|
||||
const testClass = parser.yy.getClass('Class1');
|
||||
expect(testClass.annotations.length).toBe(1);
|
||||
expect(testClass.members.length).toBe(1);
|
||||
expect(testClass.attributes.length).toBe(1);
|
||||
expect(testClass.methods.length).toBe(1);
|
||||
expect(testClass.annotations[0]).toBe('interface');
|
||||
});
|
||||
@@ -1412,12 +1413,12 @@ describe('given a class diagram with relationships, ', function () {
|
||||
|
||||
const testClass = parser.yy.getClass('Class1');
|
||||
expect(testClass.annotations.length).toBe(1);
|
||||
expect(testClass.members.length).toBe(0);
|
||||
expect(testClass.attributes.length).toBe(0);
|
||||
expect(testClass.methods.length).toBe(0);
|
||||
expect(testClass.annotations[0]).toBe('interface');
|
||||
});
|
||||
|
||||
it('should handle class annotations in brackets with members and methods', function () {
|
||||
it('should handle class annotations in brackets with attributes and methods', function () {
|
||||
const str =
|
||||
'classDiagram\n' +
|
||||
'class Class1 {\n' +
|
||||
@@ -1429,7 +1430,7 @@ describe('given a class diagram with relationships, ', function () {
|
||||
|
||||
const testClass = parser.yy.getClass('Class1');
|
||||
expect(testClass.annotations.length).toBe(1);
|
||||
expect(testClass.members.length).toBe(1);
|
||||
expect(testClass.attributes.length).toBe(1);
|
||||
expect(testClass.methods.length).toBe(1);
|
||||
expect(testClass.annotations[0]).toBe('interface');
|
||||
});
|
||||
@@ -1446,10 +1447,10 @@ describe('given a class diagram with relationships, ', function () {
|
||||
parser.parse(str);
|
||||
|
||||
const testClass = parser.yy.getClass('Class1');
|
||||
expect(testClass.members.length).toBe(2);
|
||||
expect(testClass.attributes.length).toBe(2);
|
||||
expect(testClass.methods.length).toBe(2);
|
||||
expect(testClass.members[0].getDisplayDetails().displayText).toBe('int : test');
|
||||
expect(testClass.members[1].getDisplayDetails().displayText).toBe('string : foo');
|
||||
expect(testClass.attributes[0].getDisplayDetails().displayText).toBe('int : test');
|
||||
expect(testClass.attributes[1].getDisplayDetails().displayText).toBe('string : foo');
|
||||
expect(testClass.methods[0].getDisplayDetails().displayText).toBe('test()');
|
||||
expect(testClass.methods[1].getDisplayDetails().displayText).toBe('foo()');
|
||||
});
|
||||
@@ -1460,7 +1461,7 @@ describe('given a class diagram with relationships, ', function () {
|
||||
|
||||
const testClass = parser.yy.getClass('Class1');
|
||||
expect(testClass.annotations.length).toBe(0);
|
||||
expect(testClass.members.length).toBe(0);
|
||||
expect(testClass.attributes.length).toBe(0);
|
||||
expect(testClass.methods.length).toBe(1);
|
||||
const method = testClass.methods[0];
|
||||
expect(method.getDisplayDetails().displayText).toBe('someMethod()');
|
||||
@@ -1473,7 +1474,7 @@ describe('given a class diagram with relationships, ', function () {
|
||||
|
||||
const testClass = parser.yy.getClass('Class1');
|
||||
expect(testClass.annotations.length).toBe(0);
|
||||
expect(testClass.members.length).toBe(0);
|
||||
expect(testClass.attributes.length).toBe(0);
|
||||
expect(testClass.methods.length).toBe(1);
|
||||
const method = testClass.methods[0];
|
||||
expect(method.getDisplayDetails().displayText).toBe('someMethod()');
|
||||
@@ -1688,17 +1689,17 @@ class Class2
|
||||
const testClasses = parser.yy.getClasses();
|
||||
const testRelations = parser.yy.getRelations();
|
||||
expect(testNamespaceA.classes.size).toBe(2);
|
||||
expect(testNamespaceA.classes.get('A1').members[0].getDisplayDetails().displayText).toBe(
|
||||
expect(testNamespaceA.classes.get('A1').attributes[0].getDisplayDetails().displayText).toBe(
|
||||
'+foo : string'
|
||||
);
|
||||
expect(testNamespaceA.classes.get('A2').members[0].getDisplayDetails().displayText).toBe(
|
||||
expect(testNamespaceA.classes.get('A2').attributes[0].getDisplayDetails().displayText).toBe(
|
||||
'+bar : int'
|
||||
);
|
||||
expect(testNamespaceB.classes.size).toBe(2);
|
||||
expect(testNamespaceB.classes.get('B1').members[0].getDisplayDetails().displayText).toBe(
|
||||
expect(testNamespaceB.classes.get('B1').attributes[0].getDisplayDetails().displayText).toBe(
|
||||
'+foo : bool'
|
||||
);
|
||||
expect(testNamespaceB.classes.get('B2').members[0].getDisplayDetails().displayText).toBe(
|
||||
expect(testNamespaceB.classes.get('B2').attributes[0].getDisplayDetails().displayText).toBe(
|
||||
'+bar : float'
|
||||
);
|
||||
expect(testClasses.size).toBe(4);
|
||||
@@ -1742,37 +1743,37 @@ class Class2
|
||||
expect(c2.label).toBe('Class 2 with chars @?');
|
||||
});
|
||||
|
||||
it('should parse a class with a text label and members', () => {
|
||||
it('should parse a class with a text label and attributes', () => {
|
||||
parser.parse(`classDiagram
|
||||
class C1["Class 1 with text label"] {
|
||||
+member1
|
||||
+attribute1
|
||||
}
|
||||
C1 --> C2
|
||||
`);
|
||||
const c1 = classDb.getClass('C1');
|
||||
expect(c1.label).toBe('Class 1 with text label');
|
||||
expect(c1.members.length).toBe(1);
|
||||
const member = c1.members[0];
|
||||
expect(member.getDisplayDetails().displayText).toBe('+member1');
|
||||
expect(c1.attributes.length).toBe(1);
|
||||
const attribute = c1.attributes[0];
|
||||
expect(attribute.getDisplayDetails().displayText).toBe('+attribute1');
|
||||
const c2 = classDb.getClass('C2');
|
||||
expect(c2.label).toBe('C2');
|
||||
});
|
||||
|
||||
it('should parse a class with a text label, members and annotation', () => {
|
||||
it('should parse a class with a text label, attributes and annotation', () => {
|
||||
parser.parse(`classDiagram
|
||||
class C1["Class 1 with text label"] {
|
||||
<<interface>>
|
||||
+member1
|
||||
+attribute1
|
||||
}
|
||||
C1 --> C2
|
||||
`);
|
||||
const c1 = classDb.getClass('C1');
|
||||
expect(c1.label).toBe('Class 1 with text label');
|
||||
expect(c1.members.length).toBe(1);
|
||||
expect(c1.attributes.length).toBe(1);
|
||||
expect(c1.annotations.length).toBe(1);
|
||||
expect(c1.annotations[0]).toBe('interface');
|
||||
const member = c1.members[0];
|
||||
expect(member.getDisplayDetails().displayText).toBe('+member1');
|
||||
const attribute = c1.attributes[0];
|
||||
expect(attribute.getDisplayDetails().displayText).toBe('+attribute1');
|
||||
|
||||
const c2 = classDb.getClass('C2');
|
||||
expect(c2.label).toBe('C2');
|
||||
@@ -1781,7 +1782,7 @@ class Class2
|
||||
it('should parse a class with text label and css class shorthand', () => {
|
||||
parser.parse(`classDiagram
|
||||
class C1["Class 1 with text label"]:::styleClass {
|
||||
+member1
|
||||
+attribute1
|
||||
}
|
||||
C1 --> C2
|
||||
`);
|
||||
@@ -1789,14 +1790,14 @@ C1 --> C2
|
||||
const c1 = classDb.getClass('C1');
|
||||
expect(c1.label).toBe('Class 1 with text label');
|
||||
expect(c1.cssClasses).toBe('default styleClass');
|
||||
const member = c1.members[0];
|
||||
expect(member.getDisplayDetails().displayText).toBe('+member1');
|
||||
const attribute = c1.attributes[0];
|
||||
expect(attribute.getDisplayDetails().displayText).toBe('+attribute1');
|
||||
});
|
||||
|
||||
it('should parse a class with text label and css class', () => {
|
||||
parser.parse(`classDiagram
|
||||
class C1["Class 1 with text label"] {
|
||||
+member1
|
||||
+attribute1
|
||||
}
|
||||
C1 --> C2
|
||||
cssClass "C1" styleClass
|
||||
@@ -1805,14 +1806,14 @@ cssClass "C1" styleClass
|
||||
const c1 = classDb.getClass('C1');
|
||||
expect(c1.label).toBe('Class 1 with text label');
|
||||
expect(c1.cssClasses).toBe('default styleClass');
|
||||
const member = c1.members[0];
|
||||
expect(member.getDisplayDetails().displayText).toBe('+member1');
|
||||
const attribute = c1.attributes[0];
|
||||
expect(attribute.getDisplayDetails().displayText).toBe('+attribute1');
|
||||
});
|
||||
|
||||
it('should parse two classes with text labels and css classes', () => {
|
||||
parser.parse(`classDiagram
|
||||
class C1["Class 1 with text label"] {
|
||||
+member1
|
||||
+attribute1
|
||||
}
|
||||
class C2["Long long long long long long long long long long label"]
|
||||
C1 --> C2
|
||||
@@ -1831,7 +1832,7 @@ cssClass "C1,C2" styleClass
|
||||
it('should parse two classes with text labels and css class shorthands', () => {
|
||||
parser.parse(`classDiagram
|
||||
class C1["Class 1 with text label"]:::styleClass1 {
|
||||
+member1
|
||||
+attribute1
|
||||
}
|
||||
class C2["Class 2 !@#$%^&*() label"]:::styleClass2
|
||||
C1 --> C2
|
||||
|
||||
@@ -3,13 +3,13 @@ import { parseGenericTypes, sanitizeText } from '../common/common.js';
|
||||
|
||||
export interface ClassNode {
|
||||
id: string;
|
||||
type: string;
|
||||
label: string;
|
||||
type?: string;
|
||||
label?: string;
|
||||
shape: string;
|
||||
text: string;
|
||||
text?: string;
|
||||
cssClasses: string;
|
||||
methods: ClassMember[];
|
||||
members: ClassMember[];
|
||||
attributes: ClassMember[];
|
||||
annotations: string[];
|
||||
domId: string;
|
||||
styles: string[];
|
||||
|
||||
@@ -297,7 +297,7 @@ classStatement
|
||||
|
||||
classIdentifier
|
||||
: CLASS className {$$=$2; yy.addClass($2);}
|
||||
| CLASS className classLabel {$$=$2; yy.addClass($2);yy.setClassLabel($2, $3);}
|
||||
| CLASS className classLabel {$$=$2; yy.addClass($2, $3);}
|
||||
;
|
||||
|
||||
annotationStatement
|
||||
|
||||
@@ -27,12 +27,12 @@ export async function textHelper<T extends SVGGraphicsElement>(
|
||||
|
||||
let annotationGroup = null;
|
||||
let labelGroup = null;
|
||||
let membersGroup = null;
|
||||
let attributeGroup = null;
|
||||
let methodsGroup = null;
|
||||
|
||||
let annotationGroupHeight = 0;
|
||||
let labelGroupHeight = 0;
|
||||
let membersGroupHeight = 0;
|
||||
let attributeGroupHeight = 0;
|
||||
|
||||
annotationGroup = shapeSvg.insert('g').attr('class', 'annotation-group text');
|
||||
if (node.annotations.length > 0) {
|
||||
@@ -48,15 +48,15 @@ export async function textHelper<T extends SVGGraphicsElement>(
|
||||
const labelGroupBBox = labelGroup.node()!.getBBox();
|
||||
labelGroupHeight = labelGroupBBox.height;
|
||||
|
||||
membersGroup = shapeSvg.insert('g').attr('class', 'members-group text');
|
||||
attributeGroup = shapeSvg.insert('g').attr('class', 'attribute-group text');
|
||||
let yOffset = 0;
|
||||
for (const member of node.members) {
|
||||
const height = await addText(membersGroup, member, yOffset, [member.parseClassifier()]);
|
||||
for (const attribute of node.attributes) {
|
||||
const height = await addText(attributeGroup, attribute, yOffset, [attribute.parseClassifier()]);
|
||||
yOffset += height + TEXT_PADDING;
|
||||
}
|
||||
membersGroupHeight = membersGroup.node()!.getBBox().height;
|
||||
if (membersGroupHeight <= 0) {
|
||||
membersGroupHeight = GAP / 2;
|
||||
attributeGroupHeight = attributeGroup.node()!.getBBox().height;
|
||||
if (attributeGroupHeight <= 0) {
|
||||
attributeGroupHeight = GAP / 2;
|
||||
}
|
||||
|
||||
methodsGroup = shapeSvg.insert('g').attr('class', 'methods-group text');
|
||||
@@ -79,14 +79,14 @@ export async function textHelper<T extends SVGGraphicsElement>(
|
||||
|
||||
bbox = shapeSvg.node()!.getBBox();
|
||||
|
||||
membersGroup.attr(
|
||||
attributeGroup.attr(
|
||||
'transform',
|
||||
`translate(${0}, ${annotationGroupHeight + labelGroupHeight + GAP * 2})`
|
||||
);
|
||||
bbox = shapeSvg.node()!.getBBox();
|
||||
methodsGroup.attr(
|
||||
'transform',
|
||||
`translate(${0}, ${annotationGroupHeight + labelGroupHeight + (membersGroupHeight ? membersGroupHeight + GAP * 4 : GAP * 2)})`
|
||||
`translate(${0}, ${annotationGroupHeight + labelGroupHeight + (attributeGroupHeight ? attributeGroupHeight + GAP * 4 : GAP * 2)})`
|
||||
);
|
||||
|
||||
bbox = shapeSvg.node()!.getBBox();
|
||||
@@ -107,9 +107,10 @@ async function addText<T extends SVGGraphicsElement>(
|
||||
'useHtmlLabels' in node ? node.useHtmlLabels : (evaluate(config.htmlLabels) ?? true);
|
||||
|
||||
let textContent = '';
|
||||
|
||||
// Support regular node type (.label) and classNodes (.text)
|
||||
if ('text' in node) {
|
||||
textContent = node.text;
|
||||
textContent = node.text ?? '';
|
||||
} else {
|
||||
textContent = node.label!;
|
||||
}
|
||||
|
||||
@@ -190,8 +190,8 @@ export const drawClass = function (elem, classDef, conf, diagObj) {
|
||||
|
||||
// add annotations
|
||||
let isFirst = true;
|
||||
classDef.annotations.forEach(function (member) {
|
||||
const titleText2 = title.append('tspan').text('«' + member + '»');
|
||||
classDef.annotations.forEach(function (annotation) {
|
||||
const titleText2 = title.append('tspan').text('«' + annotation + '»');
|
||||
if (!isFirst) {
|
||||
titleText2.attr('dy', conf.textHeight);
|
||||
}
|
||||
@@ -208,19 +208,19 @@ export const drawClass = function (elem, classDef, conf, diagObj) {
|
||||
}
|
||||
|
||||
const titleHeight = title.node().getBBox().height;
|
||||
let membersLine;
|
||||
let membersBox;
|
||||
let attributesLine;
|
||||
let attributesBox;
|
||||
let methodsLine;
|
||||
|
||||
// don't draw box if no members
|
||||
if (classDef.members.length > 0) {
|
||||
membersLine = g
|
||||
// don't draw box if no attributes
|
||||
if (classDef.attributes.length > 0) {
|
||||
attributesLine = g
|
||||
.append('line') // text label for the x axis
|
||||
.attr('x1', 0)
|
||||
.attr('y1', conf.padding + titleHeight + conf.dividerMargin / 2)
|
||||
.attr('y2', conf.padding + titleHeight + conf.dividerMargin / 2);
|
||||
|
||||
const members = g
|
||||
const attributes = g
|
||||
.append('text') // text label for the x axis
|
||||
.attr('x', conf.padding)
|
||||
.attr('y', titleHeight + conf.dividerMargin + conf.textHeight)
|
||||
@@ -228,12 +228,12 @@ export const drawClass = function (elem, classDef, conf, diagObj) {
|
||||
.attr('class', 'classText');
|
||||
|
||||
isFirst = true;
|
||||
classDef.members.forEach(function (member) {
|
||||
addTspan(members, member, isFirst, conf);
|
||||
classDef.attributes.forEach(function (attribute) {
|
||||
addTspan(attributes, attribute, isFirst, conf);
|
||||
isFirst = false;
|
||||
});
|
||||
|
||||
membersBox = members.node().getBBox();
|
||||
attributesBox = attributes.node().getBBox();
|
||||
}
|
||||
|
||||
// don't draw box if no methods
|
||||
@@ -241,13 +241,13 @@ export const drawClass = function (elem, classDef, conf, diagObj) {
|
||||
methodsLine = g
|
||||
.append('line') // text label for the x axis
|
||||
.attr('x1', 0)
|
||||
.attr('y1', conf.padding + titleHeight + conf.dividerMargin + membersBox.height)
|
||||
.attr('y2', conf.padding + titleHeight + conf.dividerMargin + membersBox.height);
|
||||
.attr('y1', conf.padding + titleHeight + conf.dividerMargin + attributesBox.height)
|
||||
.attr('y2', conf.padding + titleHeight + conf.dividerMargin + attributesBox.height);
|
||||
|
||||
const methods = g
|
||||
.append('text') // text label for the x axis
|
||||
.attr('x', conf.padding)
|
||||
.attr('y', titleHeight + 2 * conf.dividerMargin + membersBox.height + conf.textHeight)
|
||||
.attr('y', titleHeight + 2 * conf.dividerMargin + attributesBox.height + conf.textHeight)
|
||||
.attr('fill', 'white')
|
||||
.attr('class', 'classText');
|
||||
|
||||
@@ -286,8 +286,8 @@ export const drawClass = function (elem, classDef, conf, diagObj) {
|
||||
title.insert('title').text(classDef.tooltip);
|
||||
}
|
||||
|
||||
if (membersLine) {
|
||||
membersLine.attr('x2', rectWidth);
|
||||
if (attributesLine) {
|
||||
attributesLine.attr('x2', rectWidth);
|
||||
}
|
||||
if (methodsLine) {
|
||||
methodsLine.attr('x2', rectWidth);
|
||||
|
||||
@@ -32,14 +32,14 @@ const setupDompurifyHooksIfNotSetup = (() => {
|
||||
function setupDompurifyHooks() {
|
||||
const TEMPORARY_ATTRIBUTE = 'data-temp-href-target';
|
||||
|
||||
DOMPurify.addHook('beforeSanitizeAttributes', (node: Element) => {
|
||||
if (node.tagName === 'A' && node.hasAttribute('target')) {
|
||||
DOMPurify.addHook('beforeSanitizeAttributes', (node) => {
|
||||
if (node instanceof Element && node.tagName === 'A' && node.hasAttribute('target')) {
|
||||
node.setAttribute(TEMPORARY_ATTRIBUTE, node.getAttribute('target') ?? '');
|
||||
}
|
||||
});
|
||||
|
||||
DOMPurify.addHook('afterSanitizeAttributes', (node: Element) => {
|
||||
if (node.tagName === 'A' && node.hasAttribute(TEMPORARY_ATTRIBUTE)) {
|
||||
DOMPurify.addHook('afterSanitizeAttributes', (node) => {
|
||||
if (node instanceof Element && node.tagName === 'A' && node.hasAttribute(TEMPORARY_ATTRIBUTE)) {
|
||||
node.setAttribute('target', node.getAttribute(TEMPORARY_ATTRIBUTE) ?? '');
|
||||
node.removeAttribute(TEMPORARY_ATTRIBUTE);
|
||||
if (node.getAttribute('target') === '_blank') {
|
||||
@@ -83,7 +83,6 @@ export const sanitizeText = (text: string, config: MermaidConfig): string => {
|
||||
return text;
|
||||
}
|
||||
if (config.dompurifyConfig) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-base-to-string
|
||||
text = DOMPurify.sanitize(sanitizeMore(text, config), config.dompurifyConfig).toString();
|
||||
} else {
|
||||
text = DOMPurify.sanitize(sanitizeMore(text, config), {
|
||||
|
||||
@@ -138,13 +138,13 @@ const addNode = (level: number, id: string, descr: string, type: number, shapeDa
|
||||
node.label = doc?.label;
|
||||
}
|
||||
if (doc?.icon) {
|
||||
node.icon = doc?.icon;
|
||||
node.icon = doc?.icon.toString();
|
||||
}
|
||||
if (doc?.assigned) {
|
||||
node.assigned = doc?.assigned;
|
||||
node.assigned = doc?.assigned.toString();
|
||||
}
|
||||
if (doc?.ticket) {
|
||||
node.ticket = doc?.ticket;
|
||||
node.ticket = doc?.ticket.toString();
|
||||
}
|
||||
|
||||
if (doc?.priority) {
|
||||
|
||||
@@ -180,8 +180,6 @@ Communication tools and platforms
|
||||
- [=Diagram block](https://github.com/zag/podlite/tree/main/packages/podlite-diagrams)
|
||||
- [Standard Notes](https://standardnotes.com/)
|
||||
- [Mermaid Extension](https://github.com/nienow/sn-mermaid)
|
||||
- [Sublime Text 3](https://sublimetext.com)
|
||||
- [Mermaid Package](https://packagecontrol.io/packages/Mermaid)
|
||||
- [VS Code](https://code.visualstudio.com/)
|
||||
- [Mermaid Editor](https://marketplace.visualstudio.com/items?itemName=tomoyukim.vscode-mermaid-editor)
|
||||
- [Mermaid Export](https://marketplace.visualstudio.com/items?itemName=Gruntfuggly.mermaid-export)
|
||||
|
||||
@@ -12,169 +12,169 @@ An entity relationship (ER) diagram acts like a blueprint for your database. Thi
|
||||
|
||||
October 24, 2024 · 4 mins
|
||||
|
||||
## [Expanding the Horizons of Mermaid Flowcharts: Introducing 30 New Shapes!](https://www.mermaidchart.com/blog/posts/expanding-the-horizons-of-mermaid-flowcharts-introducing-30-new-shapes)
|
||||
## [Expanding the Horizons of Mermaid Flowcharts: Introducing 30 New Shapes!](https://www.mermaidchart.com/blog/posts/new-mermaid-flowchart-shapes/)
|
||||
|
||||
24 September 2024 · 5 mins
|
||||
|
||||
Discover 30 new shapes in Mermaid flowcharts, offering enhanced clarity, customization, and versatility for more dynamic and expressive visualizations.
|
||||
|
||||
## [Introducing Architecture Diagrams in Mermaid](https://www.mermaidchart.com/blog/posts/introducing-architecture-diagrams-in-mermaid)
|
||||
## [Introducing Architecture Diagrams in Mermaid](https://www.mermaidchart.com/blog/posts/mermaid-supports-architecture-diagrams/)
|
||||
|
||||
2 September 2024 · 2 mins
|
||||
|
||||
Discover the fresh new and unique Neo and Hand-Drawn looks for Mermaid Diagrams, while still offering the classic look you love.
|
||||
|
||||
## [Mermaid v11 is out!](https://www.mermaidchart.com/blog/posts/mermaid-v11-is-out)
|
||||
## [Mermaid v11 is out!](https://www.mermaidchart.com/blog/posts/mermaid-v11/)
|
||||
|
||||
23 August 2024 · 2 mins
|
||||
|
||||
Mermaid v11 introduces advanced layout options, new diagram types, and enhanced customization features, thanks to the incredible contributions from our community.
|
||||
|
||||
## [Mermaid Innovation - Introducing New Looks for Mermaid Diagrams](https://www.mermaidchart.com/blog/posts/mermaid-innovation-introducing-new-looks-for-mermaid-diagrams)
|
||||
## [Mermaid Innovation - Introducing New Looks for Mermaid Diagrams](https://www.mermaidchart.com/blog/posts/mermaid-innovation-introducing-new-looks-for-mermaid-diagrams/)
|
||||
|
||||
6 August 2024 ·3 mins
|
||||
|
||||
Discover the fresh new and unique Neo and Hand-Drawn looks for Mermaid Diagrams, while still offering the classic look you love.
|
||||
|
||||
## [The Mermaid Chart Plugin for Jira: A How-To User Guide](https://www.mermaidchart.com/blog/posts/the-mermaid-chart-plugin-for-jira)
|
||||
## [The Mermaid Chart Plugin for Jira: A How-To User Guide](https://www.mermaidchart.com/blog/posts/the-mermaid-chart-plugin-for-jira-a-how-to-user-guide/)
|
||||
|
||||
31 July 2024 · 5 mins
|
||||
|
||||
The Mermaid Chart plugin for Jira has arrived!
|
||||
|
||||
## [Mermaid AI Is Here to Change the Game For Diagram Creation](https://www.mermaidchart.com/blog/posts/mermaid-ai-is-here-to-change-the-game-for-diagram-creation)
|
||||
## [Mermaid AI Is Here to Change the Game For Diagram Creation](https://www.mermaidchart.com/blog/posts/mermaid-ai-is-here-to-change-the-game-for-diagram-creation/)
|
||||
|
||||
22 July 2024 · 5 mins
|
||||
|
||||
The Mermaid AI chat interface
|
||||
|
||||
## [How to Make a Sequence Diagram with Mermaid Chart](https://www.mermaidchart.com/blog/posts/how-to-make-a-sequence-diagram-with-mermaid-chart)
|
||||
## [How to Make a Sequence Diagram with Mermaid Chart](https://www.mermaidchart.com/blog/posts/how-to-make-a-sequence-diagram-in-mermaid-chart-step-by-step-guide/)
|
||||
|
||||
8 July 2024 · 6 mins
|
||||
|
||||
Sequence diagrams are important for communicating complex systems in a clear and concise manner.
|
||||
|
||||
## [How to Use the New “Comments” Feature in Mermaid Chart](https://www.mermaidchart.com/blog/posts/how-to-use-the-new-comments-feature-in-mermaid-chart)
|
||||
## [How to Use the New “Comments” Feature in Mermaid Chart](https://www.mermaidchart.com/blog/posts/how-to-use-the-new-comments-feature-in-mermaid-chart/)
|
||||
|
||||
2 July 2024 · 3 mins
|
||||
|
||||
How to Use the New Comments Feature in Mermaid Chart
|
||||
|
||||
## [How to Use the official Mermaid Chart for Confluence app](https://www.mermaidchart.com/blog/posts/how-to-use-the-official-mermaid-chart-for-confluence-app)
|
||||
## [How to Use the official Mermaid Chart for Confluence app](https://www.mermaidchart.com/blog/posts/how-to-use-the-official-mermaid-chart-for-confluence-app/)
|
||||
|
||||
21 May 2024 · 4 mins
|
||||
|
||||
It doesn’t matter if you’re a data enthusiast, software engineer, or visual storyteller; our Confluence app can allow you to embed Mermaid Chart diagrams — and dynamically edit them — within your Confluence pages.
|
||||
|
||||
## [How to Choose the Right Documentation Software](https://www.mermaidchart.com/blog/posts/how-to-choose-the-right-documentation-software)
|
||||
## [How to Choose the Right Documentation Software](https://www.mermaidchart.com/blog/posts/how-to-choose-the-right-documentation-software/)
|
||||
|
||||
7 May 2024 · 5 mins
|
||||
|
||||
How to Choose the Right Documentation Software. Reliable and efficient documentation software is crucial in the fast-paced world of software development.
|
||||
|
||||
## [AI in software diagramming: What trends will define the future?](https://www.mermaidchart.com/blog/posts/ai-in-software-diagramming)
|
||||
## [AI in software diagramming: What trends will define the future?](https://www.mermaidchart.com/blog/posts/ai-in-software-diagramming/)
|
||||
|
||||
24 April 2024 · 5 mins
|
||||
|
||||
Artificial intelligence (AI) tools are changing the way developers work.
|
||||
|
||||
## [Mermaid Chart Unveils Visual Editor for Sequence Diagrams](https://www.mermaidchart.com/blog/posts/mermaid-chart-unveils-visual-editor-for-sequence-diagrams)
|
||||
## [Mermaid Chart Unveils Visual Editor for Sequence Diagrams](https://www.mermaidchart.com/blog/posts/mermaid-chart-unveils-visual-editor-for-sequence-diagrams/)
|
||||
|
||||
8 April 2024 · 5 mins
|
||||
|
||||
Sequence diagrams are excellent tools for communication and documentation.
|
||||
|
||||
## [Modeling system states: It starts with a Turing machine](https://www.mermaidchart.com/blog/posts/modeling-system-states-it-starts-with-a-turing-machine)
|
||||
## [Modeling system states: It starts with a Turing machine](https://www.mermaidchart.com/blog/posts/modeling-system-states/)
|
||||
|
||||
27 March 2024 · 12 mins
|
||||
|
||||
In computer science, there are a few fundamental papers that, without exaggeration, changed everything.
|
||||
|
||||
## [Mermaid Chart Raises $7.5M to Reinvent Visual Collaboration for Enterprises](https://www.mermaidchart.com/blog/posts/mermaid-chart-raises-7-5m-to-reinvent-visual-collaboration-for-enterprises)
|
||||
## [Mermaid Chart Raises $7.5M to Reinvent Visual Collaboration for Enterprises](https://www.mermaidchart.com/blog/posts/mermaid-chart-raises-7.5m-to-reinvent-visual-collaoration-for-enterprises/)
|
||||
|
||||
20 March 2024 · 4 mins
|
||||
|
||||
Mermaid Chart, the company offering text-based diagramming and workflow management tools, today announced it has raised $7.5 million in Seed funding.
|
||||
|
||||
## [Mermaid Chart GPT Is Now Available In the GPT Store!](https://www.mermaidchart.com/blog/posts/mermaid-chart-gpt-is-now-available-in-the-gpt-store)
|
||||
## [Mermaid Chart GPT Is Now Available In the GPT Store!](https://www.mermaidchart.com/blog/posts/mermaid-chart-gpt-is-now-available-in-the-gpt-store/)
|
||||
|
||||
7 March 2024 · 3 mins
|
||||
|
||||
Mermaid Chart GPT is Now Available In the GPT Store!
|
||||
|
||||
## [How to Make a Flowchart with Mermaid Chart](https://www.mermaidchart.com/blog/posts/how-to-make-a-flowchart-with-mermaid-chart)
|
||||
## [How to Make a Flowchart with Mermaid Chart](https://www.mermaidchart.com/blog/posts/how-to-make-flowcharts-with-mermaid-chart/)
|
||||
|
||||
30 January 2024 · 6 mins
|
||||
|
||||
Learn how to make a flowchart with Mermaid Chart, the leading text-to-diagram platform for both developers and non-developers.
|
||||
|
||||
## [How one data scientist uses Mermaid Chart to quickly and easily build flowcharts](https://www.mermaidchart.com/blog/posts/how-one-data-scientist-uses-mermaid-chart-to-quickly-and-easily-build-flowcharts)
|
||||
## [How one data scientist uses Mermaid Chart to quickly and easily build flowcharts](https://www.mermaidchart.com/blog/posts/customer-spotlight-ari-tal/)
|
||||
|
||||
23 January 2024 · 4 mins
|
||||
|
||||
Read about how Ari Tal, a data scientist and founder of Leveling Up with XAI, utilizes Mermaid Chart for its easy-to-use flowchart creation capabilities to enhance his work in explainable AI (XAI).
|
||||
|
||||
## [Introducing Mermaid Chart’s JetBrains IDE Extension](https://www.mermaidchart.com/blog/posts/introducing-mermaid-charts-jetbrains-ide-extension)
|
||||
## [Introducing Mermaid Chart’s JetBrains IDE Extension](https://www.mermaidchart.com/blog/posts/introducing-mermaid-charts-jetbrains-ide-extension/)
|
||||
|
||||
20 December 2023 · 5 mins
|
||||
|
||||
Diagrams are essential for documenting your code.
|
||||
|
||||
## [Mermaid Chart Releases New Visual Editor For Flowcharts](https://www.mermaidchart.com/blog/posts/mermaid-chart-releases-new-visual-editor-for-flowcharts)
|
||||
## [Mermaid Chart Releases New Visual Editor For Flowcharts](https://www.mermaidchart.com/blog/posts/mermaid-chart-releases-new-visual-editor-for-flowcharts/)
|
||||
|
||||
14 December 2023 · 5 mins
|
||||
|
||||
Mermaid Chart introduces a new Visual Editor for flowcharts, enabling users of all skill levels to create diagrams easily and efficiently, with both GUI and code-based editing options.
|
||||
|
||||
## [7 best practices (+ examples) for good developer documentation](https://www.mermaidchart.com/blog/posts/7-best-practices-examples-for-good-developer-documentation)
|
||||
## [7 best practices (+ examples) for good developer documentation](https://www.mermaidchart.com/blog/posts/7-best-practices-for-good-documentation/)
|
||||
|
||||
4 December 2023 · 11 min
|
||||
|
||||
Essential strategies for crafting grate developer documentation, with practical examples and insights from leading tech companies.
|
||||
|
||||
## [5 Reasons You Should Be Using Mermaid Chart As Your Diagram Generator](https://www.mermaidchart.com/blog/posts/5-reasons-you-should-be-using-mermaid-chart-as-your-diagram-generator)
|
||||
## [5 Reasons You Should Be Using Mermaid Chart As Your Diagram Generator](https://www.mermaidchart.com/blog/posts/5-reasons-you-should-be-using-mermaid-chart-as-your-diagram-generator/)
|
||||
|
||||
14 November 2023 · 5 mins
|
||||
|
||||
Mermaid Chart, a user-friendly, code-based diagram generator with AI integrations, templates, collaborative tools, and plugins for developers, streamlines the process of creating and sharing diagrams, enhancing both creativity and collaboration.
|
||||
|
||||
## [How to Use Mermaid Chart as an AI Diagram Generator](https://www.mermaidchart.com/blog/posts/how-to-use-mermaid-chart-as-an-ai-diagram-generator)
|
||||
## [How to Use Mermaid Chart as an AI Diagram Generator](https://www.mermaidchart.com/blog/posts/how-to-use-mermaid-chart-as-an-ai-diagram-generator/)
|
||||
|
||||
1 November 2023 · 5 mins
|
||||
|
||||
Would an AI diagram generator make your life easier?
|
||||
|
||||
## [Diagrams, Made Even Easier: Introducing “Code Snippets” in the Mermaid Chart Editor](https://www.mermaidchart.com/blog/posts/diagrams-made-even-easier-introducing-code-snippets-in-the-mermaid-chart-editor)
|
||||
## [Diagrams, Made Even Easier: Introducing “Code Snippets” in the Mermaid Chart Editor](https://www.mermaidchart.com/blog/posts/easier-diagram-editing-with-code-snippets/)
|
||||
|
||||
12 October 2023 · 4 mins
|
||||
|
||||
Mermaid Chart introduces Code Snippets in its editor, streamlining the diagramming process for developers and professionals.
|
||||
|
||||
## [How to Make a Git Graph with Mermaid Chart](https://www.mermaidchart.com/blog/posts/how-to-make-a-git-graph-with-mermaid-chart)
|
||||
## [How to Make a Git Graph with Mermaid Chart](https://www.mermaidchart.com/blog/posts/how-to-make-a-git-graph-with-mermaid-chart/)
|
||||
|
||||
22 September 2023 · 7 mins
|
||||
|
||||
A git graph is one of the more useful forms of diagrams for developers and DevOps professionals.
|
||||
|
||||
## [Present flow data using Sankey diagrams in Mermaid, thanks to Nikolay Rozhkov](https://www.mermaidchart.com/blog/posts/present-flow-data-using-sankey-diagrams-in-mermaid-thanks-to-nikolay-rozhkov)
|
||||
## [Present flow data using Sankey diagrams in Mermaid, thanks to Nikolay Rozhkov](https://www.mermaidchart.com/blog/posts/present-flow-data-using-sankey-diagrams/)
|
||||
|
||||
8 September 2023 · 4 mins
|
||||
|
||||
Sankey diagrams are a powerful tool for visualizing flow data.
|
||||
|
||||
## [Special cases broke Microsoft Zune and can ruin your code base too](https://www.mermaidchart.com/blog/posts/special-cases-broke-microsoft-zune-and-can-ruin-your-code-base-too)
|
||||
## [Special cases broke Microsoft Zune and can ruin your code base too](https://www.mermaidchart.com/blog/posts/special-cases-broke-microsoft-zune-and-can-ruin-your-code-base-too/)
|
||||
|
||||
23 August 2023 · 15 mins
|
||||
|
||||
Read about the pitfalls of special cases in programming, illustrating how they can lead to complexity, diminish readability, and create maintenance challenges.
|
||||
|
||||
## [New AI chatbot now available on Mermaid Chart to simplify text-based diagram creation](https://www.mermaidchart.com/blog/posts/new-ai-chatbot-now-available-on-mermaid-chart-to-simplify-text-based-diagram-creation)
|
||||
## [New AI chatbot now available on Mermaid Chart to simplify text-based diagram creation](https://www.mermaidchart.com/blog/posts/ai-chatbot-now-available-on-mermaid-chart-to-simplify-text-based-diagram-creation/)
|
||||
|
||||
14 August 2023 · 4 mins
|
||||
|
||||
Introducing Mermaid Chart’s new AI chatbot, a diagramming assistant that simplifies text-based diagram creation for everyone, from developers to educators, offering features to start, edit, and fix diagrams, and embodying our vision to make diagramming accessible, user-friendly, and fun.
|
||||
|
||||
## [Believe It or Not, You Still Need an Online UML Diagram Tool](https://www.mermaidchart.com/blog/posts/believe-it-or-not-you-still-need-an-online-uml-diagram-tool)
|
||||
## [Believe It or Not, You Still Need an Online UML Diagram Tool](https://www.mermaidchart.com/blog/posts/uml-diagram-tool/)
|
||||
|
||||
14 August 2023 · 8 mins
|
||||
|
||||
@@ -186,25 +186,25 @@ A UML diagram tool helps developers and other professionals quickly create and s
|
||||
|
||||
Introducing the concept of mind mapping as a tool for organizing complex information, and highlights Mermaid as a user-friendly software that simplifies the creation and editing of mind maps for applications in IT solution design, business decision-making, and knowledge organization.
|
||||
|
||||
## [Mermaid Chart Announces Visual Studio Code Plugin to Simplify Development Workflows](https://www.mermaidchart.com/blog/posts/mermaid-chart-announces-visual-studio-code-plugin-to-simplify-development-workflows)
|
||||
## [Mermaid Chart Announces Visual Studio Code Plugin to Simplify Development Workflows](https://www.mermaidchart.com/blog/posts/mermaid-chart-announces-visual-studio-code-plugin)
|
||||
|
||||
17 July 2023 · 3 mins
|
||||
|
||||
New Integration Enhances Workflows By Enabling Developers To Reference And Edit Diagrams Within Visual Studio Code.
|
||||
|
||||
## [Mermaid Chart’s ChatGPT Plugin Combines Generative AI and Smart Diagramming For Users](https://www.mermaidchart.com/blog/posts/mermaid-charts-chatgpt-plugin-combines-generative-ai-and-smart-diagramming-for-users)
|
||||
## [Mermaid Chart’s ChatGPT Plugin Combines Generative AI and Smart Diagramming For Users](https://www.mermaidchart.com/blog/posts/mermaid-chart-chatgpt-plugin-combines-generative-ai-and-smart-diagramming)
|
||||
|
||||
29 June 2023 · 4 mins
|
||||
|
||||
Mermaid Chart’s new ChatGPT plugin integrates AI-powered text prompts with Mermaid’s intuitive diagramming editor, enabling users to generate, edit, and share complex diagrams with ease and efficiency.
|
||||
|
||||
## [Sequence diagrams, the only good thing UML brought to software development](https://www.mermaidchart.com/blog/posts/sequence-diagrams-the-only-good-thing-uml-brought-to-software-development)
|
||||
## [Sequence diagrams, the only good thing UML brought to software development](https://www.mermaidchart.com/blog/posts/sequence-diagrams-the-good-thing-uml-brought-to-software-development/)
|
||||
|
||||
15 June 2023 · 12 mins
|
||||
|
||||
Sequence diagrams really shine when you’re documenting different parts of a system and the various ways these parts interact with each other.
|
||||
|
||||
## [subhash-halder contributed quadrant charts so you can show your manager what to select - just like the strategy consultants at BCG do](https://www.mermaidchart.com/blog/posts/subhash-halder-contributed-quadrant-charts-so-you-can-show-your-manager-what-to-select-just-like-the-strategy-consultants-at-bcg-do)
|
||||
## [subhash-halder contributed quadrant charts so you can show your manager what to select - just like the strategy consultants at BCG do](https://www.mermaidchart.com/blog/posts/subhash-halder-contributed-quadrant-charts-so-you-can-show-your-manager-what-to-select-just-like-the-strategy-consultants-at-bcg-do/)
|
||||
|
||||
8 June 2023 · 7 mins
|
||||
|
||||
@@ -216,31 +216,31 @@ A quadrant chart is a useful diagram that helps users visualize data and identif
|
||||
|
||||
Documentation tends to be bad because companies and projects don’t fully realize the costs of bad documentation.
|
||||
|
||||
## [Automatic text wrapping in flowcharts is here!](https://www.mermaidchart.com/blog/posts/automatic-text-wrapping-in-flowcharts-is-here)
|
||||
## [Automatic text wrapping in flowcharts is here!](https://www.mermaidchart.com/blog/posts/automatic-text-wrapping-in-flowcharts-is-here/)
|
||||
|
||||
3 April 2023 · 3 mins
|
||||
|
||||
Markdown Strings reduce the hassle # Starting from v10.
|
||||
|
||||
## [Mermaid Chart officially launched with sharable diagram links and presentation mode](https://www.mermaidchart.com/blog/posts/mermaid-chart-officially-launched-with-sharable-diagram-links-and-presentation-mode)
|
||||
## [Mermaid Chart officially launched with sharable diagram links and presentation mode](https://www.mermaidchart.com/blog/posts/mermaid-chart-officially-launched-with-sharable-diagram-links-and-presentation-mode/)
|
||||
|
||||
27 March 2023 · 2 mins
|
||||
|
||||
Exciting news for all Mermaid OSS fans: Mermaid Chart has officially launched with Mermaid Chart!
|
||||
|
||||
## [If you're not excited about ChatGPT, then you're not being creative](https://www.mermaidchart.com/blog/posts/if-youre-not-excited-about-chatgpt-then-youre-not-being-creative)
|
||||
## [If you're not excited about ChatGPT, then you're not being creative](https://www.mermaidchart.com/blog/posts/if-youre-not-excited-about-chatgpt-then-youre-not-being-creative-enough/)
|
||||
|
||||
8 March 2023 · 9 mins
|
||||
|
||||
The hype around AI in general and ChatGPT, in particular, is so intense that it’s very understandable to assume the hype train is driving straight toward the trough of disillusionment.
|
||||
|
||||
## [Flow charts are O(n)2 complex, so don't go over 100 connections](https://www.mermaidchart.com/blog/posts/flow-charts-are-on2-complex-so-dont-go-over-100-connections)
|
||||
## [Flow charts are O(n)2 complex, so don't go over 100 connections](https://www.mermaidchart.com/blog/posts/flow-charts-are-on2-complex-so-dont-go-over-100-connections/)
|
||||
|
||||
1 March 2023 · 12 mins
|
||||
|
||||
Flowchart design is a game of balance: Read about the importance of dialling in the right level of detail and how to manage complexity in large flowcharts.
|
||||
|
||||
## [Busting the myth that developers can't write](https://www.mermaidchart.com/blog/posts/busting-the-myth-that-developers-cant-write)
|
||||
## [Busting the myth that developers can't write](https://www.mermaidchart.com/blog/posts/busting-the-myth-that-developers-cant-write/)
|
||||
|
||||
10 February 2023 · 10 mins
|
||||
|
||||
|
||||
@@ -390,7 +390,7 @@ mermaid.ganttConfig = {
|
||||
sectionFontSize: 24, // Font size for sections
|
||||
numberSectionStyles: 1, // The number of alternating section styles
|
||||
axisFormat: '%d/%m', // Date/time format of the axis
|
||||
tickInterval: '1 week', // Axis ticks
|
||||
tickInterval: '1week', // Axis ticks
|
||||
topAxis: true, // When this flag is set, date labels will be added to the top of the chart
|
||||
displayMode: 'compact', // Turns compact mode on
|
||||
weekday: 'sunday', // On which day a week-based interval should start
|
||||
|
||||
@@ -64,7 +64,7 @@ todo[Todo]
|
||||
|
||||
## Configuration Options
|
||||
|
||||
You can customize the Kanban diagram using a configuration block at the beginning of your markdown file. This is useful for setting global settings like a base URL for tickets. Currently there is one configuration option for kanban diagrams tacketBaseUrl. This can be set as in the the following example:
|
||||
You can customize the Kanban diagram using a configuration block at the beginning of your markdown file. This is useful for setting global settings like a base URL for tickets. Currently there is one configuration option for kanban diagrams `ticketBaseUrl`. This can be set as in the the following example:
|
||||
|
||||
```yaml
|
||||
---
|
||||
|
||||
@@ -455,6 +455,7 @@ const render = async function (
|
||||
svgCode = DOMPurify.sanitize(svgCode, {
|
||||
ADD_TAGS: DOMPURIFY_TAGS,
|
||||
ADD_ATTR: DOMPURIFY_ATTR,
|
||||
HTML_INTEGRATION_POINTS: { foreignobject: true },
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ export async function classBox<T extends SVGGraphicsElement>(parent: D3Selection
|
||||
// Treat node as classNode
|
||||
const classNode = node as unknown as ClassNode;
|
||||
classNode.annotations = classNode.annotations ?? [];
|
||||
classNode.members = classNode.members ?? [];
|
||||
classNode.attributes = classNode.attributes ?? [];
|
||||
classNode.methods = classNode.methods ?? [];
|
||||
|
||||
const { shapeSvg, bbox } = await textHelper(parent, node, config, useHtmlLabels, GAP);
|
||||
@@ -35,7 +35,7 @@ export async function classBox<T extends SVGGraphicsElement>(parent: D3Selection
|
||||
}
|
||||
|
||||
const renderExtraBox =
|
||||
classNode.members.length === 0 &&
|
||||
classNode.attributes.length === 0 &&
|
||||
classNode.methods.length === 0 &&
|
||||
!config.class?.hideEmptyMembersBox;
|
||||
|
||||
@@ -51,9 +51,9 @@ export async function classBox<T extends SVGGraphicsElement>(parent: D3Selection
|
||||
|
||||
const w = bbox.width;
|
||||
let h = bbox.height;
|
||||
if (classNode.members.length === 0 && classNode.methods.length === 0) {
|
||||
if (classNode.attributes.length === 0 && classNode.methods.length === 0) {
|
||||
h += GAP;
|
||||
} else if (classNode.members.length > 0 && classNode.methods.length === 0) {
|
||||
} else if (classNode.attributes.length > 0 && classNode.methods.length === 0) {
|
||||
h += GAP * 2;
|
||||
}
|
||||
const x = -w / 2;
|
||||
@@ -66,7 +66,7 @@ export async function classBox<T extends SVGGraphicsElement>(parent: D3Selection
|
||||
PADDING -
|
||||
(renderExtraBox
|
||||
? PADDING
|
||||
: classNode.members.length === 0 && classNode.methods.length === 0
|
||||
: classNode.attributes.length === 0 && classNode.methods.length === 0
|
||||
? -PADDING / 2
|
||||
: 0),
|
||||
w + 2 * PADDING,
|
||||
@@ -74,7 +74,7 @@ export async function classBox<T extends SVGGraphicsElement>(parent: D3Selection
|
||||
2 * PADDING +
|
||||
(renderExtraBox
|
||||
? PADDING * 2
|
||||
: classNode.members.length === 0 && classNode.methods.length === 0
|
||||
: classNode.attributes.length === 0 && classNode.methods.length === 0
|
||||
? -PADDING
|
||||
: 0),
|
||||
options
|
||||
@@ -107,7 +107,7 @@ export async function classBox<T extends SVGGraphicsElement>(parent: D3Selection
|
||||
PADDING -
|
||||
(renderExtraBox
|
||||
? PADDING
|
||||
: classNode.members.length === 0 && classNode.methods.length === 0
|
||||
: classNode.attributes.length === 0 && classNode.methods.length === 0
|
||||
? -PADDING / 2
|
||||
: 0);
|
||||
if (!useHtmlLabels) {
|
||||
@@ -138,11 +138,11 @@ export async function classBox<T extends SVGGraphicsElement>(parent: D3Selection
|
||||
const labelGroupHeight =
|
||||
(shapeSvg.select('.label-group').node() as SVGGraphicsElement).getBBox().height -
|
||||
(renderExtraBox ? PADDING / 2 : 0) || 0;
|
||||
const membersGroupHeight =
|
||||
(shapeSvg.select('.members-group').node() as SVGGraphicsElement).getBBox().height -
|
||||
const attributeGroupHeight =
|
||||
(shapeSvg.select('.attribute-group').node() as SVGGraphicsElement).getBBox().height -
|
||||
(renderExtraBox ? PADDING / 2 : 0) || 0;
|
||||
// First line (under label)
|
||||
if (classNode.members.length > 0 || classNode.methods.length > 0 || renderExtraBox) {
|
||||
if (classNode.attributes.length > 0 || classNode.methods.length > 0 || renderExtraBox) {
|
||||
const roughLine = rc.line(
|
||||
rectBBox.x,
|
||||
annotationGroupHeight + labelGroupHeight + y + PADDING,
|
||||
@@ -154,13 +154,13 @@ export async function classBox<T extends SVGGraphicsElement>(parent: D3Selection
|
||||
line.attr('class', 'divider').attr('style', styles);
|
||||
}
|
||||
|
||||
// Second line (under members)
|
||||
if (renderExtraBox || classNode.members.length > 0 || classNode.methods.length > 0) {
|
||||
// Second line (under attributes)
|
||||
if (renderExtraBox || classNode.attributes.length > 0 || classNode.methods.length > 0) {
|
||||
const roughLine = rc.line(
|
||||
rectBBox.x,
|
||||
annotationGroupHeight + labelGroupHeight + membersGroupHeight + y + GAP * 2 + PADDING,
|
||||
annotationGroupHeight + labelGroupHeight + attributeGroupHeight + y + GAP * 2 + PADDING,
|
||||
rectBBox.x + rectBBox.width,
|
||||
annotationGroupHeight + labelGroupHeight + membersGroupHeight + y + PADDING + GAP * 2,
|
||||
annotationGroupHeight + labelGroupHeight + attributeGroupHeight + y + PADDING + GAP * 2,
|
||||
options
|
||||
);
|
||||
const line = shapeSvg.insert(() => roughLine);
|
||||
|
||||
@@ -125,7 +125,7 @@ export async function tiltedCylinder<T extends SVGGraphicsElement>(
|
||||
) {
|
||||
let x = rx * rx * (1 - (y * y) / (ry * ry));
|
||||
if (x != 0) {
|
||||
x = Math.sqrt(x);
|
||||
x = Math.sqrt(Math.abs(x));
|
||||
}
|
||||
x = rx - x;
|
||||
if (point.x - (node.x ?? 0) > 0) {
|
||||
|
||||
24
pnpm-lock.yaml
generated
24
pnpm-lock.yaml
generated
@@ -226,9 +226,6 @@ importers:
|
||||
'@types/d3':
|
||||
specifier: ^7.4.3
|
||||
version: 7.4.3
|
||||
'@types/dompurify':
|
||||
specifier: ^3.0.5
|
||||
version: 3.0.5
|
||||
cytoscape:
|
||||
specifier: ^3.29.2
|
||||
version: 3.30.2
|
||||
@@ -251,8 +248,8 @@ importers:
|
||||
specifier: ^1.11.10
|
||||
version: 1.11.13
|
||||
dompurify:
|
||||
specifier: ^3.0.11 <3.1.7
|
||||
version: 3.1.6
|
||||
specifier: ^3.2.1
|
||||
version: 3.2.1
|
||||
katex:
|
||||
specifier: ^0.16.9
|
||||
version: 0.16.11
|
||||
@@ -2768,9 +2765,6 @@ packages:
|
||||
'@types/debug@4.1.12':
|
||||
resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==}
|
||||
|
||||
'@types/dompurify@3.0.5':
|
||||
resolution: {integrity: sha512-1Wg0g3BtQF7sSb27fJQAKck1HECM6zV1EB66j8JH9i3LCjYabJa0FSdiSgsD5K/RbrsR0SiraKacLB+T8ZVYAg==}
|
||||
|
||||
'@types/estree@0.0.39':
|
||||
resolution: {integrity: sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==}
|
||||
|
||||
@@ -4720,8 +4714,8 @@ packages:
|
||||
resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==}
|
||||
engines: {node: '>= 4'}
|
||||
|
||||
dompurify@3.1.6:
|
||||
resolution: {integrity: sha512-cTOAhc36AalkjtBpfG6O8JimdTMWNXjiePT2xQH/ppBGi/4uIpmj8eKyIkMJErXWARyINV/sB38yf8JCLF5pbQ==}
|
||||
dompurify@3.2.1:
|
||||
resolution: {integrity: sha512-NBHEsc0/kzRYQd+AY6HR6B/IgsqzBABrqJbpCDQII/OK6h7B7LXzweZTDsqSW2LkTRpoxf18YUP+YjGySk6B3w==}
|
||||
|
||||
domutils@3.1.0:
|
||||
resolution: {integrity: sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==}
|
||||
@@ -12125,10 +12119,6 @@ snapshots:
|
||||
dependencies:
|
||||
'@types/ms': 0.7.34
|
||||
|
||||
'@types/dompurify@3.0.5':
|
||||
dependencies:
|
||||
'@types/trusted-types': 2.0.7
|
||||
|
||||
'@types/estree@0.0.39': {}
|
||||
|
||||
'@types/estree@1.0.6': {}
|
||||
@@ -12970,7 +12960,7 @@ snapshots:
|
||||
antlr4: 4.11.0
|
||||
color-string: 1.9.1
|
||||
dom-to-image-more: 2.16.0
|
||||
dompurify: 3.1.6
|
||||
dompurify: 3.2.1
|
||||
file-saver: 2.0.5
|
||||
highlight.js: 10.7.3
|
||||
html-to-image: 1.11.11
|
||||
@@ -14509,7 +14499,9 @@ snapshots:
|
||||
dependencies:
|
||||
domelementtype: 2.3.0
|
||||
|
||||
dompurify@3.1.6: {}
|
||||
dompurify@3.2.1:
|
||||
optionalDependencies:
|
||||
'@types/trusted-types': 2.0.7
|
||||
|
||||
domutils@3.1.0:
|
||||
dependencies:
|
||||
|
||||
@@ -38,7 +38,6 @@ const SRC = {
|
||||
// to match the real `package.json` values
|
||||
'type-fest': '*',
|
||||
'@types/d3': '^7.4.3',
|
||||
'@types/dompurify': '^3.0.5',
|
||||
typescript: '*',
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user