Merge branch 'develop' into 3061_refactoring_and_modularisation

This commit is contained in:
Knut Sveidqvist 2022-06-18 14:24:51 +02:00
commit f79d4f9a40
67 changed files with 4495 additions and 2221 deletions

View File

@ -23,7 +23,7 @@
- Missing fontawesome icon support [\#830](https://github.com/knsv/mermaid/issues/830)
- Docs for integration with wiki.js? [\#829](https://github.com/knsv/mermaid/issues/829)
- Is this project still maintained? [\#826](https://github.com/knsv/mermaid/issues/826)
- typroa [\#823](https://github.com/knsv/mermaid/issues/823)
- typora [\#823](https://github.com/knsv/mermaid/issues/823)
- Maintain the order of the nodes in Flowchart [\#815](https://github.com/knsv/mermaid/issues/815)
- Overlap, Overflow and cut titles in flowchart [\#814](https://github.com/knsv/mermaid/issues/814)
- How load mermaidApi notejs electron [\#813](https://github.com/knsv/mermaid/issues/813)

View File

@ -114,7 +114,7 @@ Finally, if it is not in the documentation, no one will know about it and then *
The docs are located in the docs folder and are ofc written in markdown. Just pick the right section and start typing. If you want to add to the structure as in adding a new section and new file you do that via the _navbar.md.
The changes in master is reflected in http://mermaid-js.github.io/mermaid/ once released the updates are committed to https://mermaid-js.github.io/#/
The changes in master is reflected in https://mermaid-js.github.io/mermaid/ once released the updates are committed to https://mermaid-js.github.io/#/
## Last words

View File

@ -126,7 +126,83 @@ describe('Git Graph diagram', () => {
branch branch8
branch branch9
checkout branch1
commit
commit id: "1"
`,
{}
);
});
it('9: should render a simple gitgraph with rotated labels', () => {
imgSnapshotTest(
`%%{init: { 'logLevel': 'debug', 'theme': 'default' , 'gitGraph': {
'rotateCommitLabel': true
} } }%%
gitGraph
commit id: "75f7219e83b321cd3fdde7dcf83bc7c1000a6828"
commit id: "0db4784daf82736dec4569e0dc92980d328c1f2e"
commit id: "7067e9973f9eaa6cd4a4b723c506d1eab598e83e"
commit id: "66972321ad6c199013b5b31f03b3a86fa3f9817d"
`,
{}
);
});
it('10: should render a simple gitgraph with horizontal labels', () => {
imgSnapshotTest(
`%%{init: { 'logLevel': 'debug', 'theme': 'default' , 'gitGraph': {
'rotateCommitLabel': false
} } }%%
gitGraph
commit id: "Alpha"
commit id: "Beta"
commit id: "Gamma"
commit id: "Delta"
`,
{}
);
});
it('11: should render a simple gitgraph with cherry pick commit', () => {
imgSnapshotTest(
`
gitGraph
commit id: "ZERO"
branch develop
commit id:"A"
checkout main
commit id:"ONE"
checkout develop
commit id:"B"
checkout main
commit id:"TWO"
cherry-pick id:"A"
commit id:"THREE"
checkout develop
commit id:"C"
`,
{}
);
});
it('11: should render a simple gitgraph with two cherry pick commit', () => {
imgSnapshotTest(
`
gitGraph
commit id: "ZERO"
branch develop
commit id:"A"
checkout main
commit id:"ONE"
checkout develop
commit id:"B"
branch featureA
commit id:"FIX"
commit id: "FIX-2"
checkout main
commit id:"TWO"
cherry-pick id:"A"
commit id:"THREE"
cherry-pick id:"FIX"
checkout develop
commit id:"C"
merge featureA
`,
{}
);

View File

@ -78,7 +78,7 @@
a_a --> c --> d_d --> c_c
classDef apa fill:#f9f,stroke:#333,stroke-width:4px;
class a_a apa;
click a_a "http://www.aftonbladet.se" "apa"
click a_a "https://www.aftonbladet.se" "apa"
</div>

View File

@ -22,16 +22,16 @@
<body>
<h1>info below</h1>
<div class="flex">
<div class="mermaid2" style="width: 50%; height: 20%;">
<div class="mermaid" style="width: 50%; height: 20%;">
flowchart BT
subgraph two
b1
end
subgraph three
c1-->c2
end
c1 --apa apa apa--> b1
two --> c2
subgraph S1
sub1 -->sub2
end
subgraph S2
sub4
end
S1 --> S2
sub1 --> sub4
</div>
<div class="mermaid2" style="width: 50%; height: 200px;">
sequenceDiagram
@ -163,7 +163,7 @@ _one --> b
// arrowMarkerAbsolute: true,
// themeCSS: '.edgePath .path {stroke: red;} .arrowheadPath {fill: red;}',
logLevel: 0,
flowchart: { curve: 'cardinal', htmlLabels: true },
flowchart: { curve: 'cardinal', htmlLabels: false },
// gantt: { axisFormat: '%m/%d/%Y' },
sequence: { actorMargin: 50, showSequenceNumbers: true },
// sequenceDiagram: { actorMargin: 300 } // deprecated

View File

@ -230,6 +230,7 @@ class Class10 {
nodeSpacing: 10,
curve: 'cardinal',
htmlLabels: true,
useMaxWidth: false,
// defaultRenderer: 'dagre-d3',
},
class: {

View File

@ -11,52 +11,207 @@
body {
/* background: rgb(221, 208, 208); */
/* background:#333; */
font-family: 'Arial';
font-family: 'Courier New', Courier, monospace;
/* font-size: 18px !important; */
}
h1 { color: grey;}
.mermaid2 {
display: none;
}
.mermaid svg {
.mermaid {
border: 1px solid red;
font-family: 'Courier New', Courier, monospace;
/* font-size: 18px !important; */
}
</style>
</head>
<body>
<div>info below</div>
<div class="flex">
<div class="">
<div class="mermaid2" style="width: 100%; height: 400px;">
%%{init: { "logLevel": 1, "er": {"fontSize":18 }} }%%
erDiagram
CUSTOMER }|..|{ DELIVERY-ADDRESS : has
CUSTOMER ||--o{ ORDER : places
CUSTOMER ||--o{ INVOICE : "liable for"
DELIVERY-ADDRESS ||--o{ ORDER : receives
INVOICE ||--|{ ORDER : covers
ORDER ||--|{ ORDER-ITEM : includes
PRODUCT-CATEGORY ||--|{ PRODUCT : contains
PRODUCT ||--o{ ORDER-ITEM : "ordered in"
flowchart TB;subgraph "number as labels";1;end;
</div>
<div class="mermaid2" style="width: 50%; height: 400px;">
<div class="mermaid2" style="width: 100%; height: 400px;">
flowchart TB;a[APA];
</div>
<div class="mermaid2" style="margin-left:100px;">
graph TD
work --> sleep
sleep --> work
eat --> sleep
work --> eat
</div>
<div class="mermaid2" style="margin-left:100px;">
flowchart TD
A[Christmas] ==> D
A[Christmas] -->|Get money| B(Go shopping)
A[Christmas] ==> C
subgraph T ["Test"]
A
B
C
end
work --> sleep
sleep --> work
eat --> sleep
work --> eat
</div>
<div class="mermaid2" style="">
graph TB
A
B
subgraph foo[Foo SubGraph]
C
D
end
subgraph bar[Bar SubGraph]
E
F
end
G
classDef Test fill:#F84E68,stroke:#333,color:white;
class A,T Test
classDef TestSub fill:green;
class T TestSub
linkStyle 0,1 color:orange, stroke: orange;
A-->B
B-->C
C-->D
B-->D
D-->E
E-->A
E-->F
F-->D
F-->G
B-->G
G-->D
style foo fill:#F99,stroke-width:2px,stroke:#F0F,color:darkred
style bar fill:#999,stroke-width:2px,stroke:#0F0,color:blue
</div>
<div class="mermaid2" style="">
graph TB
%%{init: { "logLevel": 1, "flowchart": {"htmlLabels":true }} }%%
A
B
subgraph foo[Foo SubGraph]
C
D
end
subgraph bar[Bar SubGraph]
E
F
end
G
A-->B
B-->C
C-->D
B-->D
D-->E
E-->A
E-->F
F-->D
F-->G
B-->G
G-->D
style foo fill:#F99,stroke-width:2px,stroke:#F0F,color:darkred
style bar fill:#999,stroke-width:10px,stroke:#0F0,color:blue
</div>
<div class="mermaid2" style="">
graph TD
A[Christmas] ==> D
A[Christmas] -->|Get money| B(Go shopping)
A[Christmas] ==> C
</div>
<div class="mermaid2" style="">
graph TD
%%{init: { "logLevel": 1, "flowchart": {"htmlLabels":true }} }%%
A[Christmas] ==> D
A[Christmas] -->|Get money| B(Go shopping)
A[Christmas] ==> C
</div>
<div class="mermaid2" style="">
flowchart TD
A[Christmas] ==> D
A[Christmas] -->|Get money| B(Go shopping)
A[Christmas] ==> C
</div>
<div class="mermaid2" style="">
flowchart TD
%%{init: { "logLevel": 1, "flowchart": {"htmlLabels":true }} }%%
A[Christmas] ==> D
A[Christmas] -->|Get money| B(Go shopping)
A[Christmas] ==> C
</div>
<div class="mermaid2" style="">
flowchart LR
a["<strong>Haiya</strong>"]---->b
</div>
<div class="mermaid" style="width: 100%; height: 20%;">
flowchart TB
<div class="mermaid" style="">
flowchart LR
%%{init: { "logLevel": 1, "flowchart": {"htmlLabels":true }} }%%
a["<strong>Haiya</strong>"]---->b
</div>
<div class="mermaid2" style="">
flowchart TD
A[Christmas] ==> D
A[Christmas] -->|Get money| B(Go shopping)
A[Christmas] ==> C
</div>
<div class="mermaid2" style="">
flowchart TD
%%{init: { "logLevel": 1, "flowchart": {"htmlLabels":true }} }%%
A[Christmas] ==> D
A[Christmas] -->|Get money| B(Go shopping)
A[Christmas] ==> C
</div>
<div class="mermaid2" style="">
%%{init: { "logLevel": 1, "flowchart": {"htmlLabels":true }} }%%
classDiagram-v2
Class01 <|-- AveryLongClass : Cool
&lt;&lt;interface&gt;&gt; Class01
Class03 *-- Class04
Class05 o-- Class06
Class07 .. Class08
Class09 --> C2 : Where am i?
Class09 --* C3
Class09 --|> Class07
Class12 <|.. Class08
Class11 ..>Class12
Class07 : equals()
Class07 : Object[] elementData
Class01 : size()
Class01 : int chimp
Class01 : int gorilla
Class01 : -int privateChimp
Class01 : +int publicGorilla
Class01 : #int protectedMarmoset
Class08 <--> C2: Cool label
class Class10 {
&lt;&lt;service&gt;&gt;
int id
test()
}
</div>
<div class="mermaid2" style="">
classDiagram-v2
Class01 <|-- AveryLongClass : Cool
&lt;&lt;interface&gt;&gt; Class01
Class03 *-- Class04
Class05 o-- Class06
Class07 .. Class08
Class09 --> C2 : Where am i?
Class09 --* C3
Class09 --|> Class07
Class12 <|.. Class08
Class11 ..>Class12
Class07 : equals()
Class07 : Object[] elementData
Class01 : size()
Class01 : int chimp
Class01 : int gorilla
Class01 : -int privateChimp
Class01 : +int publicGorilla
Class01 : #int protectedMarmoset
Class08 <--> C2: Cool label
class Class10 {
&lt;&lt;service&gt;&gt;
int id
test()
}
</div>
<div class="mermaid" style="">
flowchart BT
subgraph S1
sub1 -->sub2
end
@ -66,141 +221,25 @@ flowchart TB
S1 --> S2
sub1 --> sub4
</div>
<div class="mermaid2" style="width: 100%; height: 20%;">
flowchart TB
c1-->a2
subgraph one
a1-->a2
end
subgraph two
b1-->b2
end
subgraph three
c1-->c2
end
one --> two
three --> two
two --> c2
</div>
<div class="mermaid2" style="width: 100%; height: 20%;">
stateDiagram-v2
state S1 {
sub1 -->sub2
}
state S2 {
sub4
}
S1 --> S2
sub1 --> sub4
</div>
<div class="mermaid2" style="width: 100%; height: 20%;">
requirementDiagram
requirement test_req {
id: 1
text: the test text.
risk: high
verifymethod: test
}
functionalRequirement test_req2 {
id: 1.1
text: the second test text.
risk: low
verifymethod: inspection
}
performanceRequirement test_req3 {
id: 1.2
text: the third test text.
risk: medium
verifymethod: demonstration
}
element test_entity {
type: simulation
}
element test_entity2 {
type: word doc
docRef: reqs/test_entity
}
test_entity - satisfies -> test_req2
test_req - traces -> test_req2
test_req - contains -> test_req3
test_req <- copies - test_entity2
</div>
<div class="mermaid2" style="width: 50%; height: 20%;">
flowchart LR
classDef dark fill:#000,stroke:#000,stroke-width:4px,color:#fff
Lorem --> Ipsum --> Dolor
class Lorem,Dolor dark
</div>
<div class="mermaid2" style="width: 50%; height: 20%;">
%%{init: {'theme': 'base' }}%%
%%{init2: { 'logLevel': 0, 'theme': 'forest'} }%%
flowchart TD
L1 --- L2
L2 --- C
M1 ---> C
R1 .-> R2
R2 <.-> C
C -->|Label 1| E1
C <-- Label 2 ---> E2
C ----> E3
C <-...-> E4
C ======> E5
</div>
<div class="mermaid2" style="width: 50%; height: 21%;">
flowchart LR
A[red text] -->|default style| B(blue text)
C([red text]) -->|default style| D[[blue text]]
E[(red text)] -->|default style| F((blue text))
G>red text] -->|default style| H{blue text}
I{{red text}} -->|default style| J[/blue text/]
K[
ed text] -->|default style| L[/blue text]
M[
ed text/] -->|default style| N[blue text]
linkStyle default color:Sienna;
style A stroke:#ff0000,fill:#ffcccc,color:#ff0000
style B stroke:#0000ff,fill:#ccccff,color:#0000ff
style C stroke:#ff0000,fill:#ffcccc,color:#ff0000
style D stroke:#0000ff,fill:#ccccff,color:#0000ff
style E stroke:#ff0000,fill:#ffcccc,color:#ff0000
style F stroke:#0000ff,fill:#ccccff,color:#0000ff
style G stroke:#ff0000,fill:#ffcccc,color:#ff0000
style H stroke:#0000ff,fill:#ccccff,color:#0000ff
style I stroke:#ff0000,fill:#ffcccc,color:#ff0000
style J stroke:#0000ff,fill:#ccccff,color:#0000ff
style K stroke:#ff0000,fill:#ffcccc,color:#ff0000
style L stroke:#0000ff,fill:#ccccff,color:#0000ff
style M stroke:#ff0000,fill:#ffcccc,color:#ff0000
style N stroke:#0000ff,fill:#ccccff,color:#0000ff
</div>
<script src="./mermaid.js"></script>
<script>
mermaid.parseError = function (err, hash) {
// console.error('Mermaid error: ', err);
};
mermaid.initialize({
theme: 'neutral',
arrowMarkerAbsolute: true,
// theme: 'neutral',
// arrowMarkerAbsolute: true,
// themeCSS: '.edgePath .path {stroke: red;} .arrowheadPath {fill: red;}',
logLevel: 0,
flowchart: { nodeSpacing: 10, curve: 'cardinal', htmlLabels: true },
htmlLabels: true,
flowchart: { curve: 'cardinal', htmlLabels: false },
// htmlLabels: true,
// gantt: { axisFormat: '%m/%d/%Y' },
sequence: { actorFontFamily: 'courier', actorMargin: 50, showSequenceNumbers: false },
// sequence: { actorFontFamily: 'courier', actorMargin: 50, showSequenceNumbers: false },
// sequenceDiagram: { actorMargin: 300 } // deprecated
// fontFamily: '"times", sans-serif',
// fontFamily: 'courier',
fontSize: 18,
curve: 'cardinal',
fontFamily: 'courier',
// fontSize: 18,
// curve: 'cardinal',
securityLevel: 'loose',
// themeVariables: {relationLabelColor: 'red'}
});

View File

@ -20,6 +20,165 @@
</div>
<hr />
<div class="mermaid">
C4Context
title System Context diagram for Internet Banking System
Enterprise_Boundary(b0, "BankBoundary0") {
Person(customerA, "Banking Customer A", "A customer of the bank, with personal bank accounts.")
Person(customerB, "Banking Customer B")
Person_Ext(customerC, "Banking Customer C", "desc")
Person(customerD, "Banking Customer D", "A customer of the bank, <br/> with personal bank accounts.")
System(SystemAA, "Internet Banking System", "Allows customers to view information about their bank accounts, and make payments.")
Enterprise_Boundary(b1, "BankBoundary") {
SystemDb_Ext(SystemE, "Mainframe Banking System", "Stores all of the core banking information about customers, accounts, transactions, etc.")
System_Boundary(b2, "BankBoundary2") {
System(SystemA, "Banking System A")
System(SystemB, "Banking System B", "A system of the bank, with personal bank accounts. next line.")
}
System_Ext(SystemC, "E-mail system", "The internal Microsoft Exchange e-mail system.")
SystemDb(SystemD, "Banking System D Database", "A system of the bank, with personal bank accounts.")
Boundary(b3, "BankBoundary3", "boundary") {
SystemQueue(SystemF, "Banking System F Queue", "A system of the bank.")
SystemQueue_Ext(SystemG, "Banking System G Queue", "A system of the bank, with personal bank accounts.")
}
}
}
BiRel(customerA, SystemAA, "Uses")
BiRel(SystemAA, SystemE, "Uses")
Rel(SystemAA, SystemC, "Sends e-mails", "SMTP")
Rel(SystemC, customerA, "Sends e-mails to")
</div>
<div class="mermaid">
C4Container
title Container diagram for Internet Banking System
System_Ext(email_system, "E-Mail System", "The internal Microsoft Exchange system")
Person(customer, Customer, "A customer of the bank, with personal bank accounts")
Container_Boundary(c1, "Internet Banking") {
Container(spa, "Single-Page App", "JavaScript, Angular", "Provides all the Internet banking functionality to cutomers via their web browser")
Container_Ext(mobile_app, "Mobile App", "C#, Xamarin", "Provides a limited subset of the Internet banking functionality to customers via their mobile device")
Container(web_app, "Web Application", "Java, Spring MVC", "Delivers the static content and the Internet banking SPA")
ContainerDb(database, "Database", "SQL Database", "Stores user registration information, hashed auth credentials, access logs, etc.")
ContainerDb_Ext(backend_api, "API Application", "Java, Docker Container", "Provides Internet banking functionality via API")
}
System_Ext(banking_system, "Mainframe Banking System", "Stores all of the core banking information about customers, accounts, transactions, etc.")
Rel(customer, web_app, "Uses", "HTTPS")
Rel(customer, spa, "Uses", "HTTPS")
Rel(customer, mobile_app, "Uses")
Rel(web_app, spa, "Delivers")
Rel(spa, backend_api, "Uses", "async, JSON/HTTPS")
Rel(mobile_app, backend_api, "Uses", "async, JSON/HTTPS")
Rel_Back(database, backend_api, "Reads from and writes to", "sync, JDBC")
Rel(email_system, customer, "Sends e-mails to")
Rel(backend_api, email_system, "Sends e-mails using", "sync, SMTP")
Rel(backend_api, banking_system, "Uses", "sync/async, XML/HTTPS")
</div>
<div class="mermaid">
C4Component
title Component diagram for Internet Banking System - API Application
Container(spa, "Single Page Application", "javascript and angular", "Provides all the internet banking functionality to customers via their web browser.")
Container(ma, "Mobile App", "Xamarin", "Provides a limited subset ot the internet banking functionality to customers via their mobile mobile device.")
ContainerDb(db, "Database", "Relational Database Schema", "Stores user registration information, hashed authentication credentials, access logs, etc.")
System_Ext(mbs, "Mainframe Banking System", "Stores all of the core banking information about customers, accounts, transactions, etc.")
Container_Boundary(api, "API Application") {
Component(sign, "Sign In Controller", "MVC Rest Controlle", "Allows users to sign in to the internet banking system")
Component(accounts, "Accounts Summary Controller", "MVC Rest Controller", "Provides customers with a summary of their bank accounts")
Component(security, "Security Component", "Spring Bean", "Provides functionality related to singing in, changing passwords, etc.")
Component(mbsfacade, "Mainframe Banking System Facade", "Spring Bean", "A facade onto the mainframe banking system.")
Rel(sign, security, "Uses")
Rel(accounts, mbsfacade, "Uses")
Rel(security, db, "Read & write to", "JDBC")
Rel(mbsfacade, mbs, "Uses", "XML/HTTPS")
}
Rel_Back(spa, sign, "Uses", "JSON/HTTPS")
Rel(spa, accounts, "Uses", "JSON/HTTPS")
Rel(ma, sign, "Uses", "JSON/HTTPS")
Rel(ma, accounts, "Uses", "JSON/HTTPS")
</div>
<div class="mermaid">
C4Dynamic
title Dynamic diagram for Internet Banking System - API Application
ContainerDb(c4, "Database", "Relational Database Schema", "Stores user registration information, hashed authentication credentials, access logs, etc.")
Container(c1, "Single-Page Application", "JavaScript and Angular", "Provides all of the Internet banking functionality to customers via their web browser.")
Container_Boundary(b, "API Application") {
Component(c3, "Security Component", "Spring Bean", "Provides functionality Related to signing in, changing passwords, etc.")
Component(c2, "Sign In Controller", "Spring MVC Rest Controller", "Allows users to sign in to the Internet Banking System.")
}
Rel(c1, c2, "Submits credentials to", "JSON/HTTPS")
Rel(c2, c3, "Calls isAuthenticated() on")
Rel(c3, c4, "select * from users where username = ?", "JDBC")
</div>
<div class="mermaid">
C4Deployment
title Deployment Diagram for Internet Banking System - Live
Deployment_Node(mob, "Customer's mobile device", "Apple IOS or Android"){
Container(mobile, "Mobile App", "Xamarin", "Provides a limited subset of the Internet Banking functionality to customers via their mobile device.")
}
Deployment_Node(comp, "Customer's computer", "Mircosoft Windows or Apple macOS"){
Deployment_Node(browser, "Web Browser", "Google Chrome, Mozilla Firefox,<br/> Apple Safari or Microsoft Edge"){
Container(spa, "Single Page Application", "JavaScript and Angular", "Provides all of the Internet Banking functionality to customers via their web browser.")
}
}
Deployment_Node(plc, "Big Bank plc", "Big Bank plc data center"){
Deployment_Node(dn, "bigbank-api*** x8", "Ubuntu 16.04 LTS"){
Deployment_Node(apache, "Apache Tomcat", "Apache Tomcat 8.x"){
Container(api, "API Application", "Java and Spring MVC", "Provides Internet Banking functionality via a JSON/HTTPS API.")
}
}
Deployment_Node(bb2, "bigbank-web*** x4", "Ubuntu 16.04 LTS"){
Deployment_Node(apache2, "Apache Tomcat", "Apache Tomcat 8.x"){
Container(web, "Web Application", "Java and Spring MVC", "Delivers the static content and the Internet Banking single page application.")
}
}
Deployment_Node(bigbankdb01, "bigbank-db01", "Ubuntu 16.04 LTS"){
Deployment_Node(oracle, "Oracle - Primary", "Oracle 12c"){
ContainerDb(db, "Database", "Relational Database Schema", "Stores user registration information, hashed authentication credentials, access logs, etc.")
}
}
Deployment_Node(bigbankdb02, "bigbank-db02", "Ubuntu 16.04 LTS") {
Deployment_Node(oracle2, "Oracle - Secondary", "Oracle 12c") {
ContainerDb(db2, "Database", "Relational Database Schema", "Stores user registration information, hashed authentication credentials, access logs, etc.")
}
}
}
Rel(mobile, api, "Makes API calls to", "json/HTTPS")
Rel(spa, api, "Makes API calls to", "json/HTTPS")
Rel_U(web, spa, "Delivers to the customer's web browser")
Rel(api, db, "Reads from and writes to", "JDBC")
Rel(api, db2, "Reads from and writes to", "JDBC")
Rel_R(db, db2, "Replicates data to")
</div>
<hr />
<div class="mermaid">
pie
title Key elements in Product X

View File

@ -203,7 +203,7 @@ Ensures options parameter does not attempt to override siteConfig secure keys.
| Parameter | Description |Type | Required | Values|
| --- | --- | --- | --- | --- |
| conf| base set of values, which currentConfig coul be reset to.| Dictionary | Required | Any Values, with respect to the secure Array|
| conf| base set of values, which currentConfig could be reset to.| Dictionary | Required | Any Values, with respect to the secure Array|
```note
default: current siteConfig (optional, default `getSiteConfig()`)

View File

@ -818,13 +818,13 @@ Default value: 'TB'
### entityPadding
| Parameter | Description | Type | Required | Values |
| ------------- | ----------------------------------------------------------- | ------- | -------- | ------------------ |
| entityPadding | Minimum internal padding betweentext in box and box borders | Integer | 4 | Any Positive Value |
| Parameter | Description | Type | Required | Values |
| ------------- | ------------------------------------------------------------ | ------- | -------- | ------------------ |
| entityPadding | Minimum internal padding between text in box and box borders | Integer | 4 | Any Positive Value |
**Notes:**
The minimum internal padding betweentext in an entity box and the enclosing box borders,
The minimum internal padding between text in an entity box and the enclosing box borders,
expressed in pixels.
Default value: 15
@ -902,6 +902,81 @@ available space. If set to false, the diagram reserves its absolute width.
Default value: true
## c4
The object containing configurations specific for c4 diagrams
### diagramMarginX
| Parameter | Description | Type | Required | Values |
| -------------- | ---------------------------------------------- | ------- | -------- | ------------------ |
| diagramMarginX | Margin to the right and left of the c4 diagram | Integer | Required | Any Positive Value |
**Notes:** Default value: 50
### diagramMarginY
| Parameter | Description | Type | Required | Values |
| -------------- | ------------------------------------------- | ------- | -------- | ------------------ |
| diagramMarginY | Margin to the over and under the c4 diagram | Integer | Required | Any Positive Value |
**Notes:** Default value: 10
### c4ShapeMargin
| Parameter | Description | Type | Required | Values |
| ----------- | --------------------- | ------- | -------- | ------------------ |
| shapeMargin | Margin between shapes | Integer | Required | Any Positive Value |
**Notes:** Default value: 50
### width
| Parameter | Description | Type | Required | Values |
| --------- | --------------------- | ------- | -------- | ------------------ |
| width | Width of person boxes | Integer | Required | Any Positive Value |
**Notes:** Default value: 216
### height
| Parameter | Description | Type | Required | Values |
| --------- | ---------------------- | ------- | -------- | ------------------ |
| height | Height of person boxes | Integer | Required | Any Positive Value |
**Notes:** Default value: 60
### boxMargin
| Parameter | Description | Type | Required | Values |
| --------- | ------------------------ | ------- | -------- | ------------------ |
| boxMargin | Margin around loop boxes | Integer | Required | Any Positive Value |
**Notes:** Default value: 10
### useMaxWidth
| Parameter | Description | Type | Required | Values |
| ----------- | ----------- | ------- | -------- | ----------- |
| useMaxWidth | See Notes | boolean | Required | true, false |
**Notes:** When this flag is set to true, the height and width is set to 100% and is then
scaling with the available space. If set to false, the absolute space required is used.
Default value: true
### wrap
This sets the auto-wrap state for the diagram
**Notes:** Default value: true.
### wrapPadding
This sets the auto-wrap padding for the diagram (sides only)
**Notes:** Default value: 0.
## setSiteConfig
## setSiteConfig
@ -1004,9 +1079,9 @@ Pushes in a directive to the configuration
## conf
| Parameter | Description | Type | Required | Values |
| --------- | ------------------------------------------------------------- | ---------- | -------- | -------------------------------------------- |
| conf | base set of values, which currentConfig coul be **reset** to. | Dictionary | Required | Any Values, with respect to the secure Array |
| Parameter | Description | Type | Required | Values |
| --------- | -------------------------------------------------------------- | ---------- | -------- | -------------------------------------------- |
| conf | base set of values, which currentConfig could be **reset** to. | Dictionary | Required | Any Values, with respect to the secure Array |
**Notes**: (default: current siteConfig ) (optional, default `getSiteConfig()`)

View File

@ -15,6 +15,7 @@
- [Pie Chart](pie.md)
- [Requirement Diagram](requirementDiagram.md)
- [Gitgraph (Git) Diagram 🔥](gitgraph.md)
- [C4C Diagram (Context) Diagram 🦺⚠️](c4c.md)
- [Other Examples](examples.md)
- ⚙️ Deployment and Configuration

46
docs/c4c.md Normal file
View File

@ -0,0 +1,46 @@
# C4C Diagrams
**Edit this Page** [![N|Solid](img/GitHub-Mark-32px.png)](https://github.com/mermaid-js/mermaid/blob/develop/docs/gitgraph.md)
> C4 Diagram: This is an experimental diagram for now. The syntax and properties can change in future releases. Proper documentation will be provided when the syntax is stable.
Mermaid's c4 diagram sytax is compatible with plantUML. See example below:
```mermaid-example
C4Context
title System Context diagram for Internet Banking System
Person(customerA, "Banking Customer A", "A customer of the bank, with personal bank accounts.")
Person(customerB, "Banking Customer B")
Person_Ext(customerC, "Banking Customer C")
System(SystemAA, "Internet Banking System", "Allows customers to view information about their bank accounts, and make payments.")
Person(customerD, "Banking Customer D", "A customer of the bank, <br/> with personal bank accounts.")
Enterprise_Boundary(b1, "BankBoundary") {
SystemDb_Ext(SystemE, "Mainframe Banking System", "Stores all of the core banking information about customers, accounts, transactions, etc.")
System_Boundary(b2, "BankBoundary2") {
System(SystemA, "Banking System A")
System(SystemB, "Banking System B", "A system of the bank, with personal bank accounts.")
}
System_Ext(SystemC, "E-mail system", "The internal Microsoft Exchange e-mail system.")
SystemDb(SystemD, "Banking System D Database", "A system of the bank, with personal bank accounts.")
Boundary(b3, "BankBoundary3", "boundary") {
SystemQueue(SystemF, "Banking System F Queue", "A system of the bank, with personal bank accounts.")
SystemQueue_Ext(SystemG, "Banking System G Queue", "A system of the bank, with personal bank accounts.")
}
}
BiRel(customerA, SystemAA, "Uses")
BiRel(SystemAA, SystemE, "Uses")
Rel(SystemAA, SystemC, "Sends e-mails", "SMTP")
Rel(SystemC, customerA, "Sends e-mails to")
```

View File

@ -384,9 +384,9 @@ _URL Link:_
```mmd
classDiagram
class Shape
link Shape "http://www.github.com" "This is a tooltip for a link"
link Shape "https://www.github.com" "This is a tooltip for a link"
class Shape2
click Shape2 href "http://www.github.com" "This is a tooltip for a link"
click Shape2 href "https://www.github.com" "This is a tooltip for a link"
```
_Callback:_
@ -412,11 +412,11 @@ classDiagram
class Class01
class Class02
callback Class01 "callbackFunction" "Callback tooltip"
link Class02 "http://www.github.com" "This is a link"
link Class02 "https://www.github.com" "This is a link"
class Class03
class Class04
click Class03 call callbackFunction() "Callback tooltip"
click Class04 href "http://www.github.com" "This is a link"
click Class04 href "https://www.github.com" "This is a link"
```
> **Success** The tooltip functionality and the ability to link to urls are available from version 0.5.2.
@ -449,7 +449,7 @@ Beginners tip, a full example using interactive links in an html context:
}
callback Duck callback "Tooltip"
link Zebra "http://www.github.com" "This is a link"
link Zebra "https://www.github.com" "This is a link"
</div>
<script>

View File

@ -1,9 +1,9 @@
# Configuration
When mermaid starts configuration is extracted to a configuration to be used for a diagram. There a 3 sources for configuration:
When mermaid starts configuration is extracted to a configuration to be used for a diagram. There are 3 sources for configuration:
* The default configuration
* Overrides on the site level, set is set by the initialize call and will be applied for all diagrams in the site/app. The term for this is the **siteConfig**.
* Overrides on the site level is set by the initialize call and will be applied to all diagrams in the site/app. The term for this is the **siteConfig**.
* Directives - diagram authors can update select configuration parameters directly in the diagram code via directives and these are applied to the render config.
**The render config** is configuration that is used when rendering by applying these configurations.

View File

@ -1,134 +1,135 @@
# Development and Contribution 🙌
So you want to help? That's great!
![Image of happy people jumping with excitement](https://media.giphy.com/media/BlVnrxJgTGsUw/giphy.gif)
Here are a few things to know to get you started on the right path.
**The Docs Structure is dictated by [sidebar.md](https://github.com/mermaid-js/mermaid/edit/develop/docs/_sidebar.md)**
**Note: Commits and Pull Requests should be directed to the develop branch.**
## Branching
Mermaid uses a [Git Flow](https://guides.github.com/introduction/flow/)inspired approach to branching. So development is done in the `develop` branch.
Once development is done we branch a `release` branch from `develop` for testing.
Once the release happens we merge the `release` branch with `master` and kill the `release` branch.
This means that **you should branch off your pull request from develop** and direct all Pull Requests to it.
## Contributing Code
We make all changes via Pull Requests. As we have many Pull Requests from developers new to mermaid, we have put in place a process, wherein *knsv, Knut Sveidqvist* is the primary reviewer of changes and merging pull requests. The process is as follows:
* Large changes reviewed by knsv or other developer asked to review by knsv
* Smaller, low-risk changes like dependencies, documentation, etc. can be merged by active collaborators
* Documentation (we encourage updates to the docs folder; you can submit them via direct commits)
When you commit code, create a branch with the following naming convention:
Start with the type, such as **feature** or **bug**, followed by the issue number for reference, and a text that describes the issue.
**One example:**
`feature/945_state_diagrams`
**Another example:**
`bug/123_nasty_bug_branch`
## Contributing to Documentation
If it is not in the documentation, it's like it never happened. Wouldn't that be sad? With all the effort that was put into the feature?
The docs are located in the `docs` folder and are written in Markdown. Just pick the right section and start typing. If you want to propose changes to the structure of the documentation, such as adding a new section or a new file you do that via the **[sidebar](https://github.com/mermaid-js/mermaid/edit/develop/docs/_sidebar.md)**.
> **All the documents displayed in the github.io page are listed in [sidebar.md](https://github.com/mermaid-js/mermaid/edit/develop/docs/_sidebar.md)**.
The contents of [https://mermaid-js.github.io/mermaid/](https://mermaid-js.github.io/mermaid/) are based on the docs from the `master` branch. Updates committed to the `master` branch are reflected in the [Mermaid Docs](https://mermaid-js.github.io/mermaid/) once released.
## How to Contribute to Documentation
We are a little less strict here, it is OK to commit directly in the `develop` branch if you are a collaborator.
The documentation is located in the `docs` directory and organized according to relevant subfolder.
We encourage contributions to the documentation at [mermaid-js/mermaid/docs](https://github.com/mermaid-js/mermaid/tree/develop/docs). We publish documentation using GitHub Pages with [Docsify](https://www.youtube.com/watch?v=TV88lp7egMw&t=3s)
### Add Unit Tests for Parsing
This is important so that, if someone that does not know about this great feature suggests a change to the grammar, they get notified early on when that change breaks the parser. Another important aspect is that, without proper parsing, tests refactoring is pretty much impossible.
### Add E2E Tests
This tests the rendering and visual apearance of the diagrams. This ensures that the rendering of that feature in the e2e will be reviewed in the release process going forward. Less chance that it breaks!
To start working with the e2e tests:
1. Run `yarn dev` to start the dev server
2. Start **Cypress** by running `cypress open` in the **mermaid** folder.
(Make sure you have path to Cypress in order, the binary is located in `node_modules/.bin`).
The rendering tests are very straightforward to create. There is a function `imgSnapshotTest`, which takes a diagram in text form and the mermaid options, and it renders that diagram in Cypress.
When running in CI it will take a snapshot of the rendered diagram and compare it with the snapshot from last build and flag it for review if it differs.
This is what a rendering test looks like:
```js
it('should render forks and joins', () => {
imgSnapshotTest(
`
stateDiagram
state fork_state &lt;&lt;fork&gt;&gt;
[*] --> fork_state
fork_state --> State2
fork_state --> State3
state join_state &lt;&lt;join&gt;&gt;
State2 --> join_state
State3 --> join_state
join_state --> State4
State4 --> [*]
`,
{ logLevel: 0 }
);
cy.get('svg');
});
```
### Any Questions or Suggestions?
After logging in at [GitHub.com](https://www.github.com), open or append to an issue [using the GitHub issue tracker of the mermaid-js repository](https://github.com/mermaid-js/mermaid/issues?q=is%3Aissue+is%3Aopen+label%3A%22Area%3A+Documentation%22).
### How to Contribute a Suggestion
Markdown is used to format the text, for more information about Markdown [see the GitHub Markdown help page](https://help.github.com/en/github/writing-on-github/basic-writing-and-formatting-syntax).
To edit Docs on your computer:
1. Find the Markdown file (.md) to edit in the [mermaid-js/mermaid/docs](https://github.com/mermaid-js/mermaid/tree/develop/docs) directory in the `develop` branch.
2. Create a fork of the develop branch.
3. Make changes or add new documentation.
4. Commit changes to your fork and push it to GitHub.
5. Create a Pull Request of your fork.
To edit Docs on GitHub:
1. Login to [GitHub.com](https://www.github.com).
2. Navigate to [mermaid-js/mermaid/docs](https://github.com/mermaid-js/mermaid/tree/develop/docs).
3. To edit a file, click the pencil icon at the top-right of the file contents panel.
4. Describe what you changed in the **Propose file change** section, located at the bottom of the page.
5. Submit your changes by clicking the button **Propose file change** at the bottom (by automatic creation of a fork and a new branch).
6. Create a Pull Request of your newly forked branch by clicking the green **Create Pull Request** button.
## Last Words
Don't get daunted if it is hard in the beginning. We have a great community with only encouraging words. So, if you get stuck, ask for help and hints in the Slack forum. If you want to show off something good, show it off there.
[Join our Slack community if you want closer contact!](https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE)
![Image of superhero wishing you good luck](https://media.giphy.com/media/l49JHz7kJvl6MCj3G/giphy.gif)
# Development and Contribution 🙌
So you want to help? That's great!
![Image of happy people jumping with excitement](https://media.giphy.com/media/BlVnrxJgTGsUw/giphy.gif)
Here are a few things to know to get you started on the right path.
**The Docs Structure is dictated by [sidebar.md](https://github.com/mermaid-js/mermaid/edit/develop/docs/_sidebar.md)**
**Note: Commits and Pull Requests should be directed to the develop branch.**
## Branching
Mermaid uses a [Git Flow](https://guides.github.com/introduction/flow/)inspired approach to branching. So development is done in the `develop` branch.
Once development is done we branch a `release` branch from `develop` for testing.
Once the release happens we merge the `release` branch with `master` and kill the `release` branch.
This means that **you should branch off your pull request from develop** and direct all Pull Requests to it.
## Contributing Code
We make all changes via Pull Requests. As we have many Pull Requests from developers new to mermaid, we have put in place a process, wherein *knsv, Knut Sveidqvist* is the primary reviewer of changes and merging pull requests. The process is as follows:
* Large changes reviewed by knsv or other developer asked to review by knsv
* Smaller, low-risk changes like dependencies, documentation, etc. can be merged by active collaborators
* Documentation (we encourage updates to the docs folder; you can submit them via direct commits)
When you commit code, create a branch with the following naming convention:
Start with the type, such as **feature** or **bug**, followed by the issue number for reference, and a text that describes the issue.
**One example:**
`feature/945_state_diagrams`
**Another example:**
`bug/123_nasty_bug_branch`
## Contributing to Documentation
If it is not in the documentation, it's like it never happened. Wouldn't that be sad? With all the effort that was put into the feature?
The docs are located in the `docs` folder and are written in Markdown. Just pick the right section and start typing. If you want to propose changes to the structure of the documentation, such as adding a new section or a new file you do that via the **[sidebar](https://github.com/mermaid-js/mermaid/edit/develop/docs/_sidebar.md)**.
> **All the documents displayed in the github.io page are listed in [sidebar.md](https://github.com/mermaid-js/mermaid/edit/develop/docs/_sidebar.md)**.
The contents of [https://mermaid-js.github.io/mermaid/](https://mermaid-js.github.io/mermaid/) are based on the docs from the `master` branch. Updates committed to the `master` branch are reflected in the [Mermaid Docs](https://mermaid-js.github.io/mermaid/) once released.
## How to Contribute to Documentation
We are a little less strict here, it is OK to commit directly in the `develop` branch if you are a collaborator.
The documentation is located in the `docs` directory and organized according to relevant subfolder.
We encourage contributions to the documentation at [mermaid-js/mermaid/docs](https://github.com/mermaid-js/mermaid/tree/develop/docs). We publish documentation using GitHub Pages with [Docsify](https://www.youtube.com/watch?v=TV88lp7egMw&t=3s)
### Add Unit Tests for Parsing
This is important so that, if someone that does not know about this great feature suggests a change to the grammar, they get notified early on when that change breaks the parser. Another important aspect is that, without proper parsing, tests refactoring is pretty much impossible.
### Add E2E Tests
This tests the rendering and visual appearance of the diagrams. This ensures that the rendering of that feature in the e2e will be reviewed in the release process going forward. Less chance that it breaks!
To start working with the e2e tests:
1. Run `yarn dev` to start the dev server
2. Start **Cypress** by running `cypress open` in the **mermaid** folder.
(Make sure you have path to Cypress in order, the binary is located in `node_modules/.bin`).
The rendering tests are very straightforward to create. There is a function `imgSnapshotTest`, which takes a diagram in text form and the mermaid options, and it renders that diagram in Cypress.
When running in CI it will take a snapshot of the rendered diagram and compare it with the snapshot from last build and flag it for review if it differs.
This is what a rendering test looks like:
```js
it('should render forks and joins', () => {
imgSnapshotTest(
`
stateDiagram
state fork_state &lt;&lt;fork&gt;&gt;
[*] --> fork_state
fork_state --> State2
fork_state --> State3
state join_state &lt;&lt;join&gt;&gt;
State2 --> join_state
State3 --> join_state
join_state --> State4
State4 --> [*]
`,
{ logLevel: 0 }
);
cy.get('svg');
});
```
### Any Questions or Suggestions?
After logging in at [GitHub.com](https://www.github.com), open or append to an issue [using the GitHub issue tracker of the mermaid-js repository](https://github.com/mermaid-js/mermaid/issues?q=is%3Aissue+is%3Aopen+label%3A%22Area%3A+Documentation%22).
### How to Contribute a Suggestion
Markdown is used to format the text, for more information about Markdown [see the GitHub Markdown help page](https://help.github.com/en/github/writing-on-github/basic-writing-and-formatting-syntax).
To edit Docs on your computer:
1. Find the Markdown file (.md) to edit in the [mermaid-js/mermaid/docs](https://github.com/mermaid-js/mermaid/tree/develop/docs) directory in the `develop` branch.
2. Create a fork of the develop branch.
3. Make changes or add new documentation.
4. Commit changes to your fork and push it to GitHub.
5. Create a Pull Request of your fork.
To edit Docs on GitHub:
1. Login to [GitHub.com](https://www.github.com).
2. Navigate to [mermaid-js/mermaid/docs](https://github.com/mermaid-js/mermaid/tree/develop/docs).
3. To edit a file, click the pencil icon at the top-right of the file contents panel.
4. Describe what you changed in the **Propose file change** section, located at the bottom of the page.
5. Submit your changes by clicking the button **Propose file change** at the bottom (by automatic creation of a fork and a new branch).
6. Create a Pull Request of your newly forked branch by clicking the green **Create Pull Request** button.
## Last Words
Don't get daunted if it is hard in the beginning. We have a great community with only encouraging words. So, if you get stuck, ask for help and hints in the Slack forum. If you want to show off something good, show it off there.
[Join our Slack community if you want closer contact!](https://join.slack.com/t/mermaid-talk/shared_invite/enQtNzc4NDIyNzk4OTAyLWVhYjQxOTI2OTg4YmE1ZmJkY2Y4MTU3ODliYmIwOTY3NDJlYjA0YjIyZTdkMDMyZTUwOGI0NjEzYmEwODcwOTE)
![Image of superhero wishing you good luck](https://media.giphy.com/media/l49JHz7kJvl6MCj3G/giphy.gif)

View File

@ -428,9 +428,9 @@ graph LR;
B-->C;
C-->D;
click A callback "Tooltip for a callback"
click B "http://www.github.com" "This is a tooltip for a link"
click B "https://www.github.com" "This is a tooltip for a link"
click A call callback() "Tooltip for a callback"
click B href "http://www.github.com" "This is a tooltip for a link"
click B href "https://www.github.com" "This is a tooltip for a link"
```
> **Success** The tooltip functionality and the ability to link to urls are available from version 0.5.2.
@ -443,10 +443,10 @@ graph LR;
B-->C;
C-->D;
D-->E;
click A "http://www.github.com" _blank
click B "http://www.github.com" "Open this in a new tab" _blank
click C href "http://www.github.com" _blank
click D href "http://www.github.com" "Open this in a new tab" _blank
click A "https://www.github.com" _blank
click B "https://www.github.com" "Open this in a new tab" _blank
click C href "https://www.github.com" _blank
click D href "https://www.github.com" "Open this in a new tab" _blank
```
Beginners tip, a full example using interactive links in a html context:
@ -459,9 +459,9 @@ Beginners tip, a full example using interactive links in a html context:
B-->C;
C-->D;
click A callback "Tooltip"
click B "http://www.github.com" "This is a link"
click B "https://www.github.com" "This is a link"
click C call callback() "Tooltip"
click D href "http://www.github.com" "This is a link"
click D href "https://www.github.com" "This is a link"
</div>
<script>

View File

@ -5,9 +5,9 @@
## Directives
Directives gives a diagram author the capability to alter the appearance of a diagram before rendering by changing the applied configuration.
The significance of having directives is that you have them available while writing the diagram, and can modify the defualt global and diagram specific configurations. So, directives are applied on top of the default configurations. The beauty of directives is that you can use them to alter configuration settings for a specific diagram, i.e. at an individual level.
The significance of having directives is that you have them available while writing the diagram, and can modify the default global and diagram specific configurations. So, directives are applied on top of the default configurations. The beauty of directives is that you can use them to alter configuration settings for a specific diagram, i.e. at an individual level.
While directives allow you to change most of the default configuation settings, there are some that are not available, that too for security reasons. Also, you do have the *option to define the set of configurations* that you would allow to be available to the diagram author for overriding with help of directives.
While directives allow you to change most of the default configuration settings, there are some that are not available, that too for security reasons. Also, you do have the *option to define the set of configurations* that you would allow to be available to the diagram author for overriding with help of directives.
## Types of Directives options
Mermaid basically supports two types of configuration options to be overridden by directives.
@ -21,7 +21,7 @@ Mermaid basically supports two types of configuration options to be overridden b
2) *Diagram specific configurations* : These are the configurations that are available and applied to a specific diagram. For each diagram there are specific configuration that will alter how that particular diagram looks and behaves.
For example, `mirrroActors` is a configuration that is specific to the `SequenceDiagram` and alter whether the actors are mirrored or not. So this config is available only for the `SequenceDiagram` type.
For example, `mirrorActors` is a configuration that is specific to the `SequenceDiagram` and alter whether the actors are mirrored or not. So this config is available only for the `SequenceDiagram` type.
**NOTE:** These options listed here are not all the configuration options. To get hold of all the configuration options, please refer to the [defaultConfig.js](https://github.com/mermaid-js/mermaid/blob/develop/src/defaultConfig.js) in the source code.
```
@ -173,7 +173,7 @@ Some common flowchart configurations are:
- *useMaxWidth*: number
For complete list of flowchart configurations, see [defaultConfig.js](https://github.com/mermaid-js/mermaid/blob/develop/src/defaultConfig.js) in the source code.
*Soon we plan to publis a complete list all diagram specific configurations updated in the docs*
*Soon we plan to publish a complete list all diagram specific configurations updated in the docs*
The following code snippet changes flowchart config:
@ -196,15 +196,15 @@ A --> C[End]
Some common sequence configurations are:
- *width*: number
- *height*: number
- *messgageAlign*: left, center, right
- *messageAlign*: left, center, right
- *mirrorActors*: boolean
- *useMaxWidth*: boolean
- *rightAngles*: boolean
- *showSequenceNumbers*: boolean
- *wrap*: boolean
For complete list of sequeue diagram configurations, see *defaultConfig.js* in the source code.
*Soon we plan to publis a complete list all diagram specific configurations updated in the docs*
For complete list of sequence diagram configurations, see *defaultConfig.js* in the source code.
*Soon we plan to publish a complete list all diagram specific configurations updated in the docs*
So, `wrap` by default has a value of `false` for sequence diagrams.
@ -214,12 +214,12 @@ Let us see an example:
sequenceDiagram
Alice->Bob: Hello Bob, how are you?
Bob->Alice: Fine, How did you mother like the book I suggested? And did you catch with the new book about alien invansion?
Bob->Alice: Fine, How did you mother like the book I suggested? And did you catch with the new book about alien invasion?
Alice->Bob: Good.
Bob->Alice: Cool
```
Now let us enble wrap for sequence diagrams.
Now let us enable wrap for sequence diagrams.
The following code snippet changes sequence diagram config for `wrap` to `true`:
@ -232,7 +232,7 @@ Using in the diagram above, the wrap will be enabled.
%%{init: { "sequence": { "wrap": true, "width":300 } } }%%
sequenceDiagram
Alice->Bob: Hello Bob, how are you?
Bob->Alice: Fine, How did you mother like the book I suggested? And did you catch with the new book about alien invansion?
Bob->Alice: Fine, How did you mother like the book I suggested? And did you catch with the new book about alien invasion?
Alice->Bob: Good.
Bob->Alice: Cool
```

View File

@ -449,9 +449,9 @@ flowchart LR
B-->C
C-->D
click A callback "Tooltip for a callback"
click B "http://www.github.com" "This is a tooltip for a link"
click B "https://www.github.com" "This is a tooltip for a link"
click A call callback() "Tooltip for a callback"
click B href "http://www.github.com" "This is a tooltip for a link"
click B href "https://www.github.com" "This is a tooltip for a link"
```
> **Success** The tooltip functionality and the ability to link to urls are available from version 0.5.2.
@ -465,10 +465,10 @@ flowchart LR
B-->C
C-->D
D-->E
click A "http://www.github.com" _blank
click B "http://www.github.com" "Open this in a new tab" _blank
click C href "http://www.github.com" _blank
click D href "http://www.github.com" "Open this in a new tab" _blank
click A "https://www.github.com" _blank
click B "https://www.github.com" "Open this in a new tab" _blank
click C href "https://www.github.com" _blank
click D href "https://www.github.com" "Open this in a new tab" _blank
```
Beginners tip, a full example using interactive links in a html context:
@ -480,9 +480,9 @@ Beginners tip, a full example using interactive links in a html context:
B-->C
C-->D
click A callback "Tooltip"
click B "http://www.github.com" "This is a link"
click B "https://www.github.com" "This is a link"
click C call callback() "Tooltip"
click D href "http://www.github.com" "This is a link"
click D href "https://www.github.com" "This is a link"
</div>
<script>
@ -515,8 +515,8 @@ flowchart LR
It is possible to style links. For instance you might want to style a link that is going backwards in the flow. As links
have no ids in the same way as nodes, some other way of deciding what style the links should be attached to is required.
Instead of ids, the order number of when the link was defined in the graph is used. In the example below the style
defined in the linkStyle statement will belong to the fourth link in the graph:
Instead of ids, the order number of when the link was defined in the graph is used, or use default to apply to all links.
In the example below the style defined in the linkStyle statement will belong to the fourth link in the graph:
```
linkStyle 3 stroke:#ff3,stroke-width:4px,color:red;

View File

@ -136,7 +136,7 @@ SSS 0..999 Thousandths of a second
Z ZZ +12:00 Offset from UTC as +-HH:mm, +-HHmm, or Z
```
More info in: http://momentjs.com/docs/#/parsing/string-format/
More info in: https://momentjs.com/docs/#/parsing/string-format/
### Output date format on the axis

View File

@ -182,12 +182,43 @@ After this we made use of the `checkout` keyword to set the current branch as `m
After this we merge the `develop` branch onto the current branch `main`, resulting in a merge commit.
Since the current branch at this point is still `main`, the last two commits are registered against that.
### Cherry Pick commit from another branch
Similar to how 'git' allows you to cherry pick a commit from **another branch** onto the **current** branch, Mermaid also suports this functionality. You can also cherry pick a commit from another branch using the `cherry-pick` keyword.
To use the `cherry-pick` keyword, you must specify the id using the `id` attribute, followed by `:` and your desired commit id within `""` quote. For example:
`cherry-pick id: "your_custom_id"`
Here, a new commt representing the cherry pick is created on the current branch, and is visually highlighted in the diagram with a **cherry** and a tag depicting the commit id from which it is cherry picked from.
Few Important rules to note here are:
1. You need to provide the `id` for an existing commit to be cherry picked. If given commit id does not exist it will result in an error. For this make use of the `commit id:$value` format of declaring commits. See the examples from above.
2. The given commit must not exist on the current branch. Cherry picked commit must always be a different branch than the current branch.
3. Current branch must have atleast one commit, before you can cherry pick a commit, otherwise it will case an error is throw.
Let see an example:
```mermaid-example
gitGraph
commit id: "ZERO"
branch develop
commit id:"A"
checkout main
commit id:"ONE"
checkout develop
commit id:"B"
checkout main
commit id:"TWO"
cherry-pick id:"A"
commit id:"THREE"
checkout develop
commit id:"C"
```
## Gitgraph specific configuration options
In Mermaid, you have the option to configure the gitgraph diagram. You can configure the following options:
- `showBranches` : Boolean, default is `true`. If set to `false`, the branches are not shown in the diagram.
- `showCommitLabel` : Boolean, default is `true`. If set to `false`, the commit labels are not shown in the diagram.
- `mainBranchName` : String, default is `main`. The name of the default/root branch.
- `mainBranchOrder` : Position of the main branch in the list of branches. default is `0`, meanig, by default `main` branch is the first in the order.
- `mainBranchOrder` : Position of the main branch in the list of branches. default is `0`, meaning, by default `main` branch is the first in the order.
Let's look at them one by one.
## Hiding Branch names and lines
@ -240,6 +271,55 @@ Usage example:
merge release
```
## Commit labels Layout: Rotated or Horizontal
Mermaid supports two types of commit labels layout. The default layout is **rotated**, which means the labels are placed below the commit circle, rotated at 45 degress for better readability. This is particularly useful for commits with long labels.
The other option is **horizontal**, which means the labels are placed below the commit circle centred horizontally, and are not rotated. This is particularly useful for commits with short labels.
You can change the layout of the commit labels by using the `rotateCommitLabel` keyword in the directive. It defaults to `true`, which means the commit labels are rotated.
Usage example: Rotated commit labels
```mermaid-example
%%{init: { 'logLevel': 'debug', 'theme': 'base', 'gitGraph': {'rotateCommitLabel': true}} }%%
gitGraph
commit id: "feat(api): ..."
commit id: "a"
commit id: "b"
commit id: "fix(client): .extra long label.."
branch c2
commit id: "feat(modules): ..."
commit id: "test(client): ..."
checkout main
commit id: "fix(api): ..."
commit id: "ci: ..."
branch b1
commit
branch b2
commit
```
Usage example: Horizontal commit labels
```mermaid-example
%%{init: { 'logLevel': 'debug', 'theme': 'base', 'gitGraph': {'rotateCommitLabel': false}} }%%
gitGraph
commit id: "feat(api): ..."
commit id: "a"
commit id: "b"
commit id: "fix(client): .extra long label.."
branch c2
commit id: "feat(modules): ..."
commit id: "test(client): ..."
checkout main
commit id: "fix(api): ..."
commit id: "ci: ..."
branch b1
commit
branch b2
commit
```
## Hiding commit labels
Sometimes you may want to hide the commit labels from the diagram. You can do this by using the `showCommitLabel` keyword. By default its value is `true`. You can set it to `false` using directives.
@ -321,11 +401,11 @@ Usage example:
Look at the imaginary railroad map created using Mermaid. Here, we have changed the default main branch name to `MetroLine1`.
## Customizing branch ordering
In Mermaid, by default the branches are shown in the order of their defintion or appearance in the diagram code.
In Mermaid, by default the branches are shown in the order of their definition or appearance in the diagram code.
Sometimes you may want to customize the order of the branches. You can do this by using the `order` keyword next the branch definiton. You can set it to a positive number.
Sometimes you may want to customize the order of the branches. You can do this by using the `order` keyword next the branch definition. You can set it to a positive number.
Mermaid follows the given precendence order of the `order` keyword.
Mermaid follows the given precedence order of the `order` keyword.
- Main branch is always shown first as it has default order value of `0`. (unless its order is modified and changed from `0` using the `mainBranchOrder` keyword in the config)
- Next, All branches without an `order` are shown in the order of their appearance in the diagram code.
- Next, All branches with an `order` are shown in the order of their `order` value.
@ -357,11 +437,11 @@ Usage example:
```
Look at the diagram, here, all the branches without a specified order are drawn in their order of definition.
Then, `test4` branch is drawn becuase the order of `1`.
Then, `main` branch is drawn becuase the order of `2`.
And, lastly `test1`is drawn becuase the order of `3`.
Then, `test4` branch is drawn because the order of `1`.
Then, `main` branch is drawn because the order of `2`.
And, lastly `test1`is drawn because the order of `3`.
NOTE: Becuase we have overriden the `mainBranchOrder` to `2`, the `main` branch is not drawn in the begining, instead follows the ordering.
NOTE: Because we have overridden the `mainBranchOrder` to `2`, the `main` branch is not drawn in the beginning, instead follows the ordering.
@ -641,7 +721,7 @@ See how the default theme is used to set the colors for the branches:
commit
```
> #### IMPORTANT:
> Mermaid supports the theme variables to override the default values for **upto 8 branches**, i.e., you can set the color/styling of upto 8 branches using theme variables. After this threshold of 8 branches, the theme variables are reused in the cyclic manner, i.e. 9th branch will use the color/styling of 1st branch, or branch at index postion '8' will use the color/styling of branch at index position '0'.
> Mermaid supports the theme variables to override the default values for **up to 8 branches**, i.e., you can set the color/styling of up to 8 branches using theme variables. After this threshold of 8 branches, the theme variables are reused in the cyclic manner, i.e. 9th branch will use the color/styling of 1st branch, or branch at index position '8' will use the color/styling of branch at index position '0'.
*More on this in the next section. See examples on **Customizing branch label colors** below*
### Customizing branch colors
You can customize the branch colors using the `git0` to `git7` theme variables. Mermaid allows you to set the colors for up-to 8 branches, where `git0` variable will drive the value of the first branch, `git1` will drive the value of the second branch and so on.

View File

@ -17,7 +17,7 @@
/>
<!-- <link rel="stylesheet" href="//unpkg.com/docsify/lib/themes/vue.css"> -->
<link rel="stylesheet" href="theme.css" />
<script src="//cdn.jsdelivr.net/npm/mermaid@9.1.1/dist/mermaid.min.js"></script>
<script src="//cdn.jsdelivr.net/npm/mermaid@9.1.2/dist/mermaid.min.js"></script>
<!-- <script src="http://localhost:9000/mermaid.js"></script> -->
<script>
// prettier-ignore

View File

@ -17,7 +17,7 @@ They also serve as proof of concept, for the variety of things that can be built
- [Joplin](https://joplinapp.org) (**Native support**)
- [Notion](https://notion.so) (**Native support**)
- [Observable](https://observablehq.com/@observablehq/mermaid) (**Native support**)
- [GitBook](http://gitbook.com)
- [GitBook](https://gitbook.com)
- [Mermaid Plugin](https://github.com/JozoVilcek/gitbook-plugin-mermaid)
- [Markdown with Mermaid CLI](https://github.com/miao1007/gitbook-plugin-mermaid-cli)
- [Mermaid plugin for GitBook](https://github.com/wwformat/gitbook-plugin-mermaid-pdf)
@ -33,7 +33,7 @@ They also serve as proof of concept, for the variety of things that can be built
## CRM/ERP/Similar
- [coreBOS](http://blog.corebos.org/blog/december2019)
- [coreBOS](https://blog.corebos.org/blog/december2019)
## Blogs
@ -104,18 +104,18 @@ They also serve as proof of concept, for the variety of things that can be built
- [Language Mermaid Syntax Highlighter](https://atom.io/packages/language-mermaid)
- [Sublime Text 3](https://sublimetext.com)
- [Mermaid Package](https://packagecontrol.io/packages/Mermaid)
- [Astah](http://astah.net)
- [Astah](https://astah.net)
- [Export to Mermaid](https://github.com/Avens666/Astah_Jude_UML_export_to_Markdown-mermaid-Plantuml-)
- [Light Table](http://lighttable.com/)
- [Mermaid Plugin](https://github.com/cldwalker/Mermaid)
- [Draw.io](http://draw.io) - [Plugin](https://github.com/nopeslide/drawio_mermaid_plugin)
- [Inkdrop](http://inkdrop.app) - [Plugin](https://github.com/inkdropapp/inkdrop-mermaid)
- [Draw.io](https://draw.io) - [Plugin](https://github.com/nopeslide/drawio_mermaid_plugin)
- [Inkdrop](https://www.inkdrop.app) - [Plugin](https://github.com/inkdropapp/inkdrop-mermaid)
- [Vim](https://vim.org)
- [Vim Diagram Syntax](https://github.com/zhaozg/vim-diagram)
- [GNU Emacs](https://www.gnu.org/software/emacs/)
- [Major mode for .mmd files](https://github.com/abrochard/mermaid-mode)
- [Org-Mode integration](https://github.com/arnm/ob-mermaid)
- [Brackets](http://brackets.io/)
- [Brackets](https://brackets.io/)
- [Mermaid Preview](https://s3.amazonaws.com/extend.brackets/alanhohn.mermaid-preview/alanhohn.mermaid-preview-1.0.2.zip)
- [Iodide](https://github.com/iodide-project/iodide)
- [iodide-mermaid-plugin](https://github.com/iodide-project/iodide-mermaid-plugin)

View File

@ -15,7 +15,7 @@ They also serve as proof of concept, for the variety of things that can be built
- [GitHub](https://github.com)
- [GitHub action: Compile mermaid to image](https://github.com/neenjaw/compile-mermaid-markdown-action)
- [svg-generator](https://github.com/SimonKenyonShepard/mermaidjs-github-svg-generator)
- [GitBook](http://gitbook.com)
- [GitBook](https://gitbook.com)
- [Mermaid Plugin](https://github.com/JozoVilcek/gitbook-plugin-mermaid)
- [Markdown with Mermaid CLI](https://github.com/miao1007/gitbook-plugin-mermaid-cli)
- [Mermaid plugin for GitBook](https://github.com/wwformat/gitbook-plugin-mermaid-pdf)
@ -30,7 +30,7 @@ They also serve as proof of concept, for the variety of things that can be built
## CRM/ERP/Similar
- [coreBOS](http://blog.corebos.org/blog/december2019)
- [coreBOS](https://blog.corebos.org/blog/december2019)
## Blogs
@ -101,18 +101,18 @@ They also serve as proof of concept, for the variety of things that can be built
- [Language Mermaid Syntax Highlighter](https://atom.io/packages/language-mermaid)
- [Sublime Text 3](https://sublimetext.com)
- [Mermaid Package](https://packagecontrol.io/packages/Mermaid)
- [Astah](http://astah.net)
- [Astah](https://astah.net)
- [Export to Mermaid](https://github.com/Avens666/Astah_Jude_UML_export_to_Markdown-mermaid-Plantuml-)
- [Light Table](http://lighttable.com/)
- [Mermaid Plugin](https://github.com/cldwalker/Mermaid)
- [Draw.io](http://draw.io) - [Plugin](https://github.com/nopeslide/drawio_mermaid_plugin)
- [Inkdrop](http://inkdrop.app) - [Plugin](https://github.com/inkdropapp/inkdrop-mermaid)
- [Draw.io](https://draw.io) - [Plugin](https://github.com/nopeslide/drawio_mermaid_plugin)
- [Inkdrop](https://www.inkdrop.app) - [Plugin](https://github.com/inkdropapp/inkdrop-mermaid)
- [Vim](https://vim.org)
- [Vim Diagram Syntax](https://github.com/zhaozg/vim-diagram)
- [GNU Emacs](https://www.gnu.org/software/emacs/)
- [Major mode for .mmd files](https://github.com/abrochard/mermaid-mode)
- [Org-Mode integration](https://github.com/arnm/ob-mermaid)
- [Brackets](http://brackets.io/)
- [Brackets](https://brackets.io/)
- [Mermaid Preview](https://s3.amazonaws.com/extend.brackets/alanhohn.mermaid-preview/alanhohn.mermaid-preview-1.0.2.zip)
- [Iodide](https://github.com/iodide-project/iodide)
- [iodide-mermaid-plugin](https://github.com/iodide-project/iodide-mermaid-plugin)

View File

@ -52,7 +52,7 @@ parser.yy = db
### Step 2: Rendering
Write a renderer that given the data found during parsing renders the diagram. To look at an example look at sequendeRenderer.js rather then the flowchart renderer as this is a more generic example.
Write a renderer that given the data found during parsing renders the diagram. To look at an example look at sequenceRenderer.js rather then the flowchart renderer as this is a more generic example.
Place the renderer in the diagram folder.

View File

@ -1,6 +1,6 @@
{
"name": "mermaid",
"version": "9.1.1",
"version": "9.1.2",
"description": "Markdownish syntax for generating flowcharts, sequence diagrams, class diagrams, gantt charts and git graphs.",
"main": "dist/mermaid.core.js",
"module": "dist/mermaid.esm.min.mjs",
@ -99,7 +99,7 @@
"jest-environment-jsdom": "^28.0.2",
"jison": "^0.4.18",
"js-base64": "3.7.2",
"lint-staged": "^12.1.2",
"lint-staged": "^13.0.0",
"moment": "^2.23.0",
"path-browserify": "^1.0.1",
"prettier": "^2.3.2",

View File

@ -1,3 +1,6 @@
import c4Db from './diagrams/c4/c4Db';
import c4Renderer from './diagrams/c4/c4Renderer';
import c4Parser from './diagrams/c4/parser/c4Diagram';
import classDb from './diagrams/class/classDb';
import classRenderer from './diagrams/class/classRenderer';
import classRendererV2 from './diagrams/class/classRenderer-v2';
@ -49,6 +52,12 @@ class Diagram {
this.type = utils.detectType(txt, cnf);
log.debug('Type ' + this.type);
switch (this.type) {
case 'c4':
this.parser = c4Parser;
this.parser.parser.yy = c4Db;
this.db = c4Db;
this.renderer = c4Renderer;
break;
case 'gitGraph':
this.parser = gitGraphParser;
this.parser.parser.yy = gitGraphAst;

View File

@ -209,9 +209,9 @@ export const addDirective = (directive) => {
*
* ## conf
*
* | Parameter | Description | Type | Required | Values |
* | --------- | ------------------------------------------------------------- | ---------- | -------- | -------------------------------------------- |
* | conf | base set of values, which currentConfig coul be **reset** to. | Dictionary | Required | Any Values, with respect to the secure Array |
* | Parameter | Description | Type | Required | Values |
* | --------- | -------------------------------------------------------------- | ---------- | -------- | -------------------------------------------- |
* | conf | base set of values, which currentConfig could be **reset** to. | Dictionary | Required | Any Values, with respect to the secure Array |
*
* **Notes**: (default: current siteConfig ) (optional, default `getSiteConfig()`)
*/

View File

@ -40,7 +40,7 @@ const rect = (parent, node) => {
const width = node.width <= bbox.width + padding ? bbox.width + padding : node.width;
if (node.width <= bbox.width + padding) {
node.diff = (bbox.width - node.width) / 2;
node.diff = (bbox.width - node.width) / 2 - node.padding / 2;
} else {
node.diff = -node.padding / 2;
}

View File

@ -5,7 +5,7 @@
* @param point
*/
function intersectEllipse(node, rx, ry, point) {
// Formulae from: http://mathworld.wolfram.com/Ellipse-LineIntersection.html
// Formulae from: https://mathworld.wolfram.com/Ellipse-LineIntersection.html
var cx = node.x;
var cy = node.y;

View File

@ -3,7 +3,7 @@ const intersectRect = (node, point) => {
var y = node.y;
// Rectangle intersection algorithm from:
// http://math.stackexchange.com/questions/108113/find-edge-between-two-boxes
// https://math.stackexchange.com/questions/108113/find-edge-between-two-boxes
var dx = point.x - x;
var dy = point.y - y;
var w = node.width / 2;

View File

@ -942,13 +942,13 @@ const config = {
minEntityHeight: 75,
/**
* | Parameter | Description | Type | Required | Values |
* | ------------- | ----------------------------------------------------------- | ------- | -------- | ------------------ |
* | entityPadding | Minimum internal padding betweentext in box and box borders | Integer | 4 | Any Positive Value |
* | Parameter | Description | Type | Required | Values |
* | ------------- | ------------------------------------------------------------ | ------- | -------- | ------------------ |
* | entityPadding | Minimum internal padding between text in box and box borders | Integer | 4 | Any Positive Value |
*
* **Notes:**
*
* The minimum internal padding betweentext in an entity box and the enclosing box borders,
* The minimum internal padding between text in an entity box and the enclosing box borders,
* expressed in pixels.
*
* Default value: 15
@ -1058,6 +1058,406 @@ const config = {
mainBranchOrder: 0,
showCommitLabel: true,
showBranches: true,
rotateCommitLabel: true,
},
/** The object containing configurations specific for c4 diagrams */
c4: {
useWidth: undefined,
/**
* | Parameter | Description | Type | Required | Values |
* | -------------- | ---------------------------------------------- | ------- | -------- | ------------------ |
* | diagramMarginX | Margin to the right and left of the c4 diagram | Integer | Required | Any Positive Value |
*
* **Notes:** Default value: 50
*/
diagramMarginX: 50,
/**
* | Parameter | Description | Type | Required | Values |
* | -------------- | ------------------------------------------- | ------- | -------- | ------------------ |
* | diagramMarginY | Margin to the over and under the c4 diagram | Integer | Required | Any Positive Value |
*
* **Notes:** Default value: 10
*/
diagramMarginY: 10,
/**
* | Parameter | Description | Type | Required | Values |
* | ----------- | --------------------- | ------- | -------- | ------------------ |
* | shapeMargin | Margin between shapes | Integer | Required | Any Positive Value |
*
* **Notes:** Default value: 50
*/
c4ShapeMargin: 50,
c4ShapePadding: 20,
/**
* | Parameter | Description | Type | Required | Values |
* | --------- | --------------------- | ------- | -------- | ------------------ |
* | width | Width of person boxes | Integer | Required | Any Positive Value |
*
* **Notes:** Default value: 216
*/
width: 216,
/**
* | Parameter | Description | Type | Required | Values |
* | --------- | ---------------------- | ------- | -------- | ------------------ |
* | height | Height of person boxes | Integer | Required | Any Positive Value |
*
* **Notes:** Default value: 60
*/
height: 60,
/**
* | Parameter | Description | Type | Required | Values |
* | --------- | ------------------------ | ------- | -------- | ------------------ |
* | boxMargin | Margin around loop boxes | Integer | Required | Any Positive Value |
*
* **Notes:** Default value: 10
*/
boxMargin: 10,
/**
* | Parameter | Description | Type | Required | Values |
* | ----------- | ----------- | ------- | -------- | ----------- |
* | useMaxWidth | See Notes | boolean | Required | true, false |
*
* **Notes:** When this flag is set to true, the height and width is set to 100% and is then
* scaling with the available space. If set to false, the absolute space required is used.
*
* Default value: true
*/
useMaxWidth: true,
c4ShapeInRow: 4,
nextLinePaddingX: 0,
c4BoundaryInRow: 2,
personFontSize: 14,
personFontFamily: '"Open Sans", sans-serif',
personFontWeight: 'normal',
external_personFontSize: 14,
external_personFontFamily: '"Open Sans", sans-serif',
external_personFontWeight: 'normal',
systemFontSize: 14,
systemFontFamily: '"Open Sans", sans-serif',
systemFontWeight: 'normal',
external_systemFontSize: 14,
external_systemFontFamily: '"Open Sans", sans-serif',
external_systemFontWeight: 'normal',
system_dbFontSize: 14,
system_dbFontFamily: '"Open Sans", sans-serif',
system_dbFontWeight: 'normal',
external_system_dbFontSize: 14,
external_system_dbFontFamily: '"Open Sans", sans-serif',
external_system_dbFontWeight: 'normal',
system_queueFontSize: 14,
system_queueFontFamily: '"Open Sans", sans-serif',
system_queueFontWeight: 'normal',
external_system_queueFontSize: 14,
external_system_queueFontFamily: '"Open Sans", sans-serif',
external_system_queueFontWeight: 'normal',
boundaryFontSize: 14,
boundaryFontFamily: '"Open Sans", sans-serif',
boundaryFontWeight: 'normal',
messageFontSize: 12,
messageFontFamily: '"Open Sans", sans-serif',
messageFontWeight: 'normal',
containerFontSize: 14,
containerFontFamily: '"Open Sans", sans-serif',
containerFontWeight: 'normal',
external_containerFontSize: 14,
external_containerFontFamily: '"Open Sans", sans-serif',
external_containerFontWeight: 'normal',
container_dbFontSize: 14,
container_dbFontFamily: '"Open Sans", sans-serif',
container_dbFontWeight: 'normal',
external_container_dbFontSize: 14,
external_container_dbFontFamily: '"Open Sans", sans-serif',
external_container_dbFontWeight: 'normal',
container_queueFontSize: 14,
container_queueFontFamily: '"Open Sans", sans-serif',
container_queueFontWeight: 'normal',
external_container_queueFontSize: 14,
external_container_queueFontFamily: '"Open Sans", sans-serif',
external_container_queueFontWeight: 'normal',
componentFontSize: 14,
componentFontFamily: '"Open Sans", sans-serif',
componentFontWeight: 'normal',
external_componentFontSize: 14,
external_componentFontFamily: '"Open Sans", sans-serif',
external_componentFontWeight: 'normal',
component_dbFontSize: 14,
component_dbFontFamily: '"Open Sans", sans-serif',
component_dbFontWeight: 'normal',
external_component_dbFontSize: 14,
external_component_dbFontFamily: '"Open Sans", sans-serif',
external_component_dbFontWeight: 'normal',
component_queueFontSize: 14,
component_queueFontFamily: '"Open Sans", sans-serif',
component_queueFontWeight: 'normal',
external_component_queueFontSize: 14,
external_component_queueFontFamily: '"Open Sans", sans-serif',
external_component_queueFontWeight: 'normal',
/**
* This sets the auto-wrap state for the diagram
*
* **Notes:** Default value: true.
*/
wrap: true,
/**
* This sets the auto-wrap padding for the diagram (sides only)
*
* **Notes:** Default value: 0.
*/
wrapPadding: 10,
personFont: function () {
return {
fontFamily: this.personFontFamily,
fontSize: this.personFontSize,
fontWeight: this.personFontWeight,
};
},
external_personFont: function () {
return {
fontFamily: this.external_personFontFamily,
fontSize: this.external_personFontSize,
fontWeight: this.external_personFontWeight,
};
},
systemFont: function () {
return {
fontFamily: this.systemFontFamily,
fontSize: this.systemFontSize,
fontWeight: this.systemFontWeight,
};
},
external_systemFont: function () {
return {
fontFamily: this.external_systemFontFamily,
fontSize: this.external_systemFontSize,
fontWeight: this.external_systemFontWeight,
};
},
system_dbFont: function () {
return {
fontFamily: this.system_dbFontFamily,
fontSize: this.system_dbFontSize,
fontWeight: this.system_dbFontWeight,
};
},
external_system_dbFont: function () {
return {
fontFamily: this.external_system_dbFontFamily,
fontSize: this.external_system_dbFontSize,
fontWeight: this.external_system_dbFontWeight,
};
},
system_queueFont: function () {
return {
fontFamily: this.system_queueFontFamily,
fontSize: this.system_queueFontSize,
fontWeight: this.system_queueFontWeight,
};
},
external_system_queueFont: function () {
return {
fontFamily: this.external_system_queueFontFamily,
fontSize: this.external_system_queueFontSize,
fontWeight: this.external_system_queueFontWeight,
};
},
containerFont: function () {
return {
fontFamily: this.containerFontFamily,
fontSize: this.containerFontSize,
fontWeight: this.containerFontWeight,
};
},
external_containerFont: function () {
return {
fontFamily: this.external_containerFontFamily,
fontSize: this.external_containerFontSize,
fontWeight: this.external_containerFontWeight,
};
},
container_dbFont: function () {
return {
fontFamily: this.container_dbFontFamily,
fontSize: this.container_dbFontSize,
fontWeight: this.container_dbFontWeight,
};
},
external_container_dbFont: function () {
return {
fontFamily: this.external_container_dbFontFamily,
fontSize: this.external_container_dbFontSize,
fontWeight: this.external_container_dbFontWeight,
};
},
container_queueFont: function () {
return {
fontFamily: this.container_queueFontFamily,
fontSize: this.container_queueFontSize,
fontWeight: this.container_queueFontWeight,
};
},
external_container_queueFont: function () {
return {
fontFamily: this.external_container_queueFontFamily,
fontSize: this.external_container_queueFontSize,
fontWeight: this.external_container_queueFontWeight,
};
},
componentFont: function () {
return {
fontFamily: this.componentFontFamily,
fontSize: this.componentFontSize,
fontWeight: this.componentFontWeight,
};
},
external_componentFont: function () {
return {
fontFamily: this.external_componentFontFamily,
fontSize: this.external_componentFontSize,
fontWeight: this.external_componentFontWeight,
};
},
component_dbFont: function () {
return {
fontFamily: this.component_dbFontFamily,
fontSize: this.component_dbFontSize,
fontWeight: this.component_dbFontWeight,
};
},
external_component_dbFont: function () {
return {
fontFamily: this.external_component_dbFontFamily,
fontSize: this.external_component_dbFontSize,
fontWeight: this.external_component_dbFontWeight,
};
},
component_queueFont: function () {
return {
fontFamily: this.component_queueFontFamily,
fontSize: this.component_queueFontSize,
fontWeight: this.component_queueFontWeight,
};
},
external_component_queueFont: function () {
return {
fontFamily: this.external_component_queueFontFamily,
fontSize: this.external_component_queueFontSize,
fontWeight: this.external_component_queueFontWeight,
};
},
boundaryFont: function () {
return {
fontFamily: this.boundaryFontFamily,
fontSize: this.boundaryFontSize,
fontWeight: this.boundaryFontWeight,
};
},
messageFont: function () {
return {
fontFamily: this.messageFontFamily,
fontSize: this.messageFontSize,
fontWeight: this.messageFontWeight,
};
},
// ' Colors
// ' ##################################
person_bg_color: '#08427B',
person_border_color: '#073B6F',
external_person_bg_color: '#686868',
external_person_border_color: '#8A8A8A',
system_bg_color: '#1168BD',
system_border_color: '#3C7FC0',
system_db_bg_color: '#1168BD',
system_db_border_color: '#3C7FC0',
system_queue_bg_color: '#1168BD',
system_queue_border_color: '#3C7FC0',
external_system_bg_color: '#999999',
external_system_border_color: '#8A8A8A',
external_system_db_bg_color: '#999999',
external_system_db_border_color: '#8A8A8A',
external_system_queue_bg_color: '#999999',
external_system_queue_border_color: '#8A8A8A',
container_bg_color: '#438DD5',
container_border_color: '#3C7FC0',
container_db_bg_color: '#438DD5',
container_db_border_color: '#3C7FC0',
container_queue_bg_color: '#438DD5',
container_queue_border_color: '#3C7FC0',
external_container_bg_color: '#B3B3B3',
external_container_border_color: '#A6A6A6',
external_container_db_bg_color: '#B3B3B3',
external_container_db_border_color: '#A6A6A6',
external_container_queue_bg_color: '#B3B3B3',
external_container_queue_border_color: '#A6A6A6',
component_bg_color: '#85BBF0',
component_border_color: '#78A8D8',
component_db_bg_color: '#85BBF0',
component_db_border_color: '#78A8D8',
component_queue_bg_color: '#85BBF0',
component_queue_border_color: '#78A8D8',
external_component_bg_color: '#CCCCCC',
external_component_border_color: '#BFBFBF',
external_component_db_bg_color: '#CCCCCC',
external_component_db_border_color: '#BFBFBF',
external_component_queue_bg_color: '#CCCCCC',
external_component_queue_border_color: '#BFBFBF',
},
};

480
src/diagrams/c4/c4Db.js Normal file
View File

@ -0,0 +1,480 @@
import mermaidAPI from '../../mermaidAPI';
import * as configApi from '../../config';
import { log } from '../../logger';
import { sanitizeText } from '../common/common';
import { setAccTitle, getAccTitle, getAccDescription, setAccDescription } from '../../commonDb';
let c4ShapeArray = [];
let boundaryParseStack = [''];
let currentBoundaryParse = 'global';
let parentBoundaryParse = '';
let boundarys = [
{
alias: 'global',
label: { text: 'global' },
type: { text: 'global' },
tags: null,
link: null,
parentBoundary: '',
},
];
let rels = [];
let title = '';
let wrapEnabled = false;
let description = '';
var c4Type;
export const getC4Type = function () {
return c4Type;
};
export const setC4Type = function (c4TypeParam) {
let sanitizedText = sanitizeText(c4TypeParam, configApi.getConfig());
c4Type = sanitizedText;
};
export const parseDirective = function (statement, context, type) {
mermaidAPI.parseDirective(this, statement, context, type);
};
//type, from, to, label, ?techn, ?descr, ?sprite, ?tags, $link
export const addRel = function (type, from, to, label, techn, descr, sprite, tags, link) {
// Don't allow label nulling
if (
type === undefined ||
type === null ||
from === undefined ||
from === null ||
to === undefined ||
to === null ||
label === undefined ||
label === null
)
return;
let rel = {};
const old = rels.find((rel) => rel.from === from && rel.to === to);
if (old) {
rel = old;
} else {
rels.push(rel);
}
rel.type = type;
rel.from = from;
rel.to = to;
rel.label = { text: label };
if (descr === undefined || descr === null) {
rel.descr = { text: '' };
} else {
rel.descr = { text: descr };
}
if (techn === undefined || techn === null) {
rel.techn = { text: '' };
} else {
rel.techn = { text: techn };
}
// rel.techn = techn;
rel.sprite = sprite;
rel.tags = tags;
rel.link = link;
rel.wrap = autoWrap();
};
//type, alias, label, ?descr, ?sprite, ?tags, $link
export const addPersonOrSystem = function (typeC4Shape, alias, label, descr, sprite, tags, link) {
// Don't allow label nulling
if (alias === null || label === null) return;
let personOrSystem = {};
const old = c4ShapeArray.find((personOrSystem) => personOrSystem.alias === alias);
if (old && alias === old.alias) {
personOrSystem = old;
} else {
personOrSystem.alias = alias;
c4ShapeArray.push(personOrSystem);
}
// Don't allow null labels, either
if (label === undefined || label === null) {
personOrSystem.label = { text: '' };
} else {
personOrSystem.label = { text: label };
}
if (descr === undefined || descr === null) {
personOrSystem.descr = { text: '' };
} else {
personOrSystem.descr = { text: descr };
}
personOrSystem.wrap = autoWrap();
personOrSystem.sprite = sprite;
personOrSystem.tags = tags;
personOrSystem.link = link;
personOrSystem.typeC4Shape = { text: typeC4Shape };
personOrSystem.parentBoundary = currentBoundaryParse;
};
//type, alias, label, ?techn, ?descr ?sprite, ?tags, $link
export const addContainer = function (typeC4Shape, alias, label, techn, descr, sprite, tags, link) {
// Don't allow label nulling
if (alias === null || label === null) return;
let container = {};
const old = c4ShapeArray.find((container) => container.alias === alias);
if (old && alias === old.alias) {
container = old;
} else {
container.alias = alias;
c4ShapeArray.push(container);
}
// Don't allow null labels, either
if (label === undefined || label === null) {
container.label = { text: '' };
} else {
container.label = { text: label };
}
if (techn === undefined || techn === null) {
container.techn = { text: '' };
} else {
container.techn = { text: techn };
}
if (descr === undefined || descr === null) {
container.descr = { text: '' };
} else {
container.descr = { text: descr };
}
container.sprite = sprite;
container.tags = tags;
container.link = link;
container.wrap = autoWrap();
container.typeC4Shape = { text: typeC4Shape };
container.parentBoundary = currentBoundaryParse;
};
//type, alias, label, ?techn, ?descr ?sprite, ?tags, $link
export const addComponent = function (typeC4Shape, alias, label, techn, descr, sprite, tags, link) {
// Don't allow label nulling
if (alias === null || label === null) return;
let component = {};
const old = c4ShapeArray.find((component) => component.alias === alias);
if (old && alias === old.alias) {
component = old;
} else {
component.alias = alias;
c4ShapeArray.push(component);
}
// Don't allow null labels, either
if (label === undefined || label === null) {
component.label = { text: '' };
} else {
component.label = { text: label };
}
if (techn === undefined || techn === null) {
component.techn = { text: '' };
} else {
component.techn = { text: techn };
}
if (descr === undefined || descr === null) {
component.descr = { text: '' };
} else {
component.descr = { text: descr };
}
component.sprite = sprite;
component.tags = tags;
component.link = link;
component.wrap = autoWrap();
component.typeC4Shape = { text: typeC4Shape };
component.parentBoundary = currentBoundaryParse;
};
//alias, label, ?type, ?tags, $link
export const addPersonOrSystemBoundary = function (alias, label, type, tags, link) {
// if (parentBoundary === null) return;
// Don't allow label nulling
if (alias === null || label === null) return;
let boundary = {};
const old = boundarys.find((boundary) => boundary.alias === alias);
if (old && alias === old.alias) {
boundary = old;
} else {
boundary.alias = alias;
boundarys.push(boundary);
}
// Don't allow null labels, either
if (label === undefined || label === null) {
boundary.label = { text: '' };
} else {
boundary.label = { text: label };
}
if (type === undefined || type === null) {
boundary.type = { text: 'system' };
} else {
boundary.type = { text: type };
}
boundary.tags = tags;
boundary.link = link;
boundary.parentBoundary = currentBoundaryParse;
boundary.wrap = autoWrap();
parentBoundaryParse = currentBoundaryParse;
currentBoundaryParse = alias;
boundaryParseStack.push(parentBoundaryParse);
};
//alias, label, ?type, ?tags, $link
export const addContainerBoundary = function (alias, label, type, tags, link) {
// if (parentBoundary === null) return;
// Don't allow label nulling
if (alias === null || label === null) return;
let boundary = {};
const old = boundarys.find((boundary) => boundary.alias === alias);
if (old && alias === old.alias) {
boundary = old;
} else {
boundary.alias = alias;
boundarys.push(boundary);
}
// Don't allow null labels, either
if (label === undefined || label === null) {
boundary.label = { text: '' };
} else {
boundary.label = { text: label };
}
if (type === undefined || type === null) {
boundary.type = { text: 'container' };
} else {
boundary.type = { text: type };
}
boundary.tags = tags;
boundary.link = link;
boundary.parentBoundary = currentBoundaryParse;
boundary.wrap = autoWrap();
parentBoundaryParse = currentBoundaryParse;
currentBoundaryParse = alias;
boundaryParseStack.push(parentBoundaryParse);
};
//alias, label, ?type, ?descr, ?sprite, ?tags, $link
export const addDeploymentNode = function (
nodeType,
alias,
label,
type,
descr,
sprite,
tags,
link
) {
// if (parentBoundary === null) return;
// Don't allow label nulling
if (alias === null || label === null) return;
let boundary = {};
const old = boundarys.find((boundary) => boundary.alias === alias);
if (old && alias === old.alias) {
boundary = old;
} else {
boundary.alias = alias;
boundarys.push(boundary);
}
// Don't allow null labels, either
if (label === undefined || label === null) {
boundary.label = { text: '' };
} else {
boundary.label = { text: label };
}
if (type === undefined || type === null) {
boundary.type = { text: 'node' };
} else {
boundary.type = { text: type };
}
if (descr === undefined || descr === null) {
boundary.descr = { text: '' };
} else {
boundary.descr = { text: type };
}
boundary.tags = tags;
boundary.link = link;
boundary.nodeType = nodeType;
boundary.parentBoundary = currentBoundaryParse;
boundary.wrap = autoWrap();
parentBoundaryParse = currentBoundaryParse;
currentBoundaryParse = alias;
boundaryParseStack.push(parentBoundaryParse);
};
export const popBoundaryParseStack = function () {
currentBoundaryParse = parentBoundaryParse;
boundaryParseStack.pop();
parentBoundaryParse = boundaryParseStack.pop();
boundaryParseStack.push(parentBoundaryParse);
};
export const getCurrentBoundaryParse = function () {
return currentBoundaryParse;
};
export const getParentBoundaryParse = function () {
return parentBoundaryParse;
};
export const getC4ShapeArray = function (parentBoundary) {
if (parentBoundary === undefined || parentBoundary === null) return c4ShapeArray;
else
return c4ShapeArray.filter((personOrSystem) => {
return personOrSystem.parentBoundary === parentBoundary;
});
};
export const getC4Shape = function (alias) {
return c4ShapeArray.find((personOrSystem) => personOrSystem.alias === alias);
};
export const getC4ShapeKeys = function (parentBoundary) {
return Object.keys(getC4ShapeArray(parentBoundary));
};
export const getBoundarys = function (parentBoundary) {
if (parentBoundary === undefined || parentBoundary === null) return boundarys;
else return boundarys.filter((boundary) => boundary.parentBoundary === parentBoundary);
};
export const getRels = function () {
return rels;
};
export const getTitle = function () {
return title;
};
export const setWrap = function (wrapSetting) {
wrapEnabled = wrapSetting;
};
export const autoWrap = function () {
return wrapEnabled;
};
export const clear = function () {
c4ShapeArray = [];
boundarys = [
{
alias: 'global',
label: { text: 'global' },
type: { text: 'global' },
tags: null,
link: null,
parentBoundary: '',
},
];
parentBoundaryParse = '';
currentBoundaryParse = 'global';
boundaryParseStack = [''];
rels = [];
};
export const LINETYPE = {
SOLID: 0,
DOTTED: 1,
NOTE: 2,
SOLID_CROSS: 3,
DOTTED_CROSS: 4,
SOLID_OPEN: 5,
DOTTED_OPEN: 6,
LOOP_START: 10,
LOOP_END: 11,
ALT_START: 12,
ALT_ELSE: 13,
ALT_END: 14,
OPT_START: 15,
OPT_END: 16,
ACTIVE_START: 17,
ACTIVE_END: 18,
PAR_START: 19,
PAR_AND: 20,
PAR_END: 21,
RECT_START: 22,
RECT_END: 23,
SOLID_POINT: 24,
DOTTED_POINT: 25,
};
export const ARROWTYPE = {
FILLED: 0,
OPEN: 1,
};
export const PLACEMENT = {
LEFTOF: 0,
RIGHTOF: 1,
OVER: 2,
};
export const setTitle = function (txt) {
let sanitizedText = sanitizeText(txt, configApi.getConfig());
title = sanitizedText;
};
export default {
addPersonOrSystem,
addPersonOrSystemBoundary,
addContainer,
addContainerBoundary,
addComponent,
addDeploymentNode,
popBoundaryParseStack,
addRel,
autoWrap,
setWrap,
getC4ShapeArray,
getC4Shape,
getC4ShapeKeys,
getBoundarys,
getCurrentBoundaryParse,
getParentBoundaryParse,
getRels,
getTitle,
getC4Type,
setAccTitle,
getAccTitle,
getAccDescription,
setAccDescription,
parseDirective,
getConfig: () => configApi.getConfig().c4,
clear,
LINETYPE,
ARROWTYPE,
PLACEMENT,
setTitle,
setC4Type,
// apply,
};

View File

@ -0,0 +1,670 @@
import { select } from 'd3';
import svgDraw, { drawText, fixLifeLineHeights } from './svgDraw';
import { log } from '../../logger';
import { parser } from './parser/c4Diagram';
import common from '../common/common';
import c4Db from './c4Db';
import * as configApi from '../../config';
import utils, {
wrapLabel,
calculateTextWidth,
calculateTextHeight,
assignWithDepth,
configureSvgSize,
} from '../../utils';
import addSVGAccessibilityFields from '../../accessibility';
let globalBoundaryMaxX = 0,
globalBoundaryMaxY = 0;
parser.yy = c4Db;
let conf = {};
class Bounds {
constructor() {
this.name = '';
this.data = {};
this.data.startx = undefined;
this.data.stopx = undefined;
this.data.starty = undefined;
this.data.stopy = undefined;
this.data.widthLimit = undefined;
this.nextData = {};
this.nextData.startx = undefined;
this.nextData.stopx = undefined;
this.nextData.starty = undefined;
this.nextData.stopy = undefined;
this.nextData.cnt = 0;
setConf(parser.yy.getConfig());
}
setData(startx, stopx, starty, stopy) {
this.nextData.startx = this.data.startx = startx;
this.nextData.stopx = this.data.stopx = stopx;
this.nextData.starty = this.data.starty = starty;
this.nextData.stopy = this.data.stopy = stopy;
}
updateVal(obj, key, val, fun) {
if (typeof obj[key] === 'undefined') {
obj[key] = val;
} else {
obj[key] = fun(val, obj[key]);
}
}
insert(c4Shape) {
this.nextData.cnt = this.nextData.cnt + 1;
let _startx =
this.nextData.startx === this.nextData.stopx
? this.nextData.stopx + c4Shape.margin
: this.nextData.stopx + c4Shape.margin * 2;
let _stopx = _startx + c4Shape.width;
let _starty = this.nextData.starty + c4Shape.margin * 2;
let _stopy = _starty + c4Shape.height;
if (
_startx >= this.data.widthLimit ||
_stopx >= this.data.widthLimit ||
this.nextData.cnt > conf.c4ShapeInRow
) {
_startx = this.nextData.startx + c4Shape.margin + conf.nextLinePaddingX;
_starty = this.nextData.stopy + c4Shape.margin * 2;
this.nextData.stopx = _stopx = _startx + c4Shape.width;
this.nextData.starty = this.nextData.stopy;
this.nextData.stopy = _stopy = _starty + c4Shape.height;
this.nextData.cnt = 1;
}
c4Shape.x = _startx;
c4Shape.y = _starty;
this.updateVal(this.data, 'startx', _startx, Math.min);
this.updateVal(this.data, 'starty', _starty, Math.min);
this.updateVal(this.data, 'stopx', _stopx, Math.max);
this.updateVal(this.data, 'stopy', _stopy, Math.max);
this.updateVal(this.nextData, 'startx', _startx, Math.min);
this.updateVal(this.nextData, 'starty', _starty, Math.min);
this.updateVal(this.nextData, 'stopx', _stopx, Math.max);
this.updateVal(this.nextData, 'stopy', _stopy, Math.max);
}
init() {
this.name = '';
this.data = {
startx: undefined,
stopx: undefined,
starty: undefined,
stopy: undefined,
widthLimit: undefined,
};
this.nextData = {
startx: undefined,
stopx: undefined,
starty: undefined,
stopy: undefined,
cnt: 0,
};
setConf(parser.yy.getConfig());
}
bumpLastMargin(margin) {
this.data.stopx += margin;
this.data.stopy += margin;
}
}
export const setConf = function (cnf) {
assignWithDepth(conf, cnf);
if (cnf.fontFamily) {
conf.personFontFamily = conf.systemFontFamily = conf.messageFontFamily = cnf.fontFamily;
}
if (cnf.fontSize) {
conf.personFontSize = conf.systemFontSize = conf.messageFontSize = cnf.fontSize;
}
if (cnf.fontWeight) {
conf.personFontWeight = conf.systemFontWeight = conf.messageFontWeight = cnf.fontWeight;
}
};
const c4ShapeFont = (cnf, typeC4Shape) => {
return {
fontFamily: cnf[typeC4Shape + 'FontFamily'],
fontSize: cnf[typeC4Shape + 'FontSize'],
fontWeight: cnf[typeC4Shape + 'FontWeight'],
};
};
const boundaryFont = (cnf) => {
return {
fontFamily: cnf.boundaryFontFamily,
fontSize: cnf.boundaryFontSize,
fontWeight: cnf.boundaryFontWeight,
};
};
const messageFont = (cnf) => {
return {
fontFamily: cnf.messageFontFamily,
fontSize: cnf.messageFontSize,
fontWeight: cnf.messageFontWeight,
};
};
/**
* @param textType
* @param c4Shape
* @param c4ShapeTextWrap
* @param textConf
* @param textLimitWidth
*/
function calcC4ShapeTextWH(textType, c4Shape, c4ShapeTextWrap, textConf, textLimitWidth) {
if (!c4Shape[textType].width) {
if (c4ShapeTextWrap) {
c4Shape[textType].text = wrapLabel(c4Shape[textType].text, textLimitWidth, textConf);
c4Shape[textType].textLines = c4Shape[textType].text.split(common.lineBreakRegex).length;
// c4Shape[textType].width = calculateTextWidth(c4Shape[textType].text, textConf);
c4Shape[textType].width = textLimitWidth;
// c4Shape[textType].height = c4Shape[textType].textLines * textConf.fontSize;
c4Shape[textType].height = calculateTextHeight(c4Shape[textType].text, textConf);
} else {
let lines = c4Shape[textType].text.split(common.lineBreakRegex);
c4Shape[textType].textLines = lines.length;
let lineHeight = 0;
c4Shape[textType].height = 0;
c4Shape[textType].width = 0;
for (let i = 0; i < lines.length; i++) {
c4Shape[textType].width = Math.max(
calculateTextWidth(lines[i], textConf),
c4Shape[textType].width
);
lineHeight = calculateTextHeight(lines[i], textConf);
c4Shape[textType].height = c4Shape[textType].height + lineHeight;
}
// c4Shapes[textType].height = c4Shapes[textType].textLines * textConf.fontSize;
}
}
}
export const drawBoundary = function (diagram, boundary, bounds) {
boundary.x = bounds.data.startx;
boundary.y = bounds.data.starty;
boundary.width = bounds.data.stopx - bounds.data.startx;
boundary.height = bounds.data.stopy - bounds.data.starty;
boundary.label.y = conf.c4ShapeMargin - 35;
let boundaryTextWrap = boundary.wrap && conf.wrap;
let boundaryLabelConf = boundaryFont(conf);
boundaryLabelConf.fontSize = boundaryLabelConf.fontSize + 2;
boundaryLabelConf.fontWeight = 'bold';
let textLimitWidth = calculateTextWidth(boundary.label.text, boundaryLabelConf);
calcC4ShapeTextWH('label', boundary, boundaryTextWrap, boundaryLabelConf, textLimitWidth);
svgDraw.drawBoundary(diagram, boundary, conf);
};
export const drawC4ShapeArray = function (currentBounds, diagram, c4ShapeArray, c4ShapeKeys) {
// Upper Y is relative point
let Y = 0;
// Draw the c4ShapeArray
for (let i = 0; i < c4ShapeKeys.length; i++) {
Y = 0;
const c4Shape = c4ShapeArray[c4ShapeKeys[i]];
// calc c4 shape type width and height
let c4ShapeTypeConf = c4ShapeFont(conf, c4Shape.typeC4Shape.text);
c4ShapeTypeConf.fontSize = c4ShapeTypeConf.fontSize - 2;
c4Shape.typeC4Shape.width = calculateTextWidth(
'<<' + c4Shape.typeC4Shape.text + '>>',
c4ShapeTypeConf
);
c4Shape.typeC4Shape.height = c4ShapeTypeConf.fontSize + 2;
c4Shape.typeC4Shape.Y = conf.c4ShapePadding;
Y = c4Shape.typeC4Shape.Y + c4Shape.typeC4Shape.height - 4;
// set image width and height c4Shape.x + c4Shape.width / 2 - 24, c4Shape.y + 28
// let imageWidth = 0,
// imageHeight = 0,
// imageY = 0;
//
c4Shape.image = { width: 0, height: 0, Y: 0 };
switch (c4Shape.typeC4Shape.text) {
case 'person':
case 'external_person':
c4Shape.image.width = 48;
c4Shape.image.height = 48;
c4Shape.image.Y = Y;
Y = c4Shape.image.Y + c4Shape.image.height;
break;
}
if (c4Shape.sprite) {
c4Shape.image.width = 48;
c4Shape.image.height = 48;
c4Shape.image.Y = Y;
Y = c4Shape.image.Y + c4Shape.image.height;
}
// Y = conf.c4ShapePadding + c4Shape.image.height;
let c4ShapeTextWrap = c4Shape.wrap && conf.wrap;
let textLimitWidth = conf.width - conf.c4ShapePadding * 2;
let c4ShapeLabelConf = c4ShapeFont(conf, c4Shape.typeC4Shape.text);
c4ShapeLabelConf.fontSize = c4ShapeLabelConf.fontSize + 2;
c4ShapeLabelConf.fontWeight = 'bold';
calcC4ShapeTextWH('label', c4Shape, c4ShapeTextWrap, c4ShapeLabelConf, textLimitWidth);
c4Shape['label'].Y = Y + 8;
Y = c4Shape['label'].Y + c4Shape['label'].height;
if (c4Shape.type && c4Shape.type.text !== '') {
c4Shape.type.text = '[' + c4Shape.type.text + ']';
let c4ShapeTypeConf = c4ShapeFont(conf, c4Shape.typeC4Shape.text);
calcC4ShapeTextWH('type', c4Shape, c4ShapeTextWrap, c4ShapeTypeConf, textLimitWidth);
c4Shape['type'].Y = Y + 5;
Y = c4Shape['type'].Y + c4Shape['type'].height;
} else if (c4Shape.techn && c4Shape.techn.text !== '') {
c4Shape.techn.text = '[' + c4Shape.techn.text + ']';
let c4ShapeTechnConf = c4ShapeFont(conf, c4Shape.techn.text);
calcC4ShapeTextWH('techn', c4Shape, c4ShapeTextWrap, c4ShapeTechnConf, textLimitWidth);
c4Shape['techn'].Y = Y + 5;
Y = c4Shape['techn'].Y + c4Shape['techn'].height;
}
let rectHeight = Y;
let rectWidth = c4Shape.label.width;
if (c4Shape.descr && c4Shape.descr.text !== '') {
let c4ShapeDescrConf = c4ShapeFont(conf, c4Shape.typeC4Shape.text);
calcC4ShapeTextWH('descr', c4Shape, c4ShapeTextWrap, c4ShapeDescrConf, textLimitWidth);
c4Shape['descr'].Y = Y + 20;
Y = c4Shape['descr'].Y + c4Shape['descr'].height;
rectWidth = Math.max(c4Shape.label.width, c4Shape.descr.width);
rectHeight = Y - c4Shape['descr'].textLines * 5;
}
rectWidth = rectWidth + conf.c4ShapePadding;
// let rectHeight =
c4Shape.width = Math.max(c4Shape.width || conf.width, rectWidth, conf.width);
c4Shape.height = Math.max(c4Shape.height || conf.height, rectHeight, conf.height);
c4Shape.margin = c4Shape.margin || conf.c4ShapeMargin;
currentBounds.insert(c4Shape);
const height = svgDraw.drawC4Shape(diagram, c4Shape, conf);
}
currentBounds.bumpLastMargin(conf.c4ShapeMargin);
};
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
}
/* * *
* Get the intersection of the line between the center point of a rectangle and a point outside the rectangle.
* Algorithm idea.
* Using a point outside the rectangle as the coordinate origin, the graph is divided into four quadrants, and each quadrant is divided into two cases, with separate treatment on the coordinate axes
* 1. The case of coordinate axes.
* 1. The case of the negative x-axis
* 2. The case of the positive x-axis
* 3. The case of the positive y-axis
* 4. The negative y-axis case
* 2. Quadrant cases.
* 2.1. first quadrant: the case where the line intersects the left side of the rectangle; the case where it intersects the lower side of the rectangle
* 2.2. second quadrant: the case where the line intersects the right side of the rectangle; the case where it intersects the lower edge of the rectangle
* 2.3. third quadrant: the case where the line intersects the right side of the rectangle; the case where it intersects the upper edge of the rectangle
* 2.4. fourth quadrant: the case where the line intersects the left side of the rectangle; the case where it intersects the upper side of the rectangle
*
*/
let getIntersectPoint = function (fromNode, endPoint) {
let x1 = fromNode.x;
let y1 = fromNode.y;
let x2 = endPoint.x;
let y2 = endPoint.y;
let fromCenterX = x1 + fromNode.width / 2;
let fromCenterY = y1 + fromNode.height / 2;
let dx = Math.abs(x1 - x2);
let dy = Math.abs(y1 - y2);
let tanDYX = dy / dx;
let fromDYX = fromNode.height / fromNode.width;
let returnPoint = null;
if (y1 == y2 && x1 < x2) {
returnPoint = new Point(x1 + fromNode.width, fromCenterY);
} else if (y1 == y2 && x1 > x2) {
returnPoint = new Point(x1, fromCenterY);
} else if (x1 == x2 && y1 < y2) {
returnPoint = new Point(fromCenterX, y1 + fromNode.height);
} else if (x1 == x2 && y1 > y2) {
returnPoint = new Point(fromCenterX, y1);
}
if (x1 > x2 && y1 < y2) {
if (fromDYX >= tanDYX) {
returnPoint = new Point(x1, fromCenterY + (tanDYX * fromNode.width) / 2);
} else {
returnPoint = new Point(
fromCenterX - ((dx / dy) * fromNode.height) / 2,
y1 + fromNode.height
);
}
} else if (x1 < x2 && y1 < y2) {
//
if (fromDYX >= tanDYX) {
returnPoint = new Point(x1 + fromNode.width, fromCenterY + (tanDYX * fromNode.width) / 2);
} else {
returnPoint = new Point(
fromCenterX + ((dx / dy) * fromNode.height) / 2,
y1 + fromNode.height
);
}
} else if (x1 < x2 && y1 > y2) {
if (fromDYX >= tanDYX) {
returnPoint = new Point(x1 + fromNode.width, fromCenterY - (tanDYX * fromNode.width) / 2);
} else {
returnPoint = new Point(fromCenterX + ((fromNode.height / 2) * dx) / dy, y1);
}
} else if (x1 > x2 && y1 > y2) {
if (fromDYX >= tanDYX) {
returnPoint = new Point(x1, fromCenterY - (fromNode.width / 2) * tanDYX);
} else {
returnPoint = new Point(fromCenterX - ((fromNode.height / 2) * dx) / dy, y1);
}
}
return returnPoint;
};
let getIntersectPoints = function (fromNode, endNode) {
let endIntersectPoint = { x: 0, y: 0 };
endIntersectPoint.x = endNode.x + endNode.width / 2;
endIntersectPoint.y = endNode.y + endNode.height / 2;
let startPoint = getIntersectPoint(fromNode, endIntersectPoint);
endIntersectPoint.x = fromNode.x + fromNode.width / 2;
endIntersectPoint.y = fromNode.y + fromNode.height / 2;
let endPoint = getIntersectPoint(endNode, endIntersectPoint);
return { startPoint: startPoint, endPoint: endPoint };
};
export const drawRels = function (diagram, rels, getC4ShapeObj) {
let i = 0;
for (let rel of rels) {
i = i + 1;
let relTextWrap = rel.wrap && conf.wrap;
let relConf = messageFont(conf);
let diagramType = parser.yy.getC4Type();
if (diagramType === 'C4Dynamic') rel.label.text = i + ': ' + rel.label.text;
let textLimitWidth = calculateTextWidth(rel.label.text, relConf);
calcC4ShapeTextWH('label', rel, relTextWrap, relConf, textLimitWidth);
if (rel.techn && rel.techn.text !== '') {
textLimitWidth = calculateTextWidth(rel.techn.text, relConf);
calcC4ShapeTextWH('techn', rel, relTextWrap, relConf, textLimitWidth);
}
if (rel.descr && rel.descr.text !== '') {
textLimitWidth = calculateTextWidth(rel.descr.text, relConf);
calcC4ShapeTextWH('descr', rel, relTextWrap, relConf, textLimitWidth);
}
let fromNode = getC4ShapeObj(rel.from);
let endNode = getC4ShapeObj(rel.to);
let points = getIntersectPoints(fromNode, endNode);
rel.startPoint = points.startPoint;
rel.endPoint = points.endPoint;
}
svgDraw.drawRels(diagram, rels, conf);
};
/**
* @param diagram
* @param parentBoundaryAlias
* @param parentBounds
* @param currentBoundarys
*/
function drawInsideBoundary(diagram, parentBoundaryAlias, parentBounds, currentBoundarys) {
let currentBounds = new Bounds();
// Calculate the width limit of the boundar. label/type 的长度,
currentBounds.data.widthLimit =
parentBounds.data.widthLimit / Math.min(conf.c4BoundaryInRow, currentBoundarys.length);
// Math.min(
// conf.width * conf.c4ShapeInRow + conf.c4ShapeMargin * conf.c4ShapeInRow * 2,
// parentBounds.data.widthLimit / Math.min(conf.c4BoundaryInRow, currentBoundarys.length)
// );
for (let i = 0; i < currentBoundarys.length; i++) {
let currentBoundary = currentBoundarys[i];
let Y = 0;
currentBoundary.image = { width: 0, height: 0, Y: 0 };
if (currentBoundary.sprite) {
currentBoundary.image.width = 48;
currentBoundary.image.height = 48;
currentBoundary.image.Y = Y;
Y = currentBoundary.image.Y + currentBoundary.image.height;
}
let currentBoundaryTextWrap = currentBoundary.wrap && conf.wrap;
let currentBoundaryLabelConf = boundaryFont(conf);
currentBoundaryLabelConf.fontSize = currentBoundaryLabelConf.fontSize + 2;
currentBoundaryLabelConf.fontWeight = 'bold';
calcC4ShapeTextWH(
'label',
currentBoundary,
currentBoundaryTextWrap,
currentBoundaryLabelConf,
currentBounds.data.widthLimit
);
currentBoundary['label'].Y = Y + 8;
Y = currentBoundary['label'].Y + currentBoundary['label'].height;
if (currentBoundary.type && currentBoundary.type.text !== '') {
currentBoundary.type.text = '[' + currentBoundary.type.text + ']';
let currentBoundaryTypeConf = boundaryFont(conf);
calcC4ShapeTextWH(
'type',
currentBoundary,
currentBoundaryTextWrap,
currentBoundaryTypeConf,
currentBounds.data.widthLimit
);
currentBoundary['type'].Y = Y + 5;
Y = currentBoundary['type'].Y + currentBoundary['type'].height;
}
if (currentBoundary.descr && currentBoundary.descr.text !== '') {
let currentBoundaryDescrConf = boundaryFont(conf);
currentBoundaryDescrConf.fontSize = currentBoundaryDescrConf.fontSize - 2;
calcC4ShapeTextWH(
'descr',
currentBoundary,
currentBoundaryTextWrap,
currentBoundaryDescrConf,
currentBounds.data.widthLimit
);
currentBoundary['descr'].Y = Y + 20;
Y = currentBoundary['descr'].Y + currentBoundary['descr'].height;
}
if (i == 0 || i % conf.c4BoundaryInRow === 0) {
// Calculate the drawing start point of the currentBoundarys.
let _x = parentBounds.data.startx + conf.diagramMarginX;
let _y = parentBounds.data.stopy + conf.diagramMarginY + Y;
currentBounds.setData(_x, _x, _y, _y);
} else {
// Calculate the drawing start point of the currentBoundarys.
let _x =
currentBounds.data.stopx !== currentBounds.data.startx
? currentBounds.data.stopx + conf.diagramMarginX
: currentBounds.data.startx;
let _y = currentBounds.data.starty;
currentBounds.setData(_x, _x, _y, _y);
}
currentBounds.name = currentBoundary.alias;
let currentPersonOrSystemArray = parser.yy.getC4ShapeArray(currentBoundary.alias);
let currentPersonOrSystemKeys = parser.yy.getC4ShapeKeys(currentBoundary.alias);
if (currentPersonOrSystemKeys.length > 0) {
drawC4ShapeArray(
currentBounds,
diagram,
currentPersonOrSystemArray,
currentPersonOrSystemKeys
);
}
parentBoundaryAlias = currentBoundary.alias;
let nextCurrentBoundarys = parser.yy.getBoundarys(parentBoundaryAlias);
if (nextCurrentBoundarys.length > 0) {
// draw boundary inside currentBoundary
// bounds.init();
// parentBoundaryWidthLimit = bounds.data.stopx - bounds.startx;
drawInsideBoundary(diagram, parentBoundaryAlias, currentBounds, nextCurrentBoundarys);
}
// draw boundary
if (currentBoundary.alias !== 'global') drawBoundary(diagram, currentBoundary, currentBounds);
parentBounds.data.stopy = Math.max(
currentBounds.data.stopy + conf.c4ShapeMargin,
parentBounds.data.stopy
);
parentBounds.data.stopx = Math.max(
currentBounds.data.stopx + conf.c4ShapeMargin,
parentBounds.data.stopx
);
globalBoundaryMaxX = Math.max(globalBoundaryMaxX, parentBounds.data.stopx);
globalBoundaryMaxY = Math.max(globalBoundaryMaxY, parentBounds.data.stopy);
}
}
/**
* Draws a sequenceDiagram in the tag with id: id based on the graph definition in text.
*
* @param {any} text
* @param {any} id
*/
export const draw = function (text, id) {
conf = configApi.getConfig().c4;
const securityLevel = configApi.getConfig().securityLevel;
// Handle root and ocument for when rendering in sanbox mode
let sandboxElement;
if (securityLevel === 'sandbox') {
sandboxElement = select('#i' + id);
}
const root =
securityLevel === 'sandbox'
? select(sandboxElement.nodes()[0].contentDocument.body)
: select('body');
const doc = securityLevel === 'sandbox' ? sandboxElement.nodes()[0].contentDocument : document;
parser.yy.clear();
parser.yy.setWrap(conf.wrap);
parser.parse(text + '\n');
log.debug(`C:${JSON.stringify(conf, null, 2)}`);
const diagram =
securityLevel === 'sandbox' ? root.select(`[id="${id}"]`) : select(`[id="${id}"]`);
svgDraw.insertComputerIcon(diagram);
svgDraw.insertDatabaseIcon(diagram);
svgDraw.insertClockIcon(diagram);
let screenBounds = new Bounds();
screenBounds.setData(
conf.diagramMarginX,
conf.diagramMarginX,
conf.diagramMarginY,
conf.diagramMarginY
);
screenBounds.data.widthLimit = screen.availWidth;
globalBoundaryMaxX = conf.diagramMarginX;
globalBoundaryMaxY = conf.diagramMarginY;
const title = parser.yy.getTitle();
const c4type = parser.yy.getC4Type();
let currentBoundarys = parser.yy.getBoundarys('');
// switch (c4type) {
// case 'C4Context':
drawInsideBoundary(diagram, '', screenBounds, currentBoundarys);
// break;
// }
// The arrow head definition is attached to the svg once
svgDraw.insertArrowHead(diagram);
svgDraw.insertArrowEnd(diagram);
svgDraw.insertArrowCrossHead(diagram);
svgDraw.insertArrowFilledHead(diagram);
drawRels(diagram, parser.yy.getRels(), parser.yy.getC4Shape);
screenBounds.data.stopx = globalBoundaryMaxX;
screenBounds.data.stopy = globalBoundaryMaxY;
const box = screenBounds.data;
// Make sure the height of the diagram supports long menus.
let boxHeight = box.stopy - box.starty;
let height = boxHeight + 2 * conf.diagramMarginY;
// Make sure the width of the diagram supports wide menus.
let boxWidth = box.stopx - box.startx;
const width = boxWidth + 2 * conf.diagramMarginX;
if (title) {
diagram
.append('text')
.text(title)
.attr('x', (box.stopx - box.startx) / 2 - 4 * conf.diagramMarginX)
.attr('y', box.starty + conf.diagramMarginY);
}
configureSvgSize(diagram, height, width, conf.useMaxWidth);
const extraVertForTitle = title ? 60 : 0;
diagram.attr(
'viewBox',
box.startx -
conf.diagramMarginX +
' -' +
(conf.diagramMarginY + extraVertForTitle) +
' ' +
width +
' ' +
(height + extraVertForTitle)
);
addSVGAccessibilityFields(parser.yy, diagram, id);
log.debug(`models:`, box);
};
export default {
drawPersonOrSystemArray: drawC4ShapeArray,
drawBoundary,
setConf,
draw,
};

View File

@ -0,0 +1,312 @@
/** mermaid
* https://mermaidjs.github.io/
* (c) 2022 mzhx.meng@gmail.com
* MIT license.
*/
/* lexical grammar */
%lex
/* context */
%x person
%x person_ext
%x system
%x system_db
%x system_queue
%x system_ext
%x system_ext_db
%x system_ext_queue
%x boundary
%x enterprise_boundary
%x system_boundary
%x rel
%x birel
%x rel_u
%x rel_d
%x rel_l
%x rel_r
/* container */
%x container
%x container_db
%x container_queue
%x container_ext
%x container_ext_db
%x container_ext_queue
%x container_boundary
/* component */
%x component
%x component_db
%x component_queue
%x component_ext
%x component_ext_db
%x component_ext_queue
/* Dynamic diagram */
%x rel_index
%x index
/* Deployment diagram */
%x node
%x node_l
%x node_r
/* Relationship Types */
%x rel
%x rel_bi
%x rel_u
%x rel_d
%x rel_l
%x rel_r
%x rel_b
%x attribute
%x string
%x open_directive
%x type_directive
%x arg_directive
%%
\%\%\{ { this.begin('open_directive'); return 'open_directive'; }
.*direction\s+TB[^\n]* return 'direction_tb';
.*direction\s+BT[^\n]* return 'direction_bt';
.*direction\s+RL[^\n]* return 'direction_rl';
.*direction\s+LR[^\n]* return 'direction_lr';
<open_directive>((?:(?!\}\%\%)[^:.])*) { this.begin('type_directive'); return 'type_directive'; }
<type_directive>":" { this.popState(); this.begin('arg_directive'); return ':'; }
<type_directive,arg_directive>\}\%\% { this.popState(); this.popState(); return 'close_directive'; }
<arg_directive>((?:(?!\}\%\%).|\n)*) return 'arg_directive';
\%\%(?!\{)*[^\n]*(\r?\n?)+ /* skip comments */
\%\%[^\n]*(\r?\n)* c /* skip comments */
"title"\s[^#\n;]+ return 'title';
"accDescription"\s[^#\n;]+ return 'accDescription';
\s*(\r?\n)+ return 'NEWLINE';
\s+ /* skip whitespace */
"C4Context" return 'C4_CONTEXT';
"C4Container" return 'C4_CONTAINER';
"C4Component" return 'C4_COMPONENT';
"C4Dynamic" return 'C4_DYNAMIC';
"C4Deployment" return 'C4_DEPLOYMENT';
"Person_Ext" { this.begin("person_ext"); console.log('begin person_ext'); return 'PERSON_EXT';}
"Person" { this.begin("person"); console.log('begin person'); return 'PERSON';}
"SystemQueue_Ext" { this.begin("system_ext_queue"); console.log('begin system_ext_queue'); return 'SYSTEM_EXT_QUEUE';}
"SystemDb_Ext" { this.begin("system_ext_db"); console.log('begin system_ext_db'); return 'SYSTEM_EXT_DB';}
"System_Ext" { this.begin("system_ext"); console.log('begin system_ext'); return 'SYSTEM_EXT';}
"SystemQueue" { this.begin("system_queue"); console.log('begin system_queue'); return 'SYSTEM_QUEUE';}
"SystemDb" { this.begin("system_db"); console.log('begin system_db'); return 'SYSTEM_DB';}
"System" { this.begin("system"); console.log('begin system'); return 'SYSTEM';}
"Boundary" { this.begin("boundary"); console.log('begin boundary'); return 'BOUNDARY';}
"Enterprise_Boundary" { this.begin("enterprise_boundary"); console.log('begin enterprise_boundary'); return 'ENTERPRISE_BOUNDARY';}
"System_Boundary" { this.begin("system_boundary"); console.log('begin system_boundary'); return 'SYSTEM_BOUNDARY';}
"ContainerQueue_Ext" { this.begin("container_ext_queue"); console.log('begin container_ext_queue'); return 'CONTAINER_EXT_QUEUE';}
"ContainerDb_Ext" { this.begin("container_ext_db"); console.log('begin container_ext_db'); return 'CONTAINER_EXT_DB';}
"Container_Ext" { this.begin("container_ext"); console.log('begin container_ext'); return 'CONTAINER_EXT';}
"ContainerQueue" { this.begin("container_queue"); console.log('begin container_queue'); return 'CONTAINER_QUEUE';}
"ContainerDb" { this.begin("container_db"); console.log('begin container_db'); return 'CONTAINER_DB';}
"Container" { this.begin("container"); console.log('begin container'); return 'CONTAINER';}
"Container_Boundary" { this.begin("container_boundary"); console.log('begin container_boundary'); return 'CONTAINER_BOUNDARY';}
"ComponentQueue_Ext" { this.begin("component_ext_queue"); console.log('begin component_ext_queue'); return 'COMPONENT_EXT_QUEUE';}
"ComponentDb_Ext" { this.begin("component_ext_db"); console.log('begin component_ext_db'); return 'COMPONENT_EXT_DB';}
"Component_Ext" { this.begin("component_ext"); console.log('begin component_ext'); return 'COMPONENT_EXT';}
"ComponentQueue" { this.begin("component_queue"); console.log('begin component_queue'); return 'COMPONENT_QUEUE';}
"ComponentDb" { this.begin("component_db"); console.log('begin component_db'); return 'COMPONENT_DB';}
"Component" { this.begin("component"); console.log('begin component'); return 'COMPONENT';}
"Deployment_Node" { this.begin("node"); console.log('begin node'); return 'NODE';}
"Node" { this.begin("node"); console.log('begin node'); return 'NODE';}
"Node_L" { this.begin("node_l"); console.log('begin node_l'); return 'NODE_L';}
"Node_R" { this.begin("node_r"); console.log('begin node_r'); return 'NODE_R';}
"Rel" { this.begin("rel"); console.log('begin rel'); return 'REL';}
"BiRel" { this.begin("birel"); console.log('begin birel'); return 'BIREL';}
"Rel_Up" { this.begin("rel_u"); console.log('begin rel_u'); return 'REL_U';}
"Rel_U" { this.begin("rel_u"); console.log('begin rel_u'); return 'REL_U';}
"Rel_Down" { this.begin("rel_d"); console.log('begin rel_d'); return 'REL_D';}
"Rel_D" { this.begin("rel_d"); console.log('begin rel_d'); return 'REL_D';}
"Rel_Left" { this.begin("rel_l"); console.log('begin rel_l'); return 'REL_L';}
"Rel_L" { this.begin("rel_l"); console.log('begin rel_l'); return 'REL_L';}
"Rel_Right" { this.begin("rel_r"); console.log('begin rel_r'); return 'REL_R';}
"Rel_R" { this.begin("rel_r"); console.log('begin rel_r'); return 'REL_R';}
"Rel_Back" { this.begin("rel_b"); console.log('begin rel_b'); return 'REL_B';}
"RelIndex" { this.begin("rel_index"); console.log('begin rel_index'); return 'REL_INDEX';}
<person,person_ext,system_ext_queue,system_ext_db,system_ext,system_queue,system_db,system,boundary,enterprise_boundary,system_boundary,container_ext_db,container_ext,container_queue,container_db,container,container_boundary,component_ext_db,component_ext,component_queue,component_db,component,node,node_l,node_r,rel,birel,rel_u,rel_d,rel_l,rel_r,rel_b,rel_index><<EOF>> return "EOF_IN_STRUCT";
<person,person_ext,system_ext_queue,system_ext_db,system_ext,system_queue,system_db,system,boundary,enterprise_boundary,system_boundary,container_ext_db,container_ext,container_queue,container_db,container,container_boundary,component_ext_db,component_ext,component_queue,component_db,component,node,node_l,node_r,rel,birel,rel_u,rel_d,rel_l,rel_r,rel_b,rel_index>[(][ ]*[,] { console.log('begin attribute with ATTRIBUTE_EMPTY'); this.begin("attribute"); return "ATTRIBUTE_EMPTY";}
<person,person_ext,system_ext_queue,system_ext_db,system_ext,system_queue,system_db,system,boundary,enterprise_boundary,system_boundary,container_ext_db,container_ext,container_queue,container_db,container,container_boundary,component_ext_db,component_ext,component_queue,component_db,component,node,node_l,node_r,rel,birel,rel_u,rel_d,rel_l,rel_r,rel_b,rel_index>[(] { console.log('begin attribute'); this.begin("attribute"); }
<person,person_ext,system_ext_queue,system_ext_db,system_ext,system_queue,system_db,system,boundary,enterprise_boundary,system_boundary,container_ext_db,container_ext,container_queue,container_db,container,container_boundary,component_ext_db,component_ext,component_queue,component_db,component,node,node_l,node_r,rel,birel,rel_u,rel_d,rel_l,rel_r,rel_b,rel_index,attribute>[)] { console.log('STOP attribute'); this.popState();console.log('STOP diagram'); this.popState();}
<attribute>",," { console.log(',,'); return 'ATTRIBUTE_EMPTY';}
<attribute>"," { console.log(','); }
<attribute>[ ]*["]["] { console.log('ATTRIBUTE_EMPTY'); return 'ATTRIBUTE_EMPTY';}
<attribute>[ ]*["] { console.log('begin string'); this.begin("string");}
<string>["] { console.log('STOP string'); this.popState(); }
<string>[^"]* { console.log('STR'); return "STR";}
<attribute>[^,]+ { console.log('not STR'); return "STR";}
'{' { /* this.begin("lbrace"); */ console.log('begin boundary block'); return "LBRACE";}
'}' { /* this.popState(); */ console.log('STOP boundary block'); return "RBRACE";}
[\s]+ return 'SPACE';
[\n\r]+ return 'EOL';
<<EOF>> return 'EOF';
/lex
/* operator associations and precedence */
%left '^'
%start start
%% /* language grammar */
start
: mermaidDoc
| direction
| directive start
;
direction
: direction_tb
{ yy.setDirection('TB');}
| direction_bt
{ yy.setDirection('BT');}
| direction_rl
{ yy.setDirection('RL');}
| direction_lr
{ yy.setDirection('LR');}
;
mermaidDoc
: graphConfig
;
directive
: openDirective typeDirective closeDirective NEWLINE
| openDirective typeDirective ':' argDirective closeDirective NEWLINE
;
openDirective
: open_directive { console.log("open_directive: ", $1); yy.parseDirective('%%{', 'open_directive'); }
;
typeDirective
: type_directive { }
;
argDirective
: arg_directive { $1 = $1.trim().replace(/'/g, '"'); console.log("arg_directive: ", $1); yy.parseDirective($1, 'arg_directive'); }
;
closeDirective
: close_directive { console.log("close_directive: ", $1); yy.parseDirective('}%%', 'close_directive', 'c4Context'); }
;
graphConfig
: C4_CONTEXT NEWLINE statements EOF {yy.setC4Type($1)}
| C4_CONTAINER NEWLINE statements EOF {yy.setC4Type($1)}
| C4_COMPONENT NEWLINE statements EOF {yy.setC4Type($1)}
| C4_DYNAMIC NEWLINE statements EOF {yy.setC4Type($1)}
| C4_DEPLOYMENT NEWLINE statements EOF {yy.setC4Type($1)}
;
statements
: otherStatements
| diagramStatements
| otherStatements diagramStatements
;
otherStatements
: otherStatement
| otherStatement NEWLINE
| otherStatement NEWLINE otherStatements
;
otherStatement
: title {yy.setTitle($1.substring(6));$$=$1.substring(6);}
| accDescription {yy.setAccDescription($1.substring(15));$$=$1.substring(15);}
;
boundaryStatement
: boundaryStartStatement diagramStatements boundaryStopStatement
;
boundaryStartStatement
: boundaryStart LBRACE NEWLINE
| boundaryStart NEWLINE LBRACE
| boundaryStart NEWLINE LBRACE NEWLINE
;
boundaryStart
: ENTERPRISE_BOUNDARY attributes {console.log($1,JSON.stringify($2)); $2.splice(2, 0, 'ENTERPRISE'); yy.addPersonOrSystemBoundary(...$2); $$=$2;}
| SYSTEM_BOUNDARY attributes {console.log($1,JSON.stringify($2)); $2.splice(2, 0, 'ENTERPRISE'); yy.addPersonOrSystemBoundary(...$2); $$=$2;}
| BOUNDARY attributes {console.log($1,JSON.stringify($2)); yy.addPersonOrSystemBoundary(...$2); $$=$2;}
| CONTAINER_BOUNDARY attributes {console.log($1,JSON.stringify($2)); $2.splice(2, 0, 'CONTAINER'); yy.addContainerBoundary(...$2); $$=$2;}
| NODE attributes {console.log($1,JSON.stringify($2)); yy.addDeploymentNode('node', ...$2); $$=$2;}
| NODE_L attributes {console.log($1,JSON.stringify($2)); yy.addDeploymentNode('nodeL', ...$2); $$=$2;}
| NODE_R attributes {console.log($1,JSON.stringify($2)); yy.addDeploymentNode('nodeR', ...$2); $$=$2;}
;
boundaryStopStatement
: RBRACE { yy.popBoundaryParseStack() }
;
diagramStatements
: diagramStatement
| diagramStatement NEWLINE
| diagramStatement NEWLINE statements
;
diagramStatement
: PERSON attributes {console.log($1,JSON.stringify($2)); yy.addPersonOrSystem('person', ...$2); $$=$2;}
| PERSON_EXT attributes {console.log($1,JSON.stringify($2)); yy.addPersonOrSystem('external_person', ...$2); $$=$2;}
| SYSTEM attributes {console.log($1,JSON.stringify($2)); yy.addPersonOrSystem('system', ...$2); $$=$2;}
| SYSTEM_DB attributes {console.log($1,JSON.stringify($2)); yy.addPersonOrSystem('system_db', ...$2); $$=$2;}
| SYSTEM_QUEUE attributes {console.log($1,JSON.stringify($2)); yy.addPersonOrSystem('system_queue', ...$2); $$=$2;}
| SYSTEM_EXT attributes {console.log($1,JSON.stringify($2)); yy.addPersonOrSystem('external_system', ...$2); $$=$2;}
| SYSTEM_EXT_DB attributes {console.log($1,JSON.stringify($2)); yy.addPersonOrSystem('external_system_db', ...$2); $$=$2;}
| SYSTEM_EXT_QUEUE attributes {console.log($1,JSON.stringify($2)); yy.addPersonOrSystem('external_system_queue', ...$2); $$=$2;}
| CONTAINER attributes {console.log($1,JSON.stringify($2)); yy.addContainer('container', ...$2); $$=$2;}
| CONTAINER_DB attributes {console.log($1,JSON.stringify($2)); yy.addContainer('container_db', ...$2); $$=$2;}
| CONTAINER_QUEUE attributes {console.log($1,JSON.stringify($2)); yy.addContainer('container_queue', ...$2); $$=$2;}
| CONTAINER_EXT attributes {console.log($1,JSON.stringify($2)); yy.addContainer('external_container', ...$2); $$=$2;}
| CONTAINER_EXT_DB attributes {console.log($1,JSON.stringify($2)); yy.addContainer('external_container_db', ...$2); $$=$2;}
| CONTAINER_EXT_QUEUE attributes {console.log($1,JSON.stringify($2)); yy.addContainer('external_container_queue', ...$2); $$=$2;}
| COMPONENT attributes {console.log($1,JSON.stringify($2)); yy.addComponent('component', ...$2); $$=$2;}
| COMPONENT_DB attributes {console.log($1,JSON.stringify($2)); yy.addComponent('component_db', ...$2); $$=$2;}
| COMPONENT_QUEUE attributes {console.log($1,JSON.stringify($2)); yy.addComponent('component_queue', ...$2); $$=$2;}
| COMPONENT_EXT attributes {console.log($1,JSON.stringify($2)); yy.addComponent('external_component', ...$2); $$=$2;}
| COMPONENT_EXT_DB attributes {console.log($1,JSON.stringify($2)); yy.addComponent('external_component_db', ...$2); $$=$2;}
| COMPONENT_EXT_QUEUE attributes {console.log($1,JSON.stringify($2)); yy.addComponent('external_component_queue', ...$2); $$=$2;}
| boundaryStatement
| REL attributes {console.log($1,JSON.stringify($2)); yy.addRel('rel', ...$2); $$=$2;}
| BIREL attributes {console.log($1,JSON.stringify($2)); yy.addRel('birel', ...$2); $$=$2;}
| REL_U attributes {console.log($1,JSON.stringify($2)); yy.addRel('rel_u', ...$2); $$=$2;}
| REL_D attributes {console.log($1,JSON.stringify($2)); yy.addRel('rel_d', ...$2); $$=$2;}
| REL_L attributes {console.log($1,JSON.stringify($2)); yy.addRel('rel_l', ...$2); $$=$2;}
| REL_R attributes {console.log($1,JSON.stringify($2)); yy.addRel('rel_r', ...$2); $$=$2;}
| REL_B attributes {console.log($1,JSON.stringify($2)); yy.addRel('rel_b', ...$2); $$=$2;}
| REL_INDEX attributes {console.log($1,JSON.stringify($2)); $2.splice(0, 1); yy.addRel('rel', ...$2); $$=$2;}
;
attributes
: attribute { console.log('PUSH ATTRIBUTE: ', $1); $$ = [$1]; }
| attribute attributes { console.log('PUSH ATTRIBUTE: ', $1); $2.unshift($1); $$=$2;}
;
attribute
: STR { $$ = $1.trim(); }
| ATTRIBUTE { $$ = $1.trim(); }
| ATTRIBUTE_EMPTY { $$ = ""; }
;

View File

@ -0,0 +1,8 @@
const getStyles = (options) =>
`.person {
stroke: ${options.personBorder};
fill: ${options.personBkg};
}
`;
export default getStyles;

884
src/diagrams/c4/svgDraw.js Normal file

File diff suppressed because one or more lines are too long

View File

@ -9,7 +9,7 @@ import { getConfig } from '../../config';
import { render } from '../../dagre-wrapper/index.js';
// import addHtmlLabel from 'dagre-d3/lib/label/add-html-label.js';
import { curveLinear } from 'd3';
import { interpolateToCurve, getStylesFromArray, configureSvgSize } from '../../utils';
import { interpolateToCurve, getStylesFromArray, setupGraphViewbox } from '../../utils';
import common from '../common/common';
import addSVGAccessibilityFields from '../../accessibility';
@ -322,16 +322,6 @@ export const draw = function (text, id) {
const relations = classDb.getRelations();
log.info(relations);
// let i = 0;
// for (i = subGraphs.length - 1; i >= 0; i--) {
// subG = subGraphs[i];
// selectAll('cluster').append('text');
// for (let j = 0; j < subG.nodes.length; j++) {
// g.setParent(subG.nodes[j], subG.id);
// }
// }
addClasses(classes, g, id);
addRelations(relations, g);
@ -354,28 +344,7 @@ export const draw = function (text, id) {
const element = root.select('#' + id + ' g');
render(element, g, ['aggregation', 'extension', 'composition', 'dependency'], 'classDiagram', id);
// element.selectAll('g.node').attr('title', function() {
// return flowDb.getTooltip(this.id);
// });
const padding = 8;
const svgBounds = svg.node().getBBox();
const width = svgBounds.width + padding * 2;
const height = svgBounds.height + padding * 2;
log.debug(
`new ViewBox 0 0 ${width} ${height}`,
`translate(${padding - g._label.marginx}, ${padding - g._label.marginy})`
);
configureSvgSize(svg, height, width, conf.useMaxWidth);
svg.attr('viewBox', `0 0 ${width} ${height}`);
svg
.select('g')
.attr('transform', `translate(${padding - g._label.marginx}, ${padding - svgBounds.y})`);
// Index nodes
// flowDb.indexNodes('subGraph' + i);
setupGraphViewbox(g, svg, conf.diagramPadding, conf.useMaxWidth);
// Add label rects for non html labels
if (!conf.htmlLabels) {

View File

@ -9,7 +9,7 @@ import { render } from '../../dagre-wrapper/index.js';
import addHtmlLabel from 'dagre-d3/lib/label/add-html-label.js';
import { log } from '../../logger';
import common, { evaluate } from '../common/common';
import { interpolateToCurve, getStylesFromArray, configureSvgSize } from '../../utils';
import { interpolateToCurve, getStylesFromArray, setupGraphViewbox } from '../../utils';
import addSVGAccessibilityFields from '../../accessibility';
const conf = {};
@ -452,21 +452,7 @@ export const draw = function (text, id) {
const element = root.select('#' + id + ' g');
render(element, g, ['point', 'circle', 'cross'], 'flowchart', id);
const padding = conf.diagramPadding;
const svgBounds = svg.node().getBBox();
const width = svgBounds.width + padding * 2;
const height = svgBounds.height + padding * 2;
log.debug(
`new ViewBox 0 0 ${width} ${height}`,
`translate(${padding - g._label.marginx}, ${padding - g._label.marginy})`
);
configureSvgSize(svg, height, width, conf.useMaxWidth);
svg.attr('viewBox', `0 0 ${width} ${height}`);
svg
.select('g')
.attr('transform', `translate(${padding - g._label.marginx}, ${padding - svgBounds.y})`);
setupGraphViewbox(g, svg, conf.diagramPadding, conf.useMaxWidth);
// Index nodes
flowDb.indexNodes('subGraph' + i);
@ -485,7 +471,6 @@ export const draw = function (text, id) {
rect.setAttribute('ry', 0);
rect.setAttribute('width', dim.width);
rect.setAttribute('height', dim.height);
// rect.setAttribute('style', 'fill:#e8e8e8;');
label.insertBefore(rect, label.firstChild);
}

View File

@ -9,7 +9,7 @@ import dagreD3 from 'dagre-d3';
import addHtmlLabel from 'dagre-d3/lib/label/add-html-label.js';
import { log } from '../../logger';
import common, { evaluate } from '../common/common';
import { interpolateToCurve, getStylesFromArray, configureSvgSize } from '../../utils';
import { interpolateToCurve, getStylesFromArray, setupGraphViewbox } from '../../utils';
import flowChartShapes from './flowChartShapes';
import addSVGAccessibilityFields from '../../accessibility';
@ -427,8 +427,6 @@ export const draw = function (text, id) {
const svg = root.select(`[id="${id}"]`);
svg.attr('xmlns:xlink', 'http://www.w3.org/1999/xlink');
log.warn(g);
// Adds title and description to the flow chart
addSVGAccessibilityFields(parser.yy, svg, id);
@ -440,18 +438,6 @@ export const draw = function (text, id) {
return flowDb.getTooltip(this.id);
});
const padding = conf.diagramPadding;
const svgBounds = svg.node().getBBox();
const width = svgBounds.width + padding * 2;
const height = svgBounds.height + padding * 2;
configureSvgSize(svg, height, width, conf.useMaxWidth);
// Ensure the viewBox includes the whole svgBounds area with extra space for padding
const vBox = `${svgBounds.x - padding} ${svgBounds.y - padding} ${width} ${height}`;
log.debug(`viewBox ${vBox}`);
svg.attr('viewBox', vBox);
// Index nodes
flowDb.indexNodes('subGraph' + i);
@ -468,10 +454,10 @@ export const draw = function (text, id) {
const xPos = clusterRects[0].x.baseVal.value;
const yPos = clusterRects[0].y.baseVal.value;
const width = clusterRects[0].width.baseVal.value;
const _width = clusterRects[0].width.baseVal.value;
const cluster = select(clusterEl[0]);
const te = cluster.select('.label');
te.attr('transform', `translate(${xPos + width / 2}, ${yPos + 14})`);
te.attr('transform', `translate(${xPos + _width / 2}, ${yPos + 14})`);
te.attr('id', id + 'Text');
for (let j = 0; j < subG.classes.length; j++) {
@ -499,6 +485,7 @@ export const draw = function (text, id) {
label.insertBefore(rect, label.firstChild);
}
}
setupGraphViewbox(g, svg, conf.diagramPadding, conf.useMaxWidth);
// If node has a link, wrap it in an anchor SVG object.
const keys = Object.keys(vert);

View File

@ -235,6 +235,85 @@ export const merge = function (otherBranch, tag) {
log.debug('in mergeBranch');
};
export const cherryPick = function (sourceId, targetId) {
sourceId = common.sanitizeText(sourceId, configApi.getConfig());
targetId = common.sanitizeText(targetId, configApi.getConfig());
if (!sourceId || typeof commits[sourceId] === 'undefined') {
let error = new Error(
'Incorrect usage of "cherryPick". Source commit id should exist and provided'
);
error.hash = {
text: 'cherryPick ' + sourceId + ' ' + targetId,
token: 'cherryPick ' + sourceId + ' ' + targetId,
line: '1',
loc: { first_line: 1, last_line: 1, first_column: 1, last_column: 1 },
expected: ['cherry-pick abc'],
};
throw error;
}
let sourceCommit = commits[sourceId];
let sourceCommitBranch = sourceCommit.branch;
if (sourceCommit.type === commitType.MERGE) {
let error = new Error(
'Incorrect usage of "cherryPick". Source commit should not be a merge commit'
);
error.hash = {
text: 'cherryPick ' + sourceId + ' ' + targetId,
token: 'cherryPick ' + sourceId + ' ' + targetId,
line: '1',
loc: { first_line: 1, last_line: 1, first_column: 1, last_column: 1 },
expected: ['cherry-pick abc'],
};
throw error;
}
if (!targetId || typeof commits[targetId] === 'undefined') {
// cherry-pick source commit to current branch
if (sourceCommitBranch === curBranch) {
let error = new Error(
'Incorrect usage of "cherryPick". Source commit is already on current branch'
);
error.hash = {
text: 'cherryPick ' + sourceId + ' ' + targetId,
token: 'cherryPick ' + sourceId + ' ' + targetId,
line: '1',
loc: { first_line: 1, last_line: 1, first_column: 1, last_column: 1 },
expected: ['cherry-pick abc'],
};
throw error;
}
const currentCommit = commits[branches[curBranch]];
if (typeof currentCommit === 'undefined' || !currentCommit) {
let error = new Error(
'Incorrect usage of "cherry-pick". Current branch (' + curBranch + ')has no commits'
);
error.hash = {
text: 'cherryPick ' + sourceId + ' ' + targetId,
token: 'cherryPick ' + sourceId + ' ' + targetId,
line: '1',
loc: { first_line: 1, last_line: 1, first_column: 1, last_column: 1 },
expected: ['cherry-pick abc'],
};
throw error;
}
const commit = {
id: seq + '-' + getId(),
message: 'cherry-picked ' + sourceCommit + ' into ' + curBranch,
seq: seq++,
parents: [head == null ? null : head.id, sourceCommit.id],
branch: curBranch,
type: commitType.CHERRY_PICK,
tag: 'cherry-pick:' + sourceCommit.id,
};
head = commit;
commits[commit.id] = commit;
branches[curBranch] = commit.id;
log.debug(branches);
log.debug('in cheeryPick');
}
};
export const checkout = function (branch) {
branch = common.sanitizeText(branch, configApi.getConfig());
if (typeof branches[branch] === 'undefined') {
@ -390,6 +469,7 @@ export const commitType = {
REVERSE: 1,
HIGHLIGHT: 2,
MERGE: 3,
CHERRY_PICK: 4,
};
export default {
@ -401,6 +481,7 @@ export default {
commit,
branch,
merge,
cherryPick,
checkout,
//reset,
prettyPrint,

View File

@ -14,6 +14,7 @@ const commitType = {
REVERSE: 1,
HIGHLIGHT: 2,
MERGE: 3,
CHERRY_PICK: 4,
};
let branchPos = {};
@ -103,6 +104,9 @@ const drawCommits = (svg, commits, modifyGraph) => {
case commitType.MERGE:
typeClass = 'commit-merge';
break;
case commitType.CHERRY_PICK:
typeClass = 'commit-cherry-pick';
break;
default:
typeClass = 'commit-normal';
}
@ -139,6 +143,43 @@ const drawCommits = (svg, commits, modifyGraph) => {
typeClass +
'-inner'
);
} else if (commit.type === commitType.CHERRY_PICK) {
gBullets
.append('circle')
.attr('cx', x)
.attr('cy', y)
.attr('r', 10)
.attr('class', 'commit ' + commit.id + ' ' + typeClass);
gBullets
.append('circle')
.attr('cx', x - 3)
.attr('cy', y + 2)
.attr('r', 2.75)
.attr('fill', '#fff')
.attr('class', 'commit ' + commit.id + ' ' + typeClass);
gBullets
.append('circle')
.attr('cx', x + 3)
.attr('cy', y + 2)
.attr('r', 2.75)
.attr('fill', '#fff')
.attr('class', 'commit ' + commit.id + ' ' + typeClass);
gBullets
.append('line')
.attr('x1', x + 3)
.attr('y1', y + 1)
.attr('x2', x)
.attr('y2', y - 5)
.attr('stroke', '#fff')
.attr('class', 'commit ' + commit.id + ' ' + typeClass);
gBullets
.append('line')
.attr('x1', x - 3)
.attr('y1', y + 1)
.attr('x2', x)
.attr('y2', y - 5)
.attr('stroke', '#fff')
.attr('class', 'commit ' + commit.id + ' ' + typeClass);
} else {
const circle = gBullets.append('circle');
circle.attr('cx', x);
@ -175,10 +216,15 @@ const drawCommits = (svg, commits, modifyGraph) => {
const px = 4;
const py = 2;
// Draw the commit label
if (commit.type !== commitType.MERGE && gitGraphConfig.showCommitLabel) {
const labelBkg = gLabels.insert('rect').attr('class', 'commit-label-bkg');
if (
commit.type !== commitType.CHERRY_PICK &&
commit.type !== commitType.MERGE &&
gitGraphConfig.showCommitLabel
) {
const wrapper = gLabels.append('g');
const labelBkg = wrapper.insert('rect').attr('class', 'commit-label-bkg');
const text = gLabels
const text = wrapper
.append('text')
.attr('x', pos)
.attr('y', y + 25)
@ -193,6 +239,14 @@ const drawCommits = (svg, commits, modifyGraph) => {
.attr('width', bbox.width + 2 * py)
.attr('height', bbox.height + 2 * py);
text.attr('x', pos + 10 - bbox.width / 2);
if (gitGraphConfig.rotateCommitLabel) {
let r_x = -7.5 - ((bbox.width + 10) / 25) * 9.5;
let r_y = 10 + (bbox.width / 25) * 8.5;
wrapper.attr(
'transform',
'translate(' + r_x + ', ' + r_y + ') rotate(' + -45 + ', ' + pos + ', ' + y + ')'
);
}
}
if (commit.tag) {
const rect = gLabels.insert('polygon');
@ -436,14 +490,18 @@ const drawBranches = (svg, branches) => {
.attr('class', 'branchLabelBkg label' + adjustIndexForTheme)
.attr('rx', 4)
.attr('ry', 4)
.attr('x', -bbox.width - 4)
.attr('x', -bbox.width - 4 - (gitGraphConfig.rotateCommitLabel === true ? 30 : 0))
.attr('y', -bbox.height / 2 + 8)
.attr('width', bbox.width + 18)
.attr('height', bbox.height + 4);
label.attr(
'transform',
'translate(' + (-bbox.width - 14) + ', ' + (pos - bbox.height / 2 - 1) + ')'
'translate(' +
(-bbox.width - 14 - (gitGraphConfig.rotateCommitLabel === true ? 30 : 0)) +
', ' +
(pos - bbox.height / 2 - 1) +
')'
);
bkg.attr('transform', 'translate(' + -19 + ', ' + (pos - bbox.height / 2) + ')');
});
@ -479,7 +537,7 @@ export const draw = function (txt, id, ver) {
let pos = 0;
branches.forEach((branch, index) => {
branchPos[branch.name] = { pos, index };
pos += 50;
pos += 50 + (gitGraphConfig.rotateCommitLabel ? 40 : 0);
});
const diagram = select(`[id="${id}"]`);
@ -500,7 +558,11 @@ export const draw = function (txt, id, ver) {
const height = svgBounds.height + padding * 2;
configureSvgSize(diagram, height, width, conf.useMaxWidth);
const vBox = `${svgBounds.x - padding} ${svgBounds.y - padding} ${width} ${height}`;
const vBox = `${
svgBounds.x -
padding -
(gitGraphConfig.showBranches && gitGraphConfig.rotateCommitLabel === true ? 30 : 0)
} ${svgBounds.y - padding} ${width} ${height}`;
diagram.attr('viewBox', vBox);
};

View File

@ -48,6 +48,7 @@ accDescr\s*"{"\s* { this.begin("ac
"branch" return 'BRANCH';
"order:" return 'ORDER';
"merge" return 'MERGE';
"cherry-pick" return 'CHERRY_PICK';
// "reset" return 'RESET';
"checkout" return 'CHECKOUT';
"LR" return 'DIR';
@ -102,6 +103,7 @@ line
statement
: commitStatement
| mergeStatement
| cherryPickStatement
| acc_title acc_title_value { $$=$2.trim();yy.setAccTitle($$); }
| acc_descr acc_descr_value { $$=$2.trim();yy.setAccDescription($$); }
| acc_descr_multiline_value { $$=$1.trim();yy.setAccDescription($$); } | section {yy.addSection($1.substr(8));$$=$1.substr(8);}
@ -114,6 +116,10 @@ branchStatement
| BRANCH ID ORDER NUM {yy.branch($2, $4)}
;
cherryPickStatement
: CHERRY_PICK COMMIT_ID STR {yy.cherryPick($3)}
;
mergeStatement
: MERGE ID {yy.merge($2)}
| MERGE ID COMMIT_TAG STR {yy.merge($2, $4)}

View File

@ -4,7 +4,7 @@
* MIT license.
*
* Based on js sequence diagrams jison grammr
* http://bramp.github.io/js-sequence-diagrams/
* https://bramp.github.io/js-sequence-diagrams/
* (c) 2012-2013 Andrew Brampton (bramp.net)
* Simplified BSD license.
*/

View File

@ -4,7 +4,7 @@
* MIT license.
*
* Based on js sequence diagrams jison grammr
* http://bramp.github.io/js-sequence-diagrams/
* https://bramp.github.io/js-sequence-diagrams/
* (c) 2012-2013 Andrew Brampton (bramp.net)
* Simplified BSD license.
*/

View File

@ -188,7 +188,7 @@ describe('when using mermaid and ', function () {
flowDb.clear();
flowDb.setGen('gen-2');
});
it('it should throw for an invalid definiton', function () {
it('it should throw for an invalid definition', function () {
expect(() => mermaid.parse('this is not a mermaid diagram definition')).toThrow();
});

View File

@ -19,6 +19,9 @@ import { select } from 'd3';
import { compile, serialize, stringify } from 'stylis';
import pkg from '../package.json';
import * as configApi from './config';
import c4Db from './diagrams/c4/c4Db';
import c4Renderer from './diagrams/c4/c4Renderer';
import c4Parser from './diagrams/c4/parser/c4Diagram';
import classDb from './diagrams/class/classDb';
import classRenderer from './diagrams/class/classRenderer';
import classRendererV2 from './diagrams/class/classRenderer-v2';
@ -79,6 +82,11 @@ function parse(text) {
log.debug('Type ' + graphType);
switch (graphType) {
case 'c4':
c4Db.clear();
parser = c4Parser;
parser.parser.yy = c4Db;
break;
case 'gitGraph':
gitGraphAst.clear();
parser = gitGraphParser;
@ -409,6 +417,10 @@ const render = function (id, _txt, cb, container) {
try {
switch (graphType) {
case 'c4':
c4Renderer.setConf(cnf.c4);
c4Renderer.draw(txt, id);
break;
case 'gitGraph':
gitGraphRenderer.draw(txt, id, false);
break;
@ -630,7 +642,7 @@ const handleDirective = function (p, directive, type) {
/** @param {any} conf */
function updateRendererConfigs(conf) {
// Todo remove, all diagrams should get config on demoand from the config object, no need for this
// Todo remove, all diagrams should get config on demand from the config object, no need for this
flowRenderer.setConf(conf.flowchart);
flowRendererV2.setConf(conf.flowchart);

View File

@ -122,14 +122,14 @@ describe('when using mermaidAPI and ', function () {
});
describe('test mermaidApi.parse() for checking validity of input ', function () {
mermaid.parseError = undefined; // ensure it parseError undefined
it('it should throw for an invalid definiton (with no mermaid.parseError() defined)', function () {
it('it should throw for an invalid definition (with no mermaid.parseError() defined)', function () {
expect(mermaid.parseError).toEqual(undefined);
expect(() => mermaidAPI.parse('this is not a mermaid diagram definition')).toThrow();
});
it('it should not throw for a valid definiton', function () {
it('it should not throw for a valid definition', function () {
expect(() => mermaidAPI.parse('graph TD;A--x|text including URL space|B;')).not.toThrow();
});
it('it should return false for invalid definiton WITH a parseError() callback defined', function () {
it('it should return false for invalid definition WITH a parseError() callback defined', function () {
var parseErrorWasCalled = false;
// also test setParseErrorHandler() call working to set mermaid.parseError
mermaid.setParseErrorHandler(function (error, hash) {
@ -140,7 +140,7 @@ describe('when using mermaidAPI and ', function () {
expect(mermaidAPI.parse('this is not a mermaid diagram definition')).toEqual(false);
expect(parseErrorWasCalled).toEqual(true);
});
it('it should return true for valid definiton', function () {
it('it should return true for valid definition', function () {
expect(mermaidAPI.parse('graph TD;A--x|text including URL space|B;')).toEqual(true);
});
});

View File

@ -9,6 +9,7 @@ import requirement from './diagrams/requirement/styles';
import sequence from './diagrams/sequence/styles';
import stateDiagram from './diagrams/state/styles';
import journey from './diagrams/user-journey/styles';
import c4 from './diagrams/c4/styles';
const themes = {
flowchart,
@ -26,6 +27,7 @@ const themes = {
er,
journey,
requirement,
c4,
};
export const calcThemeVariables = (theme, userOverRides) => theme.calcColors(userOverRides);

View File

@ -1,96 +0,0 @@
g.classGroup text {
fill: $nodeBorder;
stroke: none;
font-family: 'trebuchet ms', verdana, arial;
font-family: var(--mermaid-font-family);
font-size: 10px;
.title {
font-weight: bolder;
}
}
.divider {
stroke: $nodeBorder;
stroke-width: 1;
}
g.clickable {
cursor: pointer;
}
g.classGroup rect {
fill: $nodeBkg;
stroke: $nodeBorder;
}
g.classGroup line {
stroke: $nodeBorder;
stroke-width: 1;
}
.classLabel .box {
stroke: none;
stroke-width: 0;
fill: $nodeBkg;
opacity: 0.5;
}
.classLabel .label {
fill: $nodeBorder;
font-size: 10px;
}
.relation {
stroke: $nodeBorder;
stroke-width: 1;
fill: none;
}
.dashed-line{
stroke-dasharray: 3;
}
@mixin composition {
fill: $nodeBorder !important ;
stroke: $nodeBorder !important ;
stroke-width: 1;
}
#compositionStart, .composition {
@include composition;
}
#compositionEnd, .composition {
@include composition;
}
@mixin aggregation {
fill: $nodeBkg !important ;
stroke: $nodeBorder !important ;
stroke-width: 1;
}
#aggregationStart, .aggregation {
@include aggregation;
}
#aggregationEnd, .aggregation {
@include aggregation;
}
#dependencyStart, .dependency {
@include composition;
}
#dependencyEnd, .dependency {
@include composition;
}
#extensionStart , .extension{
@include composition;
}
#extensionEnd, .extension {
@include composition;
}

View File

@ -1,67 +0,0 @@
$mainBkg: #1f2020;
$secondBkg: lighten(#1f2020, 16);
$mainContrastColor: lightgrey;
$darkTextColor: #fefefe;
$lineColor: $mainContrastColor;
$border1: #81B1DB;
$border2: rgba(255, 255, 255, 0.25);
$arrowheadColor: $mainContrastColor;
/* Flowchart variables */
$nodeBkg: $mainBkg;
$nodeBorder: $border1;
$clusterBkg: $secondBkg;
$clusterBorder: $border2;
$defaultLinkColor: $lineColor;
$titleColor: #F9FFFE;
$edgeLabelBackground: #e8e8e8;
$edgeLabelcolor: #333;
/* Sequence Diagram variables */
$actorBorder: $border1;
$actorBkg: $mainBkg;
$actorTextColor: $mainContrastColor;
$actorLineColor: $mainContrastColor;
$signalColor: $mainContrastColor;
$signalTextColor: $mainContrastColor;
$labelBoxBkgColor: $actorBkg;
$labelBoxBorderColor: $actorBorder;
$labelTextColor: $mainContrastColor;
$loopTextColor: $mainContrastColor;
$noteBorderColor: $border2;
$noteBkgColor: #fff5ad;
$noteTextColor: $mainBkg;
$activationBorderColor: $border1;
$activationBkgColor: $secondBkg;
$sequenceNumberColor: black;
/* Gantt chart variables */
$sectionBkgColor: rgba(255, 255, 255, 0.3);
$altSectionBkgColor: white;
$sectionBkgColor2: #EAE8B9;
$taskBorderColor: rgba(255, 255, 255, 0.5);
$taskBkgColor: $mainBkg;
$taskTextColor: $darkTextColor;
$taskTextLightColor: $mainContrastColor;
$taskTextOutsideColor: $taskTextLightColor;
$taskTextClickableColor: #003163;
$activeTaskBorderColor: rgba(255, 255, 255, 0.5);
$activeTaskBkgColor: #81B1DB;
$gridColor: $mainContrastColor;
$doneTaskBkgColor: $mainContrastColor;
$doneTaskBorderColor: grey;
$critBorderColor: #E83737;
$critBkgColor: #E83737;
$taskTextDarkColor: $darkTextColor;
$todayLineColor: #DB5757;
/* state colors */
$labelColor: #f4f4f4;
$errorBkgColor: #a44141;
$errorTextColor: #ddd;
@import '../mermaid';

View File

@ -1,65 +0,0 @@
$mainBkg: #ECECFF;
$secondBkg: #ffffde;
$lineColor: #333333;
$border1: #CCCCFF;
$border2: #aaaa33;
$arrowheadColor: #333333;
/* Flowchart variables */
$nodeBkg: $mainBkg;
$nodeBorder: #9370DB;
$clusterBkg: $secondBkg;
$clusterBorder: $border2;
$defaultLinkColor: $lineColor;
$titleColor: #333;
$edgeLabelBackground: #e8e8e8;
$edgeLabelcolor: #333;
/* Sequence Diagram variables */
$actorBorder: $border1;
$actorBkg: $mainBkg;
$actorTextColor: black;
$actorLineColor: grey;
$signalColor: #333;
$signalTextColor: #333;
$labelBoxBkgColor: $actorBkg;
$labelBoxBorderColor: $actorBorder;
$labelTextColor: $actorTextColor;
$loopTextColor: $actorTextColor;
$noteBorderColor: $border2;
$noteBkgColor: #fff5ad;
$noteTextColor: $actorTextColor;
$activationBorderColor: #666;
$activationBkgColor: #f4f4f4;
$sequenceNumberColor: white;
/* Gantt chart variables */
$sectionBkgColor: rgba(102, 102, 255, 0.49);
$altSectionBkgColor: white;
$sectionBkgColor2: #fff400;
$taskBorderColor: #534fbc;
$taskBkgColor: #8a90dd;
$taskTextLightColor: white;
$taskTextColor: $taskTextLightColor;
$taskTextDarkColor: black;
$taskTextOutsideColor: $taskTextDarkColor;
$taskTextClickableColor: #003163;
$activeTaskBorderColor: #534fbc;
$activeTaskBkgColor: #bfc7ff;
$gridColor: lightgrey;
$doneTaskBkgColor: lightgrey;
$doneTaskBorderColor: grey;
$critBorderColor: #ff8888;
$critBkgColor: red;
$todayLineColor: red;
/* state colors */
$labelColor: black;
$errorBkgColor: #552222;
$errorTextColor: #552222;
@import '../mermaid';

View File

@ -1,78 +0,0 @@
.label {
font-family: 'trebuchet ms', verdana, arial;
font-family: var(--mermaid-font-family);
fill: $titleColor;
color: $titleColor;
}
.label text {
fill: $titleColor;
}
.node rect,
.node circle,
.node ellipse,
.node polygon,
.node path {
fill: $mainBkg;
stroke: $nodeBorder;
stroke-width: 1px;
}
.node .label {
text-align: center;
fill: $titleColor;
}
.node.clickable {
cursor: pointer;
}
.arrowheadPath {
fill: $arrowheadColor;
}
.edgePath .path {
stroke: $lineColor;
stroke-width: 1.5px;
}
.flowchart-link {
stroke: $lineColor;
fill: none;
}
.edgeLabel {
background-color: $edgeLabelBackground;
rect {
opacity: 0.9;
}
text-align: center;
span {
color: $edgeLabelcolor;
}
}
.cluster rect {
fill: $secondBkg;
stroke: $clusterBorder;
stroke-width: 1px;
}
.cluster text {
fill: $titleColor;
}
div.mermaidTooltip {
position: absolute;
text-align: center;
max-width: 200px;
padding: 2px;
font-family: 'trebuchet ms', verdana, arial;
font-family: var(--mermaid-font-family);
font-size: 12px;
background: $secondBkg;
border: 1px solid $border2;
border-radius: 2px;
pointer-events: none;
z-index: 100;
}

View File

@ -1,65 +0,0 @@
$mainBkg: #cde498;
$secondBkg: #cdffb2;
$lineColor: #1a3318;
$lineColor: green;
$border1: #13540c;
$border2: #6eaa49;
$arrowheadColor: green;
/* Flowchart variables */
$nodeBkg: $mainBkg;
$nodeBorder: $border1;
$clusterBkg: $secondBkg;
$clusterBorder: $border2;
$defaultLinkColor: $lineColor;
$titleColor: #333;
$edgeLabelBackground: #e8e8e8;
$edgeLabelcolor: #333;
/* Sequence Diagram variables */
$actorBorder: $border1;
$actorBkg: $mainBkg;
$actorTextColor: black;
$actorLineColor: grey;
$signalColor: #333;
$signalTextColor: #333;
$labelBoxBkgColor: $actorBkg;
$labelBoxBorderColor: #326932;
$labelTextColor: $actorTextColor;
$loopTextColor: $actorTextColor;
$noteBorderColor: $border2;
$noteBkgColor: #fff5ad;
$noteTextColor: $actorTextColor;
$activationBorderColor: #666;
$activationBkgColor: #f4f4f4;
$sequenceNumberColor: white;
/* Gantt chart variables */
$sectionBkgColor: #6eaa49;
$altSectionBkgColor: white;
$sectionBkgColor2: #6eaa49;
$taskBorderColor: $border1;
$taskBkgColor: #487e3a;
$taskTextLightColor: white;
$taskTextColor: $taskTextLightColor;
$taskTextDarkColor: black;
$taskTextOutsideColor: $taskTextDarkColor;
$taskTextClickableColor: #003163;
$activeTaskBorderColor: $taskBorderColor;
$activeTaskBkgColor: $mainBkg;
$gridColor: lightgrey;
$doneTaskBkgColor: lightgrey;
$doneTaskBorderColor: grey;
$critBorderColor: #ff8888;
$critBkgColor: red;
$todayLineColor: red;
/* state colors */
$labelColor: black;
$errorBkgColor: #552222;
$errorTextColor: #552222;
@import '../mermaid';

View File

@ -1,258 +0,0 @@
/** Section styling */
.mermaid-main-font {
font-family: "trebuchet ms", verdana, arial;
font-family: var(--mermaid-font-family);
}
.section {
stroke: none;
opacity: 0.2;
}
.section0 {
fill: $sectionBkgColor;
}
.section2 {
fill: $sectionBkgColor2;
}
.section1,
.section3 {
fill: $altSectionBkgColor;
opacity: 0.2;
}
.sectionTitle0 {
fill: $titleColor;
}
.sectionTitle1 {
fill: $titleColor;
}
.sectionTitle2 {
fill: $titleColor;
}
.sectionTitle3 {
fill: $titleColor;
}
.sectionTitle {
text-anchor: start;
font-size: 11px;
text-height: 14px;
font-family: 'trebuchet ms', verdana, arial;
font-family: var(--mermaid-font-family);
}
/* Grid and axis */
.grid .tick {
stroke: $gridColor;
opacity: 0.8;
shape-rendering: crispEdges;
text {
font-family: 'trebuchet ms', verdana, arial;
font-family: var(--mermaid-font-family);
}
}
.grid path {
stroke-width: 0;
}
/* Today line */
.today {
fill: none;
stroke: $todayLineColor;
stroke-width: 2px;
}
/* Task styling */
/* Default task */
.task {
stroke-width: 2;
}
.taskText {
text-anchor: middle;
font-family: 'trebuchet ms', verdana, arial;
font-family: var(--mermaid-font-family);
}
.taskText:not([font-size]) {
font-size: 11px;
}
.taskTextOutsideRight {
fill: $taskTextDarkColor;
text-anchor: start;
font-size: 11px;
font-family: 'trebuchet ms', verdana, arial;
font-family: var(--mermaid-font-family);
}
.taskTextOutsideLeft {
fill: $taskTextDarkColor;
text-anchor: end;
font-size: 11px;
}
/* Special case clickable */
.task.clickable {
cursor: pointer;
}
.taskText.clickable {
cursor: pointer;
fill: $taskTextClickableColor !important;
font-weight: bold;
}
.taskTextOutsideLeft.clickable {
cursor: pointer;
fill: $taskTextClickableColor !important;
font-weight: bold;
}
.taskTextOutsideRight.clickable {
cursor: pointer;
fill: $taskTextClickableColor !important;
font-weight: bold;
}
/* Specific task settings for the sections*/
.taskText0,
.taskText1,
.taskText2,
.taskText3 {
fill: $taskTextColor;
}
.task0,
.task1,
.task2,
.task3 {
fill: $taskBkgColor;
stroke: $taskBorderColor;
}
.taskTextOutside0,
.taskTextOutside2
{
fill: $taskTextOutsideColor;
}
.taskTextOutside1,
.taskTextOutside3 {
fill: $taskTextOutsideColor;
}
/* Active task */
.active0,
.active1,
.active2,
.active3 {
fill: $activeTaskBkgColor;
stroke: $activeTaskBorderColor;
}
.activeText0,
.activeText1,
.activeText2,
.activeText3 {
fill: $taskTextDarkColor !important;
}
/* Completed task */
.done0,
.done1,
.done2,
.done3 {
stroke: $doneTaskBorderColor;
fill: $doneTaskBkgColor;
stroke-width: 2;
}
.doneText0,
.doneText1,
.doneText2,
.doneText3 {
fill: $taskTextDarkColor !important;
}
/* Tasks on the critical line */
.crit0,
.crit1,
.crit2,
.crit3 {
stroke: $critBorderColor;
fill: $critBkgColor;
stroke-width: 2;
}
.activeCrit0,
.activeCrit1,
.activeCrit2,
.activeCrit3 {
stroke: $critBorderColor;
fill: $activeTaskBkgColor;
stroke-width: 2;
}
.doneCrit0,
.doneCrit1,
.doneCrit2,
.doneCrit3 {
stroke: $critBorderColor;
fill: $doneTaskBkgColor;
stroke-width: 2;
cursor: pointer;
shape-rendering: crispEdges;
}
.milestone {
transform: rotate(45deg) scale(0.8,0.8);
}
.milestoneText {
font-style: italic;
}
.doneCritText0,
.doneCritText1,
.doneCritText2,
.doneCritText3 {
fill: $taskTextDarkColor !important;
}
.activeCritText0,
.activeCritText1,
.activeCritText2,
.activeCritText3 {
fill: $taskTextDarkColor !important;
}
.titleText {
text-anchor: middle;
font-size: 18px;
fill: $taskTextDarkColor;
font-family: 'trebuchet ms', verdana, arial;
font-family: var(--mermaid-font-family);
}

View File

@ -1,8 +0,0 @@
.commit-id,
.commit-msg,
.branch-label {
fill: lightgrey;
color: lightgrey;
font-family: 'trebuchet ms', verdana, arial;
font-family: var(--mermaid-font-family);
}

View File

@ -1,60 +0,0 @@
// @import 'flowchart';
@import 'sequence';
@import 'gantt';
@import 'class';
@import 'git';
@import 'pie';
@import 'state';
// .composit {
// fill: white;
// border-bottom: 1px
// }
:root {
--mermaid-font-family: '"trebuchet ms", verdana, arial';
font-family: '"trebuchet ms", verdana, arial';
font-family: var(--mermaid-font-family);
font-size: 16px;
}
/* Classes common for multiple diagrams */
.error-icon {
fill: $errorBkgColor;
}
.error-text {
fill: $errorTextColor;
stroke: $errorTextColor;
}
.edge-thickness-normal {
// stroke: $lineColor;
stroke-width: 2px;
}
.edge-thickness-thick {
// stroke: $lineColor;
stroke-width: 3.5px
}
.edge-pattern-solid {
stroke-dasharray: 0;
}
.edge-pattern-dashed{
stroke-dasharray: 3;
}
.edge-pattern-dotted {
stroke-dasharray: 2;
}
.marker {
fill: $lineColor;
}
.marker.cross {
stroke: $lineColor;
}
svg {
font-family: var(--mermaid-font-family);
font-size: 24px;
}

View File

@ -1,70 +0,0 @@
$mainBkg: #eee;
$contrast: #26a;
$secondBkg: lighten($contrast, 55%);
$lineColor: #666;
$border1: #999;
$border2: $contrast;
$note: #ffa;
$text: #333;
$critical: #d42;
$done: #bbb;
$arrowheadColor: #333333;
/* Flowchart variables */
$nodeBkg: $mainBkg;
$nodeBorder: $border1;
$clusterBkg: $secondBkg;
$clusterBorder: $border2;
$defaultLinkColor: $lineColor;
$titleColor: $text;
$edgeLabelBackground: white;
$edgeLabelcolor: #333;
/* Sequence Diagram variables */
$actorBorder: $border1;
$actorBkg: $mainBkg;
$actorTextColor: $text;
$actorLineColor: $lineColor;
$signalColor: $text;
$signalTextColor: $text;
$labelBoxBkgColor: $actorBkg;
$labelBoxBorderColor: $actorBorder;
$labelTextColor: $text;
$loopTextColor: $text;
$noteBorderColor: darken($note, 60%);
$noteBkgColor: $note;
$noteTextColor: $actorTextColor;
$activationBorderColor: #666;
$activationBkgColor: #f4f4f4;
$sequenceNumberColor: white;
/* Gantt chart variables */
$sectionBkgColor: lighten($contrast, 30%);
$altSectionBkgColor: white;
$sectionBkgColor2: lighten($contrast, 30%);
$taskBorderColor: darken($contrast, 10%);
$taskBkgColor: $contrast;
$taskTextLightColor: white;
$taskTextColor: $taskTextLightColor;
$taskTextDarkColor: $text;
$taskTextOutsideColor: $taskTextDarkColor;
$taskTextClickableColor: #003163;
$activeTaskBorderColor: $taskBorderColor;
$activeTaskBkgColor: $mainBkg;
$gridColor: lighten($border1, 30%);
$doneTaskBkgColor: $done;
$doneTaskBorderColor: $lineColor;
$critBkgColor: $critical;
$critBorderColor: darken($critBkgColor, 10%);
$todayLineColor: $critBkgColor;
/* state colors */
$labelColor: black;
$errorBkgColor: #552222;
$errorTextColor: #552222;
@import '../mermaid';

View File

@ -1,16 +0,0 @@
.pieTitleText {
text-anchor: middle;
font-size: 25px;
fill: $taskTextDarkColor;
font-family: 'trebuchet ms', verdana, arial;
font-family: var(--mermaid-font-family);
}
.slice {
font-family: 'trebuchet ms', verdana, arial;
font-family: var(--mermaid-font-family);
}
.legend text {
font-family: 'trebuchet ms', verdana, arial;
font-family: var(--mermaid-font-family);
font-size: 17px;
}

View File

@ -1,96 +0,0 @@
.actor {
stroke: $actorBorder;
fill: $actorBkg;
}
text.actor > tspan {
fill: $actorTextColor;
stroke: none;
}
.actor-line {
stroke: $actorLineColor;
}
.messageLine0 {
stroke-width: 1.5;
stroke-dasharray: none;
stroke: $signalColor;
}
.messageLine1 {
stroke-width: 1.5;
stroke-dasharray: 2, 2;
stroke: $signalColor;
}
#arrowhead path {
fill: $signalColor;
stroke: $signalColor;
}
.sequenceNumber {
fill: $sequenceNumberColor;
}
#sequencenumber {
fill: $signalColor;
}
#crosshead path {
fill: $signalColor;
stroke: $signalColor;
}
.messageText {
fill: $signalTextColor;
stroke: $signalTextColor;
}
.labelBox {
stroke: $labelBoxBorderColor;
fill: $labelBoxBkgColor;
}
.labelText, .labelText > tspan {
fill: $labelTextColor;
stroke: none;
}
.loopText, .loopText > tspan {
fill: $loopTextColor;
stroke: none;
}
.loopLine {
stroke-width: 2px;
stroke-dasharray: 2, 2;
stroke: $labelBoxBorderColor;
fill: $labelBoxBorderColor;
}
.note {
//stroke: #decc93;
stroke: $noteBorderColor;
fill: $noteBkgColor;
}
.noteText, .noteText > tspan {
fill: $noteTextColor;
stroke: none;
}
.activation0 {
fill: $activationBkgColor;
stroke: $activationBorderColor;
}
.activation1 {
fill: $activationBkgColor;
stroke: $activationBorderColor;
}
.activation2 {
fill: $activationBkgColor;
stroke: $activationBorderColor;
}

View File

@ -1,140 +0,0 @@
g.stateGroup text {
fill: $nodeBorder;
stroke: none;
font-size: 10px;
font-family: 'trebuchet ms', verdana, arial;
font-family: var(--mermaid-font-family);
}
g.stateGroup text {
fill: $nodeBorder;
fill: $titleColor;
stroke: none;
font-size: 10px;
}
g.statediagram-cluster .cluster-label text {
fill: $titleColor;
}
g.stateGroup .state-title {
font-weight: bolder;
fill: $labelColor;
}
g.stateGroup rect {
fill: $nodeBkg;
stroke: $nodeBorder;
}
g.stateGroup line {
stroke: $nodeBorder;
stroke-width: 1;
}
.transition {
stroke: $nodeBorder;
stroke-width: 1;
fill: none;
}
.stateGroup .composit {
fill: white;
border-bottom: 1px
}
.stateGroup .alt-composit {
fill: #e0e0e0;
border-bottom: 1px
}
.state-note {
stroke: $noteBorderColor;
fill: $noteBkgColor;
text {
fill: black;
stroke: none;
font-size: 10px;
}
}
.stateLabel .box {
stroke: none;
stroke-width: 0;
fill: $nodeBkg;
opacity: 0.7;
}
.edgeLabel text {
fill: #333;
}
.stateLabel text {
fill: $labelColor;
font-size: 10px;
font-weight: bold;
font-family: 'trebuchet ms', verdana, arial;
font-family: var(--mermaid-font-family);
}
.node circle.state-start {
fill: black;
stroke: black;
}
.node circle.state-end {
fill: black;
stroke: white;
stroke-width: 1.5
}
#statediagram-barbEnd {
fill: $nodeBorder
}
.statediagram-cluster rect {
// fill: $nodeBkg;
stroke: $nodeBorder;
stroke-width: 1px;
}
.statediagram-cluster rect.outer {
rx: 5px;
ry: 5px;
}
.statediagram-state .divider {
stroke: $nodeBorder;
}
.statediagram-state .title-state {
rx: 5px;
ry: 5px;
}
.statediagram-cluster.statediagram-cluster .inner {
fill: white;
}
.statediagram-cluster.statediagram-cluster-alt .inner {
fill: #e0e0e0;
}
.statediagram-cluster .inner {
rx:0;
ry:0;
}
.statediagram-state rect.basic {
rx: 5px;
ry: 5px;
}
.statediagram-state rect.divider {
stroke-dasharray: 10,10;
fill: #efefef;
}
.note-edge {
stroke-dasharray: 5;
}
.statediagram-note rect {
fill: $noteBkgColor;
stroke: $noteBorderColor;
stroke-width: 1px;
rx: 0;
ry: 0;
}

View File

@ -95,6 +95,11 @@ class Theme {
this.taskTextDarkColor = this.taskTextDarkColor || this.textColor;
this.taskTextClickableColor = this.taskTextClickableColor || '#003163';
/* Sequence Diagram variables */
this.personBorder = this.personBorder || this.primaryBorderColor;
this.personBkg = this.personBkg || this.mainBkg;
/* state colors */
this.transitionColor = this.transitionColor || this.lineColor;
this.transitionLabelColor = this.transitionLabelColor || this.textColor;

View File

@ -78,6 +78,11 @@ class Theme {
this.taskTextDarkColor = 'calculated';
this.todayLineColor = '#DB5757';
/* C4 Context Diagram variables */
this.personBorder = 'calculated';
this.personBkg = 'calculated';
/* state colors */
this.labelColor = 'calculated';

View File

@ -103,6 +103,11 @@ class Theme {
this.critBkgColor = 'red';
this.todayLineColor = 'red';
/* C4 Context Diagram variables */
this.personBorder = 'calculated';
this.personBkg = 'calculated';
/* state colors */
this.labelColor = 'black';
this.errorBkgColor = '#552222';

View File

@ -76,6 +76,11 @@ class Theme {
this.critBkgColor = 'red';
this.todayLineColor = 'red';
/* C4 Context Diagram variables */
this.personBorder = 'calculated';
this.personBkg = 'calculated';
/* state colors */
this.labelColor = 'black';

View File

@ -89,6 +89,11 @@ class Theme {
this.critBorderColor = 'calculated';
this.todayLineColor = 'calculated';
/* C4 Context Diagram variables */
this.personBorder = 'calculated';
this.personBkg = 'calculated';
/* state colors */
this.labelColor = 'black';

View File

@ -185,6 +185,10 @@ export const detectDirective = function (text, type = null) {
*/
export const detectType = function (text, cnf) {
text = text.replace(directive, '').replace(anyComment, '\n');
if (text.match(/^\s*C4Context|C4Container|C4Component|C4Dynamic|C4Deployment/)) {
return 'c4';
}
if (text.match(/^\s*sequenceDiagram/)) {
return 'sequence';
}
@ -915,6 +919,52 @@ export const configureSvgSize = function (svgElem, height, width, useMaxWidth) {
const attrs = calculateSvgSizeAttrs(height, width, useMaxWidth);
d3Attrs(svgElem, attrs);
};
export const setupGraphViewbox = function (graph, svgElem, padding, useMaxWidth) {
const svgBounds = svgElem.node().getBBox();
const sWidth = svgBounds.width;
const sHeight = svgBounds.height;
let width = graph._label.width;
let height = graph._label.height;
let tx = 0;
let ty = 0;
if (sWidth > width) {
tx = (sWidth - width) / 2 + padding;
width = sWidth + padding * 2;
} else {
if (Math.abs(sWidth - width) >= 2 * padding + 1) {
width = width - padding;
}
}
if (sHeight > height) {
ty = (sHeight - height) / 2 + padding;
height = sHeight + padding * 2;
}
configureSvgSize(svgElem, height, width, useMaxWidth);
// Ensure the viewBox includes the whole svgBounds area with extra space for padding
const vBox = `0 0 ${width} ${height}`;
log.debug(
'Grpah.label',
graph._label,
'swidth',
sWidth,
'sheight',
sHeight,
'width',
width,
'height',
height,
'tx',
tx,
'ty',
ty,
'vBox',
vBox
);
svgElem.attr('viewBox', vBox);
svgElem.select('g').attr('transform', `translate(${tx}, ${ty})`);
};
export const initIdGeneratior = class iterator {
constructor(deterministic, seed) {
@ -1014,6 +1064,7 @@ export default {
calculateTextDimensions,
calculateSvgSizeAttrs,
configureSvgSize,
setupGraphViewbox,
detectInit,
detectDirective,
detectType,

1352
yarn.lock

File diff suppressed because it is too large Load Diff